Secuencias y fechas

Secuencias y fechas

Tres cosas producen la mayoría de los rechazos de la DGII, y ninguna de las tres da un mensaje que apunte a la causa: el número de comprobante, la fecha de vencimiento del rango y el formato de las fechas. Esta página es corta a propósito. Léela entera.

El e-NCF es tuyo, no de FiscalFlow

La DGII autoriza al contribuyente un rango de números por tipo de comprobante. FiscalFlow no reparte esos números: los usa como se los mandes. Quien lleva el contador es tu sistema.

El formato es E + los dos dígitos del tipo + diez dígitos de secuencia:

E310000000001
^^^^^
| |  +-- secuencia, 10 dígitos
| +----- tipo (31)
+------- literal E
Ambiente Campo encf
testecf Opcional. Si lo omites, FiscalFlow inventa uno para que puedas probar el flujo sin cargar secuencias.
certecf y ecf Obligatorio. Sin el, el documento se rechaza de inmediato con error_code: ENCF_REQUIRED, sin llegar a la DGII y sin consumir nada.

Un e-NCF se usa una sola vez, y la DGII lleva la cuenta por RNC, no por sistema.

Si el mismo RNC factura desde dos sistemas — tu ERP y un punto de venta, o FiscalFlow y una localización fiscal que ya estaba instalada — los dos avanzando sobre el mismo rango chocan, y el segundo recibe "Este número de secuencia ya ha sido utilizado". Reserva un bloque distinto para cada sistema. Un número quemado no se recupera.

FiscalFlow también rechaza por su cuenta un e-NCF repetido dentro de la misma empresa y ambiente, antes de gastar la llamada a la DGII: recibes 409 con error.code: DUPLICATE_DOCUMENT. Para ver qué números llevas emitidos por tipo:

GET /api/v1/companies/{uuid}/sequences
curl -H "X-API-Key: ffs_live_ejemplodeclavenoreal000000000000000000" \
  https://api.fiscalflowsupport.com/api/v1/companies/9f1c2d3e-4b5a-6c7d-8e9f-0a1b2c3d4e5f/sequences
200 Response
{
  "success": true,
  "data": [
    {
      "type": "31",
      "type_label": "Factura Crédito Fiscal",
      "last_encf": "E310000000042",
      "total_accepted": 42,
      "last_emitted_at": "2026-08-14T15:06:02+00:00"
    },
    {
      "type": "32",
      "type_label": "Factura de Consumo",
      "last_encf": null,
      "total_accepted": 0,
      "last_emitted_at": null
    }
  ]
}
Esto es historial de lo emitido, no el estado de tu autorización: FiscalFlow no conoce el rango que la DGII te concedió ni cuantos números te quedan. Úsalo para conciliar, no como contador.

expiration_date: la causa del rechazo 145

expiration_date se convierte en FechaVencimientoSecuencia dentro del XML, y tiene que ser la fecha de vencimiento del rango de e-NCF que la DGII te autorizó, tal como aparece en la Oficina Virtual. La DGII la valida contra la autorización real. Cualquier otra fecha — aunque sea futura y perfectamente valida como fecha — se rechaza con el código 145, "Fecha de vencimiento de secuencia inválida", y el mensaje no menciona el campo.

Tipo expiration_date
31 33 41 43 44 45 46 47 Obligatorio. Sin el, el documento se rechaza antes de firmarse, de forma permanente y sin reintentos, con una explicación de que configurar.
32 y 34 Prohibido por sus esquemas. Si lo envías se ignora: el elemento no se escribe en el XML.
Manda expiration_date en dd-mm-yyyy. Desde 2.0.0 el request lo valida contra ese formato y devuelve 422 si no cuadra, antes de crear el documento: así un valor malo ya no te cuesta un e-NCF. Hasta 1.1.5 este campo viajaba al XML tal cual lo escribías, así que un 2026-12-31 pasaba el request y moría después en el esquema de la DGII con "El formato del XML no es valido", con la secuencia ya gastada.

Formato de fechas

Dentro del e-CF todas las fechas son dd-mm-yyyy. En el payload de la API la cosa se divide, así que vale la pena tenerlo a mano:

Campo Formato a enviar Nota
emission_date yyyy-mm-dd Validado como ISO y convertido internamente. Si lo omites, se usa hoy.
payment.due_date yyyy-mm-dd Igual. Obligatorio cuando payment.type es 2 (crédito).
reference.date dd-mm-yyyy o yyyy-mm-dd Se normaliza. Antes viajaba en crudo y rompía las notas de crédito y débito; corregido en 1.1.4.
expiration_date dd-mm-yyyy El request rechaza cualquier otro formato con 422. Antes viajaba en crudo; corregido en 2.0.0.

Una fecha que no se pueda leer no se reintenta: el documento se rechaza de una vez con el mensaje "El campo {campo} no contiene una fecha valida". Es deliberado, reintentar lo mismo cinco veces no lo arregla.

Idempotencia con external_ref

external_ref es tu identificador del documento — el número de factura de tu sistema, por ejemplo. Es único por organización y es lo que evita que un timeout de red o un reintento de tu cliente HTTP consuman un segundo e-NCF.

Si envías dos veces el mismo external_ref, la segunda llamada devuelve 200 con el documento que ya existe y "duplicate": true. No se crea nada, no se emite nada:

200 Response
{
  "success": true,
  "duplicate": true,
  "data": {
    "id": "01jz8k4qm2n5p7r9t1v3w5x7y9",
    "external_ref": "venta-2026-000412",
    "status": "accepted",
    "encf": "E310000000001"
  },
  "exec_time_ms": 12
}
Sin external_ref no hay protección: dos POST idénticos crean dos documentos y consumen dos números. Mándalo siempre.

Corregir un documento rechazado

Cuando la DGII rechaza por un dato malo, el número ya suele estar quemado. El flujo correcto es descartar y reenviar corregido, no reintentar.

  1. Mira sequence_consumed. Si es false, el número sigue libre y basta con POST /api/v1/documents/{id}/retry. Si es true, sigue leyendo.
  2. Descarta el documento rechazado. Esto libera el e-NCF para poder volver a presentarlo con datos corregidos:
    curl -X POST \
      -H "X-API-Key: ffs_live_ejemplodeclavenoreal000000000000000000" \
      -H "Content-Type: application/json" \
      -d '{"reason": "Fecha de vencimiento de secuencia corregida"}' \
      https://api.fiscalflowsupport.com/api/v1/documents/01jz8k4qm2n5p7r9t1v3w5x7y9/discard
  3. Envía el documento corregido con un external_ref distinto. El del documento descartado queda reservado para siempre; reutilizarlo devuelve el documento descartado en vez de emitir. Una convención que funciona bien es sufijar el intento: venta-2026-000412, venta-2026-000412-r2.

Solo se puede descartar un documento en estado rejected. Sobre cualquier otro estado, la respuesta es 422 con error.code: INVALID_DOCUMENT_STATE.