Guía · Referencia del API

Lume · RiserUp SRL

Integración e-CF

Emite comprobantes fiscales electrónicos válidos ante la DGII desde tu propio sistema, sin construir el ciclo completo ni entregarnos la llave privada de tus clientes.

Versión v0 Staging lume-ecf-staging.up.railway.app Producción ecf.lume.com.do
v0

El contrato está probado punta a punta contra la DGII. Producción está desplegada y solo emite para emisores con la certificación DGII completa; mientras tanto se integra y se prueba contra staging. Las credenciales son distintas por ambiente.

Los nombres de campo pueden cambiar antes de la v1. La forma del flujo — token, numeración, emisión, reconciliación — no.

01TokenFirmas la semilla y nos lo entregas
02ReservarPides el siguiente eNCF
03FirmarArmas y firmas el comprobante
04EmitirNos lo mandas, transmitimos
05ReconciliarConsultamos el veredicto por ti

01Qué hace Lume y qué haces tú

LumeTú
Arma el XML del e-CF desde tu ventaLe pasas la venta (o tu propio XML firmado)
Controla la numeración eNCFLo firmas con el certificado del emisor
Valida antes de transmitirObtienes el token de autenticación
Transmite a la DGII y reintentaImprimes la representación impresa
Consulta el veredicto y reconciliaGuardas la venta
Conserva el registro fiscal

Lume nunca recibe la llave privada. Ni el .p12, ni su contraseña, ni un PIN.

No es una cortesía: custodiar certificados de terceros abre requisitos regulatorios ante INDOTEL que preferimos que ninguna de las dos partes asuma.

02Antes de escribir código

El emisor tiene que estar certificado ante la DGII con software = Lume. Sin eso no hay emisión válida, por perfecta que sea la integración. Ese proceso lo acompañamos nosotros y toma entre 7 y 18 días hábiles.

  • Un contribuyente no puede estar postulado con dos proveedores a la vez. Si venía en proceso con otro sistema, hay que reiniciar.
  • Iniciar la certificación con Lume no lo desconecta de su proveedor actual. Puede seguir facturando hasta que termine.

Puedes crear credenciales y desarrollar contra certecf desde el primer día. Lo que no funciona hasta que la certificación cierre es emitir en producción.

03Tu credencial

Header
Authorization: Bearer lum_cert_...

La credencial identifica a tu sistema, y está autorizada sobre una lista explícita de RNC emisores. El RNC viaja siempre explícito en cada petición; si no estás autorizado sobre él, la respuesta es 403 nombrando ambos.

Si tu sistema atiende a varios emisores, puedes indicar quién disparó la operación:

Opcional
X-Lume-Actor: cliente_42/usuario_7

Se guarda para auditoría. No otorga permisos.

Auto-inscripción de emisores (credenciales sistema)

Si tu credencial es de scope sistema (un SaaS que atiende a muchos emisores), puedes autorizar tus propios emisores sin intervención nuestra — ideal para altas self-service:

POST/v1/emisores/enroll
Request · Response
{ "rnc": "131123456" }   → { "ok": true, "rnc": "131123456" }
DELETE/v1/emisores/enroll/{rnc}

Es idempotente y queda auditado. La emisión real igual exige que ese RNC esté certificado ante la DGII con software = Lume; inscribir un RNC no certificado no permite emitir todavía.

04El token de DGII

Este es el paso que sorprende, así que va primero.

Transmitir a la DGII exige firmar una semilla con el certificado del emisor y cambiarla por un token de una hora. No basta con que el comprobante venga firmado: la autenticación misma necesita la llave.

Como no custodiamos certificados, ese paso lo haces tú:

Contra la DGII
# 1. Pedir la semilla
curl https://ecf.dgii.gov.do/certecf/autenticacion/api/autenticacion/semilla

# 2. Firmarla con el certificado del emisor (XML-DSig)

# 3. Cambiarla por un token
curl -X POST https://ecf.dgii.gov.do/certecf/autenticacion/api/autenticacion/validarsemilla \
  -F 'xml=@semilla-firmada.xml;type=text/xml'
# → { "token": "...", "expira": "...", "expedido": "..." }
POST/emisores/{rnc}/token
Request
{
  "token": "...",
  "expira": "2026-09-01T18:09:38Z",
  "environment": "certecf"
}

Lo cacheamos por emisor y ambiente. Renuévalo antes de que venza: sin token vigente no transmitimos — aunque el comprobante sí queda registrado y sale solo cuando entregues uno nuevo.

05Armar el XML (recomendado) o numerar tú

El eNCF va dentro del XML firmado, y la firma cubre el contenido: no se puede renumerar después. Hay dos caminos.

Opción A — Lume arma el XML desde tu venta (recomendado)

Le pasas la venta; Lume reserva el eNCF, arma el e-CF XSD-ordenado con la identidad del emisor tomada del padrón (no del payload), lo valida y te devuelve el XML sin firmar. No reimplementas la lógica fiscal de los 10 tipos.

POST/v1/documentos/armar
Request
{
  "environment": "certecf",
  "tipo": "31",
  "rnc": "133281201",
  "referencia": "POS-2026-09-01-00412",
  "comprador": { "rnc": "131123456", "razonSocial": "Ferretería La Nacional" },
  "items": [
    { "descripcion": "Servicio", "cantidad": 1, "precioUnitario": 1000, "indicadorFacturacion": "1" }
  ]
}
200 OK
{ "encf": "E310000001501", "tipo": "31", "xml": "<ECF>…</ECF>", "vencimiento": "31-12-2026" }

indicadorFacturacion: 1=gravado 18% · 2=gravado 16% · 3=gravado 0% · 4=exento.

TipoRequiere
33, 34 (notas)documentoModificado: ncfModificado, fechaNcfModificado, codigoModificacion (34 añade razonModificacion e indicadorNotaCredito)
41, 47 (compras / exterior)retencion en cada ítem: indicadorAgente, montoITBISRetenido, montoISRRetenido
32 (consumo)no va por aquí → usa POST /emitir-consumo

Luego firmas ese XML (tu vault / stack) y lo emites en el paso 6.

Opción B — armas tu propio XML

Si ya generas el e-CF en tu stack, pide sólo el número:

POST/reservar-encf
Request · Response
{ "rnc": "131123456", "ecfType": "31", "environment": "certecf" }

→ { "encf": "E310000001501", "vencimiento": null }

La reserva es atómica: dos llamadas concurrentes nunca obtienen el mismo número.

06Emitir

Firma el XML (de armar o propio) y envíalo:

POST/submit
Request
Idempotency-Key: {tu-id-de-venta}

{
  "xml": "<ECF>…</ECF>",
  "kind": "ecf",
  "environment": "certecf",
  "referencia": "POS-2026-09-01-00412"
}
202 Accepted
{
  "id": "febb8ff5-…",
  "encf": "E320000000103",
  "estado": "transmitido",
  "track_id": "e8c09c43-…",
  "codigo_seguridad": "abc123",
  "qr": "https://ecf.dgii.gov.do/…"
}

Es 202, no 200. Aceptamos el comprobante y la DGII decide después. Tu cajero no espera.

El Idempotency-Key es obligatorio. Reintentar con la misma clave devuelve el mismo comprobante con "idempotente": true y nunca crea un segundo. Es lo que hace seguro reintentar tras un timeout, cuando no sabes si llegamos a recibirlo.

Imprime de inmediato, no nos esperes. El codigo_seguridad son los primeros 6 caracteres del SignatureValue de tu propio XML, así que ya tienes todo para el Timbre y el QR.

07Saber qué pasó

GET/documentos/{id}

Y para listar los de un emisor:

GET/emisores/{rnc}/documentos

Acepta ambiente, estado y limite. Devuelve solo los de ese RNC; si tu credencial no está autorizada sobre él, 403. Para paginar, pasa antes_de con el creado_at del último que recibiste.

EstadoSignifica
recibidoLo tenemos y lo validamos. Todavía no salió
transmitidoEnviado a la DGII, esperando veredicto
aceptadoLa DGII lo aceptó
rechazadoLa DGII lo rechazó. Incluye su respuesta sin traducir

Nosotros consultamos el veredicto por ti y reconciliamos. No tienes que hacer polling contra la DGII.

08Errores

Todos verificados contra el servicio, no inventados.

CódigoCuándoQué hacer
401Falta la credencial o no es válidaRevisa el header Authorization
409Emitir en ecf con el emisor sin certificarEspera a certified; mientras tanto integra contra certecf
403No estás autorizado sobre ese RNCPídenos la autorización para ese emisor
400Falta Idempotency-KeyManda tu identificador de venta
400Falta el RNC o environmentVan siempre explícitos. No hay default
400Falta el bloque del tipo al armar33/34 requieren documentoModificado; 41/47 retencion por ítem
422El XML no está firmadoFírmalo antes. Lume no firma documentos
409No hay token de DGII vigenteEntrega uno. El comprobante ya quedó registrado
502Error hablando con la DGIIReintenta con la misma Idempotency-Key

El cuerpo de los errores trae como_resolver cuando hay algo concreto que hacer.

09Ambientes

environment es obligatorio en cada petición. No hay valor por defecto, y testecf está rechazado explícitamente.

ValorQué es
certecfCertificación. Aquí desarrollas y aquí se certifica cada emisor
ecfProducción. Comprobantes fiscales reales
No existe un sandbox permanente

Un emisor solo puede emitir en certecf mientras su postulación está activa. Una vez que llega a Finalizado, la DGII cierra esa ventana y responde "no tiene una postulación activa".

Las pruebas de integración ocurren durante la certificación de un emisor real. Es una restricción del régimen, no una decisión nuestra.

10Lo que no está en v0

  • Recepción de e-CF de terceros, ARECF y aprobación comercial
  • Anulación de secuencias no utilizadas
  • Webhooks — hoy se consulta con GET /documentos/{id}
  • Sub-rangos por punto de emisión, para POS offline con varias cajas

Ya disponible: armar el XML desde tu venta (POST /v1/documentos/armar, sección 5) para todos los tipos estándar (31, 33, 34, 41, 43–47). El consumo final (32) va por POST /emitir-consumo.

11Referencia rápida

MétodoRutaPara qué
POST/v1/emisores/enroll(scope sistema) auto-autorizar un RNC emisor
POST/v1/documentos/armarArmar el e-CF (sin firmar) desde tu venta + reservar eNCF
POST/emisores/{rnc}/tokenEntregar el token de DGII
POST/reservar-encfReservar el siguiente eNCF (si armas tu propio XML)
POST/submitEmitir un comprobante firmado
GET/documentos/{id}Estado y transiciones
GET/emisores/{rnc}/documentosListar los comprobantes de un emisor
POST/consultaConsultar un trackId
GET/healthEstado del servicio