Documentación de la API
Emite comprobantes electrónicos válidos ante SUNAT desde tu sistema. API REST, JSON, autenticación por API key.
Empieza en 3 pasos
- 1. Copia tu API key y tu URL base desde tu panel (pestaña Configuración).
- 2. Prueba que funciona:
GET {tu_url_base}/api/v1/issuer/pingcon el headerX-API-Key. - 3. Emite tu primera factura de prueba (ejemplo mínimo abajo, en Emitir comprobante). Sale en modo sandbox, sin validez fiscal.
Impórtala en Postman, pon tu api_key y url_base en las variables, y ya tienes todos los endpoints listos para probar.
Introducción
La API te permite emitir boletas, facturas, notas de crédito/débito y anulaciones a SUNAT, y obtener el PDF, el XML firmado y el CDR. Tú envías la venta en JSON; nosotros armamos el XML UBL 2.1, lo firmamos y lo enviamos a SUNAT.
URL base:
https://TU_URL_BASE/api/v1/issuerReemplaza TU_URL_BASE por la URL que aparece en tu panel, junto a tu API key (pestaña Configuración). No es la misma para todas las cuentas.
Modelo de cuenta: tu cuenta tiene una bolsa de créditos compartida y puede emitir para uno o varios RUCs. Cada comprobante emitido descuenta 1 crédito de tu cuenta.
Autenticación
Toda petición lleva tu API key en el header:
X-API-Key: TU_API_KEYSi tu cuenta tiene varios RUCs, indica el RUC emisor en cada petición con el campo ruc (en el body o como query ?ruc=20123456789). Si tu cuenta tiene un solo RUC, se usa automáticamente.
Créditos
- Todo prepago: eliges un plan mensual/anual que recarga créditos cada mes, o compras recargas sueltas. Sin cobros por consumo ni facturación a fin de mes.
- Cuesta 1 crédito: cada boleta, factura, nota de crédito, nota de débito, cada guía de remisión (al enviarse) y cada anulación (al enviarse) — también en modo sandbox, para que integres con datos reales de consumo.
- Es gratis: consultar el estado, descargar PDF/XML/CDR y ver tu saldo (esto nunca consume crédito).
- Al registrarte recibes 100 créditos de regalo para integrar y probar en modo sandbox (SUNAT beta, sin validez fiscal) antes de pasar a producción.
- Si una emisión o envío falla, no se te cobra (el crédito se devuelve automáticamente).
- Compartidos por todos los RUCs de tu cuenta.
- Vigencia de 1 año desde que se acreditan; te avisamos por correo al 20% y 10% de saldo.
- Si te quedas sin créditos, la API responde
402y no emite (subes de plan o recargas).
Pasar a producción
Cada RUC nace en modo prueba (SUNAT beta, sin validez fiscal). Puedes integrar y probar de una vez, sin certificado ni clave SOL. Cuando estés listo para emitir comprobantes reales, activa producción en ese RUC.
Paso 1 — En el portal SUNAT del RUC de tu empresa
Con la Clave SOL de la empresa, dentro del portal de SUNAT:
- Crea un usuario secundario con permisos de facturación electrónica (no uses la Clave SOL principal). Ver cómo ↗
- Descarga tu Certificado Digital Tributario (CDT) desde SUNAT. Ver cómo ↗
Paso 2 — En el panel del RUC (FactuSmart)
- Entra al panel del RUC. Es una dirección propia por cada RUC:
https://TU_RUC.s2.factusmart.pe(la misma URL base de tu API, con tu RUC adelante). Ingresa con el correo y la contraseña que pusiste al dar de alta el RUC. - Ve a Configuración → Mi Negocio → "Credenciales y certificados".
- Sube tu certificado digital (CDT). En la tarjeta de certificado, escribe la contraseña de tu archivo
.pfxy súbelo. - Cambia el entorno a "Producción". En la tarjeta "Entorno del sistema", cambia SOAP Tipo de Demo a Producción. Al hacerlo aparecen los campos de la clave SOL.
- Ingresa tu Usuario Secundario SOL. En SOAP Usuario va
RUC + usuario secundario(ej.20123456789MIUSUARIO) y en SOAP Password la clave de ese usuario secundario. Guarda.
Importante
- Antes de activar producción, borra los comprobantes de prueba que hayas emitido en ese RUC (el sistema te lo pide).
- No cambia nada en tu integración: la misma API key y los mismos endpoints siguen funcionando. Solo que ahora ese RUC emite comprobantes con validez fiscal.
¿No puedes descargar el Certificado Digital (CDT) de SUNAT?
Si perdiste tu certificado o ya usaste todos los certificados gratuitos que SUNAT otorga, necesitas un servicio PSE que reemplace el firmado del comprobante. Recomendamos smartpse.pe, el que usamos con más de 1,500 clientes. Se configura en el panel del RUC (Empresa → Credenciales y certificados → PSE).
¿Tu RUC es PRICO (Principal Contribuyente)?
Los RUC catalogados como PRICO en SUNAT no pueden enviar los comprobantes directo a SUNAT: requieren una OSE (Operador de Servicios Electrónicos) para la validación. Contrata un servicio de validación OSE — se integra de forma nativa en nuestra API desde la configuración de la empresa. La OSE también sirve para reemplazar la validación de SUNAT cuando sus servidores tienen intermitencias y el comprobante puede demorar en aceptarse.
Crear y gestionar RUCs por API
Si tu integración da de alta clientes propios (marca blanca, multi-empresa), puedes crear y administrar sus RUCs sin pasar por el portal — todo con tu misma X-API-Key. Los créditos de la cuenta se comparten entre todos los RUCs que crees.
Crear un RUC
POST /api/v1/issuer/rucs
X-API-Key: tu_api_key
{
"ruc": "20609999991",
"empresa": "Mi Cliente SAC",
"correo": "[email protected]",
"clave": "una-clave-de-al-menos-6-caracteres"
}El RUC nace en modo prueba (igual que uno creado desde el portal) — sigue Pasar a producción cuando esté listo para emitir real. Si reintentas con el mismo RUC (ej. tras un timeout de red), la API detecta que ya es tuyo y te devuelve sus datos en vez de duplicarlo o dar error — es seguro reintentar.
Listar tus RUCs
GET /api/v1/issuer/rucs
X-API-Key: tu_api_key
→ { "success": true, "rucs": [
{ "ruc": "20609999991", "nombre": "Mi Cliente SAC", "entorno": "demo", "activo": true, ... }
] }Activar / desactivar un RUC
PATCH /api/v1/issuer/rucs/20609999991/activation
X-API-Key: tu_api_key
{ "activo": false }Un RUC desactivado deja de poder emitir, consultar o descargar nada por la API (ni desde el panel del RUC) hasta que lo reactives con el mismo endpoint enviando { "activo": true }. No borra ningún dato — es reversible en cualquier momento.
No hay endpoint para eliminar un RUC
Borrar un tenant es una operación destructiva e irreversible (pierdes el historial fiscal). Si necesitas dar de baja un RUC definitivamente, contáctanos — el resto de la gestión (crear, listar, activar, desactivar) es 100% self-service.
Emitir comprobante
El correlativo lo asigna FactuSmart: envía "numero_documento": "#". Cambia codigo_tipo_documento según el tipo (01 factura, 03 boleta, 07/08 notas).
Ejemplo — factura (cURL):
curl -X POST https://TU_URL_BASE/api/v1/issuer/documents \
-H "X-API-Key: TU_API_KEY" \
-H "Idempotency-Key: venta-000123" \
-H "Content-Type: application/json" \
-d '{
"ruc": "20123456789",
"numero_documento": "#",
"fecha_de_emision": "2026-06-17",
"hora_de_emision": "10:30:00",
"codigo_tipo_operacion": "0101",
"codigo_tipo_documento": "01",
"codigo_tipo_moneda": "PEN",
"datos_del_cliente_o_receptor": {
"codigo_tipo_documento_identidad": "6",
"numero_documento": "20555555555"
},
"totales": {
"total_operaciones_gravadas": 100.00,
"total_igv": 18.00,
"total_impuestos": 18.00,
"total_valor": 100.00,
"total_venta": 118.00
},
"items": [
{
"codigo_interno": "PROD-001",
"descripcion": "Servicio de consultoría",
"unidad_de_medida": "NIU",
"cantidad": 1,
"valor_unitario": 100.00,
"codigo_tipo_precio": "01",
"precio_unitario": 118.00,
"codigo_tipo_afectacion_igv": "10",
"total_base_igv": 100.00,
"porcentaje_igv": 18,
"total_igv": 18.00,
"total_impuestos": 18.00,
"total_valor_item": 100.00,
"total_item": 118.00
}
]
}'Respuesta:
{
"success": true,
"estado": "05",
"estado_descripcion": "Aceptado",
"serie_numero": "FA01-1234",
"external_id": "9822f52c-108e-47ff-...",
"aceptado_por_sunat": true,
"sunat": { "codigo": "0", "descripcion": "La Factura FA01-1234 ha sido aceptada" },
"creditos_restantes": 4830
}⚠️ Revisa aceptado_por_sunat, no solo el HTTP 200
Un 200 significa que generamos tu comprobante — no que SUNAT lo aceptó. SUNAT puede estar caída o rechazarlo, y entonces recibirás estado: "01" con aceptado_por_sunat: false y el motivo exacto en sunat.descripcion. Qué hacer en ese caso ↓
Para boleta usa "codigo_tipo_documento": "03". Para nota de crédito/débito usa "07"/"08" e incluye documento_afectado y codigo_tipo_nota.
Recomendado: manda tu propio código de producto en codigo_interno
Usa el ID/SKU del producto de tu propio sistema. La primera vez lo registramos en el catálogo del RUC; en los siguientes envíos lo reusamos — no se crean productos duplicados por cada emisión. El precio de cada comprobante sale siempre de lo que envías en ese comprobante (no del catálogo), así que puedes variar precios entre ventas sin problema. Si no envías codigo_interno, la emisión funciona igual, pero todas tus ventas se agrupan bajo un único producto genérico del catálogo.
RUC o DNI: el cliente lo puedes mandar con solo su documento
Si codigo_tipo_documento_identidad es "6" (RUC) o "1" (DNI), no necesitas mandar apellidos_y_nombres_o_razon_social, direccion ni ubigeo. Con el número basta — la API busca el resto automáticamente en SUNAT (RUC) o RENIEC (DNI):
"datos_del_cliente_o_receptor": {
"codigo_tipo_documento_identidad": "6",
"numero_documento": "20555555555"
}Si prefieres, puedes mandar también apellidos_y_nombres_o_razon_social, direccion y ubigeo — si los envías, se usan tal cual en vez de autocompletarse. Si el RUC/DNI no se encuentra, la API responde 422 pidiendo el nombre manualmente.
Otros documentos (carnet de extranjería, pasaporte, etc.)
Solo válidos en boleta, no en factura (la factura exige RUC). No hay autocompletado — manda apellidos_y_nombres_o_razon_social manualmente. No hace falta dirección ni ubigeo para ningún tipo de documento que no sea RUC.
Campos obligatorios que no debes omitir
Incluye siempre fecha_de_emision, hora_de_emision y, para facturas a crédito, fecha_de_vencimiento. Del cliente, siempre son obligatorios codigo_tipo_documento_identidad y numero_documento; el nombre es obligatorio solo si el documento no es RUC/DNI (ver nota de arriba). Si faltan, la API responde 422 indicando el dato ausente.
Calcular IGV y totales
La API espera los importes ya calculados (IGV, base, totales por ítem y del comprobante). En vez de hacer esa cuenta a mano, copia esta función en tu sistema: recibe cada ítem con precio sin IGV, cantidad y tipo de afectación, y devuelve el bloque items + totales listos para enviar.
Afectación: 10 gravado (18% IGV), 20 exonerado, 30 inafecto (estos dos sin IGV).
JavaScript
const IGV = 0.18;
const r2 = n => Math.round(n * 100) / 100;
// items: [{ codigo_interno, descripcion, unidad_de_medida, cantidad, valor_unitario, afectacion }]
function construirComprobante(items) {
let gravadas = 0, exoneradas = 0, inafectas = 0, totalIgv = 0;
const itemsApi = items.map(it => {
const base = r2(it.valor_unitario * it.cantidad);
const gravado = it.afectacion === '10';
const igv = gravado ? r2(base * IGV) : 0;
if (gravado) gravadas += base;
else if (it.afectacion === '20') exoneradas += base;
else inafectas += base;
totalIgv += igv;
return {
codigo_interno: it.codigo_interno,
descripcion: it.descripcion,
unidad_de_medida: it.unidad_de_medida || 'NIU',
cantidad: it.cantidad,
valor_unitario: r2(it.valor_unitario),
codigo_tipo_precio: '01',
precio_unitario: r2(it.valor_unitario * (gravado ? 1 + IGV : 1)),
codigo_tipo_afectacion_igv: it.afectacion,
total_base_igv: base,
porcentaje_igv: gravado ? 18 : 0,
total_igv: igv,
total_impuestos: igv,
total_valor_item: base,
total_item: r2(base + igv),
};
});
const totalValor = r2(gravadas + exoneradas + inafectas);
return {
items: itemsApi,
totales: {
total_operaciones_gravadas: r2(gravadas),
total_operaciones_exoneradas: r2(exoneradas),
total_operaciones_inafectas: r2(inafectas),
total_igv: r2(totalIgv),
total_impuestos: r2(totalIgv),
total_valor: totalValor,
total_venta: r2(totalValor + totalIgv),
},
};
}PHP
<?php
function construirComprobante(array $items): array {
$igvRate = 0.18;
$gravadas = 0; $exoneradas = 0; $inafectas = 0; $totalIgv = 0;
$itemsApi = [];
foreach ($items as $it) {
$base = round($it['valor_unitario'] * $it['cantidad'], 2);
$gravado = $it['afectacion'] === '10';
$igv = $gravado ? round($base * $igvRate, 2) : 0;
if ($gravado) $gravadas += $base;
elseif ($it['afectacion'] === '20') $exoneradas += $base;
else $inafectas += $base;
$totalIgv += $igv;
$itemsApi[] = [
'codigo_interno' => $it['codigo_interno'] ?? null,
'descripcion' => $it['descripcion'],
'unidad_de_medida' => $it['unidad_de_medida'] ?? 'NIU',
'cantidad' => $it['cantidad'],
'valor_unitario' => round($it['valor_unitario'], 2),
'codigo_tipo_precio' => '01',
'precio_unitario' => round($it['valor_unitario'] * ($gravado ? 1 + $igvRate : 1), 2),
'codigo_tipo_afectacion_igv' => $it['afectacion'],
'total_base_igv' => $base,
'porcentaje_igv' => $gravado ? 18 : 0,
'total_igv' => $igv,
'total_impuestos' => $igv,
'total_valor_item' => $base,
'total_item' => round($base + $igv, 2),
];
}
$totalValor = round($gravadas + $exoneradas + $inafectas, 2);
return [
'items' => $itemsApi,
'totales' => [
'total_operaciones_gravadas' => round($gravadas, 2),
'total_operaciones_exoneradas' => round($exoneradas, 2),
'total_operaciones_inafectas' => round($inafectas, 2),
'total_igv' => round($totalIgv, 2),
'total_impuestos' => round($totalIgv, 2),
'total_valor' => $totalValor,
'total_venta' => round($totalValor + $totalIgv, 2),
],
];
}El resultado tiene items y totales — únelos con el resto del comprobante (ruc, cliente, fechas) y envía.
Numeración, fechas y locales
La serie y el número los pone FactuSmart — tú no los envías
La serie de cada comprobante ya está configurada en tu RUC. En facturas, boletas, guías y demás, no envíes ninguna serie: FactuSmart usa la que corresponde y le asigna el correlativo. Solo mandas "numero_documento": "#" y el número lo pone el sistema. La única excepción son las notas de crédito y débito — ver más abajo.
La fecha de emisión debe ser real (la de hoy en Perú), no una fecha futura. Una fecha futura genera comprobantes que luego no podrás anular (la comunicación de baja no puede ser anterior a la fecha del documento).
¿Varios locales? Elige desde cuál emites
Por defecto se emite desde tu establecimiento principal (código 0000) y no necesitas indicar nada. Si tu RUC tiene más de un local/almacén (cada uno con su propia serie: FA01, FA02...), envía codigo_establecimiento con el código del local (0001, 0002...):
{
"ruc": "20123456789",
"codigo_establecimiento": "0001",
"codigo_tipo_documento": "01",
...
}La API usará automáticamente la serie, dirección y datos de ESE local — sin que tengas que enviar la serie. Los códigos de tus establecimientos están en tu panel (Empresa → Establecimientos).
Evitar comprobantes duplicados
Manda un header Idempotency-Key con un valor único por cada venta (por ejemplo, el ID de la venta en tu sistema):
Idempotency-Key: venta-000123Si tu sistema reintenta el mismo pedido (porque se cortó el internet o hubo un timeout), te devolvemos el mismo comprobante que ya emitimos, sin emitir ni cobrar de nuevo. Es la forma segura de reintentar sin arriesgar un duplicado fiscal.
- Misma
Idempotency-Key+ emisión ya completada → devuelve el comprobante original. - Misma key mientras la primera petición aún se procesa → responde
409(reintenta en unos segundos). - Si la emisión falló, la key queda libre: puedes reintentar con la misma.
- Usa una key distinta por cada comprobante nuevo.
Notas de crédito / débito
Una nota es como una factura/boleta, pero con dos datos extra: codigo_tipo_nota y documento_afectado (el comprobante original al que corrige). Usa "codigo_tipo_documento": "07" para nota de crédito y "08" para nota de débito.
Este es el único caso donde SÍ envías serie_documento
A diferencia de facturas y boletas, cada RUC tiene dos series de nota por tipo: una para las notas que corrigen facturas y otra para las que corrigen boletas. Como el sistema no puede adivinar cuál, aquí debes indicar serie_documento. Consulta las series exactas de tu RUC:
Busca en la respuesta las series con codigo_tipo_documento 07 (crédito) u 08 (débito). Por convención suelen ser FN01/FD01 para notas de factura y BN01/BD01 para notas de boleta, pero usa siempre lo que devuelva el endpoint.
Ejemplo — nota de crédito (campos extra):
{
"ruc": "20123456789",
"serie_documento": "FN01",
"numero_documento": "#",
"fecha_de_emision": "2026-06-30",
"hora_de_emision": "10:45:00",
"codigo_tipo_documento": "07",
"codigo_tipo_nota": "01",
"motivo_o_sustento_de_nota": "Anulación de la operación",
"documento_afectado": {
"external_id": "7cbce41c-...",
"serie_documento": "FA01",
"numero_documento": "1",
"codigo_tipo_documento": "01"
},
"codigo_tipo_moneda": "PEN",
"datos_del_cliente_o_receptor": { "...igual que la factura original..." },
"totales": { "...": "..." },
"items": [ { "...": "..." } ]
}El resto (cliente, totales, items) va igual que en una factura/boleta. Códigos comunes de codigo_tipo_nota: crédito 01 anulación, 07 devolución por ítem; débito 02 aumento en el valor.
Detracción
Para emitir una factura sujeta a detracción usa "codigo_tipo_operacion": "1001" (o "1004" para transporte de carga) y agrega el bloque detraccion. La detracción aplica a operaciones desde S/ 700.
{
"ruc": "20123456789",
"numero_documento": "#",
"fecha_de_emision": "2026-07-08",
"hora_de_emision": "10:30:00",
"codigo_tipo_operacion": "1001",
"codigo_tipo_documento": "01",
"codigo_tipo_moneda": "PEN",
"datos_del_cliente_o_receptor": {
"codigo_tipo_documento_identidad": "6",
"numero_documento": "20555555555"
},
"totales": {
"total_operaciones_gravadas": 1000.00,
"total_igv": 180.00,
"total_impuestos": 180.00,
"total_valor": 1000.00,
"total_venta": 1180.00
},
"detraccion": {
"codigo_tipo_detraccion": "022",
"porcentaje": 12,
"monto": 141.60,
"codigo_metodo_pago": "001",
"cuenta_bancaria": "00-000-000000"
},
"items": [
{
"descripcion": "Servicio empresarial sujeto a detracción",
"unidad_de_medida": "ZZ",
"cantidad": 1,
"valor_unitario": 1000.00,
"codigo_tipo_precio": "01",
"precio_unitario": 1180.00,
"codigo_tipo_afectacion_igv": "10",
"total_base_igv": 1000.00,
"porcentaje_igv": 18,
"total_igv": 180.00,
"total_impuestos": 180.00,
"total_valor_item": 1000.00,
"total_item": 1180.00
}
]
}Campos del bloque detraccion:
codigo_tipo_detraccion— el código del bien/servicio (tabla de abajo).porcentaje— el % según el código (ver tabla).monto— la detracción calculada: % sobre el total con IGV (ej. 1180 × 12% = 141.60), redondeado a 2 decimales.codigo_metodo_pago—"001"(Depósito en cuenta), el más común.cuenta_bancaria— tu cuenta del Banco de la Nación.
Códigos de bien/servicio más usados y sus porcentajes:
| Código | % | Tipo de operación | Bien / servicio |
|---|---|---|---|
| 001 | 10% | 1001 | Azúcar y melaza de caña |
| 003 | 10% | 1001 | Alcohol etílico |
| 005 | 4% | 1001 | Maíz amarillo duro |
| 008 | 4% | 1001 | Madera |
| 016 | 10% | 1001 | Aceite de pescado |
| 019 | 10% | 1001 | Arrendamiento de bienes |
| 020 | 12% | 1001 | Mantenimiento y reparación de bienes muebles |
| 022 | 12% | 1001 | Otros servicios empresariales |
| 023 | 4% | 1001 | Leche |
| 025 | 10% | 1001 | Fabricación de bienes por encargo |
| 027 | 4% | 1004 | Servicio de transporte de carga |
| 030 | 4% | 1001 | Contratos de construcción |
La lista completa está en el Anexo del catálogo 54 de SUNAT. El código va tal cual al comprobante, así que cualquier código oficial vigente es válido.
Consultar estado más tarde
Al emitir ya recibes el estado del comprobante en la misma respuesta — no necesitas llamar a este endpoint justo después de emitir. Úsalo cuando quieras revisar un comprobante en otro momento, distinto al de la emisión:
- Tu panel de ventas muestra el historial y quieres refrescar el estado de comprobantes antiguos sin volver a emitir nada.
- El cliente pide de nuevo el PDF días o semanas después (por WhatsApp, correo, etc.) — consultas para obtener el link de descarga actual.
- Tienes un proceso propio que revisa periódicamente los comprobantes que quedaron pendientes (aunque para eso normalmente es mejor el listado con filtro de estado, que trae varios a la vez).
- Guardaste el
external_idde una emisión y quieres recuperar sus datos completos (serie-número, total, links) sin tenerlos ya en tu BD.
{
"success": true,
"estado": "05",
"estado_descripcion": "Aceptado",
"serie_numero": "FA01-1234",
"total": 118.00,
"aceptado_por_sunat": true,
"sunat": { "codigo": "0", "descripcion": "La Factura FA01-1234 ha sido aceptada" },
"links": { "pdf": "...", "xml": "...", "cdr": "..." }
}Este endpoint lee lo que ya tenemos guardado — es instantáneo y no consume crédito, pero no le pregunta nada nuevo a SUNAT. Si el comprobante quedó en 01 (no confirmado) y necesitas saber si SUNAT lo aceptó en realidad, este endpoint no te lo dirá — usa consultar-sunat, que sí pregunta en vivo.
Si un comprobante no sale "Aceptado"
⚠️ La regla de oro: HTTP 200 no significa "aceptado por SUNAT"
Un 200 significa que generamos tu comprobante. Que SUNAT lo acepte es otra cosa: SUNAT puede estar caída, tardar, o rechazarlo. Mira siempre aceptado_por_sunat, nunca solo el código HTTP.
Los 3 estados que te importan
| Estado | Significa | Qué haces |
|---|---|---|
05 | Aceptado por SUNAT. Tiene validez fiscal. | Nada. Entrégalo a tu cliente. |
01 | No llegó a SUNAT o SUNAT no lo confirmó. Sin validez fiscal todavía. | Lee sunat.descripcion y actúa (abajo). |
09 | SUNAT lo rechazó. Ese número quedó quemado. | Corrige los datos y emite uno nuevo. |
1. Encuentra los atascados
Cada uno te dice por qué se quedó ahí, sin que tengas que preguntar:
{
"success": true,
"comprobantes": [
{
"external_id": "9f8e7d6c-...",
"serie_numero": "BA01-1318",
"estado": "01",
"aceptado_por_sunat": false,
"sunat": {
"codigo": "0111",
"descripcion": "No tiene el perfil para enviar comprobantes electronicos"
},
"accion_requerida": "El comprobante NO fue aceptado por SUNAT todavía. Revisa
\"sunat.descripcion\", corrige lo que indique y reintenta
con POST /documents/9f8e7d6c-.../reenviar"
}
]
}Filtros: estado, desde, hasta, limite (máx. 100). No consume crédito.
Si tienes más de 100, pagina con antes_de: cada respuesta trae siguiente_cursor — mándalo como antes_de en la próxima llamada para seguir. siguiente_cursor: null significa que no hay más.
2. Mira el historial completo
Toda la línea de tiempo del comprobante: cada intento y qué respondió SUNAT en cada uno.
{
"historial": [
{ "fecha": "2026-07-15 14:20:08", "evento": "creado",
"mensaje": "Comprobante generado" },
{ "fecha": "2026-07-15 14:20:11", "evento": "error", "codigo_sunat": "0111",
"mensaje": "No tiene el perfil para enviar comprobantes electronicos" },
{ "fecha": "2026-07-15 18:03:26", "evento": "reintento",
"mensaje": "Reintento de envío solicitado por el integrador (API)" },
{ "fecha": "2026-07-15 18:03:29", "evento": "aceptado", "codigo_sunat": "0",
"mensaje": "La Boleta BA01-1318 ha sido aceptada",
"detalle": { "estado": "05", "estado_anterior": "01" } }
]
}Eventos: creado, enviado, aceptado, observado, rechazado, error, reintento. No consume crédito.
3. Reenvía a SUNAT
Retomamos esto en su propia sección más abajo, con todo el detalle: Reenviar a SUNAT ↓.
4. Pregúntale a SUNAT en vivo
Consulta el estado real en SUNAT (no el nuestro) y lo sincroniza. Úsalo cuando el envío quedó en el aire y no sabes si SUNAT alcanzó a aceptarlo — a veces SUNAT sí lo recibió aunque la conexión se cortó antes de que nos confirmara. No consume crédito.
Los errores más comunes y qué significan de verdad
| Código | Causa real | Solución |
|---|---|---|
0111 | El usuario SOL existe pero no tiene el perfil de Facturación Electrónica. | Detente. Ese RUC no puede emitir nada. Entra al portal SUNAT con la Clave SOL principal y dale el permiso de facturación electrónica al usuario secundario. Reenviar no sirve hasta arreglarlo. |
0102 | Usuario o contraseña SOL incorrectos. | Detente. Corrige las credenciales en el panel del RUC. Mismo caso: afecta a todo el RUC. |
1033 | SUNAT ya tiene ese serie-número con otros datos. Típico si migraste de otro sistema, o si sigues emitiendo desde tu sistema anterior con la misma serie. | No reenvíes: ese número está quemado. Averigua en qué número va realmente SUNAT y continúa desde el siguiente. Nunca emitas la misma serie desde dos sistemas a la vez. |
0306 y otros 1001–1077 | Error en el contenido del comprobante (datos inválidos). | Reenviar no ayuda. Corrige los datos y emite uno nuevo. |
| Sin código, o mensaje de red / timeout | SUNAT no respondió (caída o lenta). Tu comprobante está bien — SUNAT no estaba disponible. | Reenvía más tarde. Nosotros ya reintentamos solos 3 veces al día, así que muchas veces se resuelve sin que hagas nada. |
Cuando SUNAT se cae (pasa seguido)
SUNAT tiene caídas e intermitencias con frecuencia. Cuando pasa, tus comprobantes quedan en 01 — no se pierden ni se cobran dos veces, solo esperan.
Nosotros los reintentamos automáticamente 3 veces al día. La mayoría se resuelve sola. Si necesitas que salga ya, usa /reenviar. Lo importante: no reemitas el comprobante — crearías un duplicado y quemarías otro correlativo.
La estrategia que usamos nosotros (cópiala)
- Al emitir, guarda siempre el
external_idy revisaaceptado_por_sunat. Si esfalse, leesunat.codigoen ese mismo momento. - Si el código es 0111 o 0102 → detén la emisión de ese RUC. Es un problema de configuración: todas las boletas que mandes van a fallar igual. Arréglalo en SUNAT primero. (Este error le costó un día entero a un integrador que siguió emitiendo sin mirar el mensaje.)
- Si es 1033 → no reenvíes. Revisa tu numeración; ese número ya existe en SUNAT.
- Si es un timeout o SUNAT no respondió → no hagas nada de inmediato. Nosotros reintentamos solos.
- Una vez al día, corre
GET /documents?estado=01por si algo quedó colgado, y usa/reenviaro/consultar-sunatsegún el caso. Con eso cubres todo — no necesitas estar preguntando a cada rato.
Por qué nunca marcamos como "Aceptado" algo que SUNAT no aceptó
Si SUNAT devuelve un código de duplicado (1033 y similares), dejamos el comprobante en 01 aunque parezca que "se envió". Preferimos que veas un estado incómodo antes que darte un PDF verde de una boleta que para SUNAT no existe — eso termina en multas durante una fiscalización.
Reenviar a SUNAT
¿Para qué sirve? Un comprobante que quedó en 01 (no confirmado) casi siempre necesita un reintento, no un comprobante nuevo. Este endpoint retoma el envío de ese mismo comprobante — no crea uno nuevo ni gasta un correlativo extra. Es el mismo botón "Reenviar" que usamos nosotros desde el panel del RUC.
¿Cuándo usarlo? Solo cuando la causa es algo que ya arreglaste o que se resolvió solo — SUNAT estaba caída, corregiste el usuario SOL, etc. Si el código de error dice que ya arreglar no basta (por ejemplo 1033, número ya usado), reenviar no sirve — revisa la tabla de errores comunes antes de reenviar a ciegas.
No consume crédito — ya lo pagaste al emitirlo la primera vez.
curl -X POST "{TU_URL_BASE}/api/v1/issuer/documents/9f8e7d6c-.../reenviar" \
-H "X-API-Key: TU_API_KEY" \
-H "Content-Type: application/json" \
-d '{"ruc": "20123456789"}'
# → Si se reenvía correctamente:
# { "success": true, "estado": "05", "aceptado_por_sunat": true,
# "sunat": { "codigo": "0", "descripcion": "...ha sido aceptada" } }⚠️ "success: true" en /reenviar solo significa "el reintento se ejecutó sin error de sistema"
Si SUNAT rechaza el reenvío (por ejemplo, código 1033 porque ese número ya existe), la respuesta sigue siendo HTTP 200:
{ "success": true, "estado": "09", "aceptado_por_sunat": false,
"sunat": { "codigo": "1033", "descripcion": "El comprobante fue registrado
previamente con otros datos" } }Aplica la misma regla de oro de siempre: mira aceptado_por_sunat, nunca solo success.
Descargar PDF / XML / CDR
Los 3 archivos existen para casos distintos — normalmente solo necesitas el PDF, los otros dos son para escenarios específicos:
PDF — para tu cliente
El comprobante listo para imprimir o enviar al cliente (por correo, WhatsApp, o para que lo descargue desde tu sistema). Es el que usa el 99% de las integraciones — muestra este link apenas termina la venta.
XML — para contabilidad
El archivo firmado digitalmente (formato UBL 2.1) que SUNAT procesó. Lo pide un contador para declarar, o un cliente empresa que necesita el XML para sustentar su compra ante SUNAT — no un consumidor final que solo quiere su boleta.
CDR — la prueba de que SUNAT lo aceptó
Es el ZIP que emite SUNAT confirmando la recepción (Constancia de Recepción). Úsalo si un cliente o una fiscalización pide demostrar que el comprobante realmente fue aceptado por SUNAT y no solo generado por tu sistema — el CDR es la evidencia oficial de SUNAT, no algo que emitimos nosotros.
Solo existen si el comprobante ya fue Aceptado (05)
Mientras el comprobante esté en 01 (no confirmado por SUNAT), estos 3 endpoints responden 404 — todavía no hay nada que descargar. Revisa primero aceptado_por_sunat con Consultar estado; si es false, ve a Si no sale "Aceptado" antes de intentar descargar.
Anulaciones (comunicación de baja)
¿Cuándo usar esto? Solo cuando un comprobante ya Aceptado (05) resultó estar mal (monto equivocado, cliente equivocado, venta que no se concretó) y necesitas dejarlo sin efecto ante SUNAT. No es para corregir — no puedes editar un comprobante ya aceptado. El flujo correcto es: anular el que está mal, y si corresponde, emitir uno nuevo con los datos correctos.
¿Uno o dos documentos, cliente presente?
Si el cliente sigue ahí y el error se nota al toque (ej. cobraste de más), casi siempre es más simple emitir una nota de crédito en vez de anular — la nota de crédito corrige el monto sin dejar el comprobante original completamente sin efecto. Reserva la anulación para cuando el comprobante entero debe desaparecer (la venta nunca debió emitirse).
Es un proceso asíncrono porque SUNAT no lo confirma al instante: envías la anulación, SUNAT te devuelve un ticket, y minutos después consultas ese ticket para saber si SUNAT la aceptó. La fecha va en formato DD-MM-AAAA y debe ser igual o posterior a la fecha de emisión de los documentos. Cada anulación enviada cuesta 1 crédito (si el envío falla, se devuelve).
Paso 1 — Enviar la anulación
{
"ruc": "20123456789",
"fecha_de_emision_de_documentos": "30-06-2026",
"documentos": [
{ "external_id": "9822f52c-...", "motivo_anulacion": "Error en el documento" }
]
}Puedes mandar varios documentos en la misma anulación si todos comparten la misma fecha de emisión — útil si te diste cuenta tarde de un lote entero mal emitido.
Paso 2 — Consultar el resultado (con el ticket que te devolvió el paso 1)
Espera unos minutos antes de consultar — SUNAT procesa la baja de forma asíncrona. Si consultas muy pronto, el resultado puede seguir en trámite; vuelve a consultar más tarde.
Guías de remisión electrónica (GRE 2.0)
La API emite guías de remisión (traslado de mercadería). Es asíncrona: se envía a SUNAT (devuelve un external_id) y consultas el resultado con el endpoint de estado. Cuesta 1 crédito al enviarse correctamente.
Requisito
La GRE 2.0 usa una API de SUNAT distinta a la de comprobantes, con credenciales propias de guías (aparte del certificado digital). El RUC emisor debe tenerlas configuradas en el panel antes de emitir guías. Además, en guías sí debes enviar serie_documento (TA01 para guía del remitente, VA01 para guía del transportista).
Ejemplo — guía del remitente (transporte privado):
{
"ruc": "20123456789",
"serie_documento": "TA01",
"numero_documento": "#",
"fecha_de_emision": "2026-07-08",
"hora_de_emision": "10:30:00",
"codigo_tipo_documento": "09",
"datos_del_emisor": { "codigo_del_domicilio_fiscal": "0000" },
"datos_del_cliente_o_receptor": {
"codigo_tipo_documento_identidad": "6",
"numero_documento": "20555555555",
"apellidos_y_nombres_o_razon_social": "EMPRESA DESTINO S.A.C."
},
"codigo_motivo_traslado": "01",
"descripcion_motivo_traslado": "Venta",
"fecha_de_traslado": "2026-07-08",
"peso_total": 50,
"unidad_peso_total": "KGM",
"numero_de_bultos": 2,
"codigo_modo_transporte": "02",
"direccion_partida": {
"ubigeo": "150101",
"direccion": "Av. Partida 123 - Lima",
"codigo_del_domicilio_fiscal": "0000"
},
"direccion_llegada": {
"ubigeo": "150203",
"direccion": "Av. Llegada 456 - Barranca",
"codigo_del_domicilio_fiscal": "-"
},
"vehiculo": { "numero_de_placa": "ABC123" },
"chofer": {
"codigo_tipo_documento_identidad": "1",
"numero_documento": "12345678",
"nombres": "Juan Pérez",
"numero_licencia": "Q12345678"
},
"items": [
{
"codigo_interno": "PROD-001",
"descripcion": "Producto trasladado",
"unidad_de_medida": "NIU",
"cantidad": 10
}
]
}Campos clave:
codigo_tipo_documento:09guía del remitente (la que emite quien traslada),31guía del transportista.codigo_motivo_traslado:01venta,02compra,04traslado entre establecimientos,18traslado emisor itinerante, entre otros (catálogo 20 de SUNAT).codigo_modo_transporte:01público (transportista) o02privado (vehículo y chofer propios, como el ejemplo).datos_del_emisor.codigo_del_domicilio_fiscal: el código de tu establecimiento (0000el principal).peso_total+unidad_peso_total(KGM),direccion_partidaydireccion_llegadacon su ubigeo.- Los ítems de una guía no llevan precio — solo
descripcion,unidad_de_medidaycantidad.
Transporte público (modo 01)
Cuando el traslado lo hace una empresa de transporte, usa "codigo_modo_transporte": "01" y, en vez de vehiculo y chofer, envía el bloque transportista (el resto del payload es igual):
"codigo_modo_transporte": "01",
"transportista": {
"codigo_tipo_documento_identidad": "6",
"numero_documento": "20555555555",
"apellidos_y_nombres_o_razon_social": "TRANSPORTES RAPIDOS S.A.C.",
"numero_mtc": "1234567"
}Vehículo ligero categoría M1 o L (auto o moto)
Si trasladas en un vehículo M1 (auto de pasajeros) o L (moto), SUNAT permite una guía simplificada: no declaras conductor ni datos del vehículo, solo marcas el indicador y la placa. Usa modo privado (02) con:
"codigo_modo_transporte": "02",
"es_traslado_m1l": true,
"numero_de_placa_m1l": "MOT123"En este caso no envíes los bloques vehiculo ni chofer.
Consultar saldo
Úsalo para anticipar un corte de servicio, no para reaccionar a él. Si te quedas sin créditos a mitad de una venta, la emisión responde 402 y esa venta no genera comprobante — mejor evitarlo que descubrirlo con un cliente esperando en caja.
Casos típicos de uso:
- Mostrar el saldo en tu propio panel, junto al de tu negocio, para que el administrador lo vea sin entrar a FactuSmart.
- Alertarte automáticamente (correo, Slack, lo que uses) cuando
creditos_disponiblesbaje de un umbral que definas — por ejemplo, si emites ~50 comprobantes al día, avisa bajo 200. - Decidir si recargas o subes de plan antes de que ocurra un
402en producción.
{
"success": true,
"cuenta": "Mi Integración",
"creditos_disponibles": 4830,
"creditos_recargados_total": 5000,
"creditos_consumidos": 170,
"rucs": [ { "ruc": "20123456789", "nombre": "..." } ]
}No consume crédito. Es gratis consultarlo tantas veces como quieras.
Códigos de respuesta
| Código | Significado |
|---|---|
| 200 / 201 | OK — comprobante emitido o consulta exitosa |
| 401 | API key faltante o inválida |
| 402 | Sin créditos disponibles en la cuenta |
| 403 | El RUC no pertenece a tu cuenta |
| 404 | Comprobante o recurso no encontrado |
| 409 | Ya hay una emisión en curso con esa Idempotency-Key |
| 422 | Datos inválidos o falta indicar el RUC |
| 429 | Demasiadas peticiones (límite: 120 por minuto por API key) |
Cada cuenta puede hacer hasta 120 peticiones por minuto. Si lo superas, espera unos segundos y reintenta.
Tipos de comprobante
| codigo_tipo_documento | Comprobante |
|---|---|
| 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 |
¿Listo para integrar?
Crea tu cuenta gratis y recibe tu API key con créditos de prueba al instante.
Crear cuenta gratis