Facturación Electrónica
/v1/api/facturacionEndpoint unificado — emite los 10 tipos de documento electrónico (FE, NC, ND, DS, NC-DS, Exportación, Contingencia T03/T04, POS, Nota Ajuste POS).
Request Body
| Campo | Tipo | Requerido | Descripción |
|---|---|---|---|
| id_tipo_documento | integer | Sí | 1=FE, 2=NC, 3=ND, 4=DS, 5=NC-DS, 6=Exportación, 7=Contingencia T03, 8=Contingencia T04, 9=POS, 10=Nota Ajuste POS |
| transmit | boolean | No | true para transmitir a DIAN inmediatamente |
| async | boolean | No | true = respuesta 202 Accepted + procesamiento en background con BullMQ. false (default) = síncrono. |
| customer | object | Sí | Datos del adquiriente (ver sub-tabla) |
| invoice_lines | array | Sí | Líneas del documento (FE y DS). Para NC usar credit_note_lines, para ND usar debit_note_lines |
| legal_monetary_totals | object | No | Totales monetarios |
| tax_totals | array | No | Resumen de impuestos |
| payment_form | object | No | Forma de pago |
| notes | string | No | Observaciones |
| id_documento_referencia | integer | No | Solo NC/ND: ID del documento original al que aplica |
| id_concepto_nota | string | No | Solo NC/ND: Código del concepto/motivo |
| referencia_externa | string | No | Referencia única de tu sistema (ej: "ORD-001"). Previene duplicados — si ya existe, retorna 409 |
Customer Sub-table
| Campo | Tipo | Requerido | Descripción |
|---|---|---|---|
| identification_number | string | Sí | NIT o CC del cliente |
| name | string | Sí | Razón social |
| string | Sí | Correo para entrega del documento | |
| type_document_identification.code | string | No | 13=CC, 31=NIT, 22=CE, 41=Pasaporte |
| type_organization.code | string | No | 1=Persona Jurídica, 2=Persona Natural |
| address | string | No | Dirección |
| municipality.code | string | No | Código DANE del municipio |
| municipality.name | string | No | Nombre del municipio |
Invoice Lines Sub-table
| Campo | Tipo | Requerido | Descripción |
|---|---|---|---|
| description | string | Sí | Descripción del producto/servicio |
| invoiced_quantity | number | Sí | Cantidad |
| line_extension_amount | number | Sí | Subtotal de la línea (sin impuestos) |
| price_amount | number | Sí | Precio unitario |
| unit_measure.code | string | No | Código unidad de medida (94=Unidad) |
| tax_totals | array | No | Impuestos de esta línea |
Request Example
{
"id_tipo_documento": 1,
"referencia_externa": "ORD-2026-001",
"transmit": true,
"async": false,
"customer": {
"identification_number": "900123456",
"name": "Empresa XYZ SAS",
"email": "facturacion@xyz.com",
"type_document_identification": {
"code": "31"
},
"type_organization": {
"code": "1"
},
"address": "Calle 123 #45-67, Bogotá",
"municipality": {
"code": "11001",
"name": "Bogotá D.C."
}
},
"invoice_lines": [
{
"description": "Servicio de consultoría",
"invoiced_quantity": 1,
"line_extension_amount": 1000000,
"price_amount": 1000000,
"unit_measure": {
"code": "94"
},
"tax_totals": [
{
"tax_code": "01",
"tax_name": "IVA",
"percent": 19,
"taxable_amount": 1000000,
"tax_amount": 190000
}
]
}
],
"legal_monetary_totals": {
"line_extension_amount": 1000000,
"tax_exclusive_amount": 1000000,
"tax_inclusive_amount": 1190000,
"payable_amount": 1190000
},
"tax_totals": [
{
"tax_code": "01",
"tax_name": "IVA",
"percent": 19,
"taxable_amount": 1000000,
"tax_amount": 190000
}
]
}Respuesta Sync (200)
{
"success": true,
"message": "Factura Electrónica procesado exitosamente",
"data": {
"documento": {
"id": 1,
"prefijo": "SETT",
"numero": "001",
"cufe": "sha384...",
"total": 1190000
},
"xml": "<Invoice>...</Invoice>",
"cufe": "a1b2c3d4e5f6...",
"cufe_scheme": "CUFE-SHA384",
"qr_url": "https://catalogo-vpfe.dian.gov.co/document/searchqr?documentkey=a1b2c3...",
"transmission": {
"isValid": true,
"statusCode": "00",
"statusDescription": "Procesado Correctamente",
"errors": [],
"zipKey": "uuid-track-id",
"retryable": false
}
}
}Respuesta Async (202)
{
"success": true,
"status": 202,
"message": "Factura Electrónica en cola de transmisión",
"data": {
"documento": { "id": 1, "prefijo": "SETT", "numero": "001" },
"cufe": "a1b2c3d4e5f6...",
"cufe_scheme": "CUFE-SHA384",
"qr_url": "https://catalogo-vpfe.dian.gov.co/...",
"job_id": "bull-456",
"poll_url": "/v1/api/facturacion/1/status?id_empresa=5"
}
}curl -X POST https://api.jcflow.com.co/v1/api/facturacion \
-H "X-Api-Key: sk_test_tu_api_key_aqui" \
-H "Content-Type: application/json" \
-d '{"id_tipo_documento":1,"referencia_externa":"ORD-2026-001","transmit":true,"async":false,"customer":{"identification_number":"900123456","name":"Empresa XYZ SAS","email":"facturacion@xyz.com","type_document_identification":{"code":"31"},"type_organization":{"code":"1"},"address":"Calle 123 #45-67, Bogotá","municipality":{"code":"11001","name":"Bogotá D.C."}},"invoice_lines":[{"description":"Servicio de consultoría","invoiced_quantity":1,"line_extension_amount":1000000,"price_amount":1000000,"unit_measure":{"code":"94"},"tax_totals":[{"tax_code":"01","tax_name":"IVA","percent":19,"taxable_amount":1000000,"tax_amount":190000}]}],"legal_monetary_totals":{"line_extension_amount":1000000,"tax_exclusive_amount":1000000,"tax_inclusive_amount":1190000,"payable_amount":1190000},"tax_totals":[{"tax_code":"01","tax_name":"IVA","percent":19,"taxable_amount":1000000,"tax_amount":190000}]}'- Transmisión Síncrona: En el ambiente de producción (o utilizando API keys de producción sk_live_...), la transmisión de los documentos se procesa siempre de forma síncrona (SendBillSync) para prevenir rechazos por falta de autorización para envíos por lotes asíncronos.
- Supresión de Impuestos Vacíos: Para evitar advertencias restrictivas (como las notificaciones FAX05 y FAX14) en el portal oficial de la DIAN, el sistema suprime dinámicamente los bloques vacíos ICA (03) e INC (04) con base/porcentaje en 0.00 al operar en producción.
- Alineación de Fechas y Firma: La fecha y hora de emisión del documento XML se auto-sincronizan en tiempo real con la marca de tiempo de la firma digital (con zona horaria Colombia -05:00), eliminando de raíz el rechazo por regla FAD09e.
- Recálculo Transaccional del CUFE/CUDE: El código CUFE/CUDE se calcula e inyecta dinámicamente integrando el desfase horario oficial de -05:00 tanto en el cálculo matemático como en el tag IssueTime del XML, garantizando la consistencia exacta requerida.
Consultar Estado (Polling)
/v1/api/facturacion/:id/statusConsulta el estado actual de un documento. Útil para polling cuando usas modo async.
Query Parameters
| Campo | Tipo | Requerido | Descripción |
|---|---|---|---|
| id_empresa | integer | Sí | ID de la empresa (query param) |
| check_dian | boolean | No | true = Consultar DIAN GetStatus en vivo si el doc está En Cola |
| ambiente | string | No | 1=Producción, 2=Habilitación (default: 2) |
Estados del documento
| Código | Estado | Descripción |
|---|---|---|
| 1 | Borrador | Guardado, no transmitido |
| 2 | Enviado/Aceptado | DIAN aceptó el documento |
| 3 | En Cola | Procesándose en background (modo async) |
| 4 | Rechazado | DIAN rechazó el documento |
| 5 | Esperando DIAN | Circuit Breaker abierto — DIAN no disponible. Se reenviará automáticamente. |
| 6 | Dead Letter | Agotó 5 reintentos. El Recovery Cron lo reencolará automáticamente cuando DIAN vuelva. |
{
"success": true,
"data": {
"id": 1,
"prefijo": "SETT",
"numero": "001",
"id_tipo_documento": 1,
"id_estado_documento": 2,
"estado": "Enviado/Aceptado",
"cufe": "a1b2c3d4e5f6...",
"qr_url": "https://catalogo-vpfe.dian.gov.co/...",
"dian_track_id": "uuid-zip-key",
"dian_response": {
"isValid": true,
"statusCode": "00",
"statusDescription": "Procesado Correctamente"
},
"total": 1190000,
"fecha_emision": "2026-04-24",
"created_at": "2026-04-24T10:30:00Z",
"updated_at": "2026-04-24T10:30:05Z"
}
}Envío Masivo de Contingencia
/v1/api/facturacion/contingencia/enviarEnvía todos los documentos de contingencia (T03/T04) pendientes a la DIAN. Los documentos se encolan en BullMQ para procesamiento asíncrono.
Request Body
| Campo | Tipo | Requerido | Descripción |
|---|---|---|---|
| id_empresa | integer | Sí | ID de la empresa |
| documento_ids | array | No | IDs específicos a enviar. Si vacío, envía TODOS los pendientes. |
{
"success": true,
"message": "15 documento(s) encolado(s) para transmisión.",
"data": {
"total_pendientes": 15,
"total_encolados": 15,
"total_errores": 0,
"documentos": [
{ "id": 10, "prefijo": "SETT", "numero": "100", "job_id": "bull-789" },
{ "id": 11, "prefijo": "SETT", "numero": "101", "job_id": "bull-790" }
]
}
}Endpoints auxiliares
/v1/api/facturacion/reenviar/:idReenvía un documento en borrador o fallido a la DIAN. Regenera el XML, firma y transmite.
/v1/api/facturacion/consecutivo/:tipoObtiene el siguiente número consecutivo disponible para un tipo de documento.
/v1/api/facturacion/suscripcionConsulta el estado de la suscripción: documentos usados, disponibles y límite.
🌐 Facturas de Exportación (Multidivisa & Incoterms)
Para emitir facturas de exportación (Tipo 02 / Operación 10), especifica la moneda extranjera (USD, EUR), la tasa de cambio TRM del día y los términos Incoterms (CIF, FOB, EXW, FCA, etc.):
{
"id_tipo_documento": 2,
"id_tipo_operacion": "10",
"id_tipo_moneda": 149,
"exchange_rate": {
"source_currency": "USD",
"target_currency": "COP",
"calculation_rate": 4150.50,
"date": "2026-08-29"
},
"delivery": {
"delivery_terms": "FOB"
},
"customer": {
"name": "Global Tech Logistics LLC",
"identification_number": "US99887766",
"country_code": "US",
"type_document_identification": { "code": "41" },
"type_organization": { "code": "1" },
"email": "invoices@globaltech.us"
},
"invoice_lines": [
{
"description": "Exportación de Café Especial Colombiano (Sacos 70kg)",
"invoiced_quantity": 50,
"price_amount": 280.00,
"line_extension_amount": 14000.00,
"unit_measure": { "code": "KGM" }
}
],
"legal_monetary_totals": {
"line_extension_amount": 14000.00,
"tax_exclusive_amount": 14000.00,
"tax_inclusive_amount": 14000.00,
"payable_amount": 14000.00
},
"transmit": true
}🏥 Facturación Sectorial (Salud RIPS, Transporte RNDC, Combustibles)
Sector Salud (RIPS)
Operación 11. Valida campos sectoriales de MinSalud, código de prestador, copagos y cuotas moderadoras.
Sector Transporte (RNDC)
Operación 12. Integra remesa de carga terrestre y manifiesto oficial del Ministerio de Transporte.
Combustibles (EDS)
Soporte automático para Impuesto Nacional a Combustibles (24), Sobretasa (25) y Sordicom (26).
Eventos WebSocket (Real-time)
facturacion:update — Documento aceptado/rechazado por DIAN (estado, errores, zipKey)
facturacion:error — Máx reintentos agotados. El documento se marcará como recuperable y será reenviado automáticamente.
contingencia:batch — Inicio de envío masivo de contingencia
Rooms: empresa_{id}, user_{id}
🛡️ Motor de Resiliencia DIAN
| Capa | Mecanismo | Detalle |
|---|---|---|
| Circuit Breaker | Detección de caída | 5 fallos consecutivos → pausa envíos 60s → prueba automática → reanuda si DIAN responde |
| Exponential Backoff | Reintentos progresivos | 5 intentos: 10s → 20s → 40s → 80s → 160s |
| Dead Letter Queue | Cola de fallidos | Después de 5 intentos → estado 6 (recuperable automáticamente) |
| Recovery Cron | Recuperación automática | Cada 5 min busca docs en estado 5/6 y los reencola si DIAN está disponible |
| Rate Limiter | Control de velocidad | Máx 10 req/seg al WS DIAN, 3 workers concurrentes |
Circuit Breaker
CLOSED ──(5 fallos)──▸ OPEN ──(60s)──▸ HALF_OPEN ──(2 éxitos)──▸ CLOSED
▲ │ fallo
└─────────────────┘ (timeout escala: 60s → 120s → 5min)Estados del Documento
| Estado | ID | Descripción |
|---|---|---|
| Borrador | 1 | Generado, no transmitido a DIAN |
| Aceptado | 2 | DIAN aceptó y validó el documento |
| En Cola | 3 | En proceso vía BullMQ (modo async) |
| Rechazado | 4 | DIAN rechazó el documento (error de negocio) |
| Esperando DIAN | 5 | Circuit Breaker abierto — se reenviará automáticamente |
| Dead Letter | 6 | Agotó 5 reintentos — Recovery Cron lo reencolará |
📊 Rendimiento (Benchmark)
Resultados del stress test ejecutado en servidor local con 500 facturas electrónicas procesadas en ráfaga con 25 conexiones concurrentes (sin transmisión a DIAN).
Distribución de Latencia
| Métrica | Valor |
|---|---|
| Total requests | 500 |
| Concurrencia | 25 |
| Tiempo total | 1.78s |
| Throughput | 281 req/s |
| Avg Latency | 82ms |
| Median (P50) | 75ms |
| P95 | 162ms |
| P99 | 178ms |
| Max | 179ms |