Pacioli API e-CF

API e-CF (DGII) — Guía para integradores

Esta guía explica cómo emitir comprobantes fiscales electrónicos (e-CF) de la DGII a través de nuestro API: cómo autenticarse, qué ambiente usar, cómo armar el JSON, cómo se calculan los totales, qué pasa después del envío y cómo consultar el resultado.

Todo lo que aparece aquí sale del código del API y de los XSD oficiales de la DGII. Los ejemplos (uno por tipo de comprobante) se validan automáticamente contra las mismas reglas del endpoint y el XSD de la DGII: puedes enviarlos tal cual, cambiando solo el encf.

Recurso Para qué
Referencia del API Todos los endpoints con request, respuestas y ejemplos. Permite probar las llamadas desde el navegador.
OpenAPI 3.1 El contrato en formato estándar: impórtalo en Postman, Insomnia o un generador de clientes.
Esta guía Cómo armar el JSON, cómo calcular los totales y qué hacer con cada respuesta.

Inicio rápido

  1. Pide una API Key de testecf al administrador de tu empresa (portal → API Keys). Cada key es de un RNC y un ambiente.

  2. Envía el ejemplo E31-credito-fiscal.json, cambiando el encf por uno de tu secuencia:

    curl -X POST https://ecf.paciolird.com/api/testecf/factura/enviar-directo \
      -H "Authorization: Bearer $API_KEY" \
      -H "Content-Type: application/json" \
      -d @E31-credito-fiscal.json
    
  3. Guarda la respuesta 201: codigo_seguridad, url_dgii y qr_image son lo que va en la factura impresa, y ecf_queue_id sirve para consultar después.

  4. Consulta el resultado unos minutos después (el envío a la DGII es en segundo plano):

    curl "https://ecf.paciolird.com/api/testecf/ecf/estado?encf=E310000000001" \
      -H "Authorization: Bearer $API_KEY"
    

    Repite hasta que data.dgii.estado sea final (Aceptado, Aceptado Condicional, Rechazado, resumido, duplicado o fallido). Si no es Aceptado, el motivo está en data.dgii.mensaje.

Cuando funcione en testecf, pide la key de produccion y cambia testecf por produccion en la URL.

Contenido

  1. Ambientes y autenticación
  2. Flujo completo
  3. Endpoint principal: POST /{ambiente}/factura/enviar-directo
  4. Campos del request
  5. Cálculo de totales, redondeo y cuadre
  6. Respuestas y errores
  7. Estados del comprobante
  8. Endpoints de consulta
  9. Tablas de códigos
  10. Resumen por tipo de comprobante
  11. Recetas: casos frecuentes

Documentación por tipo: E31 · E32 · E33 · E34 · E41 · E43 · E44 · E45 · E46 · E47


1. Ambientes y autenticación

URL base

https://ecf.paciolird.com/api/{ambiente}/...
{ambiente} Ambiente DGII Para qué
testecf TesteCF Pruebas libres. Nada tiene validez fiscal.
certecf CerteCF Proceso de certificación como emisor electrónico ante la DGII.
produccion Producción (eCF) Comprobantes reales, con validez fiscal.

Cada ambiente lleva su propia secuencia de e-NCF en la DGII: el mismo e-NCF puede usarse en testecf y luego en produccion sin conflicto.

API Key

Cada request lleva el header:

Authorization: Bearer <api_key>

Errores de autenticación (todos HTTP 401):

Cuerpo Causa
{"message": "Token requerido"} Falta el header Authorization.
{"message": "Token inválido o entorno no coincide"} Key inexistente, inactiva o de otro ambiente.
{"message": "Emisor no encontrado"} La key apunta a un RNC sin emisor configurado.

Los endpoints de comprobantes recibidos (/api/ecf/recibidos...) no llevan ambiente en la URL: aceptan una key activa de cualquier ambiente y devuelven los comprobantes recibidos por su RNC.


2. Flujo completo

Tu sistema                         API                                   DGII
    │  POST /{ambiente}/factura/enviar-directo                             │
    │──────────────────────────────▶│ 1. valida el JSON                     │
    │                               │ 2. arma el XML del e-CF               │
    │                               │ 3. lo firma con el certificado        │
    │                               │ 4. lo valida contra el XSD de DGII    │
    │                               │ 5. guarda y encola (estado pendiente) │
    │◀──────────────────────────────│ 201: código de seguridad, URL, QR     │
    │                               │                                       │
    │   (imprimes / entregas el comprobante con el QR)                      │
    │                               │ worker (cada minuto)                  │
    │                               │──────────────────────────────────────▶│ envío
    │                               │◀──────────────────────────────────────│ trackId / estado
    │  GET /{ambiente}/ecf/estado   │                                       │
    │──────────────────────────────▶│ estado local (Aceptado, Rechazado…)   │
  1. Envías el comprobante a POST /{ambiente}/factura/enviar-directo.
  2. En la misma respuesta (201) recibes el código de seguridad, la URL de consulta del timbre DGII, la imagen QR (PNG en base64) y el XML firmado. Con eso ya puedes imprimir la representación impresa. Todo el paso 1–5 es atómico: si algo falla (validación, firma, XSD), no se guarda nada y puedes reintentar con el mismo e-NCF.
  3. El envío a la DGII es asíncrono. Un proceso corre cada minuto y envía los comprobantes en estado pendiente. Las Facturas de Consumo (E32) menores de RD$250,000 no se envían una por una: van en un Resumen de Factura de Consumo (RFCE) y quedan en estado resumido (ver E32).
  4. Consultas el resultado con GET /{ambiente}/ecf/estado?encf=... (o por ecf_queue_id / track_id) hasta que llegue a un estado final (Aceptado, Aceptado Condicional, Rechazado, resumido, fallido). Ver estados.

3. Endpoint principal

POST https://ecf.paciolird.com/api/{ambiente}/factura/enviar-directo
Authorization: Bearer <api_key>
Content-Type: application/json

Cuerpo: un objeto con dos claves.

{
  "factura": { "...": "encabezado: tipo, e-NCF, fechas, emisor, comprador, totales" },
  "detalle": [ { "...": "una entrada por línea" } ]
}

Ejemplo mínimo completo (Factura de Crédito Fiscal): ejemplos/E31-credito-fiscal.json. Hay un ejemplo validado por cada tipo en ejemplos/.

Solo se aceptan los campos listados en la sección 4. Cualquier otra clave (por ejemplo nombre_comercial, telefono_emisor, descripcion_item, identificador_extranjero) se descarta en silencio y no llega al XML.


4. Campos del request

Columna "XML": el elemento del e-CF que se genera. Las restricciones de largo/formato son las del XSD de la DGII; si no se cumplen, la respuesta es 422 Comprobante inválido según el esquema de DGII.

Fechas: envíalas como YYYY-MM-DD. El API las convierte al formato DGII (dd-mm-aaaa).

Tipos JSON. Estos campos se validan como texto y deben ir como string JSON (entre comillas); un número ("tipo_ecf": 31) se rechaza con 422 Error de validación ("must be a string"): tipo_ecf, encf, tipo_ingresos, termino_pago, rnc_emisor, razon_social_emisor, direccion_emisor, municipio_emisor, provincia_emisor, correo_emisor, website_emisor, codigo_vendedor, numero_factura_interna, numero_pedido_interno, zona_venta, rnc_comprador, razon_social_comprador, direccion_comprador, municipio_comprador, provincia_comprador, correo_comprador, numero_orden_compra, codigo_interno_comprador, ncf_modificado, codigo_modificacion, razon_modificacion y, en el detalle, nombre_item y unidad_medida. tipo_pago y formas_pago[].forma_pago aceptan "1" o 1 (se recomienda string). Los montos y los indicadores (indicador_monto_gravado, indicador_facturacion, indicador_bien_servicio, indicador_nota_credito, indicador_agente_retencion_percepcion, numero_linea) van como número.

Identificación del comprobante

Campo Req. XML Notas
tipo_ecf Sí TipoeCF "31", "32", "33", "34", "41", "43", "44", "45", "46", "47".
encf Sí eNCF 13 caracteres: E + tipo (2) + secuencia (10). Ej. E310000000001. Debe coincidir con tipo_ecf (un E32 numerado E31… se rechaza con 422). No se rellena: uno mal formado se rechaza.
fecha_emision Sí FechaEmision
fecha_vencimiento Según tipo FechaVencimientoSecuencia Fecha de vencimiento de la secuencia de e-NCF autorizada por la DGII, no el vencimiento de la factura. Obligatoria por XSD en 31, 33, 41, 43, 44, 45, 46 y 47. En 32 y 34 se ignora.
tipo_ingresos No TipoIngresos "01"–"06" (string). Si no se envía, "01". No se emite en 41, 43 y 47.
tipo_pago Según tipo TipoPago "1" contado, "2" crédito, "3" gratuito. Obligatorio por XSD en 31, 32, 33, 34, 44, 45 y 46; opcional en 41, 43 y 47. Otro valor → 422.
formas_pago No TablaFormasPago Lista de hasta 7 { "forma_pago": "1"-"8", "monto": 0.00 } (ver tabla). Las filas con monto 0 se descartan. Si no se envía, se deduce de tipo_pago: contado → una fila 1 (efectivo) por monto_total; crédito → una fila 4 (venta a crédito); gratuito → ninguna. No se emite en 34 ni 43, ni si falta tipo_pago. Debe sumar monto_total.
fecha_limite_pago No FechaLimitePago No se emite en 43.
termino_pago No TerminoPago Máx. 15 caracteres (letras, dígitos, espacios). Ej. "30 dias". No se emite en 34 ni 43.
indicador_monto_gravado No IndicadorMontoGravado 0 (precios sin ITBIS, recomendado) o 1 (precios con ITBIS incluido). Si no se envía, 0. Solo se emite en 31, 32, 33, 34, 41 y 45. Ver 5.4.

Emisor

Campo Req. XML Notas
rnc_emisor No RNCEmisor Se toma de la API Key. No lo envíes: si lo envías se usa tal cual en el XML, y si no coincide con el de la key el comprobante sale a nombre de otro RNC.
razon_social_emisor No RazonSocialEmisor Si no se envía, la registrada para la key.
direccion_emisor Envíalo siempre DireccionEmisor Obligatorio por XSD; máx. 100. Si falta, el XML sale con el texto literal DIRECCION.
municipio_emisor, provincia_emisor No Municipio, Provincia Código DGII de 6 dígitos (ej. 010100 Santo Domingo de Guzmán, 010000 Distrito Nacional). No se emiten en 34.
correo_emisor No CorreoEmisor No se emite en 34.
website_emisor No WebSite Máx. 50. No se emite en 34.
numero_factura_interna No NumeroFacturaInterna Tu número interno. Máx. 20.
numero_pedido_interno No NumeroPedidoInterno Solo dígitos, máx. 20.
zona_venta No ZonaVenta Máx. 20. No se emite en 41, 43 y 47.
codigo_vendedor No — Se acepta pero hoy no se incluye en el XML.

El NombreComercial del XML se toma de la empresa registrada (o su razón social); en 34 no se emite.

Comprador

Campo XML Notas
rnc_comprador RNCComprador RNC (9 dígitos) o cédula (11 dígitos), sin guiones.
razon_social_comprador RazonSocialComprador Máx. 150.
correo_comprador CorreoComprador
direccion_comprador DireccionComprador Máx. 100.
municipio_comprador, provincia_comprador MunicipioComprador, ProvinciaComprador Códigos DGII de 6 dígitos.
fecha_orden_compra, numero_orden_compra FechaOrdenCompra, NumeroOrdenCompra No se emiten en 41. numero_orden_compra máx. 20.
codigo_interno_comprador CodigoInternoComprador Máx. 20.

La sección comprador se emite si viene rnc_comprador o razon_social_comprador. En 43 nunca se emite. En 32 se emite vacía si no hay datos (consumidor final). Para 47 ver E47. Qué es obligatorio en cada tipo está en la página del tipo.

Totales

Campo XML Notas
monto_gravado_total MontoGravadoTotal I1 + I2 + I3.
monto_gravado_i1 MontoGravadoI1 Base gravada a la tasa 1 (18 %).
monto_gravado_i2 MontoGravadoI2 Base gravada a la tasa 2 (16 %).
monto_gravado_i3 MontoGravadoI3 Base gravada a la tasa 3 (0 %).
monto_exento MontoExento Suma de líneas exentas.
itbis1, itbis2, itbis3 ITBIS1/2/3 Tasa en % (entero). Por defecto 18, 16 y 0. Solo se emiten si la base correspondiente es mayor que 0.
total_itbis TotalITBIS TotalITBIS1 + 2 + 3.
total_itbis1, total_itbis2, total_itbis3 TotalITBIS1/2/3
monto_total MontoTotal Requerido.
valor_pagar ValorPagar Requerido. Si es mayor que 0, se envía a la DGII igual a monto_total (si mandas otro valor se corrige). Si es 0 (p. ej. comprobante gratuito), ValorPagar no se emite.
total_itbis_retenido, total_isr_retencion TotalITBISRetenido, TotalISRRetencion 31, 33, 34, 41 (y 47 solo ISR). Si no se envían, se suman de monto_itbis_retenido / monto_isr_retenido del detalle, también en 31, 33 y 34 aunque ahí no se emita el bloque Retencion por línea.
total_itbis_percepcion, total_isr_percepcion TotalITBISPercepcion, TotalISRPercepcion 31, 33, 34 y 41.

Montos en 0 no se emiten. En 43, 44, 46 y 47 el API no emite montos gravados ni ITBIS (ver cada tipo).

Se aceptan pero no se usan: monto_propina_legal, total_descuento, monto_no_facturable, subtotal_sin_impuesto.

Referencia (solo 33 y 34)

Campo XML Notas
ncf_modificado NCFModificado e-NCF (o NCF) del comprobante que se modifica. Obligatorio.
fecha_ncf_modificado FechaNCFModificado Fecha de emisión de ese comprobante. Obligatorio.
codigo_modificacion CodigoModificacion "1"–"5" (string) (ver tabla). Obligatorio.
razon_modificacion RazonModificacion Opcional, máx. 90.
indicador_nota_credito IndicadorNotaCredito Solo 34. 0/1. Si no se envía se calcula (ver E34).

Si falta ncf_modificado, fecha_ncf_modificado o codigo_modificacion en un 33/34, la respuesta es 500 con el mensaje El campo ... es obligatorio para Notas de Crédito (tipo 34) (también en 33).

Detalle (cada línea)

Campo Req. XML Notas
numero_linea Sí NumeroLinea 1, 2, 3…
nombre_item Sí NombreItem Máx. 80.
cantidad Sí CantidadItem Mayor que 0. Se envía con 2 decimales.
precio_unitario Sí PrecioUnitarioItem Hasta 4 decimales.
monto_item Sí MontoItem Se recalcula: cantidad × precio_unitario − descuento, redondeado a 2 decimales. Ver 5.1.
unidad_medida No UnidadMedida Código DGII como string; por defecto "43" (unidad). Ver tabla.
indicador_bien_servicio No IndicadorBienoServicio 1 bien, 2 servicio. Por defecto 2.
indicador_facturacion No IndicadorFacturacion 1 18 %, 2 16 %, 3 0 %, 4 exento, 0 no facturable. Por defecto 1.
descuento No DescuentoMonto + TablaSubDescuento Monto en pesos (no porcentaje) descontado de la línea. También se acepta como monto_descuento o descuento_monto. En 43 se ignora; en 47 no está permitido (422).
indicador_agente_retencion_percepcion Solo 41/47 Retencion/IndicadorAgenteRetencionoPercepcion 1 retención, 2 percepción. Por defecto 1.
monto_itbis_retenido 41 (ver nota) Retencion/MontoITBISRetenido En 41 se emite siempre (0.00 si no se envía). En 31, 33 y 34 no va por línea pero se suma a TotalITBISRetenido si no envías el total.
monto_isr_retenido 41; obligatorio en 47 Retencion/MontoISRRetenido

En 41 y 47 cada línea lleva siempre el bloque Retencion (lo exige el XSD). En 31, 33 y 34 no se emite el bloque por línea, pero monto_itbis_retenido / monto_isr_retenido del detalle se suman para TotalITBISRetenido / TotalISRRetencion si no envías esos totales.


5. Cálculo de totales, redondeo y cuadre

El API no calcula los totales del encabezado: usa los que envías. La DGII sí los verifica contra el detalle; si no cuadran, el comprobante vuelve como Aceptado Condicional o Rechazado. Calcula así:

5.1 MontoItem

monto_item = round(cantidad × precio_unitario − descuento, 2)

El API siempre envía a la DGII el MontoItem calculado con esa fórmula (la DGII valida la misma igualdad), aunque el monto_item que mandes sea otro. Excepción: si cantidad o precio_unitario son 0 se respeta el monto_item enviado. En E43 el descuento no se resta (E43 no admite descuentos).

CantidadItem viaja con 2 decimales: si usas cantidades con más decimales, redondéalas tú antes de calcular, para que cantidad × precio cuadre con lo que ve la DGII.

5.2 Totales por tasa (indicador_monto_gravado = 0)

monto_gravado_i1   = Σ monto_item de las líneas con indicador_facturacion = 1
monto_gravado_i2   = Σ monto_item con indicador_facturacion = 2
monto_gravado_i3   = Σ monto_item con indicador_facturacion = 3
monto_exento       = Σ monto_item con indicador_facturacion = 4
monto_gravado_total = i1 + i2 + i3

total_itbis1 = round(monto_gravado_i1 × 0.18, 2)
total_itbis2 = round(monto_gravado_i2 × 0.16, 2)
total_itbis3 = 0
total_itbis  = total_itbis1 + total_itbis2 + total_itbis3

monto_total  = monto_gravado_total + monto_exento + total_itbis
valor_pagar  = monto_total

Ejemplo (E31 con descuento y exento):

Línea Cálculo MontoItem Indicador
Laptop 2 × 35,000.00 − 3,500.00 66,500.00 1 (18 %)
Yogurt 10 × 85.00 850.00 2 (16 %)
Libro 3 × 1,200.00 3,600.00 4 (exento)

MontoGravadoI1 66,500.00 · MontoGravadoI2 850.00 · MontoGravadoTotal 67,350.00 · MontoExento 3,600.00 · TotalITBIS1 11,970.00 · TotalITBIS2 136.00 · TotalITBIS 12,106.00 · MontoTotal 83,056.00.

5.3 Retenciones no se restan

valor_pagar no es el neto después de retenciones. La DGII valida ValorPagar = MontoTotal + SaldoAnterior − MontoAvancePago; el API no maneja saldo anterior ni avances, así que ValorPagar = MontoTotal siempre que valor_pagar sea mayor que 0 (si mandas el neto, el API lo corrige). Las retenciones viajan aparte, en cada línea (monto_itbis_retenido, monto_isr_retenido) y en el encabezado (total_itbis_retenido, total_isr_retencion). Ver E41 y E47.

5.4 indicador_monto_gravado

Valor Significado Se cumple
0 Los monto_item no incluyen ITBIS monto_total = monto_gravado_total + total_itbis + monto_exento
1 Los monto_item ya incluyen el ITBIS monto_total = monto_gravado_total + monto_exento

Usa 0. Todos los ejemplos de esta guía usan 0. El API revisa los totales y, si una de las dos igualdades cuadra y la otra no, envía el indicador que cuadra aunque hayas mandado el otro.

5.5 Redondeo


6. Respuestas y errores

201 — Comprobante emitido

{
  "mensaje": "Factura procesada exitosamente",
  "factura_id": 1234,
  "encf": "E310000000001",
  "codigo_seguridad": "a1B2c3",
  "url_dgii": "https://ecf.dgii.gov.do/TesteCF/consultatimbre?rncemisor=101000001&encf=E310000000001&FechaEmision=01-10-2026&montototal=19706.00&FechaFirma=01-10-2026+10%3A15%3A30&codigoseguridad=a1B2c3&rnccomprador=131000001",
  "qr_image": "data:image/png;base64,iVBORw0KGgo...",
  "xml_firmado": "<?xml version=\"1.0\" encoding=\"UTF-8\"?><ECF>...</ECF>",
  "estado": "pendiente",
  "ecf_queue_id": 5678
}

(Valores ilustrativos.)

Campo Uso
codigo_seguridad 6 caracteres; va impreso en la representación impresa.
url_dgii URL de consulta del timbre en la DGII; es el contenido del QR. Para E32 < RD$250,000 usa fc.dgii.gov.do/.../consultatimbreFC; para todo lo demás ecf.dgii.gov.do/.../consultatimbre.
qr_image QR en PNG base64 (data URI), listo para <img src="...">.
xml_firmado XML firmado que se enviará a la DGII. Guárdalo.
estado Siempre pendiente en este punto: aún no se ha enviado a la DGII.
factura_id Para GET /{ambiente}/factura/{factura_id}/estado.
ecf_queue_id Para GET /{ambiente}/ecf/estado?ecf_queue_id=..., /{ambiente}/ecf-queue/{id} y el PDF.

Prefijo de url_dgii según ambiente:

Ambiente E32 < RD$250,000 Resto
testecf https://fc.dgii.gov.do/TesteCF/consultatimbreFC https://ecf.dgii.gov.do/TesteCF/consultatimbre
certecf https://fc.dgii.gov.do/CerteCF/consultatimbreFC https://ecf.dgii.gov.do/CerteCF/consultatimbre
produccion https://fc.dgii.gov.do/ecf/consultatimbreFC https://ecf.dgii.gov.do/ecf/consultatimbre

Parámetros: rncemisor, encf, FechaEmision (dd-mm-aaaa), montototal, FechaFirma, codigoseguridad y, si hay comprador con RNC, rnccomprador.

Errores de enviar-directo

HTTP error Causa Qué hacer
401 — (message) Ver autenticación. Revisa la key y el ambiente.
409 eNCF duplicado Ya existe un comprobante con ese e-NCF para tu RNC en ese ambiente. Ver abajo.
422 Error de validación Falta un campo requerido o tiene tipo/valor inválido. mensajes trae el detalle por campo. Corrige y reenvía con el mismo e-NCF.
422 eNCF no corresponde al tipo El prefijo del e-NCF no coincide con tipo_ecf. Usa un e-NCF de la secuencia del tipo.
422 Comprobante inválido según el esquema de DGII El XML no cumple el XSD de la DGII (campo obligatorio faltante para el tipo, largo excedido, código fuera de catálogo, e-NCF mal formado…). mensaje trae el error del XSD. Corrige y reenvía con el mismo e-NCF.
500 Error al procesar factura Error interno, certificado del emisor con problemas, o reglas del constructor (ej. faltan datos de referencia en 33/34, falta monto_isr_retenido en 47). mensaje trae la causa. Corrige si el mensaje lo indica; si no, reintenta más tarde.

En cualquier 422 o 500 no se guarda nada: puedes reenviar con el mismo e-NCF.

Ejemplo de 422 por validación:

{
  "error": "Error de validación",
  "mensajes": {
    "factura.encf": ["The factura.encf field is required."]
  }
}

409 — e-NCF duplicado y cómo recuperar la respuesta

El 409 protege contra la doble emisión. Si el comprobante existente ya tiene código de seguridad, el 409 trae sus datos para que puedas recuperarlos (por ejemplo, si tu request anterior hizo timeout y no recibiste el 201):

{
  "error": "eNCF duplicado",
  "mensaje": "Ya existe una factura con eNCF E310000000001 para este emisor",
  "factura_id": 1234,
  "encf": "E310000000001",
  "codigo_seguridad": "a1B2c3",
  "url_dgii": "https://ecf.dgii.gov.do/TesteCF/consultatimbre?...",
  "qr_image": "data:image/png;base64,...",
  "estado": "Aceptado",
  "track_id": "a2b9c1d4-...",
  "ecf_queue_id": 5678
}

Regla práctica ante un timeout: reenvía exactamente el mismo request. Si el primero se procesó, recibes 409 con los datos; si no, se procesa ahora. Antes de usar los datos del 409, verifica que corresponden a la misma venta (el 409 también aparece si reutilizaste por error un e-NCF de otra venta). El 409 no incluye xml_firmado; puedes obtenerlo con GET /{ambiente}/ecf-queue/{ecf_queue_id}/xml.


7. Estados del comprobante

Es el valor de data.dgii.estado en GET /{ambiente}/ecf/estado (y de estado en las demás consultas).

Estado Significado ¿Final? Qué hacer
pendiente En cola, aún sin respuesta de la DGII. También mientras se reintenta una falla transitoria o mientras una nota de crédito espera a que su original sea aceptado (ver mensaje). No Esperar.
enviado La DGII recibió el comprobante (hay track_id) y aún no se tiene el resultado. No Esperar; una tarea horaria consulta la DGII y actualiza.
En Proceso / Recibido La DGII lo está evaluando. No Esperar. (Para habilitar una nota de crédito, un original Recibido ya cuenta como válido: ver E34.)
Aceptado La DGII lo aceptó. Sí Nada.
Aceptado Condicional Aceptado con observaciones (por ejemplo, totales que no cuadran). Tiene validez fiscal. Sí Revisa mensaje y corrige tu cálculo para los próximos.
Rechazado La DGII lo rechazó; no tiene validez fiscal. Sí Revisa mensaje (cómo leer el motivo), corrige y emite un comprobante nuevo. Reenviar el mismo e-NCF por enviar-directo devuelve 409.
resumido E32 menor de RD$250,000: incluido en un Resumen de Factura de Consumo (RFCE) que la DGII recibió. Sí Nada. Ver E32.
duplicado La DGII respondió que la secuencia (e-NCF) ya fue utilizada. Sí Verifica si ese e-NCF ya se usó en otra venta.
fallido Error definitivo: la DGII rechazó la recepción (HTTP 400/422), se agotaron los reintentos, el RFCE fue rechazado, o una nota de crédito cuyo original no existe en el sistema o fue rechazado. Sí Lee mensaje, corrige y emite de nuevo.

Reintentos automáticos (valores por defecto): una falla de conexión con la DGII se reintenta hasta 12 veces; cualquier otra falla, hasta 3. Entre intentos se espera intentos × 5 minutos. Si un intento anterior llegó a la DGII aunque la respuesta se perdiera, el sistema lo detecta y no reenvía.

Cuando la DGII recibe el comprobante (enviado, Aceptado, Aceptado Condicional, resumido…), si tiene rnc_comprador el sistema intenta entregarlo al comprador (si este es receptor electrónico). El resultado aparece en data.comprador de ecf/estado.


8. Endpoints de consulta

Todos con Authorization: Bearer <api_key> y el prefijo de ambiente, salvo que se indique. Solo devuelven comprobantes del RNC de la key.

Método y ruta Para qué
GET /{ambiente}/ecf/estado?encf=E31…
?ecf_queue_id=…
?track_id=…
Consulta recomendada. Estado local (no llama a la DGII). Por encf toma el registro más reciente del ambiente. 404 si no existe; 422 si no envías ninguno de los tres.
GET /{ambiente}/factura/{factura_id}/estado Estado por factura_id (el del 201). Incluye codigo_seguridad, url_dgii, track_id, respuesta_dgii, intentos.
GET /{ambiente}/ecf/consulta-trackid?trackId=… Consulta en vivo a la DGII (ConsultaResultado). Devuelve la respuesta de la DGII tal cual. 503 si la DGII no responde.
GET /{ambiente}/ecf-queue Listado paginado. Filtros: estado, tipo_ecf, encf (parcial), fecha_desde, fecha_hasta, per_page.
GET /{ambiente}/ecf-queue/{ecf_queue_id} Registro completo.
GET /{ambiente}/ecf-queue/{ecf_queue_id}/xml XML firmado (JSON con campo xml).
GET /{ambiente}/ecf-queue/{ecf_queue_id}/descargar-xml XML firmado como archivo.
GET /{ambiente}/ecf-queue/estadisticas Conteos por estado y tipo.
GET /api/pdf/{ecf_queue_id} Representación impresa en PDF. Sin prefijo de ambiente; lleva la API Key y solo devuelve comprobantes de tu RNC (sirve una key de cualquier ambiente).
GET /api/ecf/recibidos Comprobantes que otros emisores te enviaron. Filtros: aprobacion_estado, tipo_ecf, encf, rnc_emisor, desde, hasta, per_page (máx. 100). Sin prefijo de ambiente.
GET /api/ecf/recibidos/{id} · GET /api/ecf/recibidos/{id}/xml Detalle (con el XML interpretado) y XML crudo de un recibido.

Errores de ecf/estado:

{ "error": true, "mensaje": "Comprobante no encontrado." }

(404). Sin track_id, encf ni ecf_queue_id: 422 con { "error": true, "mensaje": "Debe proveer al menos uno de: track_id, encf, ecf_queue_id." }.

Los endpoints /api/ecf/recibidos* y /api/pdf/{id} usan otra validación de key: una key inexistente o inactiva responde 401 {"message": "Token inválido"} (sin header: 401 {"message": "Token requerido"}).

Respuesta de ecf/estado:

{
  "status": true,
  "data": {
    "ecf_queue_id": 5678,
    "track_id": "a2b9c1d4-...",
    "encf": "E310000000001",
    "tipo_ecf": "31",
    "fecha_emision": "2026-10-01",
    "monto_total": "19706.00",
    "dgii": {
      "estado": "Aceptado",
      "codigo_respuesta": "1",
      "mensaje": null,
      "fecha_procesado": "2026-10-01T10:16:02-04:00",
      "intentos": 0
    },
    "comprador": {
      "rnc": "131000001",
      "estado": "entregado",
      "url": "...",
      "fecha": "...",
      "error": null,
      "arecf": "..."
    }
  }
}

(Valores ilustrativos.) dgii.mensaje trae los mensajes de la DGII (lista {codigo, valor}) o el texto del sistema que explica un fallido o una espera. comprador es null si no hay rnc_comprador.

Por qué la DGII rechazó un comprobante

enviar-directo no puede decirte si la DGII va a rechazar el comprobante: responde antes de enviarlo (estado: pendiente). El motivo aparece después, cuando consultas el estado:

GET /{ambiente}/ecf/estado?encf=E310000000001
{
  "status": true,
  "data": {
    "ecf_queue_id": 5679,
    "track_id": "80ef4915-...",
    "encf": "E310000000001",
    "dgii": {
      "estado": "Rechazado",
      "codigo_respuesta": "2",
      "mensaje": [
        { "codigo": 145, "valor": "texto del motivo, tal como lo devuelve la DGII" }
      ],
      "fecha_procesado": "2026-10-25T12:20:11-04:00",
      "intentos": 0
    }
  }
}

(Valores ilustrativos.)

GET /{ambiente}/factura/{factura_id}/estado también trae el motivo, en mensaje y en respuesta_dgii, pero ahí mensaje llega como texto JSON sin interpretar ("[{\"codigo\":145,...}]"). Para leer el motivo usa ecf/estado.

Un rechazado no se corrige reenviando el mismo e-NCF: enviar-directo responde 409 porque el comprobante ya existe en el sistema. Corrige lo que indica el mensaje y emite un comprobante nuevo.


9. Tablas de códigos

Fuente: enumeraciones de los XSD oficiales de la DGII.

TipoeCF

Código Comprobante
31 Factura de Crédito Fiscal Electrónica
32 Factura de Consumo Electrónica
33 Nota de Débito Electrónica
34 Nota de Crédito Electrónica
41 Comprobante Electrónico de Compras
43 Comprobante Electrónico para Gastos Menores
44 Comprobante Electrónico para Regímenes Especiales
45 Comprobante Electrónico Gubernamental
46 Comprobante Electrónico para Exportaciones
47 Comprobante Electrónico para Pagos al Exterior

TipoIngresos

Código Descripción
01 Ingresos por operaciones (no financieros)
02 Ingresos financieros
03 Ingresos extraordinarios
04 Ingresos por arrendamientos
05 Ingresos por venta de activo depreciable
06 Otros ingresos

TipoPago

Código Descripción
1 Contado
2 Crédito
3 Gratuito

FormaPago

Código Descripción
1 Efectivo
2 Cheque / transferencia / depósito
3 Tarjeta de débito / crédito
4 Venta a crédito
5 Bonos o certificados de regalo
6 Permuta
7 Nota de crédito
8 Otras formas de pago

tipo_pago (contado/crédito/gratuito) y forma_pago (cómo se pagó) son catálogos distintos: no pongas un código de forma de pago en tipo_pago.

IndicadorFacturacion

Código Descripción Va en
0 No facturable —
1 ITBIS tasa 1 (18 %) monto_gravado_i1 / total_itbis1
2 ITBIS tasa 2 (16 %) monto_gravado_i2 / total_itbis2
3 ITBIS tasa 3 (0 %) monto_gravado_i3
4 Exento monto_exento

IndicadorBienoServicio

Código Descripción
1 Bien
2 Servicio

IndicadorMontoGravado

Código Descripción
0 Los montos de las líneas no tienen ITBIS incluido
1 Los montos de las líneas tienen ITBIS incluido

CodigoModificacion

Para notas de débito (33) y crédito (34).

Código Descripción
"1" Anula el NCF modificado
"2" Corrige texto del comprobante fiscal modificado
"3" Corrige montos del NCF modificado
"4" Reemplazo de NCF emitido en contingencia
"5" Referencia a Factura de Consumo Electrónica

IndicadorNotaCredito (34)

Código Descripción
0 Nota de crédito emitida hasta 30 días calendario después del comprobante modificado
1 Emitida más de 30 días después

IndicadorAgenteRetencionoPercepcion (41 y 47)

Código Descripción
1 Retención
2 Percepción

UnidadMedida

Catálogo completo en el XSD (UnidadMedidaType, códigos 1–62). Los más usados:

Código Unidad Código Unidad
43 Unidad (por defecto) 19 Hora
6 Caja 12 Día
10 Conjunto 21 Kilogramo
13 Docena 23 Libra
15 Galones 24 Litro
17 Gramo 26 Metro
31 Paquete 27 Metro cuadrado
34 Pieza 44 Elemento
45 Millar 2 Bolsa

10. Resumen por tipo de comprobante

Tipo Cuándo usarlo Campos clave
31 Crédito Fiscal Venta a un contribuyente que usará el ITBIS como crédito fiscal (empresa o persona con RNC). rnc_comprador y razon_social_comprador obligatorios; fecha_vencimiento; totales con ITBIS.
32 Consumo Venta a consumidor final. Comprador opcional por debajo de RD$250,000; desde RD$250,000 la DGII exige RNC o cédula del comprador (el API aún no lo valida); sin fecha_vencimiento; < RD$250,000 va en resumen RFCE (resumido).
33 Nota de Débito Aumentar el monto de un comprobante ya emitido (cargos, intereses, diferencias). ncf_modificado, fecha_ncf_modificado, codigo_modificacion.
34 Nota de Crédito Anular o disminuir un comprobante ya emitido (devoluciones, descuentos, errores). Referencia obligatoria; tipo_pago obligatorio; sin fecha_vencimiento; espera a que el original esté aceptado.
41 Compras Tu empresa compra a un proveedor que no emite comprobantes (persona física/informal). Proveedor en rnc_comprador/razon_social_comprador; retención por línea; sin tipo_ingresos.
43 Gastos Menores Gastos menores de la empresa sin comprobante (caja chica: taxis, peajes, parqueos). Sin comprador, sin ITBIS, sin descuentos: todo exento.
44 Regímenes Especiales Venta a empresas en regímenes especiales exentos (zonas francas, etc.). Sin ITBIS: todo monto_exento; comprador con razón social.
45 Gubernamental Venta a entidades del gobierno. Como el 31: comprador con RNC y totales con ITBIS.
46 Exportaciones Venta de bienes/servicios al exterior. Líneas al 0 % (indicador_facturacion 3), comprador con razón social. No envíes monto_exento (> 0 → 422 por XSD). Hoy no se emiten MontoGravado*, ITBIS* ni TotalITBIS*. ⚠ Limitaciones conocidas; aceptación DGII no verificada: coordina con soporte antes de producción.
47 Pagos al Exterior Pago a un proveedor en el exterior (no residente). ISR retenido por línea obligatorio; todo exento; hoy sin datos del comprador. ⚠ Limitaciones conocidas; aceptación DGII no verificada: coordina con soporte antes de producción.

Advertencia E46 y E47: la salida actual tiene limitaciones conocidas: el E46 no emite ningún MontoGravado*, ITBIS* ni TotalITBIS* (sus totales solo llevan MontoTotal y ValorPagar) y el E47 sale sin datos del comprador. No se ha verificado que la DGII los acepte; coordina con soporte antes de usarlos en produccion.

Qué emite el API por tipo (según el XSD y el constructor del XML):

Elemento 31 32 33 34 41 43 44 45 46 47
FechaVencimientoSecuencia (obligatoria) Sí — Sí — Sí Sí Sí Sí Sí Sí
IndicadorMontoGravado Sí Sí Sí Sí Sí — — Sí — —
TipoIngresos Sí Sí Sí Sí — — Sí Sí Sí —
TipoPago obligatorio Sí Sí Sí Sí opc. opc. Sí Sí Sí opc.
TablaFormasPago Sí Sí Sí — Sí — Sí Sí Sí Sí
Comprador oblig. opc. opc. opc. oblig. — oblig. oblig. oblig. —
Montos gravados / ITBIS Sí Sí Sí Sí Sí — — Sí — —
MontoExento Sí Sí Sí Sí Sí Sí Sí Sí — Sí
Retenciones opc. — opc. opc. por línea — — — — ISR por línea
Descuento por línea Sí Sí Sí Sí Sí — Sí Sí Sí —
Referencia (ncf_modificado…) — — oblig. oblig. — — — — — —

11. Recetas: casos frecuentes

Mi request a enviar-directo dio timeout

No sabes si se procesó. Reenvía exactamente el mismo request: si el primero se procesó recibes 409 con el código de seguridad, la URL y el QR; si no, se procesa ahora. Ver 409.

La DGII rechazó el comprobante

Consulta GET /{ambiente}/ecf/estado?encf=... y lee data.dgii.mensaje: es la lista {codigo, valor} que devolvió la DGII (detalle). Corrige y emite un comprobante nuevo; reenviar el mismo e-NCF devuelve 409.

Quedó Aceptado Condicional

Tiene validez fiscal, no hay que reemitir. data.dgii.mensaje dice qué observó la DGII (por ejemplo, totales que no cuadran con el detalle). Revisa tu cálculo con la sección 5 para los próximos comprobantes.

Quedó fallido

El comprobante no llegó a la DGII o la DGII no aceptó recibirlo. data.dgii.mensaje trae el texto del error. Corrige y emite de nuevo.

Sigue en pendiente o enviado después de varios minutos

Es normal si la DGII está lenta: el sistema reintenta solo (ver estados). data.dgii.intentos dice cuántas veces lo intentó y data.dgii.mensaje qué está esperando.

Necesito el XML firmado otra vez

GET /{ambiente}/ecf-queue/{ecf_queue_id}/xml (JSON con el campo xml) o GET /{ambiente}/ecf-queue/{ecf_queue_id}/descargar-xml (archivo {rnc}{encf}.xml).

Necesito el PDF

GET /api/pdf/{ecf_queue_id} con tu API Key (header Authorization). Para mostrárselo a un cliente, descárgalo desde tu sistema y entrégale el archivo: el enlace no abre sin la key.

Tengo que anular o corregir una factura ya aceptada

No se anula: se emite una nota de crédito (E34) que referencia la factura original, o una nota de débito (E33) para aumentar el monto. Ver E34 y E33.