Inicio rápido

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 .p12 cargado.
  • 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].

En 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

GET /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.

POST /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"])
200 Response
{
  "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.

Si en vez de 200 recibes 202 con 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}
  }'
422 Response
{
  "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:

  1. El e-NCF pasa a ser tuyo. Fuera de testecf, el campo encf es obligatorio y tu sistema lleva el contador sobre el rango que la DGII autorizó.
  2. Manda expiration_date en todos los tipos que lo exigen, en dd-mm-yyyy y con el vencimiento real de tu autorización. Es la causa del rechazo 145.
  3. Manda siempre external_ref. Es lo único que evita que un reintento consuma un segundo número.
  4. Prepara el flujo asíncrono. Casi todo llega en processing. Registra un webhook o programa una conciliación.
  5. Cambia las dos cosas a la vez: emite una key ffs_live_ y pon la empresa en ambiente ecf.

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.