Documentación para desarrolladores

API de facturación electrónica SUNAT

Tú envías los datos ya calculados; nosotros armamos el XML UBL 2.1, lo firmamos, lo enviamos a SUNAT y te devolvemos el CDR. Todo en JSON, con ejemplos reales por cada caso.

Empieza en 3 pasos

De cero a tu primera factura aceptada por SUNAT, sin comprar certificado digital.

Tu cuenta se crea en el entorno de pruebas, el ambiente de homologación que la propia SUNAT ofrece para integrar: los comprobantes se emiten y se validan igual que en producción, pero sin efecto fiscal. La plataforma pone el certificado digital de ese entorno, así que puedes integrar completo antes de contratar el tuyo. Cuando termines, activamos tu emisor en producción con tu certificado y tus credenciales SOL.

Documentación API — Facturador electrónico SUNAT

Referencia completa de los endpoints de emisión.

API de pura emisión: el consumidor envía los datos ya calculados y el facturador arma el XML UBL 2.1, lo firma, lo envía a SUNAT y guarda el CDR. El PDF se genera en el momento en que se solicita, siempre con los datos vigentes del documento. Todas las peticiones y respuestas son JSON.

URL base: https://e-factura.jotitasoft.com/api

Archivos por UUID: cada documento devuelve un uuid; sus archivos se abren/descargan solo por UUID y sin token: https://e-factura.jotitasoft.com/api/doc/{uuid}/pdf?format=a4|ticket (PDF en tiempo real), https://e-factura.jotitasoft.com/api/doc/{uuid}/xml (descarga el XML) y https://e-factura.jotitasoft.com/api/doc/{uuid}/cdr (descarga el CDR; ?format=xml para el XML del CDR). Son URLs públicas que puedes enviarle al cliente final.

Content-Type: application/json
Accept: application/json
Authorization: Bearer TU_API_TOKEN

1. Autenticación (Bearer Token)

Método recomendado

Cada emisor tiene un API Token fijo (no vence). Lo encuentras en el panel: Usuarios → Datos de facturación → API Token. Envíalo en el header de cada petición:

Authorization: Bearer 9aF3...elTokenDe64Caracteres...Xz

Con el token, el sistema identifica solo al emisor: NO necesitas enviar user_id ni emisor_id en el body.

  • Token inválido o ausente con datos faltantes → 401 / 422.
  • Puedes regenerarlo en el panel (invalida el anterior).

Método antiguo (eliminado): antes se podía identificar al emisor enviando user_id (o emisor_id) en Base64 dentro del body, sin header Authorization. Se quitó por seguridad (ese valor era el ID correlativo del usuario, adivinable). Hoy esas peticiones responden 401: el token es obligatorio.

2. Tablas de referencia (SUNAT)

Tipo de comprobante (cat. 01)

01Factura
03Boleta de venta
04Liquidación de compra
07Nota de crédito
08Nota de débito
09Guía de remisión remitente
31Guía de remisión transportista
20Comprobante de retención
40Comprobante de percepción

Afectación IGV — afectacion de cada ítem

letracodigo_afectaciontributo_codigotributo_nombretributo_tipoCaso
S101000IGVVATGravado
E209997EXOVATExonerado
O309998INAFREInafecto
Z11..169996GRAFREGratuito
G409995EXPFREExportación

Código de producto SUNAT (cat. 25 — UNSPSC)

Cada línea lleva la clasificación del bien según el estándar UNSPSC del catálogo N° 25. Se envía por ítem:

"items": [
  { "codigo": "P001", "nombre": "GASEOSA INCA KOLA 1L", "unidad": "NIU",
    "codigo_producto_sunat": "50202301", "cantidad": 2, ... }
]
FormatoNumérico de hasta 8 dígitos, no puede ser solo ceros
Debe existirEn el catálogo N° 25 de SUNAT (UNSPSC)
Nivel mínimoTercer nivel jerárquico (clase del UNSPSC)
Aplica aFactura, boleta, liquidación, detracción, notas de crédito y débito, guías 09 y 31
Errores4332 inválido · 4337 nivel insuficiente · en guías 3002 formato, 3373 no existe, 3372 obligatorio si el bien es normalizado

Consultar el catálogo por API

El facturador trae los 52 840 códigos oficiales cargados (3 818 clases + 49 022 productos, del archivo CCNU de SUNAT). Cada sistema conectado puede buscarlos y guardarlos en su propio maestro de productos:

GET /api/catalogos/producto-sunat?buscar=gaseosa
GET /api/catalogos/producto-sunat?buscar=cemento&nivel=producto&por_pagina=50
GET /api/catalogos/producto-sunat/50202306          // valida un código exacto
GET /api/catalogos/producto-sunat/rubros            // los 56 segmentos
GET /api/catalogos/producto-sunat/rubros?segmento=50000000   // sus familias
ParámetroPara qué
buscarTexto libre o código. Entiende cómo se dice acá: gaseosa → Refrescos, laptop → Computadores, celular → Teléfonos móviles
nivelclase (3.er nivel) o producto (4.º nivel)
segmento · familia · claseFiltrar por rubro
por_pagina1 a 200 (por defecto 25)

Los resultados vienen ordenados por relevancia. Si ninguna coincidencia usa todas las palabras, responde con las que usan alguna y "coincidencia": "aproximada".

✔ Validación automática: si envías un codigo_producto_sunat que no existe en el catálogo, la emisión responde 422 con el motivo, en vez de que SUNAT lo rechace después.

⚠ Si no envías el campo, el facturador manda un código de relleno (10191509) para no romper las integraciones actuales, pero ese código no describe tu mercadería. Hoy SUNAT solo observa un código que no corresponde (4332/4337); con las nuevas reglas pasa a ser el ERROR 3496, que RECHAZA el comprobante. Manda el código real de cada producto lo antes posible.

La fecha de entrada en vigor ha circulado con dos versiones —1 de agosto de 2026 y 1 de enero de 2027—, así que conviene tratarla como vigente desde ya y enviar el código real de cada producto: adelantarse no cuesta nada y evita rechazos el día que la regla se aplique.

Estados del comprobante (estado_comprobante)

01Registrado / por regularizar (SUNAT no respondió)
03Enviado (resumen/baja, esperando CDR)
05Aceptado por SUNAT
07Aceptado con observaciones
09Rechazado
11Anulado / dado de baja
13En proceso de anulación

Re-emisión sobre rechazados: si un comprobante quedó 09 Rechazado, para SUNAT nunca existió, así que se puede volver a emitir la misma serie-correlativo corregida: el sistema libera el registro rechazado y procesa la nueva emisión (aplica a factura/boleta/liquidación/detracción y notas). Los demás estados sí bloquean el duplicado. En las guías (09 y 31) se libera también el estado 01 Registrado: mientras SUNAT no la haya aceptado, la misma serie-correlativo se puede reenviar corregida.

Tipo de documento del cliente (cat. 06)

1DNI
6RUC
4Carnet de extranjería
7Pasaporte
0Sin documento

Motivos

Nota de crédito (cat. 09): 01..13. Nota de débito (cat. 10): 01, 02, 03, 11, 12.

Validación de montos: el facturador NO calcula; pero valida que los importes cuadren (IGV de línea = base × %, totales = suma de líneas, balance final). Si no cuadran responde 422 con la lista de errores y NO envía a SUNAT.

3. Endpoints

POST /api/send/factura/boleta Factura (01) · Boleta (03) · Liquidación (04) · + Detracción

Endpoint único. El consumidor envía cada ítem y los totales ya calculados. Si incluye el bloque detraccion, se emite con detracción.

{
  "tipo_comprobante": "01",
  "serie": "F001",
  "correlativo": "123",
  "fecha_emision": "2026-06-02",
  "hora_emision": "10:30:00",
  "moneda": "PEN",
  "tipo_operacion": "0101",
  "forma_pago": "Contado",
  "porcentaje_igv": 18,
  "cliente": {
    "tipo_documento": "6",
    "numero_documento": "20512345678",
    "razon_social": "EMPRESA CLIENTE SAC",
    "direccion": "AV. SIEMPRE VIVA 123"
  },
  "items": [
    {
      "codigo": "P001",
      "nombre": "Producto gravado",
      "unidad": "NIU",
      "codigo_producto_sunat": "50202301",
      "cantidad": 2,
      "valor_unitario": 50.00,
      "precio_unitario": 59.00,
      "valor_total": 100.00,
      "igv": 18.00,
      "porcentaje_igv": 18.00,
      "icbper": 0,
      "factor_icbper": 0,
      "total_impuestos": 18.00,
      "importe_total": 118.00,
      "es_gratuita": false,
      "afectacion": { "letra": "S", "codigo_afectacion": "10", "tributo_codigo": "1000", "tributo_nombre": "IGV", "tributo_tipo": "VAT" }
    }
  ],
  "totales": {
    "op_gravadas": 100.00,
    "op_exoneradas": 0, "op_inafectas": 0, "op_gratuitas": 0, "exportacion": 0,
    "igv": 18.00, "icbper": 0,
    "descuento_global": 0, "total_cargos_globales": 0, "total_percepcion": 0, "total_anticipos": 0,
    "allowance_total": 0, "charge_total": 0,
    "total_antes_impuestos": 100.00,
    "total_impuestos": 18.00,
    "total_despues_impuestos": 118.00,
    "total_a_pagar": 118.00
  },
  "leyendas": [{ "codigo": "1000", "descripcion": "SON CIENTO DIECIOCHO CON 00/100 SOLES" }]
}

Crédito (cuotas)

"forma_pago": "Credito", "monto_credito": 118.00,
"cuotas": [{ "numero": "001", "importe": 118.00, "vencimiento": "2026-07-02" }]

Con detracción

"tipo_operacion": "1001",
"detraccion": { "codigo": "037", "porcentaje": 12, "monto": 141.60, "medio_pago": "001", "cuenta": "00-123-456789" }

Emisión por SEDE / establecimiento anexo (opcional)

Si emites desde una sede distinta a la casa matriz, envía el bloque establecimiento con el código del anexo (de tu Ficha RUC) y su dirección. El comprobante (XML y PDF) sale con ese código y esa dirección.

"establecimiento": {
  "codigo": "0001",
  "direccion": "AV. SEDE NORTE 456",
  "ubigeo": "150132", "departamento": "LIMA", "provincia": "LIMA", "distrito": "SAN ISIDRO"
}

Si se omite → casa matriz 0000 con la dirección del emisor. Aplica a factura (01), boleta (03), liquidación (04), notas (07/08) y también a retención (20) y percepción (40) (en 20/40 solo la dirección, sin código de anexo). Las series las organiza cada sede; los resúmenes y el SIRE son a nivel de RUC (traen todas las sedes). El código va en <cbc:AddressTypeCode listName="Establecimientos anexos"> y la dirección en <cac:RegistrationAddress>.

Datos de caja / POS (opcional — solo en el PDF)

Datos del ticket (cajero, medio de pago, con cuánto pagó, vuelto). Solo salen en el PDF (A4 y ticket), no en el XML. Si no se envían, no se muestran.

"pos": {
  "cajero": "JUAN PEREZ",
  "medio_pago": "Efectivo",
  "monto_pagado": 150.00, "vuelto": 32.00,
  "observaciones": "Gracias por su compra"
}

Aplica a factura (01), boleta (03) y liquidación (04). Todos los campos opcionales.

Respuesta

{
  "success": true,
  "message": "Comprobante armado y procesado por el Facturador.",
  "estado_comprobante": "05",
  "estado_texto": "Aceptado",
  "documento": "20512345678-01-F001-123",
  "uuid": "cf1285b1-18eb-4ed7-af26-0b174fb52c6a",
  "pdfA4": "{DOMINIO}/api/doc/cf1285b1-.../pdf?format=a4",
  "pdfTicket": "{DOMINIO}/api/doc/cf1285b1-.../pdf?format=ticket",
  "xml": "{DOMINIO}/api/doc/cf1285b1-.../xml",
  "cdr": "{DOMINIO}/api/doc/cf1285b1-.../cdr",
  "data": { "xml": "{DOMINIO}/api/doc/cf1285b1-.../xml", "cdr": "{DOMINIO}/api/doc/cf1285b1-.../cdr", "hash_cpe": "...", "mensaje_sunat": "...aceptada" }
}

Abre/descarga el documento con el uuid (URLs públicas, sin token). El PDF se genera al momento.

Boleta = "tipo_comprobante": "03" · Liquidación de compra = "04".

⚠ Liquidación de compra (04): la serie debe empezar con "E" (ej. E001) y el cliente es el proveedor con DNI (tipo_documento: "1"). Solo emite en producción con el emisor inscrito como emisor electrónico de LC; el ambiente beta (MODDATOS) no procesa el tipo 04.


CASO: Boleta a consumidor final (DNI o sin documento)

Cambia tipo_comprobante a 03 y el cliente con DNI (tipo_documento: "1") o sin documento ("0", número "00000000").

"tipo_comprobante": "03",
"serie": "B001",
"cliente": { "tipo_documento": "1", "numero_documento": "44556677", "razon_social": "JUAN PEREZ", "direccion": "-" }

CASO: Ítem EXONERADO (sin IGV)

El ítem no lleva IGV. igv = 0, y va a op_exoneradas.

"items": [{
  "codigo": "P002", "nombre": "Producto exonerado", "unidad": "NIU", "cantidad": 1,
  "valor_unitario": 100.00, "precio_unitario": 100.00, "valor_total": 100.00,
  "igv": 0, "porcentaje_igv": 0, "total_impuestos": 0, "importe_total": 100.00,
  "afectacion": { "letra": "E", "codigo_afectacion": "20", "tributo_codigo": "9997", "tributo_nombre": "EXO", "tributo_tipo": "VAT" }
}],
"totales": { "op_gravadas": 0, "op_exoneradas": 100.00, "igv": 0,
  "total_antes_impuestos": 100.00, "total_impuestos": 0, "total_despues_impuestos": 100.00, "total_a_pagar": 100.00 }

CASO: Ítem INAFECTO

Afectación O (cat.07 = 30, tributo 9998). El monto va a op_inafectas, sin IGV.

"afectacion": { "letra": "O", "codigo_afectacion": "30", "tributo_codigo": "9998", "tributo_nombre": "INA", "tributo_tipo": "FRE" }

CASO: Operación GRATUITA (muestra, bonificación)

es_gratuita: true, afectación Z (11–16), tributo 9996. NO se cobra: el monto va a op_gratuitas y a allowance_total; el total_a_pagar no la incluye.

"items": [{
  "codigo": "MX01", "nombre": "Muestra gratis", "unidad": "NIU", "cantidad": 1,
  "valor_unitario": 50.00, "precio_unitario": 0, "valor_total": 50.00,
  "igv": 9.00, "porcentaje_igv": 18, "total_impuestos": 9.00, "importe_total": 50.00,
  "es_gratuita": true,
  "afectacion": { "letra": "Z", "codigo_afectacion": "11", "tributo_codigo": "9996", "tributo_nombre": "GRA", "tributo_tipo": "FRE" }
}],
"totales": { "op_gravadas": 0, "op_gratuitas": 50.00, "igv_gratuitas": 9.00, "igv": 0,
  "allowance_total": 50.00, "total_antes_impuestos": 50.00, "total_impuestos": 0,
  "total_despues_impuestos": 0, "total_a_pagar": 0 }

Tip: agrega la leyenda 1002 "TRANSFERENCIA GRATUITA...".

CASO: EXPORTACIÓN

Afectación G (cat.07 = 40, tributo 9995), sin IGV; usa tipo_operacion: "0200". El monto va a exportacion.

"tipo_operacion": "0200",
"items": [{ "...": "...", "afectacion": { "letra": "G", "codigo_afectacion": "40", "tributo_codigo": "9995", "tributo_nombre": "EXP", "tributo_tipo": "FRE" } }],
"totales": { "exportacion": 1000.00, "igv": 0, "total_antes_impuestos": 1000.00, "total_a_pagar": 1000.00 }

CASO: con ICBPER (bolsas plásticas)

"items": [{ "...": "...", "icbper": 0.60, "factor_icbper": 0.30, "cantidad": 2, "total_impuestos": 18.60 }],
"totales": { "icbper": 0.60, "...": "..." }

CASO: ANTICIPOS (anticipo + comprobante final que lo deduce)

Flujo en 2 pasos: 1) el comprobante DE anticipo es una factura/boleta normal con tipo_operacion: "0101" (ítem "ANTICIPO DE ...", p. ej. F001-100 por 590.00; NO hay "marca de anticipo": el 0104 del catálogo 51 es RECHAZADO por SUNAT, error 3206). 2) el comprobante FINAL lleva los ítems por la venta COMPLETA y el bloque totales.anticipos[]; el sistema arma solo la referencia (cat.12) + identificador de pago + PrepaidPayment + descuento 04 (cat.53) por la base. Los totales se declaran NETOS (el IGV del anticipo ya se declaró) y total_a_pagar = total_despues_impuestos (el saldo).

// Venta total 1000.00 + IGV 180.00 = 1180.00, con anticipo F001-100 de 590.00 (base 500.00):
"items": [{ "codigo": "S001", "nombre": "SERVICIO DE CONSULTORIA", "unidad": "ZZ", "cantidad": 1,
  "valor_unitario": 1000.00, "precio_unitario": 1180.00, "valor_total": 1000.00,
  "igv": 180.00, "porcentaje_igv": 18, "total_impuestos": 180.00, "importe_total": 1180.00,
  "afectacion": { "letra": "S", "codigo_afectacion": "10", "tributo_codigo": "1000", "tributo_nombre": "IGV", "tributo_tipo": "VAT" } }],
"totales": {
  "op_gravadas": 500.00,            // 1000 - 500 (base del anticipo = monto / 1.18)
  "igv": 90.00,                     // IGV neto = 500 x 18%
  "total_antes_impuestos": 1000.00, // líneas completas
  "total_impuestos": 90.00,
  "total_despues_impuestos": 590.00, // 1000 - 500 (base) + 90
  "total_a_pagar": 590.00,          // = total_despues_impuestos (NO se resta de nuevo)
  "total_anticipos": 590.00,
  "anticipos": [ { "tipo_doc": "02", "serie": "F001", "correlativo": "100", "monto": 590.00 } ]
}

OJO: allowance_total NO incluye la base del anticipo (solo descuentos ordinarios). Opcionales por anticipo: base (sin IGV; si no llega se deriva con el % IGV), afectacion (gravado por defecto, exonerado → desc. 05, inafecto → desc. 06) y ruc_emisor. Si el anticipo cubre el 100%, los netos quedan en 0 y total_a_pagar: 0.

Respuesta: el XML generado

En data.xml viene el link al XML firmado; en data.cdr el CDR de SUNAT. El XML sin firmar también queda en xml/sinfirmar/ (auditoría).

POST /api/send/notadecredito Nota de Crédito (07)

Envía totales + items (igual que factura) + referencia del documento afectado + motivo (cat. 09).

{
  "serie_factura": "F001",
  "correlativo_factura": "123",
  "tipo_comprobante_factura": "01",
  "serie_nota": "FC01",
  "correlativo_nota": "1",
  "cod_motivo": "01",
  "descripcion_motivo": "ANULACION DE LA OPERACION",
  "moneda": "PEN",
  "fecha_emision": "2026-06-02",
  "cliente": {
    "tipo_documento": "6",
    "numero_documento": "20512345678",
    "razon_social": "EMPRESA CLIENTE SAC",
    "direccion": "AV. SIEMPRE VIVA 123"
  },
  "items": [
    {
      "codigo": "P001",
      "nombre": "Producto gravado",
      "unidad": "NIU",
      "codigo_producto_sunat": "50202301",
      "cantidad": 2,
      "valor_unitario": 50.00,
      "precio_unitario": 59.00,
      "valor_total": 100.00,
      "igv": 18.00,
      "porcentaje_igv": 18.00,
      "icbper": 0,
      "factor_icbper": 0,
      "total_impuestos": 18.00,
      "importe_total": 118.00,
      "es_gratuita": false,
      "afectacion": { "letra": "S", "codigo_afectacion": "10", "tributo_codigo": "1000", "tributo_nombre": "IGV", "tributo_tipo": "VAT" }
    }
  ],
  "totales": {
    "op_gravadas": 100.00,
    "op_exoneradas": 0, "op_inafectas": 0, "op_gratuitas": 0, "exportacion": 0,
    "igv": 18.00, "icbper": 0,
    "descuento_global": 0, "total_cargos_globales": 0, "total_percepcion": 0, "total_anticipos": 0,
    "allowance_total": 0, "charge_total": 0,
    "total_antes_impuestos": 100.00,
    "total_impuestos": 18.00,
    "total_despues_impuestos": 118.00,
    "total_a_pagar": 118.00
  }
}

Motivos cat. 09: 01 anulación, 02 error RUC, 03 corrección descripción, 04 descuento global, 05 descuento por ítem, 06 devolución total, 07 devolución por ítem, 08 bonificación, 09 disminución valor, 10 otros, 11 export, 12 IVAP, 13 corrección montos/fechas.


NOTA DE BOLETA → va por RESUMEN (automático)

Si la nota modifica una boleta (tipo_comprobante_factura: "03") y tu emisor está en modo resumen, la nota NO se envía directo: se firma y queda pendiente para informarse en el resumen diario (igual que las boletas). La respuesta trae via_resumen: 1 y estado Registrado. Luego envías el resumen del día y queda Aceptada.

  • Nota de factura ("01") → se envía directo a SUNAT (Aceptada al instante).
  • Nota de boleta ("03") con emisor resumen → por resumen diario.
POST /api/send/notadedebito Nota de Débito (08)

Misma estructura que la nota de crédito; cambia el motivo (cat. 10: 01, 02, 03, 11, 12).

{
  "serie_factura": "F001",
  "correlativo_factura": "123",
  "tipo_comprobante_factura": "01",
  "serie_nota": "FD01",
  "correlativo_nota": "1",
  "cod_motivo": "02",
  "descripcion_motivo": "AUMENTO EN EL VALOR",
  "moneda": "PEN",
  "fecha_emision": "2026-06-02",
  "cliente": {
    "tipo_documento": "6",
    "numero_documento": "20512345678",
    "razon_social": "EMPRESA CLIENTE SAC",
    "direccion": "AV. SIEMPRE VIVA 123"
  },
  "items": [
    {
      "codigo": "INT01",
      "nombre": "Interes por mora",
      "unidad": "NIU",
      "cantidad": 1,
      "valor_unitario": 50.00,
      "precio_unitario": 59.00,
      "valor_total": 50.00,
      "igv": 9.00,
      "porcentaje_igv": 18.00,
      "icbper": 0,
      "factor_icbper": 0,
      "total_impuestos": 9.00,
      "importe_total": 59.00,
      "es_gratuita": false,
      "afectacion": { "letra": "S", "codigo_afectacion": "10", "tributo_codigo": "1000", "tributo_nombre": "IGV", "tributo_tipo": "VAT" }
    }
  ],
  "totales": {
    "op_gravadas": 50.00,
    "op_exoneradas": 0, "op_inafectas": 0, "op_gratuitas": 0, "exportacion": 0,
    "igv": 9.00, "icbper": 0,
    "descuento_global": 0, "total_cargos_globales": 0, "total_percepcion": 0, "total_anticipos": 0,
    "allowance_total": 0, "charge_total": 0,
    "total_antes_impuestos": 50.00,
    "total_impuestos": 9.00,
    "total_despues_impuestos": 59.00,
    "total_a_pagar": 59.00
  }
}
POST /api/send/retencion Comprobante de Retención (20)
{
  "serie": "R001", "correlativo": 1, "fecha_emision": "2026-06-02",
  "codigo_regimen": "01", "porcentaje_retencion": 3,
  "receptor_tipo_documento": "6", "receptor_numero_documento": "20999999999",
  "receptor_razon_social": "PROVEEDOR SAC", "receptor_direccion": "AV. PROVEEDOR 456",
  "documentos": [
    {
      "tipo_documento": "01", "serie": "F001", "correlativo": "55",
      "fecha_emision": "2026-05-20", "total_documento": 1000.00, "moneda": "PEN",
      "fecha_pago": "2026-06-01", "numero_pago": 1, "importe_pago": 1000.00,
      "importe_retenido": 30.00, "fecha_retencion": "2026-06-01"
    }
  ]
}

Régimen: 01 = 3%, 02 = 6%. Para moneda ≠ PEN envía tipo_cambio. importe_retenido = importe_pago × % (validado).

POST /api/send/percepcion Comprobante de Percepción (40)
{
  "serie": "P001", "correlativo": 1, "fecha_emision": "2026-06-02",
  "codigo_regimen": "01", "porcentaje_percepcion": 2,
  "receptor_tipo_documento": "6", "receptor_numero_documento": "20888888888",
  "receptor_razon_social": "CLIENTE SAC",
  "documentos": [
    {
      "tipo_documento": "01", "serie": "F001", "correlativo": "60",
      "fecha_emision": "2026-05-22", "total_documento": 1000.00, "moneda": "PEN",
      "fecha_cobro": "2026-06-01", "numero_cobro": 1, "importe_cobro": 1000.00,
      "importe_percibido": 20.00, "fecha_percepcion": "2026-06-01"
    }
  ]
}

Las guías SÍ se pueden probar. A diferencia de las facturas y boletas, SUNAT no publica un entorno de homologación para las guías electrónicas (GRE 2.0). Por eso, mientras tu emisor esté en modo pruebas, la plataforma envía las guías a un entorno de verificación GRE que responde igual que el de SUNAT: obtienes tu ticket y tu CDR, y validas la integración completa sin efecto fiscal. Al pasar a producción, las mismas peticiones viajan a SUNAT sin que cambies una línea.

Requisito: el RUC del emisor debe ser válido (dígito verificador correcto). El servicio de guías lo comprueba al autenticar — a diferencia del de facturas, que no lo hace —, así que un RUC mal tecleado permite emitir facturas en pruebas pero impide enviar guías.

POST /api/send/guiaremision Guía de Remisión Remitente (09) — GRE 2.0
{
  "serie": "T001", "correlativo": 1, "fecha_emision": "2026-06-02", "fecha_envio": "2026-06-03",
  "doc_cliente": "20512345678", "cliente": "DESTINATARIO SAC", "tipo_documento_cliente": "6",
  "partida_ubigeo": "150101", "partida_direccion": "ALMACEN ORIGEN",
  "destino_ubigeo": "040101", "destino_direccion": "DESTINO FINAL",
  "modo_transporte": "02", "codigo_motivo_traslado": "01", "peso": 100, "unidad_peso": "KGM",
  "conductor_tipo_doc": "1", "conductor_nro_doc": "44556677", "conductor_nombres": "JUAN",
  "conductor_apellidos": "PEREZ", "conductor_licencia": "Q12345678", "vehiculo_placa": "ABC123",

  "serie_ref": "F001", "correlativo_ref": "123",
  "tipo_comprobante_ref": "01", "comprobante_ref_letras": "FACTURA",

  "items": [{ "codigo": "P001", "nombre": "Producto", "cantidad": 10, "unidad": "NIU", "codigo_producto_sunat": "50202306" }]
}

DOCUMENTO RELACIONADO (la venta que se traslada)

La guía referencia el comprobante de venta (factura/boleta) que origina el traslado:

serie_refSerie del comprobante (ej. F001, B001)
correlativo_refNúmero del comprobante (ej. 123)
tipo_comprobante_refTipo (cat.01): 01 Factura · 03 Boleta
comprobante_ref_letrasDescripción: FACTURA / BOLETA DE VENTA
ruc_emisor_ref · tipodoc_emisor_refOpcional. Emisor del documento relacionado (por defecto, el mismo emisor)

Si la venta la emitió OTRO contribuyente, manda ruc_emisor_ref con su RUC. Para traslados sin venta (ej. traslado entre almacenes, motivo 04), puede omitirse.


INDICADORES ESPECIALES (opcional) — ej. retorno con envases vacíos

Envía indicadores[] con los códigos que apliquen al traslado:

"indicadores": [ "SUNAT_Envio_IndicadorRetornoVehiculoEnvaseVacio" ]
CódigoCaso
SUNAT_Envio_IndicadorRetornoVehiculoEnvaseVacioRetorno con envases vacíos (ej. devolver botellas/cilindros)
SUNAT_Envio_IndicadorRetornoVehiculoVacioRetorno de vehículo vacío
SUNAT_Envio_IndicadorTransbordoProgramadoTransbordo programado
SUNAT_Envio_IndicadorVehiculoConductoresTranspEn transporte público: el remitente declara el vehículo y el conductor del transportista. Con él, vehiculo_placa y conductor pasan a ser obligatorios.
SUNAT_Envio_IndicadorTrasladoTotalDAMoDSTraslado total de la DAM/DS (importación/exportación)
SUNAT_Envio_IndicadorTrasladoContenedorManifiestoCargaTraslado en contenedor del manifiesto de carga
SUNAT_Envio_IndicadorTrasladoVehiculoM1LTraslado contratado en vehículo categoría M1 (auto) o L (moto/mototaxi). Solo transporte público. Con él NO se manda transportista, ni placa, ni conductor.

⚠ El indicador M1/L es exclusivo del transporte PÚBLICO (modo_transporte: "01"). Existe para cuando contratas una moto o un mototaxi y no sabes qué vehículo ni qué conductor harán el traslado. Si lo mandas en transporte privado, SUNAT lo evalúa igual como público y rechaza por falta de datos del transportista (3617). Para trasladar con tu propio vehículo usa "02" con placa y conductor, aunque sea una moto.

⚠ Con M1/L la placa y el conductor están prohibidos, no son opcionales: si se envían, SUNAT rechaza con el error 3453 (placa) o 3455 (conductor). Se puede combinar con cualquier motivo de traslado, incluido el 04 entre sedes.

ModalidadQué debes enviar
02 Privadovehiculo_placa + conductor (errores 2566/3357). El indicador M1/L no aplica
01 Públicotransportista_nro_doc (2558) + fecha_entrega_transportista (3617). Sin placa ni conductor
01 Público + M1/LSolo fecha_entrega_transportista. Ni transportista, ni placa, ni conductor
01 Público + VehiculoConductoresTranspTransportista + fecha_entrega_transportista + placa y conductor (pasan a ser obligatorios)

Si falta alguno de esos datos obligatorios, el facturador responde 422 antes de enviar a SUNAT.


CASO A: Transporte PRIVADO (modo_transporte: "02")

El propio emisor traslada con su vehículo y conductor. Obligatorio: datos del conductor y la placa.

"modo_transporte": "02",
"conductor_tipo_doc": "1", "conductor_nro_doc": "44556677",
"conductor_nombres": "JUAN", "conductor_apellidos": "PEREZ",
"conductor_licencia": "Q12345678",
"vehiculo_placa": "ABC123"

CASO B: Transporte PÚBLICO (modo_transporte: "01")

Contratas a una empresa de transporte. Obligatorio: datos del transportista (su RUC) y la fecha de entrega de los bienes al transportista. El conductor/placa los pone el transportista en su propia guía (31).

"modo_transporte": "01",
"transportista_tipo_doc": "6",
"transportista_nro_doc": "20444444444",
"transportista_nombre": "TRANSPORTES RAPIDOS SAC",
"fecha_entrega_transportista": "2026-08-12"

⚠ Campo nuevo (R.S. 108-2026, vigente desde el 01/06/2026). Antes esta fecha viajaba junto con la de inicio de traslado; ahora tiene su propio tag y SUNAT rechaza con el error 3617 si falta en transporte público. Si no la envías, el facturador usa fecha_envio. Debe ser igual o posterior a la fecha de emisión (error 3618).

CASO C: Traslado INTERNO entre sedes de la misma empresa (codigo_motivo_traslado: "04")

Dos condiciones que SUNAT verifica siempre en este motivo: el destinatario es el propio emisor (error 2554) y hay que indicar el código de establecimiento anexo (4 dígitos, tal como está declarado en el RUC) del punto de partida y del de llegada (errores 3365 y 3369).

"codigo_motivo_traslado": "04",
"partida_ubigeo": "150101", "partida_direccion": "ALMACEN CENTRAL",
"partida_codigo_establecimiento": "0000",   // "0000" = domicilio fiscal
"destino_ubigeo": "070101", "destino_direccion": "SEDE CALLAO",
"destino_codigo_establecimiento": "0001",   // sede de destino declarada en el RUC

// El destinatario debe ser el MISMO emisor (regla SUNAT 2554)
"tipo_documento_cliente": "6", "doc_cliente": "{RUC DEL EMISOR}", "cliente": "{RAZÓN SOCIAL DEL EMISOR}"
partida_codigo_establecimientoObligatorio en motivos 04 y 08
destino_codigo_establecimientoObligatorio en motivos 04, 09 y 19
partida_ruc_establecimiento
destino_ruc_establecimiento
Opcional. RUC dueño del establecimiento. Por defecto el del emisor; en el motivo 04 SUNAT obliga a que sea el del remitente y el sistema lo fuerza.

Si ya envías el bloque establecimiento (multi-sede), su codigo se usa como punto de partida cuando no mandas partida_codigo_establecimiento.

⚠ El código debe estar declarado en el RUC (si no: errores 3366/3370) y su ubigeo debe coincidir con el partida_ubigeo/destino_ubigeo que envías (si no: errores 3367/3371).

El traslado interno funciona con cualquier modalidad de transporte: el motivo 04 solo manda sobre los establecimientos y el destinatario, el vehículo se rige por modo_transporte.

Traslado interno con…Qué mandas además de los establecimientos
Camión / auto propio
modo_transporte: "02"
vehiculo_placa + datos del conductor
Transportista contratado
modo_transporte: "01"
transportista_nro_doc y nombre + fecha_entrega_transportista. Sin placa ni conductor: los declara él en su guía 31 (errores 3453/3455 si los envías)
Moto / mototaxi contratada
"01" + indicador M1/L
Solo fecha_entrega_transportista. Ni transportista, ni vehículo, ni conductor

Variante: traslado interno con transportista contratado (04 + modo 01)

"codigo_motivo_traslado": "04", "modo_transporte": "01",
"partida_codigo_establecimiento": "0000",
"destino_codigo_establecimiento": "0001",
"tipo_documento_cliente": "6", "doc_cliente": "{RUC DEL EMISOR}", "cliente": "{RAZÓN SOCIAL DEL EMISOR}",
"transportista_tipo_doc": "6", "transportista_nro_doc": "20444444444",
"transportista_nombre": "TRANSPORTES RAPIDOS SAC"

Si el remitente sí conoce el vehículo y el conductor del transportista y quiere declararlos, añade el indicador SUNAT_Envio_IndicadorVehiculoConductoresTransp y entonces vehiculo_placa y el conductor pasan a ser obligatorios (errores 2566/3357). Ese indicador no se puede combinar con M1/L (error 3451).

Variante: traslado interno en moto/mototaxi contratada (04 + M1/L)

El motivo de traslado y el indicador M1/L son independientes: se combinan sin problema. Es el caso de mandar mercadería entre sedes cercanas en una moto o mototaxi contratada — van los códigos de establecimiento y la fecha de entrega, y no van transportista, placa ni conductor.

"codigo_motivo_traslado": "04", "modo_transporte": "01",
"partida_codigo_establecimiento": "0000",
"destino_codigo_establecimiento": "0001",
"tipo_documento_cliente": "6", "doc_cliente": "{RUC DEL EMISOR}", "cliente": "{RAZÓN SOCIAL DEL EMISOR}",
"indicadores": ["SUNAT_Envio_IndicadorTrasladoVehiculoM1L"],
"fecha_entrega_transportista": "2026-08-12"
// SIN vehiculo_placa y SIN conductor_*: con M1/L están PROHIBIDOS (errores 3453 / 3455)

El facturador omite placa y conductor del XML automáticamente cuando detecta el indicador, aunque vengan en el request.

⚠ Si el traslado entre sedes lo haces con tu propia moto o auto, eso es transporte privado: modo_transporte: "02" con su placa y su conductor, sin el indicador M1/L.

CASO D: COMPRA / recojo de bienes ("02" o "07")

La mercadería la recoge el propio emisor, así que él es también el destinatario (error 2554 si no coincide). El punto de partida es el local del proveedor.

"codigo_motivo_traslado": "02",
"partida_direccion": "ALMACEN DEL PROVEEDOR",
"destino_direccion": "ALMACEN PROPIO", "destino_codigo_establecimiento": "0000",
"tipo_documento_cliente": "6", "doc_cliente": "{RUC DEL EMISOR}", "cliente": "{RAZÓN SOCIAL DEL EMISOR}"

CASO E: OTROS motivos ("13")

Obligatorio describir el traslado en descripcion_motivo_traslado (3 a 100 caracteres, con al menos 3 letras). Sin él, SUNAT rechaza con el error 3457.

"codigo_motivo_traslado": "13",
"descripcion_motivo_traslado": "TRASLADO A FERIA COMERCIAL"

Motivos de traslado (codigo_motivo_traslado, cat.20)

Catálogo completo y qué exige SUNAT en cada caso:

Cód.MotivoExige además
01Venta—
02CompraDestinatario = emisor (2554)
03Venta con entrega a terceros—
04Traslado entre establecimientos de la misma empresaDestinatario = emisor (2554) + establecimiento de partida y llegada (3365/3369)
05Consignación—
06Devolución—
07Recojo de bienes transformadosDestinatario = emisor (2554)
08ImportaciónDAM/DS + contenedores — no disponible por la API
09ExportaciónDAM/DS + contenedores — no disponible por la API
13Otrosdescripcion_motivo_traslado obligatoria (3457)
14Venta sujeta a confirmación del comprador—
17Traslado de bienes para transformación—
18Traslado emisor itinerante CP—
19Traslado de mercancía extranjeraDAM/DS + contenedores — no disponible por la API

Los motivos 08, 09 y 19 exigen además documentos aduaneros (DAM/DS tipo 50/52), contenedores, precintos y puerto/aeropuerto: el facturador todavía no arma esos bloques del XML.

Validación previa (no gasta correlativo)

Si falta un campo obligatorio según el motivo, la respuesta es HTTP 422 con el detalle antes de generar el XML e ir a SUNAT, así no se consume la serie-correlativo.

{
  "success": false,
  "message": "Falta \"partida_codigo_establecimiento\": … Sin él, SUNAT rechaza con el error 3365.",
  "errores": { "partida_codigo_establecimiento": ["…"] }
}

Respuesta

La guía siempre queda registrada (aceptada, rechazada o sin respuesta de SUNAT) y siempre devuelve uuid con sus enlaces a PDF/XML/CDR.

{
  "success": true,
  "aceptada": true,
  "message": "Guía de remisión aceptada por SUNAT. La guía numero T001-1, ha sido aceptada",
  "estado_comprobante": "05", "estado_texto": "Aceptado",
  "codigo_sunat": "0", "mensaje_sunat": "La guía numero T001-1, ha sido aceptada",
  "ticket": "202606021234567",
  "uuid": "cf1285b1-18eb-4ed7-af26-0b174fb52c6a",
  "pdfA4": "{DOMINIO}/api/doc/cf1285b1-.../pdf?format=a4",
  "pdfTicket": "{DOMINIO}/api/doc/cf1285b1-.../pdf?format=ticket",
  "xml": "{DOMINIO}/api/doc/cf1285b1-.../xml",
  "cdr": "{DOMINIO}/api/doc/cf1285b1-.../cdr"
}

Si SUNAT la rechaza, la respuesta es HTTP 400 con el motivo exacto (y la guía igual queda registrada para consultarla en el panel):

{
  "success": false, "aceptada": false,
  "message": "Guía de remisión RECHAZADA por SUNAT: [2325] El XML no contiene el número de placa del vehículo",
  "estado_comprobante": "09", "estado_texto": "Rechazado",
  "codigo_sunat": "2325", "mensaje_sunat": "El XML no contiene el número de placa del vehículo",
  "uuid": "…", "pdfA4": "…", "xml": "…"
}

Si SUNAT no responde o sigue procesando el ticket, la respuesta es HTTP 200 con estado_comprobante: "01" (Registrado / por regularizar) y el número de ticket en el mensaje. La guía NO se pierde: aparece en Documentos del emisor con su motivo.

Reenvío corregido: mientras la guía no esté aceptada (rechazada o por regularizar) puedes volver a enviar la misma serie-correlativo ya corregida; el sistema libera el registro anterior.

POST /api/send/guiatransportista Guía de Transportista (31) — GRE 2.0

El emisor es el transportista. Remitente y destinatario van en el request; conductor y vehículo obligatorios.

¿09 o 31? Quién emite cada una

Son dos guías distintas, emitidas por dos empresas distintas — no son alternativas.

Guía Remitente (09)Guía Transportista (31)
La emiteEl dueño de la mercaderíaLa empresa de transporte contratada
El emisor de la API esEl remitenteEl transportista
CuándoSiempre que se traslada mercaderíaSolo si el traslado lo hace un tercero
  • Transporte privado (modo_transporte: "02"): mueves con tu vehículo → solo la 09.
  • Transporte público (modo_transporte: "01"): contratas transportista → las dos. Tú emites la 09 con el RUC del transportista; él emite su 31 desde su propio sistema. La 31 no reemplaza a la 09.
  • El traslado interno entre sedes (motivo 04) siempre es una 09.

Un emisor solo usa este endpoint si su negocio es el transporte. Para tiendas, distribuidoras o fábricas, el endpoint es el de la guía remitente (09).

Caso base

{
  "serie": "V001", "correlativo": 1, "fecha_emision": "2026-06-02", "fecha_envio": "2026-06-03",
  "remitente_tipo_doc": "6", "remitente_doc": "20111111111", "remitente_nombre": "EMPRESA REMITENTE SAC",
  "tipo_documento_cliente": "6", "doc_cliente": "20999999999", "cliente": "EMPRESA DESTINO SA",
  "partida_ubigeo": "150101", "partida_direccion": "ORIGEN", "destino_ubigeo": "040101", "destino_direccion": "DESTINO",
  "codigo_motivo_traslado": "01", "peso": 100, "unidad_peso": "KGM",
  "conductor_tipo_doc": "1", "conductor_nro_doc": "44556677", "conductor_nombres": "JUAN",
  "conductor_apellidos": "PEREZ", "conductor_licencia": "Q12345678", "vehiculo_placa": "ABC123",
  "referencias": [{ "numero": "T001-1", "tipo": "09", "tipo_desc": "GUIA REMITENTE", "emisor_doc": "20111111111" }],
  "items": [{ "codigo": "P001", "nombre": "Producto", "cantidad": 10, "unidad": "NIU", "codigo_producto_sunat": "50202306" }]
}

Documentos relacionados (referencias[])

Puedes referenciar varias guías remitente (09) y/o documentos de venta. Cada referencia:

numeroSerie-correlativo (ej. T001-1, F001-123)
tipoTipo (cat.01): 09 Guía remitente · 01 Factura · 03 Boleta
tipo_descDescripción (sale en el PDF)
emisor_docRUC del emisor del documento relacionado (el remitente)

⚠ Regla SUNAT 3381: el emisor_doc de cada referencia NO puede ser el RUC del transportista (el emisor de esta guía); debe ser el del remitente/emisor de la venta. El facturador lo corta con un 422 antes de enviar.

CASO: carga consolidada (varios remitentes en un viaje)

Un solo viaje que lleva mercadería de varios clientes: se referencian todas las guías 09 involucradas, cada una con el RUC de su propio remitente.

"referencias": [
  { "numero": "T001-1",   "tipo": "09", "tipo_desc": "GUIA REMITENTE", "emisor_doc": "20111111111" },
  { "numero": "T002-15",  "tipo": "09", "tipo_desc": "GUIA REMITENTE", "emisor_doc": "20555555555" },
  { "numero": "F001-300", "tipo": "01", "tipo_desc": "FACTURA",        "emisor_doc": "20111111111" }
]

CASO: relevo de conductores y cambio de unidad (viaje largo)

"conductor_nro_doc": "87654321", "conductor_nombres": "PEDRO",
"conductor_apellidos": "RAMOS", "conductor_licencia": "L87654321",
"vehiculo_placa": "XYZ987", "vehiculo_tuc": "T1234567890",

"conductores_secundarios": [
  { "tipo_doc": "1", "nro_doc": "11223344", "nombres": "LUIS", "apellidos": "QUISPE", "licencia": "B11223344" }
],
"vehiculos_secundarios": [ { "placa": "DEF456", "tuc": "T0987654321" } ]

Respuesta

Idéntica a la de la guía remitente (09): se registra siempre y devuelve estado_comprobante, codigo_sunat, mensaje_sunat, ticket, uuid y los enlaces a PDF/XML/CDR. Rechazo → HTTP 400 con el motivo; sin respuesta de SUNAT → HTTP 200 con estado 01 (por regularizar).

Validaciones previas de las guías (09 y 31)

Antes de armar el XML, el facturador comprueba lo que SUNAT valida después. Si algo no cuadra responde 422 con el campo, el formato esperado y el código de error de SUNAT, sin consumir la serie-correlativo.

CampoReglaErrorGuía
partida_ubigeo · destino_ubigeoNumérico de 6 dígitos277609 y 31
vehiculo_placa6 a 8 caracteres, solo A-Z y 0-9, ni todo ceros256709 y 31
conductor_licencia9 a 10 caracteres, solo A-Z y 0-9, ni todo ceros257309 y 31
pesoNumérico mayor que cero252309 y 31
fecha_envioObligatoria (inicio del traslado)340609 y 31
modo_transporteSolo 01 o 02—09
items[].cantidadNumérica mayor que cero—09 y 31
partida_codigo_establecimientoObligatorio en motivos 04 y 08336509
destino_codigo_establecimientoObligatorio en motivos 04, 09 y 19336909
descripcion_motivo_trasladoObligatoria en motivo 13345709
Placa + conductorObligatorios en modo 02; prohibidos con M1/L2566 345309
transportista_nro_docObligatorio en modo 01 (salvo M1/L)255809
fecha_entrega_transportistaObligatoria en modo 01; si no se envía se asume fecha_envio3617 361809
Indicador M1/LSolo con modo_transporte: "01" (es transporte público)361709
M1/L + VehiculoConductoresTranspNo pueden ir juntos en modo 01345109
remitente_docRUC de 11 dígitos—31
referencias[].emisor_docObligatorio y distinto al RUC del transportista en tipos 09/313380 338131

Normalización automática: las placas y licencias se pasan a MAYÚSCULAS y se les quitan guiones y espacios antes de validar, así que "abc-123" se envía como ABC123 sin que la integración tenga que limpiarlo.

POST /api/send/resumen Resumen diario de boletas (asíncrono, devuelve ticket)

Flujo ASÍNCRONO (2 pasos): 1) Envías el resumen → SUNAT te da un ticket. 2) Consultas ese ticket en /api/consult/resumen para obtener el resultado (aceptado/rechazado). El resumen agrupa las boletas (03) (se reportan por resumen, no una por una).

¿Qué quiero hacer?Endpoint de envíoCampo claveConsultar ticket en
Reportar boletas del día (CASO 1 y 2)POST /api/send/resumen— (o comprobantes[])POST /api/consult/resumen
ANULAR boletas (03) (CASO 3)POST /api/send/resumencondicion_resumen: 3POST /api/consult/resumen
ANULAR facturas (01) y notasPOST /api/send/baja(ver pestaña Baja)POST /api/consult/baja

Regla: boletas → se anulan por RESUMEN (condición 3, se consultan en /consult/resumen); facturas/notas → se anulan por BAJA (se consultan en /consult/baja).

CASO 1: Resumen diario de TODAS las boletas de una fecha

Toma automáticamente las boletas pendientes de esa fecha y también sus notas de crédito/débito (07/08) de boletas que quedaron por resumen. Un solo envío reporta todo.

// Header: Authorization: Bearer TU_API_TOKEN
{ "fecha_referencia": "2026-06-01" }

Con el token NO envías user_id (el sistema ya sabe el emisor). Solo si NO usas token, agrega "user_id" (numérico o base64).

CASO 2: Resumen de boletas ESPECÍFICAS

{
  "fecha_referencia": "2026-06-01",
  "comprobantes": [
    { "tipo_comprobante": "03", "serie": "B001", "correlativo": "10" },
    { "tipo_comprobante": "03", "serie": "B001", "correlativo": "11" }
  ]
}

CASO 3: BAJA / anulación de boletas (vía resumen)

Las boletas NO se anulan con comunicación de baja, sino con un resumen de condición 3.

{
  "fecha_referencia": "2026-06-01",
  "condicion_resumen": 3,
  "motivo_baja": "ANULACION DE LA OPERACION",
  "comprobantes": [{ "tipo_comprobante": "03", "serie": "B001", "correlativo": "10" }]
}

Respuesta y luego consulta del ticket

// 1) Respuesta del envío
{ "success": true, "ticket": "1718900000000", "xml": "https://.../xml/...xml" }

// 2) POST /api/consult/resumen   (sirve para CASO 1, 2 y 3 — boletas)
// Header: Authorization: Bearer TU_API_TOKEN
{ "ticket": "1718900000000" }
→ { "success": true, "data": { "mensaje_sunat": "...aceptado" } }

Al aceptarse, las boletas del CASO 3 pasan a estado 11 Anulado.

El resumen diario también puede generarse y consultarse de forma automática: es una opción que se habilita por emisor. Escríbenos si quieres activarla en tu cuenta.

POST /api/send/baja Comunicación de Baja (anula facturas) — devuelve ticket

¿Cuándo usar Baja? Para anular FACTURAS (01) y notas (07/08) ya aceptadas (hasta 7 días). Flujo asíncrono: devuelve ticket → consultar en /api/consult/baja.

¿Qué anular?Enviar aConsultar ticket en
Factura (01) / Nota (07/08)POST /api/send/bajaPOST /api/consult/baja
Boleta (03)POST /api/send/resumen con condicion_resumen: 3POST /api/consult/resumen

CASO: Anular una o varias facturas

fecha_referencia = fecha de emisión de los comprobantes a anular.

// Header: Authorization: Bearer TU_API_TOKEN
{
  "fecha_referencia": "2026-06-01",
  "motivo": "ERROR EN LA OPERACION",
  "comprobantes": [
    { "tipo_comprobante": "01", "serie": "F001", "correlativo": "123", "motivo": "ERROR EN EL CLIENTE" },
    { "tipo_comprobante": "01", "serie": "F001", "correlativo": "124", "motivo": "DUPLICADO" }
  ]
}

Si omites comprobantes[], toma las facturas de esa fecha. motivo por ítem es opcional (usa el general si falta).

Respuesta y consulta

// Envío
{ "success": true, "ticket": "1718900000123" }

// POST /api/consult/baja
{ "ticket": "1718900000123" }   →  aceptado: los comprobantes pasan a estado 11 (Anulado)

Al enviar la baja, los comprobantes pasan a 13 En proceso de anulación; al consultar el ticket aceptado, a 11 Anulado.

GET /api/catalogos/producto-sunat Catálogo 25 — código de producto (UNSPSC)

El facturador trae cargados los 52 840 códigos oficiales del catálogo 25 (3 818 clases + 49 022 productos), tomados del archivo CCNU de SUNAT. Sirve para que cada sistema conectado encuentre el código que le toca a sus productos y lo guarde en su propio maestro.

Buscar

GET /api/catalogos/producto-sunat?buscar=gaseosa
GET /api/catalogos/producto-sunat?buscar=cemento&nivel=producto&por_pagina=50
GET /api/catalogos/producto-sunat?segmento=50000000        // todo un rubro
ParámetroPara qué
buscarTexto libre o código. Entiende cómo se dice acá: gaseosa → Refrescos, laptop → Computadores, celular → Teléfonos móviles
nivelclase (3.er nivel) o producto (4.º nivel)
segmento · familia · claseFiltrar por rubro (código de 8 dígitos)
por_pagina1 a 200 (por defecto 25)
{
  "success": true,
  "coincidencia": "exacta",
  "total": 228,
  "data": [
    { "codigo": "50202306", "descripcion": "Refrescos", "nivel": "producto",
      "clase_codigo": "50202300", "clase": "Bebidas no alcohólicas",
      "familia_codigo": "50200000", "familia": "Bebidas",
      "segmento_codigo": "50000000", "segmento": "Alimentos, Bebidas y Tabaco" }
  ]
}

Los resultados salen ordenados por relevancia. Si ninguna coincidencia usa todas las palabras, responde con las que usan alguna y "coincidencia": "aproximada".

Validar un código

GET /api/catalogos/producto-sunat/50202306   // 200 → { "valido": true, "data": {...} }
GET /api/catalogos/producto-sunat/99999999   // 404 → { "valido": false }

Rubros (para armar un selector)

GET /api/catalogos/producto-sunat/rubros                    // 56 segmentos
GET /api/catalogos/producto-sunat/rubros?segmento=50000000  // sus familias
GET /api/catalogos/producto-sunat/rubros?familia=50200000   // sus clases
POST /api/consult/resumen · /consult/baja · /consult/cdr · /consult/comprobante
Endpoint¿Para qué sirve?Qué enviar
/consult/resumenResultado del ticket de un RESUMEN de boletas (reporte o anulación cond.3)ticket
/consult/bajaResultado del ticket de una BAJA de facturas/notasticket
/consult/cdrDescargar/recuperar el CDR de un comprobante aceptadotipo, serie, correlativo
/consult/comprobanteEstado guardado + verifica en vivo si quedó por regularizartipo, serie, correlativo
/consult/validezValidez oficial ante SUNAT (estado CPE + estado/condición del RUC)ruc_emisor, tipo, serie, correlativo, fecha, monto

Todas autentican con el token Bearer (sin user_id en el body).

/consult/resumen y /consult/baja (consultar ticket):

{ "ticket": "1718900000000" }

/consult/cdr (recupera el CDR de un aceptado):

{ "tipo_comprobante": "01", "serie": "F001", "correlativo": "123" }

/consult/comprobante (estado + verifica en vivo si quedó por regularizar):

{ "tipo_comprobante": "01", "serie": "F001", "correlativo": "123" }
{ "success": true, "estado_comprobante": "05", "estado_texto": "Aceptado",
  "uuid": "cf1285b1-18eb-4ed7-af26-0b174fb52c6a",
  "xml": "{DOMINIO}/api/doc/{uuid}/xml",
  "cdr": "{DOMINIO}/api/doc/{uuid}/cdr",
  "pdfA4": "{DOMINIO}/api/doc/{uuid}/pdf?format=a4",
  "pdfTicket": "{DOMINIO}/api/doc/{uuid}/pdf?format=ticket" }

/api/consult/validez — VALIDEZ de un comprobante ante SUNAT (Consulta Integrada). Valida CUALQUIER comprobante: estado del CPE + estado/condición del RUC. Requiere credenciales consulta_client_id/secret del emisor.

POST /api/consult/validez
{
  "ruc_emisor": "20512345678",
  "tipo_comprobante": "01",
  "serie": "F001",
  "correlativo": "123",
  "fecha_emision": "2026-06-02",
  "monto": 118.00
}
{
  "success": true,
  "data": {
    "estadoCp": "1", "estadoCp_texto": "ACEPTADO",
    "estadoRuc": "00", "estadoRuc_texto": "ACTIVO",
    "condDomiRuc": "00", "condDomiRuc_texto": "HABIDO"
  }
}

estadoCp: 0 No existe · 1 Aceptado · 2 Anulado · 3 Con reparos · 4 No autorizado.

SIRE /api/sire/…  (RVIE ventas / RCE compras) Libros electrónicos — documentación aparte

SIRE (RVIE/RCE) tiene su documentación dedicada: ciclo de vida, los pasos con endpoint+payload copiables, el catálogo de edición individual (ventas/compras) y la tabla de cod_proceso. Está separada para no inflar esta página.

Abrir documentación SIRE

4. Automatización (reenvío + resúmenes)

La plataforma puede encargarse sola de dos tareas recurrentes, sin que tu sistema tenga que orquestarlas:

  • Reenvío automático: los comprobantes que quedaron sin respuesta de SUNAT (caídas del servicio, cortes de red) se reintentan hasta obtener su CDR.
  • Resumen diario automático: las boletas del día se agrupan, se envían y se consulta su ticket sin intervención.

Ambas se habilitan por emisor. Escríbenos si quieres activarlas en tu cuenta.