API de facturación electrónica
Conecta cualquier sistema (ERP, punto de venta, tienda en línea) con SUNAT. Envías el comprobante en JSON y la API genera el XML UBL 2.1, lo firma con el certificado de la empresa, lo envía a SUNAT y te devuelve la constancia de recepción (CDR). Los comprobantes emitidos por la API también aparecen en el panel.
- Registra tu empresa y sus series en el panel.
- Crea un token en Sistemas y tokens API. El token identifica a la empresa que emite.
- Prueba tu token y tus datos en el probador.
- Copia el código de ejemplo en tu lenguaje y conéctalo a tu sistema.
- Mientras la empresa esté en modo beta los comprobantes van al entorno de pruebas de SUNAT. Actívale el modo producción cuando tengas tu usuario SOL y certificado digital.
Pega tu token, elige factura, boleta, nota o guía, y envíala con datos de prueba. Ve la respuesta real y el código en cURL, PHP, JavaScript, Python, C# y Java.
URL base y autenticación
Todas las rutas empiezan con https://facpro.hachedev.online/api/v1 y reciben y devuelven JSON.
En esta documentación se escriben sin la versión (/api/...): esas rutas también funcionan y son iguales a la versión 1.
Cada petición debe llevar estas cabeceras:
| Authorization | Bearer 1|tu-token | El token de la empresa. Lo creas en Sistemas y tokens API y solo se muestra una vez. |
| Accept | application/json | Para recibir siempre JSON, también en los errores. |
| Content-Type | application/json | En las peticiones POST con cuerpo. |
El token define la empresa que emite: los datos del emisor (RUC, razón social, dirección, certificado) se toman de ella, así que no los envíes.
Cada token tiene permisos (invoices, notes, despatches, documents) y puede limitarse a ciertas series.
Las peticiones por minuto dependen de tu plan: ver límites y uso.
Ejemplos en tu lenguaje
Emitir una factura y revisar el resultado. Reemplaza TU_TOKEN por tu token. En el
probador puedes generar este código para cualquier endpoint y con tus propios datos.
OpenAPI y Postman
La especificación OpenAPI 3 describe todos los endpoints, sus permisos, errores y ejemplos de factura, boleta, notas y guías.
https://facpro.hachedev.online/docs/openapi.json
- Postman: Import → Link → pega la URL. Crea una colección con todos los endpoints; en la pestaña Authorization elige Bearer Token y pega tu token.
- Insomnia o Bruno: importa la misma URL o el archivo.
- Cliente en tu lenguaje:
npx @openapitools/openapi-generator-cli generate -i https://facpro.hachedev.online/docs/openapi.json -g php -o cliente-api(cambiaphpportypescript-fetch,python,csharp,java…).
Formato de respuesta
Al emitir, la API responde con HTTP 200 aunque SUNAT rechace el comprobante: revisa siempre success y estado.
Los códigos 4xx solo aparecen cuando la petición no llegó a SUNAT (token, plan o datos inválidos). Ver errores.
| estado | success | Qué significa y qué hacer |
|---|---|---|
| aceptado | true | SUNAT aceptó el comprobante (CDR código 0). Listo. |
| observado | true | Aceptado con observaciones (CDR código 4000 o más). Es válido; corrige las observaciones en los siguientes. |
| rechazado | false | SUNAT lo rechazó (código 2000 a 3999). No es válido: corrige los datos y vuelve a enviarlo con el mismo número. |
| pendiente | false | SUNAT no respondió (caída o sin conexión). El comprobante sí quedó emitido: tiene XML firmado, hash y PDF válidos. La API lo envía sola cada 5 minutos; document.plazoEnvio indica el último día para que llegue. Ver "Cuando SUNAT no está disponible". |
| error | false | No se pudo enviar por un problema de la empresa (usuario SOL, certificado, etc.), o SUNAT aún procesa el ticket de una guía (código 98). Corrige y reintenta. |
| anulado | false | El comprobante fue anulado con una comunicación de baja o resumen diario. |
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
| success | boolean | Sí | true si quedó aceptado u observado. |
| estado | string | Sí | aceptado, observado, rechazado, pendiente, error o anulado. |
| duplicado | boolean | Sí | true si ya existía un comprobante aceptado con el mismo externalId y no se volvió a emitir. |
| document.id | integer | Sí | ID del comprobante en la API. Úsalo en /api/invoices/{id}/... |
| document.externalId | string|null | Sí | La referencia que enviaste. |
| document.sistema | string | Sí | Nombre del token que lo emitió o panel. |
| document.numero | string | Sí | Serie y correlativo, ej. F001-00000006. |
| document.links | objeto | Sí | URLs de pdf, xml y cdr (se descargan con el mismo token). |
| document.plazoEnvio | fecha|null | Sí | Si quedó pendiente porque SUNAT no respondió, último día para que llegue a SUNAT (AAAA-MM-DD). |
| document.anulacion | objeto|null | Sí | Estado de la anulación, si la hay. |
| hash | string | Sí | Valor resumen (DigestValue) del XML firmado. Va en la representación impresa. |
| xml | string | Sí | XML firmado. |
| sunatResponse.success | boolean | Sí | true si SUNAT devolvió CDR. |
| sunatResponse.cdrZip | string|null | Sí | CDR (zip) en base64. |
| sunatResponse.cdrResponse | objeto|null | Sí | code, description y notes (observaciones) del CDR. |
| sunatResponse.error | objeto|null | Sí | code y message cuando SUNAT rechaza o hay un error de envío. |
| sunatResponse.ticket | string|null | Sí | Ticket de SUNAT (solo guías de remisión). |
{
"success": true,
"estado": "aceptado",
"duplicado": false,
"document": {
"id": 15,
"externalId": "VENTA-1050",
"sistema": "ERP",
"tipoDoc": "01",
"serie": "F001",
"correlativo": 6,
"numero": "F001-00000006",
"fechaEmision": "2026-10-08",
"links": {
"pdf": "https://facpro.hachedev.online/api/invoices/15/pdf",
"xml": "https://facpro.hachedev.online/api/invoices/15/xml",
"cdr": "https://facpro.hachedev.online/api/invoices/15/cdr"
},
"plazoEnvio": null,
"anulacion": null
},
"hash": "hGOQAxdx0WyKUadm/E1xJh2/MIs=",
"xml": "<?xml version=\"1.0\" encoding=\"utf-8\"?>...",
"sunatResponse": {
"success": true,
"cdrZip": "UEsDBBQAAgAIA...",
"cdrResponse": {
"code": "0",
"description": "La Factura numero F001-6, ha sido aceptada",
"notes": []
},
"error": null,
"ticket": null
}
}
{
"success": false,
"estado": "rechazado",
"duplicado": false,
"document": {
"id": 16,
"numero": "F001-00000007",
"links": { "pdf": "https://facpro.hachedev.online/api/invoices/16/pdf", "xml": "https://facpro.hachedev.online/api/invoices/16/xml", "cdr": null },
"...": "..."
},
"hash": "q1Dz0tS8m4vC2hXJk3o9Wl5sY6E=",
"xml": "<?xml version=\"1.0\" encoding=\"utf-8\"?>...",
"sunatResponse": {
"success": false,
"cdrZip": null,
"cdrResponse": null,
"error": {
"code": "2800",
"message": "El dato ingresado en el tipo de documento de identidad del receptor no esta permitido."
},
"ticket": null
}
}
Errores
Cuando la petición no se puede procesar, la API responde con un código HTTP 4xx y un JSON con message.
| 401 | Token ausente o inválido. |
| 402 | Tu plan no lo permite: sin plan (no_subscription), plan vencido (subscription_expired), límite de comprobantes del mes (documents_limit) o módulo no incluido (feature_not_included). Ver "code". |
| 403 | El token no tiene permiso para este endpoint, o la cuenta está suspendida (account_suspended). |
| 404 | El comprobante no existe o pertenece a otra empresa, o el RUC/DNI consultado no está registrado (code: not_registered). |
| 422 | Datos inválidos, serie no registrada o no permitida para el token, comprobante ya aceptado o no anulable. El detalle viene en "errors". |
| 429 | Superaste las peticiones por minuto de tu plan (code: rate_limited). Espera los segundos de la cabecera Retry-After. |
{
"message": "The serie field is required. (and 1 more error)",
"errors": {
"serie": ["La serie F009 no está registrada para el tipo de documento 01."],
"details.0.cantidad": ["The details.0.cantidad field must be greater than 0."]
}
}
{
"message": "Alcanzaste el límite de 100 comprobantes de este mes de tu plan Básico. Mejora tu plan para seguir emitiendo.",
"code": "documents_limit"
}
Un comprobante rechazado o que no llegó a SUNAT se puede volver a enviar con el mismo número después de corregirlo.
Límites y uso
Cada plan permite un número de peticiones por minuto, que suman todos los tokens de todas tus empresas. Cada respuesta trae cuántas te quedan:
| X-RateLimit-Limit | Peticiones por minuto de tu plan. |
| X-RateLimit-Remaining | Peticiones que te quedan en este minuto. |
| Retry-After | Solo en la respuesta 429: segundos que debes esperar. |
{
"message": "Superaste el límite de 60 peticiones por minuto de tu plan. Espera 23 segundos y vuelve a intentarlo.",
"code": "rate_limited"
}
Si emites en lote, espera lo que indica Retry-After y reintenta con el mismo externalId: así nunca se emite dos veces la misma venta.
Aparte, el plan limita los comprobantes por mes en producción (HTTP 402, documents_limit). Las pruebas en beta no cuentan.
En el panel, Uso de la API muestra cada llamada de los últimos 90 días por token y endpoint, con su estado y tiempo, para depurar tu integración.
Cuando SUNAT no está disponible
Si SUNAT no responde (caída, mantenimiento o sin conexión), el comprobante igual se emite: la API firma el XML, guarda el hash
y el PDF es válido para entregarlo al cliente. La respuesta llega con "estado": "pendiente" y document.plazoEnvio.
- Envío automático: los pendientes se reenvían cada 5 minutos hasta que SUNAT responda. Si configuraste webhooks, recibirás
document.emittedcon el estado final. - Sin esperas: después de un fallo, durante unos minutos los siguientes comprobantes no esperan a SUNAT y responden de inmediato como pendientes.
- Envío manual: en el panel, Comprobantes muestra los pendientes y el botón Enviar pendientes ahora. Desde tu sistema puedes reenviar el mismo comprobante con el mismo
externalId. - Plazo: SUNAT da 3 días calendario contados desde el día siguiente a la emisión. Después de ese plazo puede rechazarlo.
Cambios de la API
Versión actual: 1.2.0. Los cambios dentro de la versión 1 solo agregan cosas: nunca quitan campos ni cambian su significado.
Si algún día hace falta un cambio incompatible, saldrá como /api/v2 y la versión 1 seguirá funcionando.
- PDF en A4, A5, ticket de 80 mm y de 58 mm: ?format=a4|a5|ticket-80|ticket-58 (sin él, el formato configurado en la empresa).
- Descarga en ZIP de los XML, CDR y PDF de un periodo: GET /documents/export.
- Cobranzas: pagos de comprobantes a crédito y cuentas por cobrar con antigüedad (permiso "payments").
- Cotizaciones y notas de venta, con conversión a factura o boleta (permiso "sales").
- Clientes y productos por API (permiso "catalog"); inventario, kardex y compras (permiso "inventory").
- Indicadores del panel (GET /dashboard), catálogos de SUNAT y ubigeos (GET /catalogs).
- Webhook nuevo: payment.registered.
- Validación de comprobantes de cualquier emisor en SUNAT: POST /lookup/cpe.
- Comprobantes de retención (20) y de percepción (40): /retentions y /perceptions (permiso "withholdings").
- Conciliación con SIRE: compara la propuesta del Registro de Ventas de SUNAT con tus comprobantes (/sire/reconciliations).
- Catálogo de códigos de producto SUNAT (UNSPSC): GET /catalogs/sunat-products; codProdSunat se valida al guardar productos.
- Guía de remisión transportista (31): POST /despatches/send con "tipoDoc": "31" (serie V…).
- Rutas con versión: /api/v1/... (las rutas /api/... siguen funcionando igual).
- Límite de peticiones por minuto según tu plan, con las cabeceras X-RateLimit-Limit y X-RateLimit-Remaining. Al superarlo: HTTP 429 con code "rate_limited" y Retry-After.
- Especificación OpenAPI en /docs/openapi.json para Postman, Insomnia o generar clientes.
- Registro de uso: cada llamada aparece en "Uso de la API" del panel.
- Facturas, boletas, notas, guías, anulaciones, consultas, webhooks y consulta RUC/DNI.
Varios sistemas, una empresa
Un sistema por empresa: cada empresa tiene sus propios tokens, series y comprobantes. Un token nunca ve datos de otra empresa.
Varios sistemas en la misma empresa (por ejemplo un ERP y un punto de venta): crea un token por sistema en Sistemas y tokens API. Cada comprobante queda marcado con el sistema que lo emitió (document.sistema).
- Numeración sin choques: limita cada token a sus series (p. ej. ERP → F001, POS → F002), o no envíes
correlativoy la API asigna el siguiente de forma segura aunque dos sistemas emitan al mismo tiempo. - Sin duplicados: envía
externalIdcon el ID de la venta en tu sistema. - Cruce de información: cualquier sistema puede buscar comprobantes de los demás por referencia, número, cliente o sistema, y emitir notas o anular comprobantes emitidos por otro sistema.
- Sincronización: los webhooks avisan a cada sistema de lo que emiten o anulan los otros.
Referencia externa (externalId)
Es única por empresa. Si reenvías un comprobante con un externalId que ya fue aceptado (por ejemplo, porque se cortó la conexión
antes de recibir la respuesta), la API devuelve ese mismo comprobante con "duplicado": true y no lo vuelve a emitir.
Si el anterior falló o fue rechazado, se reintenta con el mismo número.
Webhooks
Configúralos en el panel (Webhooks). Se envía un POST JSON a tu URL con los eventos
document.emitted, document.voided y despatch.emitted, sin importar qué sistema o usuario lo originó.
originTokenId indica qué token lo hizo (null si fue desde el panel). Verifica la firma con el secreto del webhook:
{
"event": "document.emitted",
"ruc": "20000000001",
"originTokenId": 3,
"sentAt": "2026-10-08T10:30:05-05:00",
"data": { "success": true, "estado": "aceptado", "document": { "...": "..." } }
}
$body = file_get_contents('php://input');
$firma = 'sha256=' . hash_hmac('sha256', $body, $secreto);
if (! hash_equals($firma, $_SERVER['HTTP_X_APISUNAT_SIGNATURE'] ?? '')) {
http_response_code(401);
exit;
}
$evento = json_decode($body, true);
Datos de la empresa
ProbarDevuelve la empresa del token, su entorno (beta o producción), sus sucursales y series con el último correlativo emitido.
Úsalo para comprobar que tu token funciona y qué series puedes usar.
{
"ruc": "20000000001",
"razonSocial": "MI EMPRESA S.A.C.",
"nombreComercial": "MI EMPRESA",
"direccion": "AV. PRINCIPAL 123",
"ubigeo": "150101",
"entorno": "beta",
"sucursales": [
{
"nombre": "Principal",
"codigo": "0000",
"direccion": "AV. PRINCIPAL 123",
"series": [
{ "tipoDoc": "01", "serie": "F001", "ultimoCorrelativo": 5 },
{ "tipoDoc": "03", "serie": "B001", "ultimoCorrelativo": 12 }
]
}
],
"permisos": ["invoices", "notes", "despatches", "documents"]
}
Emitir factura o boleta
ProbarGenera el XML, lo firma, lo envía a SUNAT y devuelve el resultado en el formato de respuesta. El cuerpo usa los nombres de campos de Greenter. Los datos del emisor se toman de la empresa del token.
Mínimo indispensable: tipoOperacion, tipoDoc, serie, fechaEmision, tipoMoneda,
client, los totales, details y, en facturas, formaPago. Parte de los ejemplos de abajo y cambia solo tus datos.
Las emisiones en beta no consumen los comprobantes de tu plan.
{
"ublVersion": "2.1",
"tipoOperacion": "0101",
"tipoDoc": "01",
"serie": "F001",
"correlativo": "1",
"fechaEmision": "2026-10-08T10:30:00-05:00",
"formaPago": {
"tipo": "Contado"
},
"tipoMoneda": "PEN",
"client": {
"tipoDoc": "6",
"numDoc": "20100070970",
"rznSocial": "EMPRESA CLIENTE S.A.C.",
"address": {
"direccion": "AV. LOS OLIVOS 123, LIMA"
}
},
"mtoOperGravadas": 200.0,
"mtoIGV": 36.0,
"totalImpuestos": 36.0,
"valorVenta": 200.0,
"subTotal": 236.0,
"mtoImpVenta": 236.0,
"details": [
{
"codProducto": "P001",
"unidad": "NIU",
"cantidad": 2.0,
"descripcion": "PRODUCTO 1",
"mtoValorUnitario": 50.0,
"mtoBaseIgv": 100.0,
"porcentajeIgv": 18,
"igv": 18.0,
"tipAfeIgv": "10",
"totalImpuestos": 18.0,
"mtoValorVenta": 100.0,
"mtoPrecioUnitario": 59.0
},
{
"codProducto": "P002",
"unidad": "NIU",
"cantidad": 4.0,
"descripcion": "PRODUCTO 2",
"mtoValorUnitario": 25.0,
"mtoBaseIgv": 100.0,
"porcentajeIgv": 18,
"igv": 18.0,
"tipAfeIgv": "10",
"totalImpuestos": 18.0,
"mtoValorVenta": 100.0,
"mtoPrecioUnitario": 29.5
}
],
"legends": [
{
"code": "1000",
"value": "SON DOSCIENTOS TREINTA Y SEIS CON 00/100 SOLES"
}
]
}
{
"ublVersion": "2.1",
"tipoOperacion": "0101",
"tipoDoc": "03",
"serie": "B001",
"correlativo": "1",
"fechaEmision": "2026-10-08T10:30:00-05:00",
"tipoMoneda": "PEN",
"client": {
"tipoDoc": "1",
"numDoc": "12345678",
"rznSocial": "JUAN PEREZ GARCIA"
},
"mtoOperGravadas": 200.0,
"mtoIGV": 36.0,
"totalImpuestos": 36.0,
"valorVenta": 200.0,
"subTotal": 236.0,
"mtoImpVenta": 236.0,
"details": [
{
"codProducto": "P001",
"unidad": "NIU",
"cantidad": 2.0,
"descripcion": "PRODUCTO 1",
"mtoValorUnitario": 50.0,
"mtoBaseIgv": 100.0,
"porcentajeIgv": 18,
"igv": 18.0,
"tipAfeIgv": "10",
"totalImpuestos": 18.0,
"mtoValorVenta": 100.0,
"mtoPrecioUnitario": 59.0
},
{
"codProducto": "P002",
"unidad": "NIU",
"cantidad": 4.0,
"descripcion": "PRODUCTO 2",
"mtoValorUnitario": 25.0,
"mtoBaseIgv": 100.0,
"porcentajeIgv": 18,
"igv": 18.0,
"tipAfeIgv": "10",
"totalImpuestos": 18.0,
"mtoValorVenta": 100.0,
"mtoPrecioUnitario": 29.5
}
],
"legends": [
{
"code": "1000",
"value": "SON DOSCIENTOS TREINTA Y SEIS CON 00/100 SOLES"
}
]
}
{
"ublVersion": "2.1",
"tipoOperacion": "0101",
"tipoDoc": "01",
"serie": "F001",
"correlativo": "1",
"fechaEmision": "2026-10-08T10:30:00-05:00",
"formaPago": {
"tipo": "Credito",
"monto": 236.0,
"moneda": "PEN"
},
"tipoMoneda": "PEN",
"client": {
"tipoDoc": "6",
"numDoc": "20100070970",
"rznSocial": "EMPRESA CLIENTE S.A.C.",
"address": {
"direccion": "AV. LOS OLIVOS 123, LIMA"
}
},
"mtoOperGravadas": 200.0,
"mtoIGV": 36.0,
"totalImpuestos": 36.0,
"valorVenta": 200.0,
"subTotal": 236.0,
"mtoImpVenta": 236.0,
"details": [
{
"codProducto": "P001",
"unidad": "NIU",
"cantidad": 2.0,
"descripcion": "PRODUCTO 1",
"mtoValorUnitario": 50.0,
"mtoBaseIgv": 100.0,
"porcentajeIgv": 18,
"igv": 18.0,
"tipAfeIgv": "10",
"totalImpuestos": 18.0,
"mtoValorVenta": 100.0,
"mtoPrecioUnitario": 59.0
},
{
"codProducto": "P002",
"unidad": "NIU",
"cantidad": 4.0,
"descripcion": "PRODUCTO 2",
"mtoValorUnitario": 25.0,
"mtoBaseIgv": 100.0,
"porcentajeIgv": 18,
"igv": 18.0,
"tipAfeIgv": "10",
"totalImpuestos": 18.0,
"mtoValorVenta": 100.0,
"mtoPrecioUnitario": 29.5
}
],
"legends": [
{
"code": "1000",
"value": "SON DOSCIENTOS TREINTA Y SEIS CON 00/100 SOLES"
}
],
"cuotas": [
{
"moneda": "PEN",
"monto": 118.0,
"fechaPago": "2026-11-08T00:00:00-05:00"
},
{
"moneda": "PEN",
"monto": 118.0,
"fechaPago": "2026-12-08T00:00:00-05:00"
}
]
}
{
"ublVersion": "2.1",
"tipoOperacion": "0101",
"tipoDoc": "01",
"serie": "F001",
"correlativo": "1",
"fechaEmision": "2026-10-08T10:30:00-05:00",
"formaPago": {
"tipo": "Contado"
},
"tipoMoneda": "PEN",
"client": {
"tipoDoc": "6",
"numDoc": "20100070970",
"rznSocial": "EMPRESA CLIENTE S.A.C.",
"address": {
"direccion": "AV. LOS OLIVOS 123, LIMA"
}
},
"mtoIGV": 0,
"totalImpuestos": 0,
"valorVenta": 100.0,
"subTotal": 100.0,
"mtoImpVenta": 100.0,
"details": [
{
"codProducto": "L001",
"unidad": "NIU",
"cantidad": 2,
"descripcion": "LIBRO DE MATEMÁTICAS",
"mtoValorUnitario": 50.0,
"mtoBaseIgv": 100.0,
"porcentajeIgv": 0,
"igv": 0,
"tipAfeIgv": "20",
"totalImpuestos": 0,
"mtoValorVenta": 100.0,
"mtoPrecioUnitario": 50.0
}
],
"legends": [
{
"code": "1000",
"value": "SON CIEN CON 00/100 SOLES"
}
],
"mtoOperExoneradas": 100.0
}
{
"ublVersion": "2.1",
"tipoOperacion": "0101",
"tipoDoc": "01",
"serie": "F001",
"correlativo": "1",
"fechaEmision": "2026-10-08T10:30:00-05:00",
"formaPago": {
"tipo": "Contado"
},
"tipoMoneda": "PEN",
"client": {
"tipoDoc": "6",
"numDoc": "20100070970",
"rznSocial": "EMPRESA CLIENTE S.A.C.",
"address": {
"direccion": "AV. LOS OLIVOS 123, LIMA"
}
},
"mtoOperGravadas": 200.0,
"mtoIGV": 36.0,
"totalImpuestos": 36.0,
"valorVenta": 200.0,
"subTotal": 236.0,
"mtoImpVenta": 236.0,
"details": [
{
"codProducto": "P001",
"unidad": "NIU",
"cantidad": 2.0,
"descripcion": "PRODUCTO 1",
"mtoValorUnitario": 50.0,
"mtoBaseIgv": 100.0,
"porcentajeIgv": 18,
"igv": 18.0,
"tipAfeIgv": "10",
"totalImpuestos": 18.0,
"mtoValorVenta": 100.0,
"mtoPrecioUnitario": 59.0
},
{
"codProducto": "P002",
"unidad": "NIU",
"cantidad": 4.0,
"descripcion": "PRODUCTO 2",
"mtoValorUnitario": 25.0,
"mtoBaseIgv": 100.0,
"porcentajeIgv": 18,
"igv": 18.0,
"tipAfeIgv": "10",
"totalImpuestos": 18.0,
"mtoValorVenta": 100.0,
"mtoPrecioUnitario": 29.5
},
{
"codProducto": "P003",
"unidad": "NIU",
"cantidad": 1,
"descripcion": "PRODUCTO DE REGALO",
"mtoValorUnitario": 0,
"mtoValorGratuito": 10.0,
"mtoBaseIgv": 10.0,
"porcentajeIgv": 18,
"igv": 1.8000000000000000444089209850062616169452667236328125,
"tipAfeIgv": "15",
"totalImpuestos": 1.8000000000000000444089209850062616169452667236328125,
"mtoValorVenta": 10.0,
"mtoPrecioUnitario": 0
}
],
"legends": [
{
"code": "1000",
"value": "SON DOSCIENTOS TREINTA Y SEIS CON 00/100 SOLES"
},
{
"code": "1002",
"value": "TRANSFERENCIA GRATUITA DE UN BIEN Y/O SERVICIO PRESTADO GRATUITAMENTE"
}
],
"mtoOperGratuitas": 10.0,
"mtoIGVGratuitas": 1.8000000000000000444089209850062616169452667236328125
}
{
"ublVersion": "2.1",
"tipoOperacion": "0101",
"tipoDoc": "01",
"serie": "F001",
"correlativo": "1",
"fechaEmision": "2026-10-08T10:30:00-05:00",
"formaPago": {
"tipo": "Contado"
},
"tipoMoneda": "PEN",
"client": {
"tipoDoc": "6",
"numDoc": "20100070970",
"rznSocial": "EMPRESA CLIENTE S.A.C.",
"address": {
"direccion": "AV. LOS OLIVOS 123, LIMA"
}
},
"mtoOperGravadas": 200.0,
"mtoIGV": 41.39999999999999857891452847979962825775146484375,
"totalImpuestos": 71.400000000000005684341886080801486968994140625,
"valorVenta": 200.0,
"subTotal": 271.3999999999999772626324556767940521240234375,
"mtoImpVenta": 271.3999999999999772626324556767940521240234375,
"details": [
{
"codProducto": "C001",
"unidad": "NIU",
"cantidad": 2,
"descripcion": "CERVEZA 620 ML",
"mtoValorUnitario": 100.0,
"mtoBaseIsc": 200.0,
"porcentajeIsc": 15,
"isc": 30.0,
"tipSisIsc": "01",
"mtoBaseIgv": 230.0,
"porcentajeIgv": 18,
"igv": 41.39999999999999857891452847979962825775146484375,
"tipAfeIgv": "10",
"totalImpuestos": 71.400000000000005684341886080801486968994140625,
"mtoValorVenta": 200.0,
"mtoPrecioUnitario": 135.69999999999998863131622783839702606201171875
}
],
"legends": [
{
"code": "1000",
"value": "SON DOSCIENTOS SETENTA Y UNO CON 40/100 SOLES"
}
],
"mtoBaseIsc": 200.0,
"mtoISC": 30.0
}
{
"ublVersion": "2.1",
"tipoOperacion": "0101",
"tipoDoc": "01",
"serie": "F001",
"correlativo": "1",
"fechaEmision": "2026-10-08T10:30:00-05:00",
"formaPago": {
"tipo": "Contado"
},
"tipoMoneda": "PEN",
"client": {
"tipoDoc": "6",
"numDoc": "20100070970",
"rznSocial": "EMPRESA CLIENTE S.A.C.",
"address": {
"direccion": "AV. LOS OLIVOS 123, LIMA"
}
},
"totalImpuestos": 8.0,
"valorVenta": 200.0,
"subTotal": 208.0,
"mtoImpVenta": 208.0,
"details": [
{
"codProducto": "A001",
"unidad": "KGM",
"cantidad": 50,
"descripcion": "ARROZ PILADO",
"mtoValorUnitario": 4.0,
"mtoBaseIgv": 200.0,
"porcentajeIgv": 4,
"igv": 8.0,
"tipAfeIgv": "17",
"totalImpuestos": 8.0,
"mtoValorVenta": 200.0,
"mtoPrecioUnitario": 4.160000000000000142108547152020037174224853515625
}
],
"legends": [
{
"code": "1000",
"value": "SON DOSCIENTOS OCHO CON 00/100 SOLES"
},
{
"code": "2007",
"value": "Operación sujeta al IVAP"
}
],
"mtoBaseIvap": 200.0,
"mtoIvap": 8.0
}
{
"ublVersion": "2.1",
"tipoOperacion": "0101",
"tipoDoc": "01",
"serie": "F001",
"correlativo": "1",
"fechaEmision": "2026-10-08T10:30:00-05:00",
"formaPago": {
"tipo": "Contado"
},
"tipoMoneda": "PEN",
"client": {
"tipoDoc": "6",
"numDoc": "20100070970",
"rznSocial": "EMPRESA CLIENTE S.A.C.",
"address": {
"direccion": "AV. LOS OLIVOS 123, LIMA"
}
},
"mtoOperGravadas": 200.19999999999998863131622783839702606201171875,
"mtoIGV": 36.03999999999999914734871708787977695465087890625,
"totalImpuestos": 37.03999999999999914734871708787977695465087890625,
"valorVenta": 200.19999999999998863131622783839702606201171875,
"subTotal": 237.240000000000009094947017729282379150390625,
"mtoImpVenta": 237.240000000000009094947017729282379150390625,
"details": [
{
"codProducto": "P001",
"unidad": "NIU",
"cantidad": 2.0,
"descripcion": "PRODUCTO 1",
"mtoValorUnitario": 50.0,
"mtoBaseIgv": 100.0,
"porcentajeIgv": 18,
"igv": 18.0,
"tipAfeIgv": "10",
"totalImpuestos": 18.0,
"mtoValorVenta": 100.0,
"mtoPrecioUnitario": 59.0
},
{
"codProducto": "P002",
"unidad": "NIU",
"cantidad": 4.0,
"descripcion": "PRODUCTO 2",
"mtoValorUnitario": 25.0,
"mtoBaseIgv": 100.0,
"porcentajeIgv": 18,
"igv": 18.0,
"tipAfeIgv": "10",
"totalImpuestos": 18.0,
"mtoValorVenta": 100.0,
"mtoPrecioUnitario": 29.5
},
{
"codProducto": "BOL01",
"unidad": "NIU",
"cantidad": 2,
"descripcion": "BOLSA DE PLÁSTICO",
"mtoValorUnitario": 0.1000000000000000055511151231257827021181583404541015625,
"mtoBaseIgv": 0.200000000000000011102230246251565404236316680908203125,
"porcentajeIgv": 18,
"igv": 0.040000000000000000832667268468867405317723751068115234375,
"tipAfeIgv": "10",
"icbper": 1.0,
"factorIcbper": 0.5,
"totalImpuestos": 1.04000000000000003552713678800500929355621337890625,
"mtoValorVenta": 0.200000000000000011102230246251565404236316680908203125,
"mtoPrecioUnitario": 0.61999999999999999555910790149937383830547332763671875
}
],
"legends": [
{
"code": "1000",
"value": "SON DOSCIENTOS TREINTA Y SIETE CON 24/100 SOLES"
}
],
"icbper": 1.0
}
{
"ublVersion": "2.1",
"tipoOperacion": "1001",
"tipoDoc": "01",
"serie": "F001",
"correlativo": "1",
"fechaEmision": "2026-10-08T10:30:00-05:00",
"formaPago": {
"tipo": "Contado"
},
"tipoMoneda": "PEN",
"client": {
"tipoDoc": "6",
"numDoc": "20100070970",
"rznSocial": "EMPRESA CLIENTE S.A.C.",
"address": {
"direccion": "AV. LOS OLIVOS 123, LIMA"
}
},
"mtoOperGravadas": 1000.0,
"mtoIGV": 180.0,
"totalImpuestos": 180.0,
"valorVenta": 1000.0,
"subTotal": 1180.0,
"mtoImpVenta": 1180.0,
"details": [
{
"codProducto": "S001",
"unidad": "ZZ",
"cantidad": 1.0,
"descripcion": "SERVICIO DE MANTENIMIENTO",
"mtoValorUnitario": 1000.0,
"mtoBaseIgv": 1000.0,
"porcentajeIgv": 18,
"igv": 180.0,
"tipAfeIgv": "10",
"totalImpuestos": 180.0,
"mtoValorVenta": 1000.0,
"mtoPrecioUnitario": 1180.0
}
],
"legends": [
{
"code": "1000",
"value": "SON MIL CIENTO OCHENTA CON 00/100 SOLES"
},
{
"code": "2006",
"value": "Operación sujeta a detracción"
}
],
"detraccion": {
"codBienDetraccion": "022",
"codMedioPago": "001",
"ctaBanco": "00-000-000000",
"percent": 12,
"mount": 141.599999999999994315658113919198513031005859375
}
}
Campos
Sí la API responde 422 si falta. SUNAT la API no lo valida, pero SUNAT rechaza el comprobante si falta o no cuadra. Las demás condiciones indican cuándo es obligatorio.
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
| externalId | string(100) | No | ID de la venta en tu sistema. Evita duplicados en reintentos y permite que otros sistemas encuentren el comprobante. Ver referencia externa. |
| ublVersion | string | No | Versión UBL. Siempre "2.1". |
| tipoOperacion | string(4) | Sí | Tipo de operación según el catálogo 51. 0101 venta interna, 1001 sujeta a detracción. |
| tipoDoc | string(2) | Sí | 01 factura o 03 boleta (catálogo 01). |
| serie | string(4) | Sí | Serie registrada en el panel (Sucursales y series). Facturas empiezan con F (F001), boletas con B (B001). |
| correlativo | integer | No | Número del comprobante. Si no lo envías, la API asigna el siguiente de la serie (recomendado). |
| fechaEmision | fecha ISO 8601 | Sí | Fecha y hora de emisión. Ej. 2026-10-08T10:30:00-05:00. SUNAT acepta facturas con hasta 3 días de antigüedad. |
| tipoMoneda | string(3) | Sí | PEN o USD (catálogo 02). |
| formaPago | objeto | Solo facturas | Forma de pago de la factura. |
| formaPago.tipo | string | Solo facturas | Contado o Credito. |
| formaPago.monto | number | Si es crédito | Monto pendiente de pago. |
| formaPago.moneda | string(3) | Si es crédito | Moneda del monto pendiente. |
| cuotas[] | arreglo | Si es crédito | Cuotas del crédito: moneda, monto y fechaPago. La suma debe ser igual a formaPago.monto. |
| client | objeto | Sí | Cliente (adquiriente). |
| client.tipoDoc | string(1) | Sí | Tipo de documento (catálogo 06): 6 RUC (obligatorio en facturas), 1 DNI, 0 sin documento (boletas menores a S/ 700). |
| client.numDoc | string(15) | Sí | Número de documento (RUC de 11 dígitos, DNI de 8). |
| client.rznSocial | string(255) | Sí | Razón social o nombre completo. |
| client.address.direccion | string | No | Dirección del cliente. |
| mtoOperGravadas | number | Si hay gravados | Suma de mtoValorVenta de los ítems gravados (afectación 10). |
| mtoOperExoneradas | number | Si hay exonerados | Suma de mtoValorVenta de los ítems exonerados (afectación 20). |
| mtoOperInafectas | number | Si hay inafectos | Suma de mtoValorVenta de los ítems inafectos (afectación 30). |
| mtoOperGratuitas | number | Si hay gratuitos | Valor referencial de los ítems gratuitos; con mtoIGVGratuitas si son gravados. |
| mtoIGV | number | SUNAT | Total del IGV. |
| mtoBaseIsc / mtoISC | number | Si hay ISC | Base imponible y total del ISC. |
| mtoBaseIvap / mtoIvap | number | Si hay IVAP | Base imponible y total del IVAP (4%). |
| icbper | number | Si hay ICBPER | Total del impuesto a las bolsas plásticas. |
| totalImpuestos | number | SUNAT | Suma de todos los tributos (IGV + ISC + IVAP + ICBPER). |
| valorVenta | number | SUNAT | Total valor de venta (sin impuestos). |
| subTotal | number | SUNAT | Valor de venta + impuestos. |
| mtoImpVenta | number | Sí | Importe total a pagar. |
| detraccion | objeto | Si tipoOperacion 1001 | codBienDetraccion, codMedioPago, ctaBanco, percent y mount. Ver el ejemplo "Factura con detracción". |
| details[] | arreglo | Sí | Ítems del comprobante (al menos uno). |
| details[].codProducto | string | No | Código interno del producto. |
| details[].unidad | string | Sí | Unidad de medida (catálogo 03): NIU bienes, ZZ servicios. |
| details[].cantidad | number | Sí | Cantidad. Mayor que 0. |
| details[].descripcion | string | Sí | Descripción del producto o servicio. |
| details[].tipAfeIgv | string(2) | Sí | Afectación del IGV (catálogo 07): 10 gravado, 20 exonerado, 30 inafecto. |
| details[].mtoValorUnitario | number | Sí | Valor unitario sin IGV. |
| details[].mtoPrecioUnitario | number | SUNAT | Precio unitario con IGV. |
| details[].mtoValorVenta | number | Sí | cantidad × mtoValorUnitario. |
| details[].mtoBaseIgv | number | SUNAT | Base del IGV (normalmente igual a mtoValorVenta). |
| details[].porcentajeIgv | number | SUNAT | 18 para gravados, 0 para exonerados e inafectos. |
| details[].igv | number | SUNAT | mtoBaseIgv × porcentajeIgv / 100. |
| details[].totalImpuestos | number | SUNAT | Suma de los tributos del ítem. |
| legends[] | arreglo | No | Leyendas: {"code": "1000", "value": "SON ... SOLES"} es el monto en letras (recomendado). |
Cómo calcular los montos
Redondea cada monto a 2 decimales. Para un ítem gravado con IGV 18%:
mtoValorVenta = cantidad × mtoValorUnitario 2 × 50.00 = 100.00
mtoBaseIgv = mtoValorVenta = 100.00
igv = mtoBaseIgv × 18 / 100 = 18.00
totalImpuestos = igv (+ isc + icbper) = 18.00
mtoPrecioUnitario = mtoValorUnitario × 1.18 50.00 × 1.18 = 59.00
mtoOperGravadas = suma de mtoValorVenta de los ítems gravados = 200.00
mtoIGV = suma de igv de los ítems = 36.00
totalImpuestos = mtoIGV (+ mtoISC + icbper) = 36.00
valorVenta = mtoOperGravadas + mtoOperExoneradas + mtoOperInafectas = 200.00
subTotal = valorVenta + totalImpuestos = 236.00
mtoImpVenta = subTotal = 236.00
Si tus precios ya incluyen IGV, obtén el valor unitario dividiendo entre 1.18. Usa POST /api/invoices/xml
o la vista previa PDF para validar tus cálculos sin enviar nada a SUNAT.
Generar XML firmado (sin enviar)
ProbarRecibe el mismo cuerpo que /api/invoices/send y devuelve xml y hash sin enviarlo a SUNAT ni guardarlo. Útil para validar tus datos.
Vista previa en PDF
ProbarRecibe el mismo cuerpo y devuelve el PDF del comprobante sin emitirlo.
Emitir nota de crédito o débito
Probar| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
| tipoDoc | string(2) | Sí | 07 nota de crédito, 08 nota de débito. |
| serie | string(4) | Sí | Empieza con F si modifica una factura (FC01, FD01) o con B si modifica una boleta (BC01, BD01). |
| tipDocAfectado | string(2) | Sí | Tipo del comprobante que se modifica: 01 o 03. |
| numDocfectado | string | Sí | Serie y número del comprobante que se modifica. Ej. F001-1. |
| codMotivo | string(2) | Sí | Motivo según el catálogo 09 (crédito) o el catálogo 10 (débito). |
| desMotivo | string(250) | Sí | Descripción del motivo. |
| … | El resto de campos (externalId, correlativo, fechaEmision, tipoMoneda, client, montos, details y legends) son iguales a los de la factura, sin tipoOperacion ni formaPago. |
{
"ublVersion": "2.1",
"tipoDoc": "07",
"serie": "FC01",
"correlativo": "1",
"fechaEmision": "2026-10-08T10:30:00-05:00",
"tipDocAfectado": "01",
"numDocfectado": "F001-1",
"codMotivo": "07",
"desMotivo": "DEVOLUCIÓN POR ÍTEM",
"tipoMoneda": "PEN",
"client": {
"tipoDoc": "6",
"numDoc": "20100070970",
"rznSocial": "EMPRESA CLIENTE S.A.C.",
"address": {
"direccion": "AV. LOS OLIVOS 123, LIMA"
}
},
"mtoOperGravadas": 100.0,
"mtoIGV": 18.0,
"totalImpuestos": 18.0,
"valorVenta": 100.0,
"subTotal": 118.0,
"mtoImpVenta": 118.0,
"details": [
{
"codProducto": "P001",
"unidad": "NIU",
"cantidad": 2.0,
"descripcion": "PRODUCTO 1",
"mtoValorUnitario": 50.0,
"mtoBaseIgv": 100.0,
"porcentajeIgv": 18,
"igv": 18.0,
"tipAfeIgv": "10",
"totalImpuestos": 18.0,
"mtoValorVenta": 100.0,
"mtoPrecioUnitario": 59.0
}
],
"legends": [
{
"code": "1000",
"value": "SON CIENTO DIECIOCHO CON 00/100 SOLES"
}
]
}
{
"ublVersion": "2.1",
"tipoDoc": "08",
"serie": "FD01",
"correlativo": "1",
"fechaEmision": "2026-10-08T10:30:00-05:00",
"tipDocAfectado": "01",
"numDocfectado": "F001-1",
"codMotivo": "01",
"desMotivo": "INTERESES POR MORA",
"tipoMoneda": "PEN",
"client": {
"tipoDoc": "6",
"numDoc": "20100070970",
"rznSocial": "EMPRESA CLIENTE S.A.C.",
"address": {
"direccion": "AV. LOS OLIVOS 123, LIMA"
}
},
"mtoOperGravadas": 20.0,
"mtoIGV": 3.600000000000000088817841970012523233890533447265625,
"totalImpuestos": 3.600000000000000088817841970012523233890533447265625,
"valorVenta": 20.0,
"subTotal": 23.60000000000000142108547152020037174224853515625,
"mtoImpVenta": 23.60000000000000142108547152020037174224853515625,
"details": [
{
"codProducto": "INT",
"unidad": "ZZ",
"cantidad": 1.0,
"descripcion": "INTERESES POR MORA",
"mtoValorUnitario": 20.0,
"mtoBaseIgv": 20.0,
"porcentajeIgv": 18,
"igv": 3.600000000000000088817841970012523233890533447265625,
"tipAfeIgv": "10",
"totalImpuestos": 3.600000000000000088817841970012523233890533447265625,
"mtoValorVenta": 20.0,
"mtoPrecioUnitario": 23.60000000000000142108547152020037174224853515625
}
],
"legends": [
{
"code": "1000",
"value": "SON VEINTITRÉS CON 60/100 SOLES"
}
]
}
También existe POST /api/notes/xml para generar el XML sin enviarlo.
Emitir guía de remisión remitente
Probar| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
| externalId | string(100) | No | ID de la guía en tu sistema. |
| version | string | No | Siempre "2022". |
| tipoDoc | string(2) | No | 09 guía de remisión remitente. |
| serie | string(4) | Sí | Serie de guías registrada en el panel. Ej. T001. |
| correlativo | integer | No | Si no lo envías, la API asigna el siguiente. |
| fechaEmision | fecha ISO 8601 | Sí | Fecha y hora de emisión. |
| destinatario | objeto | Sí | tipoDoc, numDoc y rznSocial de quien recibe los bienes. |
| envio | objeto | Sí | Datos del traslado. |
| envio.codTraslado | string(2) | Sí | Motivo según el catálogo 20. Ej. 01 venta. |
| envio.desTraslado | string | No | Descripción del motivo. |
| envio.modTraslado | string(2) | Sí | Modalidad según el catálogo 18: 01 público, 02 privado. |
| envio.fecTraslado | fecha ISO 8601 | Sí | Fecha de inicio del traslado. |
| envio.pesoTotal | number | Sí | Peso bruto total. Mayor que 0. |
| envio.undPesoTotal | string | Sí | KGM o TNE. |
| envio.numBultos | integer | No | Número de bultos. |
| envio.partida | objeto | Sí | ubigueo (6 dígitos INEI) y direccion del punto de partida. |
| envio.llegada | objeto | Sí | ubigueo y direccion del punto de llegada. |
| envio.transportista | objeto | Si modTraslado 01 | tipoDoc, numDoc, rznSocial y nroMtc de la empresa de transporte. |
| envio.vehiculo | objeto | Si modTraslado 02 | placa del vehículo (no hace falta con vehículos M1/L). |
| envio.choferes[] | arreglo | Si modTraslado 02 | tipo, tipoDoc, nroDoc, nombres, apellidos y licencia (no hace falta con vehículos M1/L). |
| envio.indicadores | arreglo | No | ["SUNAT_Envio_IndicadorTrasladoVehiculoM1L"] cuando el traslado es en autos o motos. |
| details[] | arreglo | Sí | Bienes trasladados: codigo, descripcion, unidad y cantidad. |
{
"version": "2022",
"tipoDoc": "09",
"serie": "T001",
"correlativo": "1",
"fechaEmision": "2026-10-08T10:30:00-05:00",
"destinatario": {
"tipoDoc": "6",
"numDoc": "20100070970",
"rznSocial": "EMPRESA CLIENTE S.A.C."
},
"envio": {
"codTraslado": "01",
"desTraslado": "VENTA",
"modTraslado": "02",
"fecTraslado": "2026-10-08T10:30:00-05:00",
"pesoTotal": 12.5,
"undPesoTotal": "KGM",
"numBultos": 2,
"partida": {
"ubigueo": "150101",
"direccion": "AV. LIMA 123"
},
"llegada": {
"ubigueo": "150122",
"direccion": "AV. LARCO 456"
},
"vehiculo": {
"placa": "ABC123"
},
"choferes": [
{
"tipo": "Principal",
"tipoDoc": "1",
"nroDoc": "44556677",
"nombres": "JUAN",
"apellidos": "PÉREZ",
"licencia": "Q44556677"
}
]
},
"details": [
{
"codigo": "P001",
"descripcion": "PRODUCTO 1",
"unidad": "NIU",
"cantidad": 2
},
{
"codigo": "P002",
"descripcion": "PRODUCTO 2",
"unidad": "KGM",
"cantidad": 10.5
}
]
}
{
"version": "2022",
"tipoDoc": "09",
"serie": "T001",
"correlativo": "1",
"fechaEmision": "2026-10-08T10:30:00-05:00",
"destinatario": {
"tipoDoc": "6",
"numDoc": "20100070970",
"rznSocial": "EMPRESA CLIENTE S.A.C."
},
"envio": {
"codTraslado": "01",
"desTraslado": "VENTA",
"modTraslado": "02",
"fecTraslado": "2026-10-08T10:30:00-05:00",
"pesoTotal": 12.5,
"undPesoTotal": "KGM",
"numBultos": 2,
"partida": {
"ubigueo": "150101",
"direccion": "AV. LIMA 123"
},
"llegada": {
"ubigueo": "150122",
"direccion": "AV. LARCO 456"
},
"indicadores": [
"SUNAT_Envio_IndicadorTrasladoVehiculoM1L"
]
},
"details": [
{
"codigo": "P001",
"descripcion": "PRODUCTO 1",
"unidad": "NIU",
"cantidad": 2
},
{
"codigo": "P002",
"descripcion": "PRODUCTO 2",
"unidad": "KGM",
"cantidad": 10.5
}
]
}
{
"version": "2022",
"tipoDoc": "09",
"serie": "T001",
"correlativo": "1",
"fechaEmision": "2026-10-08T10:30:00-05:00",
"destinatario": {
"tipoDoc": "6",
"numDoc": "20100070970",
"rznSocial": "EMPRESA CLIENTE S.A.C."
},
"envio": {
"codTraslado": "01",
"desTraslado": "VENTA",
"modTraslado": "01",
"fecTraslado": "2026-10-08T10:30:00-05:00",
"pesoTotal": 12.5,
"undPesoTotal": "KGM",
"numBultos": 2,
"partida": {
"ubigueo": "150101",
"direccion": "AV. LIMA 123"
},
"llegada": {
"ubigueo": "150122",
"direccion": "AV. LARCO 456"
},
"transportista": {
"tipoDoc": "6",
"numDoc": "20000000002",
"rznSocial": "TRANSPORTES S.A.C.",
"nroMtc": "0001"
}
},
"details": [
{
"codigo": "P001",
"descripcion": "PRODUCTO 1",
"unidad": "NIU",
"cantidad": 2
},
{
"codigo": "P002",
"descripcion": "PRODUCTO 2",
"unidad": "KGM",
"cantidad": 10.5
}
]
}
{
"tipoDoc": "31",
"serie": "V001",
"fechaEmision": "2026-10-08T10:30:00-05:00",
"remitente": {
"tipoDoc": "6",
"numDoc": "20100070970",
"rznSocial": "EMPRESA CLIENTE S.A.C."
},
"destinatario": {
"tipoDoc": "6",
"numDoc": "20100070970",
"rznSocial": "EMPRESA CLIENTE S.A.C."
},
"relDocs": [
{
"tipo": "09",
"nro": "T001-123",
"emisor": "20100070970"
}
],
"envio": {
"fecTraslado": "2026-10-08",
"pesoTotal": 1500,
"undPesoTotal": "KGM",
"indicadores": [
"SUNAT_Envio_IndicadorPagadorFlete_Remitente"
],
"partida": {
"ubigueo": "150101",
"direccion": "AV. ARGENTINA 123"
},
"llegada": {
"ubigueo": "040101",
"direccion": "AV. EJÉRCITO 456"
},
"vehiculo": {
"placa": "ABC123",
"nroCirculacion": "15M21028326E",
"secundarios": [
{
"placa": "XYZ789"
}
]
},
"choferes": [
{
"tipo": "Principal",
"tipoDoc": "1",
"nroDoc": "44556677",
"nombres": "JUAN",
"apellidos": "PÉREZ",
"licencia": "Q44556677"
}
]
},
"details": [
{
"codigo": "P001",
"descripcion": "BOLSAS DE CEMENTO 42.5 KG",
"unidad": "NIU",
"cantidad": 50
}
]
}
Las guías se envían con la API REST de SUNAT: la respuesta incluye el ticket. Si SUNAT aún la está procesando,
el estado será error con código 98; consúltala de nuevo con el endpoint siguiente.
También existe POST /api/despatches/xml.
Guía de remisión transportista (31)
Probar
La emiten las empresas de transporte y los dueños de camiones que trasladan carga de terceros. Se usa el mismo endpoint con "tipoDoc": "31"
y una serie que empiece con V (regístrala en el panel). El emisor es tu empresa (el transportista); su número de registro MTC se toma de
"Datos de la empresa" o de nroMtc. No lleva motivo ni modalidad de traslado.
remitente: el dueño de la carga.destinatario: quien la recibe (puede ser el mismo remitente).relDocs: documentos relacionados, normalmente la guía remitente (tipo09) con el RUC de suemisor.envio.vehiculo(placa obligatoria,nroCirculacion= TUC, hasta 2secundarios) yenvio.choferes(1 a 3; el primero es el principal).envio.indicadores: SUNAT_Envio_IndicadorTransbordoProgramado, SUNAT_Envio_IndicadorRetornoVehiculoVacio, SUNAT_Envio_IndicadorRetornoVehiculoEnvaseVacio, SUNAT_Envio_IndicadorTrasporteSubcontratado, SUNAT_Envio_IndicadorPagadorFlete_Remitente, SUNAT_Envio_IndicadorPagadorFlete_Subcontratador, SUNAT_Envio_IndicadorPagadorFlete_Tercero. ConSUNAT_Envio_IndicadorPagadorFlete_Terceroenvía tambiénpagadorFlete.
{
"tipoDoc": "31",
"serie": "V001",
"fechaEmision": "2026-10-08T10:30:00-05:00",
"remitente": {
"tipoDoc": "6",
"numDoc": "20100070970",
"rznSocial": "EMPRESA CLIENTE S.A.C."
},
"destinatario": {
"tipoDoc": "6",
"numDoc": "20100070970",
"rznSocial": "EMPRESA CLIENTE S.A.C."
},
"relDocs": [
{
"tipo": "09",
"nro": "T001-123",
"emisor": "20100070970"
}
],
"envio": {
"fecTraslado": "2026-10-08",
"pesoTotal": 1500,
"undPesoTotal": "KGM",
"indicadores": [
"SUNAT_Envio_IndicadorPagadorFlete_Remitente"
],
"partida": {
"ubigueo": "150101",
"direccion": "AV. ARGENTINA 123"
},
"llegada": {
"ubigueo": "040101",
"direccion": "AV. EJÉRCITO 456"
},
"vehiculo": {
"placa": "ABC123",
"nroCirculacion": "15M21028326E",
"secundarios": [
{
"placa": "XYZ789"
}
]
},
"choferes": [
{
"tipo": "Principal",
"tipoDoc": "1",
"nroDoc": "44556677",
"nombres": "JUAN",
"apellidos": "PÉREZ",
"licencia": "Q44556677"
}
]
},
"details": [
{
"codigo": "P001",
"descripcion": "BOLSAS DE CEMENTO 42.5 KG",
"unidad": "NIU",
"cantidad": 50
}
]
}
Consultar ticket de una guía
ProbarVuelve a consultar en SUNAT una guía que quedó en proceso y devuelve su estado actualizado.
Anular comprobante
ProbarFacturas y sus notas (series F) se anulan con comunicación de baja (RA); boletas y sus notas (series B) con resumen diario con estado anulado (RC). Solo comprobantes aceptados y hasta 7 días después de su emisión; después emite una nota de crédito. Cualquier sistema de la empresa puede anular un comprobante emitido por otro.
{ "motivo": "ERROR EN EL RUC DEL CLIENTE" }
{
"estado": "anulado",
"document": {
"numero": "F001-00000006",
"anulacion": { "estado": "anulado", "motivo": "ERROR EN EL RUC DEL CLIENTE", "documento": "RA-20261008-1" }
},
"summary": { "id": 4, "tipo": "RA", "numero": "RA-20261008-1", "estado": "aceptado", "ticket": "1791479950715" }
}
Si SUNAT aún procesa el ticket, summary.estado será en_proceso y anulacion.estado pendiente.
Comunicaciones de baja y resúmenes
Lista las bajas (RA) y resúmenes (RC). GET /api/summaries/{id} devuelve uno y
POST /api/summaries/{id}/status vuelve a consultar su ticket en SUNAT.
Listar y filtrar comprobantes
Probar
Lista paginada de todos los comprobantes de la empresa, de cualquier sistema. Filtros opcionales:
tipoDoc, serie, correlativo, cliente (número de documento), desde y
hasta (AAAA-MM-DD), externalId, sistema (nombre del token o panel),
mios=1 (solo los del token que consulta) y per_page (máx. 100).
Para guías usa GET /api/despatches. GET /api/invoices/{id} devuelve un comprobante.
GET https://facpro.hachedev.online/api/invoices?sistema=POS&desde=2026-10-01&tipoDoc=03
Buscar por referencia externa
ProbarDevuelve el comprobante que un sistema emitió con ese externalId. Para guías: GET /api/despatches/reference/{externalId}.
Descargar PDF, XML y CDR
Probar
/api/invoices/{id}/pdf, /api/invoices/{id}/xml y /api/invoices/{id}/cdr descargan los archivos del comprobante.
Para guías: /api/despatches/{id}/pdf, /xml y /cdr. Los enlaces vienen en document.links.
Consultar CDR en SUNAT
Consulta en SUNAT el estado del comprobante y, si existe, descarga y guarda su CDR. Solo funciona con la empresa en producción (usa la clave SOL).
Enviar por correo
ProbarEnvía el PDF, XML y CDR al correo indicado: { "email": "cliente@correo.com" }. El correo sale en segundo plano, así que la respuesta es inmediata. Para guías: POST /api/despatches/{id}/email.
Consulta de RUC y DNI
Probar
GET /api/lookup/ruc/{ruc} y GET /api/lookup/dni/{dni} devuelven los datos listos para usar como client,
sin servicios externos ni límites de consultas. Buscan en:
- El padrón de SUNAT guardado en el servidor (se actualiza cada semana): todos los RUC, y el nombre de las personas que tienen RUC 10.
- Los clientes de tu empresa: los registrados en el panel y los de comprobantes aceptados (se registran solos al emitir).
fuente indica de dónde salió el dato: padron o clientes.
Si no se encuentra, la respuesta es 404 con "code": "not_registered": pide el nombre al usuario y emite el comprobante con esos datos;
al ser aceptado, el cliente queda registrado para la próxima consulta.
{
"tipoDoc": "6",
"numDoc": "20100070970",
"rznSocial": "EMPRESA CONSULTADA S.A.C.",
"direccion": "AV. PRINCIPAL NRO. 123, LIMA - LIMA - LIMA",
"ubigeo": "150101",
"estado": "ACTIVO",
"condicion": "HABIDO",
"fuente": "padron"
}
{
"message": "El DNI 12345678 no está registrado. Regístralo con el nombre del cliente.",
"code": "not_registered"
}
Formatos de PDF
Todos los PDF aceptan ?format=: a4, a5, ticket-80 (80 mm) y ticket-58 (58 mm).
Sin el parámetro se usa el formato configurado en la empresa (panel → Datos de la empresa), que también define el PDF que se envía por correo.
Las guías y las retenciones admiten a4 y a5. El ticket se genera en una sola página con el largo justo de su contenido.
Descarga en ZIP (para el contador)
Un ZIP con una carpeta por tipo de documento. Parámetros: desde y hasta (obligatorios),
tipos separados por comas (01,03,07,08,09,20,40,RC,RA; por defecto todos),
archivos (xml,cdr,pdf; por defecto los tres) y format para el PDF.
Máximo 3000 documentos por descarga, o 500 si incluye PDF.
La cabecera X-Documents-Count indica cuántos se incluyeron.
GET https://facpro.hachedev.online/api/documents/export?desde=2026-10-01&hasta=2026-10-31&tipos=01,03,07&archivos=xml,cdr
Indicadores (dashboard)
Para armar el panel de tu sistema: ventas del periodo por moneda (desde/hasta, por defecto el mes actual),
por tipo y por día, mejores clientes y productos, comprobantes por estado de SUNAT, pendientes de envío,
ventas de los últimos 12 meses, cuentas por cobrar y productos con stock bajo.
Catálogos y ubigeos
GET /api/catalogs devuelve los catálogos de SUNAT que usa la API (unidades, afectación del IGV, monedas, motivos de notas y traslado,
regímenes de retención y percepción, métodos de pago y formatos de PDF).
GET /api/catalogs/ubigeos?buscar=miraflores busca ubigeos por código o nombre (filtros departamento y provincia).
Códigos de producto SUNAT (UNSPSC), el valor de codProdSunat de cada ítem:
GET /api/catalogs/sunat-products?buscar=notebook busca productos por palabras o por el inicio del código;
?nivel=segmento, ?padre=43 (familias), ?padre=4321 (clases) y ?padre=432115 (productos) recorren el catálogo por niveles;
GET /api/catalogs/sunat-products/43211503 devuelve el código con su segmento, familia y clase (404 si no existe).
Al registrar productos, codProdSunat debe ser un código de 8 dígitos del catálogo.
Clientes
Los mismos clientes del panel. GET (filtros buscar y numDoc), POST,
GET/PUT/DELETE /api/customers/{id}. Campos: tipoDoc, numDoc, rznSocial, direccion, email, telefono.
{ "tipoDoc": "6", "numDoc": "20100070970", "rznSocial": "SUPERMERCADOS PERUANOS SOCIEDAD ANONIMA", "email": "compras@cliente.com" }
Productos
GET (filtros buscar, codigo, bajoStock=1), POST, GET/PUT/DELETE /api/products/{id}.
Con controlaStock: true el código es obligatorio: las ventas se relacionan con el producto por codProducto = codigo.
stockInicial registra el primer movimiento del kardex.
{ "codigo": "P001", "descripcion": "CEMENTO SOL 42.5 KG", "unidad": "NIU", "precio": 32.5, "tipAfeIgv": "10", "controlaStock": true, "stockInicial": 100, "stockMinimo": 10, "costo": 27.8 }
Inventario y compras
El stock se mueve solo:
- Factura o boleta emitida (aceptada, observada o pendiente de envío): salida. Si SUNAT la rechaza o se anula, se revierte.
- Nota de crédito por anulación o devolución (motivos 01, 02, 06 y 07): entrada.
- Nota de venta: salida; al convertirla en comprobante no se vuelve a descontar.
- Compra: entrada, y el costo del producto pasa a ser el promedio ponderado.
GET /api/inventory (resumen y stock bajo), GET /api/inventory/movements (kardex),
GET /api/products/{id}/movements, POST /api/products/{id}/adjust
({"cantidad": -2, "motivo": "MERMA"} o {"stock": 48, "motivo": "INVENTARIO FISICO"}),
GET/POST /api/purchases, GET/DELETE /api/purchases/{id} (eliminar revierte el stock).
{
"proveedor": { "tipoDoc": "6", "numDoc": "20100070970", "rznSocial": "DISTRIBUIDORA SAC" },
"tipoDoc": "01", "serie": "F001", "numero": "4521", "fecha": "2026-10-15",
"items": [ { "codProducto": "P001", "cantidad": 50, "costo": 27.8 } ]
}
Cotizaciones y notas de venta
Documentos internos que no van a SUNAT. Rutas iguales para /api/quotes (cotizaciones, serie COT1) y /api/sale-notes (notas de venta, serie NV01):
GET, POST, GET/PUT {id}, PUT {id}/status, GET {id}/pdf y
POST {id}/convert, que emite la factura o boleta (el token necesita además el permiso invoices).
Los precios incluyen IGV: el sistema calcula los totales. Estados de la cotización: pendiente, aceptada, rechazada
(y vencida si pasó fechaVencimiento); de la nota de venta: emitida y anulada (devuelve el stock). Ambas pasan a facturada al convertirse.
{
"client": { "tipoDoc": "6", "numDoc": "20100070970", "rznSocial": "SUPERMERCADOS PERUANOS SOCIEDAD ANONIMA" },
"fechaVencimiento": "2026-10-30",
"items": [
{ "codProducto": "P001", "descripcion": "CEMENTO SOL 42.5 KG", "unidad": "NIU", "cantidad": 10, "precio": 32.5, "tipAfeIgv": "10" }
],
"condiciones": "Entrega en 48 horas"
}
{ "tipoDoc": "01", "serie": "F001", "formaPago": "Credito",
"cuotas": [ { "monto": 383.5, "fechaPago": "2026-11-15" } ] }
Cobranzas
Para facturas y boletas a crédito. Los pagos se aplican a las cuotas en orden. GET /api/invoices/{id}/payments devuelve el saldo,
el estado (pendiente, parcial, vencido, pagado) y cada cuota; DELETE /api/invoices/{id}/payments/{pago} elimina un pago.
GET /api/receivables lista las cuentas por cobrar con la antigüedad de la deuda (filtros cliente y estado=vencido|por_vencer).
Cada pago dispara el webhook payment.registered. Métodos: efectivo, yape, plin, transferencia, deposito, tarjeta, cheque, nota_credito, otro.
{ "monto": 500, "metodo": "transferencia", "referencia": "OP 123456", "fecha": "2026-10-15" }
Retenciones y percepciones
Comprobantes de retención (20, series R…) y de percepción (40, series P…), para agentes designados por SUNAT. Registra antes la serie en el panel.
Rutas iguales para /api/retentions (con proveedor) y /api/perceptions (con cliente):
GET, POST send, POST xml, GET {id} y GET {id}/pdf|xml|cdr.
El sistema calcula los importes con la tasa del régimen (retención 01 = 3 %; percepción 01 = 2 %, 02 = 1 %, 03 = 0,5 %), o con tasa si la envías.
Para comprobantes en dólares envía tipoCambio; importe permite registrar un pago parcial.
{
"serie": "R001",
"regimen": "01",
"proveedor": { "tipoDoc": "6", "numDoc": "20100070970", "rznSocial": "DISTRIBUIDORA SAC" },
"details": [
{ "tipoDoc": "01", "numDoc": "F001-4521", "fechaEmision": "2026-10-01", "moneda": "PEN", "impTotal": 1180 },
{ "tipoDoc": "01", "numDoc": "F001-4522", "fechaEmision": "2026-10-02", "moneda": "USD", "impTotal": 100, "tipoCambio": 3.75 }
]
}
Validar comprobantes en SUNAT
Consulta Integrada de SUNAT: valida un comprobante de cualquier emisor, por ejemplo la factura de un proveedor antes de usar su crédito fiscal.
Usa el Client ID y el Client secret de la API SUNAT de tu empresa (los mismos de las guías). Responde valido, estado
(ACEPTADO, ANULADO, NO EXISTE, AUTORIZADO, NO AUTORIZADO), el estado del RUC emisor y su condición de domicilio.
{ "ruc": "20100070970", "tipoDoc": "01", "serie": "F001", "numero": 4521, "fecha": "2026-10-10", "monto": 1180 }
{
"valido": true,
"estado": "ACEPTADO",
"estadoRuc": "ACTIVO",
"condicionDomicilio": "HABIDO",
"observaciones": []
}
Conciliación con SIRE (Registro de Ventas)
Compara la propuesta del Registro de Ventas e Ingresos (RVIE) que arma SUNAT con los comprobantes de la empresa. Es solo una consulta: no acepta ni modifica nada en SUNAT.
Envía periodo (AAAAMM) y el archivo de la propuesta (multipart: TXT, CSV o ZIP descargado de SUNAT SOL).
Sin archivo, la API descarga la propuesta con la API SIRE (requiere modo producción, clave SOL y las credenciales de la API SUNAT); si SUNAT aún la genera,
queda procesando y se consulta con POST /api/sire/reconciliations/{id}/refresh.
Cada comprobante sale con un resultado: coincide, importe_distinto, solo_sistema (aceptado aquí pero no figura en SUNAT),
solo_sunat, estado_distinto (SUNAT lo tiene y aquí figura rechazado o con error), anulado_en_sistema o pendiente_envio.
curl -X POST https://facpro.hachedev.online/api/sire/reconciliations \
-H "Authorization: Bearer {token}" -H "Accept: application/json" \
-F periodo=202610 -F archivo=@propuesta-rvie-202610.zip
Catálogos SUNAT
Códigos que se usan en los campos de los comprobantes.
| 01 | Factura |
| 03 | Boleta de venta |
| 07 | Nota de crédito |
| 08 | Nota de débito |
| 09 | Guía de remisión remitente |
| 31 | Guía de remisión transportista |
| 20 | Comprobante de retención |
| 40 | Comprobante de percepción |
| 0 | Doc. trib. no dom. sin RUC |
| 1 | DNI |
| 4 | Carnet de extranjería |
| 6 | RUC |
| 7 | Pasaporte |
| A | Cédula diplomática de identidad |
| B | Doc. identidad país de residencia |
| 0101 | Venta interna |
| 0112 | Venta interna - Sustenta gastos deducibles persona natural |
| 0113 | Venta interna - NRUS |
| 0200 | Exportación de bienes |
| 0201 | Exportación de servicios - Prestación servicios realizados íntegramente en el país |
| 0401 | Ventas no domiciliados que no califican como exportación |
| 1001 | Operación sujeta a detracción |
| 2001 | Operación sujeta a percepción |
| 10 | Gravado - Operación onerosa |
| 11 | Gravado - Retiro por premio |
| 12 | Gravado - Retiro por donación |
| 13 | Gravado - Retiro |
| 14 | Gravado - Retiro por publicidad |
| 15 | Gravado - Bonificaciones |
| 16 | Gravado - Retiro por entrega a trabajadores |
| 17 | Gravado - IVAP |
| 20 | Exonerado - Operación onerosa |
| 21 | Exonerado - Transferencia gratuita |
| 30 | Inafecto - Operación onerosa |
| 31 | Inafecto - Retiro por bonificación |
| 32 | Inafecto - Retiro |
| 33 | Inafecto - Retiro por muestras médicas |
| 34 | Inafecto - Retiro por convenio colectivo |
| 35 | Inafecto - Retiro por premio |
| 36 | Inafecto - Retiro por publicidad |
| 37 | Inafecto - Transferencia gratuita |
| 40 | Exportación de bienes o servicios |
| NIU | Unidad (bienes) |
| ZZ | Unidad (servicios) |
| KGM | Kilogramo |
| GRM | Gramo |
| LTR | Litro |
| GLL | Galón |
| MTR | Metro |
| MTK | Metro cuadrado |
| MTQ | Metro cúbico |
| TNE | Tonelada |
| BX | Caja |
| PK | Paquete |
| DZN | Docena |
| MIL | Millar |
| SET | Juego |
| BG | Bolsa |
| HUR | Hora |
| DAY | Día |
| MON | Mes |
| PEN | Soles |
| USD | Dólares americanos |
| 01 | Anulación de la operación |
| 02 | Anulación por error en el RUC |
| 03 | Corrección por error en la descripción |
| 04 | Descuento global |
| 05 | Descuento por ítem |
| 06 | Devolución total |
| 07 | Devolución por ítem |
| 08 | Bonificación |
| 09 | Disminución en el valor |
| 10 | Otros conceptos |
| 11 | Ajustes de operaciones de exportación |
| 12 | Ajustes afectos al IVAP |
| 13 | Ajustes - montos y/o fechas de pago |
| 01 | Intereses por mora |
| 02 | Aumento en el valor |
| 03 | Penalidades / otros conceptos |
| 11 | Ajustes de operaciones de exportación |
| 12 | Ajustes afectos al IVAP |
| 01 | Venta |
| 02 | Compra |
| 03 | Venta con entrega a terceros |
| 04 | Traslado entre establecimientos de la misma empresa |
| 05 | Consignación |
| 06 | Devolución |
| 07 | Recojo de bienes transformados |
| 08 | Importación |
| 09 | Exportación |
| 13 | Otros |
| 14 | Venta sujeta a confirmación del comprador |
| 17 | Traslado de bienes para transformación |
| 18 | Traslado emisor itinerante CP |
| 01 | Transporte público |
| 02 | Transporte privado |