Saltar a contenido

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_id llega null porque la transmisión a la DGII ocurre en segundo plano. Consúltelo después con GET /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

  1. Guarde el e_ncf y el document_id que devuelve el 202: son su referencia para consultar.
  2. 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.
  3. Consulte el estado con espaciado creciente. La DGII suele resolver en segundos, pero puede tardar; nosotros consultamos automáticamente con reintentos progresivos.
  4. Un rejected_dgii es definitivo: el comprobante es nulo fiscalmente. Revise errors y emita uno nuevo. El campo sequence_reusable le indica si puede reutilizar ese e-NCF.
  5. system_error no es culpa de su JSON: es un fallo nuestro y se reintenta solo.