Endpoints
Invoices

Invoices

Tres endpoints alrededor del recurso invoice:

MétodoPathPara qué
POST/invoicesEnviar un nuevo e-CF
GET/invoices/:trackOrIdConsultar estado
GET/invoicesListar historial paginado

Todos requieren Authorization: Bearer <JWT>.

📋

"Invoices" cubre TODA la familia de e-CFs DGII, no solo facturas. El tipo de documento se determina por el campo TipoeCF dentro del XML/JSON que mandas — no por el endpoint o un parámetro de URL.

Tipos de e-CF soportados

POST /invoices acepta cualquiera de los siguientes tipos vía el campo TipoeCF del header (Encabezado.IdDoc.TipoeCF en JSON Digimart):

CódigoTipo de documentoUso típico
31Factura de Crédito FiscalB2B con derecho a crédito ITBIS
32Factura de ConsumoB2C — consumidor final
33Nota de Débito ElectrónicaAumento de un e-CF previamente emitido
34Nota de Crédito ElectrónicaDevolución / descuento sobre un e-CF previo
41ComprasRegistro de compras a no-emisores (gastos informales)
43Gastos MenoresOperaciones < umbral DGII
44Régimen EspecialSectores con tratamiento fiscal específico
45GubernamentalOperaciones con el Estado
46Comprobante Pago ExteriorPagos a proveedores fuera del país
47Régimen Especial Pago ExteriorCombinación de 44 y 46

Otros documentos también soportados

POST /invoices también acepta Resumen de Facturas de Consumo (RFCE) y Aprobaciones Comerciales (ACECF / ANECF). El endpoint del cliente es el mismo — el worker auto-detecta el root element del XML/JSON y rutea al endpoint DGII correcto bajo el capó:

Root elementTipo de documentoEndpoint DGII destino
<ECF>e-CF estándar (tipos 31-47)ecf.dgii.gov.do/{env}/recepcion/api/FacturasElectronicas
<RFCE>Resumen Facturas Consumofc.dgii.gov.do/{env}/recepcionfc/api/recepcion/ecf
<ACECF>Aprobación Comercial (emisor → receptor)ecf.dgii.gov.do/{env}/aprobacionComercial/api/AprobacionComercial
<ANECF>Aprobación de Notasecf.dgii.gov.do/{env}/aprobacionComercial/api/AprobacionComercial

Si mandas format: 'digimart' con un JSON cuyo root es RFCE, el worker lo convierte a XML con el tag correcto, lo firma, y lo manda al host CF de DGII. Tú no tienes que hacer nada distinto — un solo POST, el routing es invisible.


POST /invoices

Envía un comprobante para procesamiento async. Responde 202 con un identificador que puedes usar para consultar estado.

POST /api/v1/fe/invoices
Authorization: Bearer <JWT>
Content-Type: application/json

Scope requerido: invoices:write

Request body

CampoTipoRequeridoDescripción
format"xml" | "digimart"Forma del payload
xmlstringSi format="xml"XML completo del e-CF
payloadobjectSi format="digimart"JSON estructurado
clientRequestIdstringIdempotency key opcional

format: "xml"

Le pasas el XML del e-CF tal cual lo construiste. Lo firmamos y enviamos.

{
  "format": "xml",
  "clientRequestId": "factura-001-2026-06-15",
  "xml": "<?xml version=\"1.0\" encoding=\"UTF-8\"?><ECF xmlns:xsi=\"...\">...</ECF>"
}

format: "digimart"

Le pasas un JSON estructurado que sigue el esquema interno de Digimart. Nosotros lo convertimos a XML, firmamos, y enviamos.

{
  "format": "digimart",
  "clientRequestId": "factura-001-2026-06-15",
  "payload": {
    "Encabezado": {
      "Version": "1.0",
      "IdDoc": {
        "TipoeCF": "31",
        "eNCF": "E310000000001",
        "FechaVencimientoSecuencia": "31-12-2026"
      },
      "Emisor": { /* ... */ },
      "Comprador": { /* ... */ },
      "Totales": { /* ... */ }
    },
    "DetallesItems": { /* ... */ }
  }
}

Si necesitas el esquema completo del JSON Digimart, contáctanos — publicamos la definición en formato JSON Schema.

clientRequestId (idempotency)

Si tu sistema reintenta la misma factura (timeout de red, retry interno, etc.), envía el mismo clientRequestId en cada intento. Detectamos la duplicación y devolvemos el envío original en vez de procesar dos veces.

  • Recomendación: usa un id determinístico desde TU sistema (ej. tu_factura_id + fecha).
  • Longitud: 1-120 caracteres.
  • Si lo omites, no hay protección contra retries duplicados.

Response — 202 Accepted

{
  "dgiiLogId": "a3f7b8c9-d1e2-3f4g-5h6i-7j8k9l0m1n2o",
  "status": "queued",
  "environment": "ecf",
  "billable": true,
  "message": "Invoice queued for processing"
}
CampoDescripción
dgiiLogIdUUID del registro. Úsalo para consultar estado (ver abajo).
statusSiempre "queued" inicialmente. Cambia a "Aceptado", "Rechazado", etc. después de la respuesta de DGII.
environmentAmbiente al que se envía (determinado por la key).
billabletrue solo si environment === "ecf". Pruebas no facturan.

Response — 400 Bad Request

{
  "message": "xml is required when format=\"xml\"",
  "statusCode": 400
}

Otros errores 400 comunes:

  • payload is required when format="digimart"
  • format must be one of: xml, digimart

Idempotency response

Si reutilizas un clientRequestId:

{
  "dgiiLogId": "a3f...",
  "status": "queued",
  "deduped": true,
  "message": "Existing submission returned (idempotency key matched)"
}

El deduped: true te dice que NO procesamos de nuevo — te devolvimos el envío original.


GET /invoices/:trackOrId

Consulta el estado de un comprobante. Acepta tanto el dgiiLogId (que te dimos al hacer POST) como el trackId (que DGII asigna después).

GET /api/v1/fe/invoices/{trackOrId}
Authorization: Bearer <JWT>

Scope requerido: invoices:read

Response — 200 OK (procesado)

{
  "dgiiLogId": "a3f7b8c9-...",
  "trackId": "DGII-2026-06-15-12345",
  "environment": "ecf",
  "status": "Aceptado",
  "qrCodeUrl": "https://ecf.dgii.gov.do/ConsultaTimbre?...",
  "securityCode": "abc123",
  "ncfExpiration": "31-12-2026",
  "fechaHoraFirma": "2026-06-15T14:23:11Z",
  "response": { /* respuesta completa de DGII */ },
  "submittedAt": "2026-06-15T14:23:10Z",
  "updatedAt": "2026-06-15T14:23:13Z",
  "clientRequestId": "factura-001-2026-06-15"
}
CampoDescripción
status"Aceptado", "Aceptado Condicional", "Rechazado", "En Proceso", o null (todavía no procesado)
qrCodeUrlURL del QR oficial para incluir en tu PDF de factura
securityCodeCódigo de seguridad asignado por DGII
ncfExpirationFecha en que expira la secuencia NCF
responseRespuesta cruda de DGII (para debugging)

Estados posibles

EstadoSignificado¿Es facturable?
"Aceptado"DGII aceptó el e-CF sin observaciones.✅ Sí
"Aceptado Condicional"DGII aceptó con observaciones (revisa mensajes).✅ Sí
"Rechazado"DGII rechazó. Mira response.mensajes para detalles.❌ No
"En Proceso"DGII todavía procesando. Vuelve a consultar en ~30s.❌ Todavía no
null o "queued"Aún no enviado a DGII. Vuelve a consultar en ~5s.❌ Todavía no

Response — 200 OK (no encontrado)

{
  "found": false
}

Significa que el trackOrId no corresponde a ningún envío tuyo.


GET /invoices

Lista paginada del historial de envíos del tenant. Solo retorna envíos hechos a través de esta API pública (source = 'fe-api').

GET /api/v1/fe/invoices?page=1&limit=50&from=2026-06-01&to=2026-06-30
Authorization: Bearer <JWT>

Scope requerido: invoices:read

Query params

ParamTipoDefaultDescripción
pagenumber1Página (1-indexed)
limitnumber50Items por página (max 200)
fromISO dateFiltro: createdAt >= from
toISO dateFiltro: createdAt <= to
statusstring(reservado para uso futuro)

Response — 200 OK

{
  "page": 1,
  "limit": 50,
  "total": 247,
  "items": [
    {
      "dgiiLogId": "a3f...",
      "trackId": "DGII-...",
      "environment": "ecf",
      "status": "Aceptado",
      "qrCodeUrl": "...",
      "submittedAt": "2026-06-15T14:23:10Z",
      "updatedAt": "2026-06-15T14:23:13Z",
      "clientRequestId": "factura-001-2026-06-15"
    }
    /* ... más items ... */
  ]
}

Ordenado por submittedAt DESC (más recientes primero).