API de facturación electrónica — República Dominicana (e-CF / DGII)¶
Guía de integración para enviar comprobantes fiscales electrónicos a la DGII a través de esta API. Usted envía JSON; nosotros construimos el XML del e-CF, lo firmamos digitalmente, lo transmitimos a la DGII, resolvemos su estado y generamos la representación impresa.
No necesita conocer el formato XML de la DGII ni tener certificado digital propio: ambos los resolvemos nosotros. Y si su sistema ya genera el XML e-CF, envíelo tal cual: lo firmamos y lo transmitimos igual. Vea passthrough-xml.md.
Documentos disponibles¶
| Tipo | Documento | Cuándo se usa | Documentación |
|---|---|---|---|
| 31 | Factura de Crédito Fiscal Electrónica | Ventas a contribuyentes (B2B). Sustenta crédito fiscal del comprador. | ecf-31.md |
| 32 | Factura de Consumo Electrónica | Ventas a consumidor final (B2C). | ecf-32.md |
| 33 | Nota de Débito Electrónica | Aumenta el valor de un comprobante ya emitido. | ecf-33.md |
| 34 | Nota de Crédito Electrónica | Anula, corrige o disminuye un comprobante ya emitido. | ecf-34.md |
| 41 | Comprobante de Compras Electrónico | Compras a proveedores que no emiten e-CF, con retención. | ecf-41.md |
| 43 | Gastos Menores Electrónico | Gastos de caja chica sin comprobante del vendedor. | ecf-43.md |
| 44 | Regímenes Especiales Electrónico | Ventas exentas a zonas francas, diplomáticos y similares. | ecf-44.md |
| 45 | Gubernamental Electrónico | Ventas al Estado. | ecf-45.md |
| 46 | Comprobante de Exportaciones Electrónico | Ventas al exterior, gravadas a tasa 0%. | ecf-46.md |
| 47 | Pagos al Exterior Electrónico | Pagos a beneficiarios extranjeros, con retención de ISR. | ecf-47.md |
Los diez tipos se validan con el mismo rigor: cuadratura de totales, totales condicionales según el indicador de facturación, coherencia del ISC y reglas de todos los bloques (subtotales informativos, descuentos y recargos globales, otra moneda, paginación). Si algo no cuadra, la respuesta es un 422 con el detalle por campo, sin consumir la secuencia.
Documentos de apoyo: - campos-comunes.md — nodos y campos compartidos por todos los tipos. - catalogos.md — valores permitidos (tipos de ingreso, formas de pago, unidades…). - estados.md — códigos de estado internos y el ciclo de vida del e-CF. - consultas-dgii.md — consultas en vivo: estado de un e-CF, validez fiscal de lo que recibe, y los envíos de un e-NCF. - passthrough-xml.md — enviar su propio XML en vez del JSON canónico. - entrega-al-receptor.md — cómo llega el e-CF al receptor y qué responde. - directorio.md — a quién puede enviarle e-CF y por qué URL. - anulacion-secuencias.md — anular rangos de e-NCF no utilizados. - ejemplos/ — los JSON de esta documentación, listos para copiar.
Todos los ejemplos de esta documentación se verifican automáticamente contra la API en cada ejecución de la suite de pruebas: si un ejemplo dejara de ser válido, la compilación falla. Puede copiarlos con la confianza de que funcionan.
Autenticación¶
Token Bearer por emisor. Cada credencial pertenece a un solo RNC emisor, así que el emisor no viaja en el JSON: se deduce del token.
POST /api/v1/documents/31 HTTP/1.1
Host: <su-host>
Authorization: Bearer <su-token>
Content-Type: application/json
Accept: application/json
Ciclo de vida de un e-CF¶
Su sistema Esta API DGII
│ │ │
├── POST /documents/31 ──►│ │
│ ├─ valida el JSON │
│ ├─ asigna el e-NCF │
│◄── 202 received ───────┤ │
│ ├─ construye + firma el XML │
│ ├──────── transmite ────────────►│
│ │◄──────── TrackID ──────────────┤
│ │ in_process_dgii │
│ ├──── consulta el resultado ────►│
│ │◄─── aceptado / rechazado ──────┤
│ ├─ genera la representación impresa (PDF)
├── GET /documents/{eNCF}►│ │
│◄── accepted_dgii ──────┤ │
El envío es asíncrono: la respuesta 202 confirma que recibimos el comprobante y le asignamos un
e-NCF, no que la DGII ya lo aceptó. Consulte el estado con GET /api/v1/documents/{eNCF}.
Endpoints¶
| Método | Ruta | Descripción |
|---|---|---|
POST |
/api/v1/documents/{tipo} |
Emite un e-CF. {tipo} = 31, 32, 33, 34, 41, 43, 44, 45, 46, 47. |
GET |
/api/v1/documents/{eNCF} |
Consulta el estado de un e-CF emitido. |
GET |
/api/v1/received-documents |
e-CF que otros emisores le enviaron. |
POST |
/api/v1/received-documents/{eNCF}/commercial-approval |
Acepta o rechaza comercialmente un e-CF recibido. |
GET |
/api/v1/documents/{eNCF}/dgii-status |
Estado del e-CF consultado en vivo a la DGII. |
GET |
/api/v1/documents/{eNCF}/track-ids |
Envíos (TrackID) de ese e-NCF ante la DGII. |
GET |
/api/v1/received-documents/{eNCF}/dgii-status |
Validez fiscal de un e-CF que usted recibió. |
GET |
/api/v1/directory · /api/v1/directory/{rnc} |
Directorio de emisores y sus URL de recepción. |
GET |
/api/v1/voided-sequences · POST |
Consulta y anulación de rangos de e-NCF. |
GET |
/api/v1/certificate |
Estado de su certificado digital (sólo firma propia). |
POST |
/api/v1/certificate |
Sube o reemplaza su certificado .p12. |
GET |
/api/v1/statuses |
Catálogo de estados internos. |
Recepción: usted también recibe comprobantes¶
Como emisor electrónico, la DGII le exige poder recibir e-CF de sus proveedores. Eso lo
resolvemos nosotros: exponemos los servicios que el estándar define (/fe/recepcion/api/ecf y
/fe/aprobacioncomercial/api/ecf), respondemos el Acuse de Recibo firmado y registramos lo
recibido. Usted sólo consulta GET /api/v1/received-documents y, si quiere, aprueba o rechaza
comercialmente la transacción:
POST /api/v1/received-documents/E310000000055/commercial-approval
{
"estado": 2, // 1 acepta, 2 rechaza
"motivo_rechazo": "La mercancía no corresponde al pedido" // obligatorio si rechaza (máx. 250)
}
El acuse de recibo (automático) sólo dice que el comprobante llegó y es válido en forma. La aprobación comercial es su conformidad con la operación, y es opcional.
Certificado digital¶
Si su empresa firma con su propio certificado, súbalo una vez:
curl -X POST https://<host>/api/v1/certificate \
-H "Authorization: Bearer <su-token>" \
-F "certificate=@mi-firma.p12" \
-F "password=<clave del .p12>"
Antes de aceptarlo verificamos que abra con esa contraseña, que el RNC del certificado sea el
suyo (la DGII lo exige: si no, rechazaría todos sus comprobantes) y que esté vigente. El archivo
queda cifrado y nunca se devuelve; con GET /api/v1/certificate consulta su vigencia y cuántos días
faltan para que venza.
Si firma con nuestro certificado de proveedor no tiene que subir nada: basta la Delegación de Roles ("Firmante Autorizado") a nuestro favor en su Oficina Virtual de la DGII.
Formato de las respuestas¶
Todas las respuestas usan el mismo envelope: status (success | error), message y document.
Éxito — 202 Accepted¶
{
"status": "success",
"message": "e-CF recibido y encolado para envío a la DGII.",
"document": {
"document_id": 1234,
"ecf_type_code": "31",
"e_ncf": "E310000000001",
"track_id": null,
"status_code": 1,
"status": "received",
"status_description": "El e-CF fue recibido, validado y encolado para su envío a la DGII. Ya tiene e-NCF asignado."
}
}
track_idlleganullporque la transmisión a la DGII ocurre en segundo plano. Consúltelo después conGET /api/v1/documents/{eNCF}.
Error de validación — 422 Unprocessable Entity¶
El e-CF no se transmitió y el e-NCF no se consumió: corrija y reintente.
{
"status": "error",
"message": "Los datos enviados no son válidos.",
"document": {
"status_code": 2,
"status": "rejected_validation",
"status_description": "El e-CF no superó las validaciones previas al envío; no se transmitió a la DGII y el e-NCF no fue consumido.",
"errors": [
"El campo tipo de ingresos es obligatorio.",
"El campo cantidad del ítem debe ser mayor que 0."
],
"detailed_errors": {
"id_doc.tipo_ingresos": ["El campo tipo de ingresos es obligatorio."],
"items.0.cantidad": ["El campo cantidad del ítem debe ser mayor que 0."]
}
}
}
errors— lista plana de mensajes, en español. Útil para mostrar al usuario final.detailed_errors— los mismos mensajes indexados por campo. Útil para resaltar campos en un formulario.
Otro caso de 422 es no tener secuencias disponibles:
{
"status": "error",
"message": "No se pudo recibir el e-CF.",
"document": {
"status_code": 2,
"status": "rejected_validation",
"status_description": "…",
"errors": ["No hay secuencia e-NCF vigente/disponible para el tipo 31."]
}
}
Consulta de estado — 200 OK¶
{
"status": "success",
"document": {
"document_id": 1234,
"ecf_type_code": "31",
"e_ncf": "E310000000001",
"track_id": "a1b2c3d4-...",
"status_code": 4,
"status": "accepted_dgii",
"status_description": "La DGII aceptó el e-CF: tiene validez fiscal.",
"is_valid_fiscally": true,
"security_code": "aB12cd",
"issued_at": "27-07-2026",
"signed_at": "27-07-2026 09:15:03",
"total_amount": "1180.00",
"total_itbis": "180.00",
"sequence_reusable": null,
"errors": null
}
}
Si el e-NCF no existe o pertenece a otro emisor: 404 con status: "error".
Otros códigos HTTP¶
| Código | Significado |
|---|---|
202 |
Recibido y encolado. |
401 |
Token ausente, inválido o revocado. |
404 |
El e-NCF consultado no existe para su emisor. |
422 |
El JSON no pasó las validaciones, o no hay secuencia disponible. |
500 |
Error interno. El e-CF queda en system_error y se reintenta automáticamente. |
Convenciones del JSON¶
| Tema | Convención |
|---|---|
| Nombres | snake_case en español (precio_unitario, razon_social). |
| Emisor | No se envía. Se deduce del token. |
| e-NCF | No se envía. Lo asignamos desde sus secuencias autorizadas. |
| Fechas | dd-MM-aaaa (p. ej. 27-07-2026). Fecha y hora: dd-MM-aaaa HH:mm:ss. |
| Montos | Número JSON con hasta 2 decimales y punto decimal (1180.50). Sin separador de miles ni símbolo de moneda. |
| Códigos de catálogo | Siempre string, respetando ceros a la izquierda ("01", "002"). |
| Campos opcionales | Omítalos. Enviar null es equivalente a omitirlos. |
| Zona horaria | America/Santo_Domingo (UTC−4, sin horario de verano). |
Estructura general del JSON¶
{
"comprador": { /* datos del cliente (según el tipo) */ },
"id_doc": { /* identificación del documento: ingresos, pago, plazos */ },
"items": [ /* líneas del detalle: 1 a 1.000 */ ],
"totales": { /* montos gravados, exentos, ITBIS, total */ },
"referencia": { /* SOLO notas de crédito/débito: NCF que modifica */ },
"descuentos_recargos": [ /* opcional: descuentos o recargos globales */ ],
"otra_moneda": { /* opcional: si factura en divisa */ },
"subtotales": [ /* opcional: subtotales informativos */ ],
"informacion_adicional":{ /* opcional */ }
}
Detalle campo por campo en campos-comunes.md y en la página de cada tipo.
Topes y límites¶
| Límite | Valor |
|---|---|
| Líneas de detalle | 1.000; 10.000 en Factura de Consumo (32) por debajo de RD$250.000 |
| Formas de pago | 7 |
| Descuentos/recargos globales | 20 |
| Subtotales informativos | 20 |
| Decimales en montos | 2 |
| Umbral de la Factura de Consumo | RD$250.000 (define el comportamiento del tipo 32) |
Recomendaciones¶
- Guarde el
e_ncfy eldocument_idque devuelve el202: son su referencia para consultar. - No reenvíe el mismo comprobante si recibió
202: ya tiene un e-NCF asignado. Reenviarlo consumiría otro número de su secuencia autorizada. - Consulte el estado con espaciado creciente. La DGII suele resolver en segundos, pero puede tardar; nosotros consultamos automáticamente con reintentos progresivos.
- Un
rejected_dgiies definitivo: el comprobante es nulo fiscalmente. Reviseerrorsy emita uno nuevo. El camposequence_reusablele indica si puede reutilizar ese e-NCF. system_errorno es culpa de su JSON: es un fallo nuestro y se reintenta solo.