Inicio rápido
Vamos a emitir un e-CF de verdad en el ambiente de pruebas, de principio a fin: comprobar la conexión, emitir una factura de consumo, ver el veredicto de la DGII y descargar el PDF fiscal. Diez minutos.
Lo que necesitas
- Una empresa creada en FiscalFlow, con su certificado
.p12cargado. - Una API key de pruebas, con prefijo
ffs_test_, tomada de la pantalla Integraciones de esa empresa.
Las cuentas las crea el equipo de FiscalFlow. Si aún no tienes una, escribe a [email protected].
testecf puedes emitir sin cargar secuencias: si omites el campo encf,
FiscalFlow genera uno ficticio. En certificación y producción el número lo pones tu.
Paso 1: comprobar la conexión
/api/v1/ping
curl -H "X-API-Key: ffs_test_ejemplodeclavenoreal000000000000000000" \
https://api.fiscalflowsupport.com/api/v1/ping
import requests
BASE = "https://api.fiscalflowsupport.com/api/v1"
HEADERS = {"X-API-Key": "ffs_test_ejemplodeclavenoreal000000000000000000"}
r = requests.get(f"{BASE}/ping", headers=HEADERS)
r.raise_for_status()
print(r.json()["data"]["environment"]) # -> testecf
Confirma dos cosas antes de seguir: que environment dice testecf, y que
company.rnc es el RNC bajo el que quieres facturar. Si el ambiente no es el que
esperas, estás usando la key equivocada.
Paso 2: emitir una factura de consumo
Empezamos con una E32 de monto bajo a propósito: por debajo de RD$250,000 la DGII responde en la misma petición, así que sabrás de inmediato si algo esta mal. Una E31 te dejaría esperando el veredicto sin saber si el problema es tuyo o de la cola.
/api/v1/documents
curl -X POST https://api.fiscalflowsupport.com/api/v1/documents \
-H "X-API-Key: ffs_test_ejemplodeclavenoreal000000000000000000" \
-H "Content-Type: application/json" \
-d '{
"type": "32",
"external_ref": "prueba-001",
"items": [
{
"description": "Producto de prueba",
"quantity": 1,
"unit_price": 1000.00,
"amount": 1000.00,
"itbis_amount": 180.00
}
],
"totals": {
"subtotal": 1000.00,
"exempt_amount": 0.00,
"itbis": 180.00,
"total": 1180.00
}
}'
r = requests.post(
f"{BASE}/documents",
headers=HEADERS,
json={
"type": "32",
"external_ref": "prueba-001",
"items": [{
"description": "Producto de prueba",
"quantity": 1,
"unit_price": 1000.00,
"amount": 1000.00,
"itbis_amount": 180.00,
}],
"totals": {
"subtotal": 1000.00,
"exempt_amount": 0.00,
"itbis": 180.00,
"total": 1180.00,
},
},
)
doc = r.json()["data"]
print(doc["id"], doc["status"], doc["encf"])
{
"success": true,
"data": {
"id": "01jz8k4qm2n5p7r9t1v3w5x7y9",
"external_ref": "prueba-001",
"type": "32",
"type_label": "Factura de Consumo",
"encf": "E320000004417",
"status": "accepted",
"legal_status": "accepted",
"authorized": true,
"environment": "testecf",
"totals": { "subtotal": 1000, "exempt_amount": 0, "itbis": 180, "total": 1180 },
"currency": "DOP",
"accepted_at": "2026-08-14T15:04:12+00:00",
"_links": {
"self": "https://api.fiscalflowsupport.com/api/v1/documents/01JZ8K4QM2N5P7R9T1V3W5X7Y9",
"pdf": "https://api.fiscalflowsupport.com/api/v1/documents/01JZ8K4QM2N5P7R9T1V3W5X7Y9/pdf",
"xml": "https://api.fiscalflowsupport.com/api/v1/documents/01JZ8K4QM2N5P7R9T1V3W5X7Y9/xml",
"qr": "https://api.fiscalflowsupport.com/api/v1/documents/01JZ8K4QM2N5P7R9T1V3W5X7Y9/qr"
}
},
"exec_time_ms": 2104
}
status: "accepted" significa que la DGII lo acepto. Guarda el id: es el
identificador del documento en todo lo demás.
status: "processing", no es un
error: es el comportamiento normal de todos los demás tipos, cuyo veredicto llega después.
Ciclo de vida de un e-CF explica como enterarte.
Paso 3: descargar el PDF fiscal
curl -H "X-API-Key: ffs_test_ejemplodeclavenoreal000000000000000000" \
https://api.fiscalflowsupport.com/api/v1/documents/01jz8k4qm2n5p7r9t1v3w5x7y9/pdf \
-o factura.pdf
El PDF trae el código QR de verificación y el código de seguridad. Con
?format=pos obtienes la versión estrecha para impresora térmica. El XML firmado,
que es el documento con valor legal y el que hay que archivar, está en el mismo camino terminado
en /xml.
Paso 4: probar un rechazo
Vale la pena ver como se ve un fallo antes de encontrarte uno en producción. Manda unos totales que no cuadren:
curl -X POST https://api.fiscalflowsupport.com/api/v1/documents \
-H "X-API-Key: ffs_test_ejemplodeclavenoreal000000000000000000" \
-H "Content-Type: application/json" \
-d '{
"type": "32",
"external_ref": "prueba-002",
"items": [{"description": "Producto", "quantity": 1, "unit_price": 1000.00, "amount": 1000.00, "itbis_amount": 180.00}],
"totals": {"subtotal": 1000.00, "exempt_amount": 0.00, "itbis": 180.00, "total": 9999.00}
}'
{
"success": false,
"error": {
"code": "INVALID_TOTALS",
"message": "total (9999.00) does not match subtotal + itbis (1180.00).",
"field": "totals.total"
}
}
Antes de pasar a producción
Una lista corta de lo que cambia, y donde se rompen casi todas las integraciones:
-
El e-NCF pasa a ser tuyo. Fuera de
testecf, el campoencfes obligatorio y tu sistema lleva el contador sobre el rango que la DGII autorizó. -
Manda
expiration_dateen todos los tipos que lo exigen, endd-mm-yyyyy con el vencimiento real de tu autorización. Es la causa del rechazo 145. -
Manda siempre
external_ref. Es lo único que evita que un reintento consuma un segundo número. -
Prepara el flujo asíncrono. Casi todo llega en
processing. Registra un webhook o programa una conciliación. -
Cambia las dos cosas a la vez: emite una key
ffs_live_y pon la empresa en ambienteecf.
Los puntos 1 y 2 están desarrollados en Secuencias y fechas, que es la página que más problemas evita. La referencia completa del payload esta en Emitir un e-CF.