Cufy API
Documentos

Ciclo de vida de una factura

Qué pasa después del 202, qué significa cada estado, cada cuánto consultar y cuándo todavía se puede cancelar.

Los campos del cuerpo están en Crear una factura. Esta página es lo que pasa alrededor: cómo revisarla antes de emitirla, qué significan sus estados, cada cuánto preguntar por ella y qué puedes hacer cuando ya salió.

El recorrido completo

Revísala sin emitirla. POST /v1/invoice-validations recibe exactamente el mismo cuerpo que la emisión y te dice si cumple las reglas, sin numerar, firmar ni enviar nada.

curl -s -X POST https://api-sandbox.cufy.co/v1/invoice-validations \
  -H "X-API-Key: TU_API_KEY" \
  -H "Content-Type: application/json" \
  -d @factura.json

Responde valid: true o valid: false con la lista de errors, campo por campo. No gasta numeración ni cupo diario, así que úsala todo lo que quieras mientras desarrollas.

Guarda lo que vas a enviar antes de enviarlo: los bytes exactos del cuerpo, tu external_reference y la Idempotency-Key. Si la respuesta no llega, eso es lo único que te permite reintentar sin duplicar (idempotencia).

Emítela con POST /v1/invoices. Responde 202 con document_id, operation_id y status_url. Guarda el document_id en tu base de datos junto al pedido.

Espera el resultado. Consulta GET /v1/documents/{id} o, mejor, deja que te avisemos con un webhook y consulta solo cuando llegue el aviso.

Prevalidar no es permiso para emitir

La prevalidación comprueba las reglas fiscales del cuerpo, no el estado de tu empresa ni el de tu rango. Una factura puede prevalidar como valid: true y luego no emitirse porque el rango se agotó, la empresa no está lista o gastaste la cuota del día. Lee siempre el code de la respuesta.

202 no es «aprobada»

202 significa que recibimos y guardamos tu factura. A partir de ahí trabajamos en segundo plano: le asignamos el número, la firmamos, la enviamos a la DIAN y generamos sus archivos. Todo eso tarda segundos, pero no ocurre dentro de tu petición.

La única fuente de verdad es el documento, y tiene dos estados que hay que leer por separado.

processing_status: en qué vamos nosotros

ValorQué significa
queuedLa recibimos. Está en fila.
processingLa estamos numerando, firmando o enviando.
retry_scheduledAlgo falló de forma pasajera y lo reintentamos solos. No hagas nada.
action_requiredSe quedó atascada y necesita que intervengas. Lee blocked_reason.
completedTerminamos. Ojo: también termina en completed una factura rechazada.
cancelledLa cancelaste antes de que saliera.

dian.status: qué dijo la DIAN

ValorQué significaQué haces
not_sentTodavía no ha salido.Esperar.
pendingEstá en la DIAN, sin respuesta aún.Esperar.
validatedLa DIAN la aceptó.Ya tienes factura. Puede traer avisos en dian.warnings.
rejectedLa DIAN la rechazó.Lee dian.errors, corrige y emite otra. Esta no sirve.
unknownNo sabemos qué pasó.No la vuelvas a emitir. Sigue consultando el mismo documento.

En el sandbox verás casi siempre avisos de la DIAN sobre el emisor (FAJ43b, FAJ44b, RUT01): son del emisor de pruebas compartido, no de tu factura. La tabla de reglas está en Errores.

Consultar el documento

curl -s https://api-sandbox.cufy.co/v1/documents/DOCUMENT_ID \
  -H "X-API-Key: TU_API_KEY"

Lo que te interesa de la respuesta:

CampoQué es
processing_status y dianLos dos estados de arriba.
fiscal_identity.prefix y fiscal_identity.numberEl número que se le asignó, por ejemplo SETP y 990000258.
signature.cufeEl CUFE. Está aquí, no en fiscal_identity.
delivery_statusSi se le envió al comprador (Entrega).
allowed_actionsQué puedes hacerle ahora mismo: cancel, correct, resume, deliver, download, issue_credit_note, issue_debit_note.
blocked_reasonPor qué se quedó quieta, cuando processing_status es action_required.
billing_statusEl consumo comercial. En el sandbox siempre not_billable.
related_note_idsLas notas crédito y débito que ya la referencian.

allowed_actions es la forma más cómoda de saber si todavía puedes cancelar o si ya toca emitir una nota: dilo con ese campo en lugar de deducirlo de los estados.

Cada cuánto preguntar

No consultes en un bucle cerrado: tienes 60 peticiones por minuto y las consultas cuentan.

  • Espera unos 3 segundos antes de la primera consulta.
  • Si sigue en queued o processing, duplica la espera en cada intento hasta un máximo de un minuto.
  • Ríndete después de unos minutos y déjalo para un proceso en segundo plano: el documento no se pierde.
  • Mejor aún, registra un webhook y consulta solo cuando te avisemos.

Un documento que quedó en unknown no se resuelve consultando más rápido. Se resuelve consultándolo más tarde.

Ver lo que has emitido

GET /v1/documents lista tus documentos, del más reciente al más antiguo, con paginación. Si guardaste tu external_reference, esa es la forma de encontrar una factura sin depender de nuestros identificadores.

El listado recorre una instantánea: lo que emitas después de pedir la primera página no aparece hasta que reinicies el recorrido.

Cancelar

Una factura solo se cancela antes de que empiece a firmarse: dian.status en not_sent y procesamiento sin terminar. Es una ventana de segundos, útil sobre todo cuando te das cuenta del error nada más enviarla.

Consulta el documento y guarda el ETag de la respuesta.

Llama POST /v1/documents/{id}/cancellation con If-Match, Idempotency-Key y el motivo:

POST /v1/documents/{id}/cancellation
{ "reason": "El pedido se anuló antes de enviarse a la DIAN" }

Responde con cancelled: true y la versión nueva. Si ya había empezado la firma, responde 409 CANCELLATION_NOT_ALLOWED.

Cancelar antes de numerar devuelve la capacidad al rango. Un número ya asignado no se recicla: ese consecutivo queda gastado.

Después ya no se cancela

Una factura que la DIAN validó no se borra ni se edita. Para deshacerla o rebajarla, emites una nota crédito; para cobrar de más, una nota débito.

Si algo sale mal

RespuestaQué pasóQué hacer
422 al emitir lo que había prevalidadoUna regla del ambiente, no del cuerpo.Lee code. La prevalidación no cubre estas reglas.
422 NUMBERING_TYPE_MISMATCHUsaste el rango de otro tipo de documento.Filtra los rangos por document_type (Empresa).
409 IDEMPOTENCY_CONFLICTRepetiste la clave con un cuerpo distinto.Compara con lo que guardaste. Si es otra factura, usa otra clave y otra referencia.
429 SANDBOX_DAILY_LIMITGastaste tus 50 facturas del día.Retry-After te dice cuánto falta para la medianoche de Colombia.
processing_status: action_requiredSe bloqueó antes de llegar a la DIAN.Lee blocked_reason y ve a Corregir y reanudar.
No llegó la respuesta del 202No sabes si se creó.Reintenta el mismo cuerpo con la misma clave. Nunca cambies nada (reintentar sin duplicar).

Los archivos (PDF, XML firmado, respuesta de la DIAN) pueden tardar un poco más que el resultado fiscal: ver Archivos descargables.

En esta página