Electronic invoices
Factura, boleta, nota de crédito, nota de débito
UBL 2.1 documents, XAdES-BES signatures, SOAP straight to SUNAT. Verified end to end against the beta endpoint.
$ sunat-cli cpe factura emit \
--params @factura.json --yesPeru's tax authority exposes ten different surfaces: SOAP with signed XML, REST with OAuth, a ticket queue, a resumable upload, a legacy inbox, a JSON API, and a stateful HTTP form session. This wraps them in one supervised agent-facing binary.
npm install -g @crafter/sunat-cli# Install once. Runs on Node.
$ npm install -g @crafter/sunat-cli
# Ask what is present, and what each gap needs
$ sunat-cli doctor
ready · agent-browser · node · config
# Ask what a command accepts. Versioned, so pin it.
$ sunat-cli schema cpe-factura
{ "version": "1.0.0", "command": "cpe factura emit" }
# Preview returns the real shape, plus a hash
$ sunat-cli cpe factura preview --params @f.json
{ "dryRun": true, "validacion": { "ok": true } }
# Commit. UBL 2.1, XAdES, SOAP, end to end.
$ sunat-cli cpe factura emit --params @f.json --yes
Aceptado · CDR 0000 · F001-1234Factura, boleta, nota de crédito, nota de débito
UBL 2.1 documents, XAdES-BES signatures, SOAP straight to SUNAT. Verified end to end against the beta endpoint.
$ sunat-cli cpe factura emit \
--params @factura.json --yesGRE remitente, modal 02
REST with JWT. The tracker is idempotent, so a retry after a timeout resolves the original submission instead of duplicating it.
$ sunat-cli cpe gre emit \
--params @guia.json --yesSIRE RVIE and RCE
Pull the proposal, poll the ticket, download the ZIP, push corrections back through a TUS 1.0.0 upload.
$ sunat-cli sire rvie propuesta \
--periodo 202504 --yesResumen diario, comunicación de baja
Boletas under S/700 batch into one daily summary. Voids carry the same ticket-polling contract.
$ sunat-cli cpe resumen send \
--fecha 2026-04-29 --yesRHE and F616
For RHE, the browser obtains the SOL entry, HTTP reaches the draft, the legal confirmation stays supervised, and XML/PDF download is wired for validation on the next real issuance. F616 keeps its headless API read path.
$ sunat-cli rhe emit \
--params '{"empresa":"Client","descripcion":"Service","monto":100}' --preview-onlyPadrón RUC, consulta CPE, tipo de cambio
OAuth2 client credentials against the public REST surface. The padrón syncs incrementally so a local lookup answers in under a millisecond.
$ sunat-cli api consulta \
--tipo 01 --serie F001 --numero 123Messages and notifications, metadata only
Lists without opening detail, preserves contradictory counts as evidence, and detects changes with a private local snapshot.
$ sunat-cli buzon listCertificate passwords, clave SOL
A hidden prompt writes to the macOS or Linux keychain, which keeps the value out of shell history, environment variables, and the process table.
$ sunat-cli keychain set CPE_CERT_PASSWORD25+ versioned schemas
An agent asks the binary what a command accepts instead of guessing field names. The version is part of the response, so a caller can pin it.
$ sunat-cli schema cpe-facturaThe F616 declaration page looks like a form. It is a single-page app talking to a JSON API, and the form fields are the least reliable way to reach it.
RHE is different: Menu SOL mints an ephemeral entry and the backend returns HTML. The CLI uses HTTP for deduction, identity, and details, renders the draft again, reserves DOM automation for the legal confirmation, and wires XML/PDF through endpoints after issuance.
Open SOL and obtain the entry or token required by the official surface.
Call the API or form session and validate the server's real response.
For RHE, keep the legal action under human control, then validate and save artifacts only when SUNAT returns real XML/PDF bytes.
Percentages are a judgement about how much of each surface is wrapped and callable by an agent. The Buzón SOL metadata reader was verified with an own production account. Tax submissions remain beta.
| Surface | Wrapped | % | State |
|---|---|---|---|
| REST lookupsConsulta CPE, padrón, tipo de cambio | 90 | shipped | |
| RHE and F616Supervised RHE; XML/PDF wired, live pending | 85 | partial | |
| Buzón SOLMetadata, snapshot and changes | 45 | partial | |
| InvoicesFactura, boleta, NC, ND | 85 | shipped | |
| Daily summary and voidResumen diario, comunicación de baja | 80 | shipped | |
| SIRERVIE ventas and RCE compras | 70 | partial | |
| Shipping noticesModal 02 only, transportista pending | 50 | partial | |
| Drivers2 of 5: mock and sunat-direct | 40 | partial | |
| Void with intent tokenShaped, not built | 30 | planned | |
| Production submissionsNever run against live credentials | 10 | untested |
An agent will get a field name wrong, retry a call that already succeeded, and read past an error it should have stopped on. Each rule below exists because one of those failures is cheap to prevent and expensive to undo when the other end is a tax authority.