🆕 Novedades SUNAT 2026
- Código de Producto SUNAT (Catálogo N°25 · UNSPSC). Desde el 01/08/2026 (RS 000048-2026) SUNAT valida el código de producto para bienes sujetos a percepción (combustibles, cemento, cerveza/gaseosas, trigo, etc.). Si vendes esos bienes, envía el campo
codigo_producto_sunaten cada ítem con el código UNSPSC correcto; de lo contrario el comprobante puede ser rechazado. Para el resto de productos es opcional. Se emite en el UBL comocbc:ItemClassificationCode. Revisa el detalle de códigos. - Varios locales: código de establecimiento. Si emites desde un local anexo, manda su código de la ficha RUC en
"establecimiento"(por ejemplo"0001"). Si no lo mandas, sale0000(domicilio fiscal) como siempre. Ver ejemplo. - Guías de Remisión Electrónica (GRE). Nuevas reglas de validación SUNAT 2026 ya soportadas por AstosCPE. Envío por JSON con
POST /api/v1/gre.
💡 En simple (para todos)
Piensa en AstosCPE como un courier de documentos para SUNAT. Tú le entregas el "paquete" (el comprobante), y nosotros nos encargamos de sellarlo (firma digital) y llevarlo a SUNAT, y te devolvemos la constancia (CDR) de que SUNAT lo aceptó.
No necesitas saber nada de SUNAT ni de SOAP. Tu sistema solo hace una petición por internet (un POST) y listo. Si no programas, puedes pasarle esta página a tu desarrollador o escribirnos por WhatsApp y te ayudamos a conectar.
¿Cómo funciona el flujo?
Cómo empezar (3 pasos)
Registramos tu empresa
Con tu RUC, razón social y el modo de envío. El más común es FIRMAPSE: nosotros ponemos el certificado y firmamos por ti (no necesitas certificado propio).
Te damos tus llaves de acceso
Una X-Api-Key y una
X-Api-Secret. Son como el usuario y la contraseña de tu sistema.
El secret se muestra una sola vez, guárdalo bien.
X-Ambiente: produccion:
puedes equivocarte sin miedo, nada sale a nombre de tu empresa. Cuando tu sistema (o tu Excel) ya emite bien, nos avisas y
la pasamos a producción; es la misma llave, no cambias nada en tu código.
Tu sistema empieza a enviar
Haces un POST con el XML del comprobante. Te respondemos con el estado y la constancia (CDR) de SUNAT.
X-Ambiente: beta para
pruebas (no afecta nada real) y produccion para envíos de verdad.
Con una llave de pruebas el servidor usa beta siempre, mandes lo que mandes. Las guías (GRE), SIRE, buzón SOL, T-Registro
y la descarga de comprobantes de SUNAT trabajan con SUNAT real (no tienen beta), así que con la llave de pruebas responden 403.
422) y solo ves tus propios comprobantes. La clave SOL y el
certificado digital no se cambian con la llave: se actualizan con nosotros, así una llave que se filtre no puede tocarlos.
Límites: 120 peticiones por minuto por llave y, en la consulta de DNI/RUC, 20 por minuto y 1.000 al día.
Si te pasas responde 429: espera el tiempo de la cabecera Retry-After y reintenta.
Si emites desde un servidor con IP fija, pídenos limitar la llave a esa IP. Desde un Excel en una PC de oficina normalmente no conviene (la IP cambia).
⚡ Conéctate en 5 minutos
Elige tu lenguaje y copia el código. Es el mismo ejemplo en todos: envía una boleta y muestra la respuesta de SUNAT.
Solo necesitas cambiar TU_API_KEY y TU_API_SECRET.
?sync=1 esperas la respuesta de SUNAT en la misma llamada
(2–6 s); sin él te responde al instante y consultas después.
curl -X POST "https://e-sunat.astos.pe/api/v1/comprobantes?sync=1" \
-H "X-Api-Key: TU_API_KEY" \
-H "X-Api-Secret: TU_API_SECRET" \
-H "Content-Type: application/json" \
-d '{
"tipo": "03",
"serie": "B001",
"numero": 1,
"moneda": "PEN",
"cliente": { "tipo_doc": "1", "num_doc": "00000000", "razon_social": "CLIENTE FINAL" },
"items": [
{ "cantidad": 1, "unidad": "NIU", "descripcion": "PRODUCTO DE PRUEBA",
"codigo": "P001", "precio_unitario": 50, "afectacion": "10" }
]
}'
✅ Si todo salió bien
{
"comprobante_id": 12345,
"estado": "aceptado",
"sunat_codigo": "0",
"sunat_descripcion": "La Boleta B001-1 ha sido aceptada",
"serie_numero": "B001-00000001"
}
❌ Si hay un dato mal
{
"error": "VALIDACION_LOCAL",
"mensaje": "El comprobante tiene errores...",
"errores": [{
"campo": "cliente.numero_doc",
"mensaje": "El DNI debe tener 8 digitos.",
"recomendacion": "Corrige el DNI a 8 digitos."
}]
}
Lo frenamos antes de mandarlo a SUNAT: no se quema el correlativo. Lee siempre errores[], ahí está qué corregir.
🧪 Prueba tus credenciales antes de programar nada
curl "https://e-sunat.astos.pe/api/v1/auth/check" -H "X-Api-Key: TU_API_KEY" -H "X-Api-Secret: TU_API_SECRET"
Si responde con los datos de tu empresa, ya estás conectado. Si no, el problema son las llaves — no tu código.
📑 Enviar facturas, boletas y notas
Todas usan el mismo endpoint. El sistema detecta el tipo leyendo el XML.
Agrega ?sync=true si quieres recibir el CDR en la misma respuesta (ideal para caja/POS).
Lo que envías
- Headers:
X-Api-Key,X-Api-Secret,Content-Type. - El XML del comprobante (en el cuerpo de la petición). Puede ir sin firmar (lo firmamos nosotros) o ya firmado (solo lo reenviamos a SUNAT — se detecta solo).
▶ Ejemplo: cURL (línea de comandos)
curl -X POST "https://e-sunat.astos.pe/api/v1/comprobantes?sync=true" \ -H "X-Api-Key: TU_API_KEY" \ -H "X-Api-Secret: TU_API_SECRET" \ -H "X-Ambiente: produccion" \ -H "Content-Type: application/xml" \ --data-binary @factura.xml
▶ Ejemplo: Java
String xml = Files.readString(Path.of("factura.xml"));
HttpRequest req = HttpRequest.newBuilder()
.uri(URI.create("https://e-sunat.astos.pe/api/v1/comprobantes?sync=true"))
.header("X-Api-Key", "TU_API_KEY")
.header("X-Api-Secret", "TU_API_SECRET")
.header("X-Ambiente", "produccion")
.header("Content-Type", "application/xml")
.POST(HttpRequest.BodyPublishers.ofString(xml))
.build();
var res = HttpClient.newHttpClient().send(req, HttpResponse.BodyHandlers.ofString());
System.out.println(res.statusCode() + " -> " + res.body());
▶ Ejemplo: Excel (VBA)
Sub Enviar()
Dim http As Object: Set http = CreateObject("MSXML2.ServerXMLHTTP.6.0")
http.Open "POST", "https://e-sunat.astos.pe/api/v1/comprobantes?sync=true", False
http.setRequestHeader "X-Api-Key", "TU_API_KEY"
http.setRequestHeader "X-Api-Secret", "TU_API_SECRET"
http.setRequestHeader "X-Ambiente", "produccion"
http.setRequestHeader "Content-Type", "application/xml"
http.send Range("A1").Value ' el XML
MsgBox http.Status & " - " & http.responseText
End Sub
▶ Ejemplo: PHP
$ch = curl_init("https://e-sunat.astos.pe/api/v1/comprobantes?sync=true");
curl_setopt_array($ch, [
CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
"X-Api-Key: TU_API_KEY", "X-Api-Secret: TU_API_SECRET",
"X-Ambiente: produccion", "Content-Type: application/xml",
],
CURLOPT_POSTFIELDS => file_get_contents("factura.xml"),
]);
echo curl_exec($ch);
Lo que te respondemos
Con ?sync=true recibes el CDR al instante:
{
"comprobante_id": 1234,
"serie_numero": "F001-00000123",
"estado": "aceptado",
"sunat_descripcion": "La Factura F001-00000123 ha sido aceptada",
"cdr_base64": "UEsDBBQAAAAIA...",
"cdr_disponible": true
}
Sin ?sync recibes un 202 y consultas luego el estado en
GET /api/v1/comprobantes/{id}.
La consulta GET /api/v1/comprobantes/{id} tambien devuelve hash_cpe (resumen del documento firmado), hash_cdr (resumen del CDR) y — para guias (GRE) — qr_link: la URL del codigo QR de SUNAT que va en la representacion impresa.
✨ Comprobantes por JSON (e-sunat arma el XML)
Manda JSON a POST https://e-sunat.astos.pe/api/v1/comprobantes con headers X-Api-Key, X-Api-Secret, Content-Type: application/json y (opcional) ?sync=true para recibir el CDR en la misma respuesta. e-sunat firma y envia a SUNAT. El emisor sale de tu API key.
Tambien puedes seguir mandando el XML directo (modo clasico) si tu sistema ya lo arma. El XML soporta cualquier caso (ISC, descuentos globales, percepcion, anticipos...).
▶ Factura / Boleta
Lo mas comun. Cambia "tipo" entre 01 (factura) y 03 (boleta).
{
"tipo": "01", // 01=Factura, 03=Boleta
"serie": "F001", "numero": 1, "moneda": "PEN", "forma_pago": "Contado",
"establecimiento": "0000", // opcional: codigo del local anexo de tu ficha RUC (0000 = domicilio fiscal)
"cliente": { "tipo_doc": "6", "num_doc": "20131312955", "razon_social": "CLIENTE SAC", "direccion": "AV X 123" },
"items": [
{ "cantidad": 2, "unidad": "NIU", "descripcion": "PRODUCTO", "codigo": "P001", "precio_unitario": 50, "afectacion": "10", "codigo_producto_sunat": "" }
]
}
// afectacion: 10=gravado, 20=exonerado, 30=inafecto, 11-17=gratis gravada, 21/31=gratis exon/inaf
// precio_unitario = valor SIN IGV. El IGV 18%, totales y leyenda se calculan solos. Emisor = tu API key.
// codigo_producto_sunat (opcional): codigo UNSPSC cat.25. Se emite como cbc:ItemClassificationCode.
// OBLIGATORIO para bienes de percepcion desde el 01/08/2026 (RS 000048-2026); opcional para el resto.
// igv (opcional): IGV ya calculado de la linea (solo si manejas precios con IGV incluido y quieres total exacto).
▶ Boleta (consumidor final)
Cliente con DNI.
{
"tipo": "03", "serie": "B001", "numero": 1, "moneda": "PEN", "forma_pago": "Contado",
"cliente": { "tipo_doc": "1", "num_doc": "12345678", "razon_social": "CLIENTE FINAL" },
"items": [ { "cantidad": 1, "unidad": "NIU", "descripcion": "PRODUCTO", "codigo": "P1", "precio_unitario": 50, "afectacion": "10" } ]
}
// Boleta: cliente con DNI (tipo_doc 1). Para consumidor final puedes usar num_doc "00000000".
▶ Emitir desde un local anexo (varios locales)
Si tu empresa vende en más de un local, cada local tiene un código de establecimiento anexo de 4 dígitos en tu ficha RUC (Consulta RUC → "Establecimientos anexos"). Mándalo en "establecimiento" para que SUNAT registre desde qué local se emitió. Sirve para facturas, boletas y notas de crédito/débito.
{
"tipo": "03", "serie": "B002", "numero": 15, "moneda": "PEN", "forma_pago": "Contado",
"establecimiento": "0001", // local anexo 0001 de tu ficha RUC
"cliente": { "tipo_doc": "1", "num_doc": "12345678", "razon_social": "CLIENTE FINAL" },
"items": [ { "cantidad": 1, "unidad": "NIU", "descripcion": "PRODUCTO", "codigo": "P1", "precio_unitario": 50, "afectacion": "10" } ]
}
// Opcional. Si no lo mandas sale 0000 (domicilio fiscal), igual que siempre: no tienes que cambiar nada si tienes un solo local.
// Tambien se acepta dentro de "emisor": { "establecimiento": "0001" }. "1" se completa a "0001".
// Si no es numerico respondemos 422 ESTABLECIMIENTO_INVALIDO y no se usa tu correlativo.
// Usa SOLO codigos que existan en tu ficha RUC: un codigo inventado puede ser observado o rechazado por SUNAT.
// Consejo: una serie por local (B001 en el principal, B002 en el anexo 0001...).
// Modo XML: si armas tu propio XML, el codigo va en cac:RegistrationAddress/cbc:AddressTypeCode del emisor.
▶ Factura con DETRACCION (servicios)
Igual que una factura pero agregas el bloque "detraccion".
{
"tipo": "01", "serie": "F001", "numero": 2, "moneda": "PEN", "forma_pago": "Contado",
"detraccion": {
"codigo_bien_servicio": "037", // catalogo 54 (037=demas servicios, 022=otros serv. empresariales, 019=arrendamiento...)
"porcentaje": 12, // % de detraccion
"cuenta_bn": "00-123-456789" // cuenta del Banco de la Nacion
},
"cliente": { "tipo_doc": "6", "num_doc": "20131312955", "razon_social": "CLIENTE SAC", "direccion": "AV X 1" },
"items": [ { "cantidad": 1, "unidad": "ZZ", "descripcion": "SERVICIO DE CONSULTORIA", "codigo": "S1", "precio_unitario": 1000, "afectacion": "10" } ]
}
// Solo agregas el bloque "detraccion". El monto (total x %) y la operacion sujeta a detraccion se arman solos. Total minimo S/700.
▶ Nota de Credito (07)
Referencia al documento que corrige/anula + motivo.
{
"tipo": "07", // Nota de Credito
"serie": "FC01", "numero": 1, "moneda": "PEN",
"doc_afectado": { "tipo": "01", "serie_numero": "F001-00000001" },
"motivo_codigo": "01", // catalogo 09: 01=anulacion, 03=correccion, 07=devolucion...
"motivo_desc": "ANULACION DE LA OPERACION",
"cliente": { "tipo_doc": "6", "num_doc": "20131312955", "razon_social": "CLIENTE SAC", "direccion": "AV X 1" },
"items": [ { "cantidad": 2, "unidad": "NIU", "descripcion": "PRODUCTO", "codigo": "P001", "precio_unitario": 50, "afectacion": "10" } ]
}
▶ Nota de Debito (08)
Igual que NC pero para aumentar el valor.
{
"tipo": "08", // Nota de Debito
"serie": "FD01", "numero": 1, "moneda": "PEN",
"doc_afectado": { "tipo": "01", "serie_numero": "F001-00000001" },
"motivo_codigo": "02", // catalogo 10: 01=intereses mora, 02=aumento de valor, 03=penalidad
"motivo_desc": "AUMENTO EN EL VALOR",
"cliente": { "tipo_doc": "6", "num_doc": "20131312955", "razon_social": "CLIENTE SAC", "direccion": "AV X 1" },
"items": [ { "cantidad": 1, "unidad": "NIU", "descripcion": "AJUSTE", "codigo": "AJ1", "precio_unitario": 10, "afectacion": "10" } ]
}
▶ Resumen diario de boletas (RC)
Lote de boletas. Es asincrono: la respuesta trae un comprobante_id; consulta el estado con GET /api/v1/comprobantes/{id}.
{
"tipo": "RC", // Resumen diario de boletas (asincrono: devuelve ticket)
"correlativo": 1,
"fecha_referencia": "2026-06-01", // fecha de emision de las boletas
"fecha_generacion": "2026-06-02", // fecha de envio del resumen
"boletas": [
{ "doc_tipo": "03", "serie_numero": "B001-00000010", "cliente_tipo": "1", "cliente_num": "12345678",
"estado": "1", // 1=adicionar, 2=modificar, 3=anular
"total": 118.00, "gravado": 100.00, "igv": 18.00 }
]
}
▶ Comunicacion de baja (RA)
Anula facturas/notas ya emitidas. Asincrono.
{
"tipo": "RA", // Comunicacion de baja (anular facturas/notas; asincrono)
"correlativo": 1,
"fecha_referencia": "2026-06-01", // fecha de emision del documento a dar de baja
"fecha_generacion": "2026-06-02",
"documentos": [
{ "doc_tipo": "01", "serie": "F001", "numero": "00000008", "motivo": "ERROR DE DIGITACION" }
]
}
🔍 Verificar documento en SUNAT
Consulta directamente a SUNAT si un comprobante esta registrado (tiene CDR). Util para control: SUNAT balancea entre servidores y a veces uno responde "no existe" aunque el documento sea valido; este endpoint reintenta y reporta el estado real. (Aplica a factura/boleta/NC/ND/resumen/baja; en produccion.)
GET https://e-sunat.astos.pe/api/v1/verificar?tipo=01&serie=F001&numero=123
-H "X-Api-Key: TU_API_KEY" -H "X-Api-Secret: TU_API_SECRET"
# Respuesta:
# { "serie_numero":"F001-00000123", "existe_en_sunat": true,
# "sunat_codigo":"0001", "sunat_descripcion":"Comprobante REGISTRADO en SUNAT (tiene CDR)" }
# Tambien por id de un comprobante enviado por aqui:
GET https://e-sunat.astos.pe/api/v1/comprobantes/{id}/verificar
codigo 0001 = registrado/aceptado, 0004 = no existe en SUNAT.
GET https://e-sunat.astos.pe/api/v1/validar?tipo=01&serie=F001&numero=123&fecha=2026-01-15&monto=118.00
-H "X-Api-Key: ..." -H "X-Api-Secret: ..."
# -> { "valido": true, "estado_cp":"1", "estado_descripcion":"ACEPTADO", "estado_ruc":"00" }
🚚 Guías de remisión — enviar por JSON
Si no quieres construir el XML UBL, manda los datos en JSON a POST https://e-sunat.astos.pe/api/v1/gre y e-sunat arma el XML, lo firma y lo envia. Mismos headers (X-Api-Key + X-Api-Secret), Content-Type: application/json. El emisor se toma de tu API key (no hace falta enviarlo).
Las guías se emiten aquí, pases donde pases
Una guía de remisión electrónica no se puede emitir a través de un OSE: solo por el sistema del contribuyente o por el portal de SUNAT. Así que si tu empresa crece y queda obligada a emitir sus facturas por un OSE —pasa cuando SUNAT te designa principal contribuyente—, tus guías siguen saliendo por aquí, sin cambiar nada de tu integración.
Y recuerda el plazo: la guía se envía el mismo día y el traslado no debe empezar hasta que la constancia esté aceptada. Te avisamos en cuanto lo está.
▶ Ejemplo: enviar guia por JSON (cURL)
curl -X POST "https://e-sunat.astos.pe/api/v1/gre" -H "X-Api-Key: TU_API_KEY" -H "X-Api-Secret: TU_API_SECRET" -H "Content-Type: application/json" -d '{
"tipo": "09", // 09=remitente, 31=transportista
"serie": "T001", "numero": 40,
"motivo": "01", // motivo traslado (cat.20): 01=Venta, 04=Entre establecimientos...
"modalidad": "02", // 01=Publico, 02=Privado
"peso": "1.00", "bultos": "1",
"fecha_emision": "2026-01-15", // opcional (por defecto hoy)
"destinatario": { "tipo_doc": "6", "num_doc": "20100000002", "razon_social": "CLIENTE SAC" },
"partida": { "ubigeo": "150101", "direccion": "JR AZANGARO 993 LIMA" },
"llegada": { "ubigeo": "120701", "direccion": "AV DESTINO 674 TARMA" },
"vehiculo": { "placa": "ABC123" }, // si modalidad=02 (privado)
"conductor": { "tipo_doc":"1","num_doc":"12345678","nombres":"JUAN","apellidos":"PEREZ","licencia":"Q12345678" },
// "transportista": { "ruc":"20...", "razon_social":"TRANSPORTES SAC" } // si modalidad=01 (publico)
// "remitente": { "ruc":"20...", "razon_social":"REMITENTE SAC" } // solo si tipo=31
"pagador_flete": "Remitente", // solo tipo=31: Remitente | Subcontratador | Tercero
"items": [ { "cantidad":"2","unidad":"NIU","descripcion":"PRODUCTO","codigo":"COD001" } ]
}'
# Respuesta: comprobante_id + estado. Consulta el avance en:
# GET https://e-sunat.astos.pe/api/v1/comprobantes/{id}
Tipo 09 (remitente): manda destinatario. Tipo 31 (transportista): agrega remitente. Privado: vehiculo+conductor. Publico: transportista.
Ejemplos de XML de guias (descargar)
Plantillas listas para copiar y rellenar con tus datos. Estructura ya validada y aceptada por SUNAT.
Campos clave del traslado
| Campo | Donde / valor |
|---|---|
| DespatchAdviceTypeCode | 09=remitente, 31=transportista |
| HandlingCode | Motivo de traslado (cat.20): 01=Venta, 04=Entre establecimientos, 13=Otros... |
| TransportModeCode | 01=Transporte publico, 02=Transporte privado |
| LicensePlateID + TransportEquipment/ID | La placa va en LOS DOS (si falta en TransportEquipment, error 2566) |
| DriverPerson | Conductor (obligatorio en privado): DNI + nombres + N licencia |
| DeliveryAddress / DespatchAddress | Ubigeo (6 dig.) y direccion de llegada y partida |
| GrossWeightMeasure | Peso bruto total en KGM (mayor a 0) |
| DespatchParty | Solo en transportista (31): RUC del remitente que contrato el transporte |
- 2108 "presentacion fuera de fecha": usa
IssueTime=00:00:00(no una hora futura). - 2566 "numero de placa": la placa debe ir tambien en
TransportHandlingUnit/TransportEquipment/ID. - Si mandas sin firmar, deja
ext:ExtensionContentvacio: e-sunat firma. - Las guias van siempre a produccion (SUNAT no tiene beta para GRE).
Tipos de documento soportados
| Documento | Código | Se envía a |
|---|---|---|
| Factura | 01 | /api/v1/comprobantes |
| Boleta | 03 | /api/v1/comprobantes |
| Nota de Crédito | 07 | /api/v1/comprobantes |
| Nota de Débito | 08 | /api/v1/comprobantes |
| Resumen diario | RC | /api/v1/comprobantes |
| Comunicación de Baja | RA | /api/v1/comprobantes |
| Guía de Remisión (Remitente) | 09 | /api/v1/gre |
| Guía de Remisión (Transportista) | 31 | /api/v1/gre |
No necesitas indicar el tipo en la URL: se detecta leyendo el XML.
Estados de un documento
- 🟡
recibido— en cola - 🔵
enviando— yendo a SUNAT - 🟢
aceptado— SUNAT lo aceptó (CDR listo) - 🟢
aceptado_con_observaciones— aceptado con observaciones - 🔴
rechazado— revisarsunat_descripcion - 🟠
error_red— falló la conexión, se reintenta solo
Códigos de respuesta
- 200 — OK, o ya existía (no se duplica)
- 202 — recibido y encolado
- 401 — llave inválida o desactivada
- 402 — período FIRMAPSE vencido
- 403 — IP no autorizada / empresa inactiva /
LLAVE_SIN_PERMISO(esa ruta no corresponde a tu llave, por ejemplo una llave de pruebas pidiendo guías) - 422 — el RUC del XML no es el tuyo, o
EMISOR_SIN_RUC(el XML no trae el RUC del emisor) - 429 — pasaste el límite por minuto; espera lo que diga
Retry-After
♻️ Reintenta sin miedo
El caso de siempre: mandas un comprobante, se corta la conexión y no sabes si llegó. Aquí nunca vas a duplicar un documento por reintentar.
Si envías dos veces el mismo documento (misma serie y número), no lo duplicamos ni lo reenviamos a SUNAT: detectamos que ya existe y te devolvemos el que ya tienes.
Y si SUNAT lo rechazó, sí puedes corregirlo y reenviarlo con el mismo número: un rechazado no quedó registrado en SUNAT. Solo los aceptados o en proceso no se reenvían. Aplica a facturas, boletas, notas, resúmenes, bajas y guías.
Manda la cabecera Idempotency-Key con un valor único tuyo por comprobante
(un UUID, o RUC-TIPO-SERIE-NUMERO).
Repetir la llamada con la misma clave y el mismo contenido te devuelve exactamente la misma respuesta de la primera vez.
POST /api/v1/comprobantes
X-Api-Key: ...
X-Api-Secret: ...
Idempotency-Key: 20123456789-01-F001-123
Devolvemos la respuesta guardada, con la cabecera Idempotency-Replayed: true. No se reenvía a SUNAT.
Respondemos 409: esa clave ya se usó para otro documento. Usa una clave por comprobante.
Todo funciona igual que siempre. Es opcional y no rompe ninguna integración.
Las claves se recuerdan 48 horas; pasado ese tiempo, la misma clave vuelve a considerarse nueva.
🔔 Te avisamos nosotros (webhooks)
En vez de preguntar cada rato «¿ya está?», danos una URL y te avisamos en cuanto SUNAT responde.
Desde tu panel, en Configuración. Puedes poner también una clave secreta.
Cuando el documento llega a un estado final, te mandamos un POST con JSON.
Reintentamos a 1 min, 5, 15, 30 min, 1 h, 2 h y 4 h. No se pierde el aviso.
Lo que te enviamos
{
"evento": "comprobante.aceptado",
"empresa_ruc": "20123456789",
"comprobante_id": 12345,
"tipo": "01",
"serie": "F001",
"numero": 123,
"serie_numero": "F001-00000123",
"estado": "aceptado",
"es_final": true,
"resultado": "aceptado",
"sunat_codigo": 0,
"sunat_descripcion": "La Factura numero F001-123, ha sido aceptada",
"diagnostico": null,
"cdr_disponible": true,
"fecha": "2026-09-17T18:20:31-05:00"
}
Si configuraste clave secreta, mandamos la cabecera X-Webhook-Signature con sha256= y la firma del cuerpo. Calcula el HMAC-SHA256 del cuerpo con tu clave y compara.
Responde 200 apenas lo recibas; procesa después. Si respondes otra cosa, reintentamos. Y usa es_final: cuando llega en true, deja de consultar ese documento.
Para activarlos, pon tu URL en el panel (Configuración) o pídenoslo por WhatsApp y la dejamos puesta. Puedes añadir una clave secreta para verificar la firma.
✅ Cuadra tu día solo (conciliación)
Para responder a la pregunta que importa al cierre: ¿se me quedó algo sin declarar? Sin entrar a ninguna pantalla y sin llamar a soporte.
1. ¿Cómo voy?
GET /api/v1/conciliacion?desde=2026-09-01&hasta=2026-09-17
Devuelve el total del periodo, el reparto por estado, y dos listas: sin_resolver (emitidos que aún no tienen respuesta final) y rechazados (hay que emitir otro documento con número nuevo). Si todo_cuadrado viene en true, no te falta nada.
2. ¿Llegó todo lo que emití?
Mándanos tu lista y te decimos cuáles no existen aquí. Son los peligrosos: los que tu sistema da por enviados y en realidad nunca salieron.
POST /api/v1/conciliacion
{
"documentos": [
{"tipo": "01", "serie": "F001", "numero": 120},
{"tipo": "03", "serie": "B001", "numero": 4501}
]
}
Respondemos con no_llegaron (no existen aquí: revisa si de verdad se emitieron) y sin_resolver. Hasta 2.000 documentos por llamada.
Cuándo usarlo: una vez al día, al cerrar caja, y otra al cerrar el mes. Es la forma de enterarte tú antes de que te lo diga tu contador.
⏱️ Plazos y qué hacer con cada respuesta
Lo que más cuesta al integrarse no es enviar: es saber qué hacer cuando SUNAT dice que no.
Plazo para enviar cada documento
| Documento | Plazo desde la emisión | Si se pasa |
|---|---|---|
| Factura (01) y notas (07/08) de factura | 3 días calendario | SUNAT rechaza (2108). Hay que emitir de nuevo con fecha vigente. |
| Boleta (03) enviada suelta | 5 días calendario | SUNAT rechaza (1079), pero por resumen diario sí entra. |
| Resumen diario de boletas (RC) | 7 días calendario | Se acepta igual, con observación. |
| Comunicación de baja (RA) | 7 días calendario | Ya no se puede dar de baja (2957). |
| Guía de remisión (09/31) | 1 día | Pierde validez como guía. Además el traslado no debe empezar sin la constancia aceptada. |
Te avisamos cuando a un documento tuyo le queda poco plazo, así no te enteras cuando ya es tarde.
Cómo leer la respuesta
No se registró nada en SUNAT. Corrige y reenvía con el mismo número.
Rechazado. Ese número ya no sirve: emite otro documento con número nuevo. No hace falta nota de crédito, porque para SUNAT nunca existió.
Aceptado con observación. El documento vale. Corrige el detalle para los siguientes.
Tres respuestas que no se arreglan reenviando
/verificar. Si el número está ocupado, usa una serie o número libre.Lo que revisamos antes de gastar tu correlativo
Antes de enviar nada a SUNAT validamos tu documento y te devolvemos el error con la recomendación, para que corrijas sin quemar el número. Dos de esas reglas son nuevas:
- Una sola tasa de IGV por documento. Desde 2026 SUNAT rechaza mezclar 18% con la tasa reducida de 10.5% (restaurantes y hoteles MYPE) en el mismo comprobante. Si los tienes que mezclar, emite por separado.
- El IGV tiene que cuadrar al céntimo. Si no cuadra te llega una advertencia (no bloquea todavía): SUNAT está convirtiendo esas observaciones de cálculo en rechazo.
🖊️ Quién firma y por dónde se envía
Son dos cosas distintas y se configuran por separado. Tú no cambias nada en tu código: lo configuramos en tu empresa.
- Tu certificado. Nos subes tu certificado digital (el que compraste) y firmamos con él.
- Nuestro certificado. Si todavía no tienes uno, firmamos nosotros y puedes emitir desde el primer día.
- Directo a SUNAT. Es lo habitual.
- Por un OSE en preparación. Obligatorio cuando tu empresa pasa a PRICO: nos das las credenciales de tu OSE y seguimos enviando igual, sin que cambies tu integración.
Las dos opciones se combinan: puedes firmar con nuestro certificado y enviar por tu OSE, o firmar con el tuyo y salir directo. Si firmamos nosotros, nuestro certificado tiene que estar declarado ante SUNAT para tu RUC. Las guías de remisión siempre salen directo a SUNAT, porque por OSE no se pueden emitir.
🔧 Otros endpoints disponibles
Todos requieren los headers X-Api-Key y X-Api-Secret.
Representación impresa (PDF) del comprobante con QR SUNAT. Agrega ?formato=ticket para el formato 80mm; por defecto es A4.
Datos de un RUC (11 díg.) o DNI (8 díg.): razón social / nombres, estado y dirección. Útil para autocompletar clientes.
Tipo de cambio SUNAT del día, o de una fecha (formato YYYY-MM-DD).
SIRE: propuesta de SUNAT del Registro de Ventas (rvie) o de Compras (rce) para un periodo YYYYMM, y presentación del libro.
Descarga de comprobantes recibidos (los que otros te emitieron): listar, ver detalle y bajar el archivo.
Mensajes del buzón SUNAT de tu empresa.
💡 Retención (20) y Percepción (40) también se pueden enviar por JSON a POST /api/v1/comprobantes (igual que factura/boleta), no solo por XML.
📚 SIRE — Registro de Ventas y Compras
El SIRE es el libro electrónico que SUNAT arma sola con tus comprobantes. Desde aquí puedes leer lo que SUNAT tiene registrado y presentar el libro, sin entrar al portal.
Lo que SUNAT tiene registrado que vendiste. Sirve para cuadrar contra tu sistema.
Las facturas que tus proveedores te emitieron. Sirve para registrarlas sin tipearlas.
1. Leer lo que SUNAT tiene
GET https://e-sunat.astos.pe/api/v1/sire/{libro}/{periodo}
-H "X-Api-Key: TU_API_KEY"
-H "X-Api-Secret: TU_API_SECRET"
# libro : rvie (ventas) | rce (compras)
# periodo : YYYYMM -> 202608 = agosto 2026
# Ejemplos:
curl "https://e-sunat.astos.pe/api/v1/sire/rce/202608" -H "X-Api-Key: KEY" -H "X-Api-Secret: SECRET" # compras
curl "https://e-sunat.astos.pe/api/v1/sire/rvie/202608" -H "X-Api-Key: KEY" -H "X-Api-Secret: SECRET" # ventas
Respuesta:
{
"periodo": "202608",
"libro": "rce",
"total": 42,
"registros": [
{
"fecha_emision": "2026-08-03",
"tipo": "01", // tipo de comprobante
"serie": "F001",
"numero": "1234",
"ruc": "20123456789", // del proveedor (RCE) o del cliente (RVIE)
"razon_social": "PROVEEDOR SAC",
"moneda": "PEN",
"base": 100.00,
"igv": 18.00,
"total": 118.00
}
]
}
2. Presentar el libro
Acepta la propuesta que SUNAT preparó. Es asíncrono: SUNAT devuelve un ticket y el resultado llega después.
POST https://e-sunat.astos.pe/api/v1/sire/presentar/{libro}/{periodo}
-H "X-Api-Key: TU_API_KEY"
-H "X-Api-Secret: TU_API_SECRET"
curl -X POST "https://e-sunat.astos.pe/api/v1/sire/presentar/rce/202608" \
-H "X-Api-Key: KEY" -H "X-Api-Secret: SECRET"
GET) es inofensivo y lo puedes
llamar cuantas veces quieras.
▶ Ejemplo completo en Python: bajar las compras del mes a un Excel
import requests, csv # pip install requests
CAB = {"X-Api-Key": "TU_API_KEY", "X-Api-Secret": "TU_API_SECRET"}
PERIODO = "202608"
r = requests.get("https://e-sunat.astos.pe/api/v1/sire/rce/" + PERIODO, headers=CAB, timeout=120)
datos = r.json()
print("Compras del periodo", datos["periodo"], "->", datos["total"], "facturas")
with open("compras_" + PERIODO + ".csv", "w", newline="", encoding="utf-8-sig") as f:
w = csv.writer(f, delimiter=";")
w.writerow(["Fecha", "Tipo", "Serie", "Numero", "RUC", "Proveedor", "Base", "IGV", "Total"])
for c in datos["registros"]:
w.writerow([c.get("fecha_emision"), c.get("tipo"), c.get("serie"), c.get("numero"),
c.get("ruc"), c.get("razon_social"),
c.get("base"), c.get("igv"), c.get("total")])
print("Listo: se puede abrir con Excel.")
💡 El uso más valioso: cuadrar SUNAT contra tu sistema
Trae el RVIE de un mes cerrado y compáralo con tus ventas. Las diferencias te dicen tres cosas que de otra forma no verías:
- Está en tu sistema y no en SUNAT → ese comprobante nunca llegó.
- Está en SUNAT y no en tu sistema → alguien emitió por fuera (portal SOL, otra caja, otro proveedor).
- Está en los dos con montos distintos → hay una diferencia que corregir antes de declarar.
Nota: la propuesta del SIRE se arma por periodo y va con algo de retraso, así que es una revisión mensual, no en tiempo real. Para lo inmediato usa Verificar documento.
Requisito: el SIRE usa las credenciales SIRE/GRE de tu empresa (Client ID, Client Secret y usuario SOL).
Si te responde 502 con un mensaje de credenciales, escríbenos y las configuramos.
¿No programas o necesitas ayuda para integrar?
Escríbenos y te ayudamos a conectar tu sistema paso a paso.
💬 WhatsApp 984 115 056© 2026 Astos — AstosCPE · Documentación de integración