Electronic Invoicing
/v1/api/facturacionUnified endpoint — issues all 10 electronic document types (FE, NC, ND, DS, NC-DS, Export, Contingency T03/T04, POS, POS Adjustment Note).
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| id_tipo_documento | integer | Yes | 1=FE, 2=NC, 3=ND, 4=DS, 5=NC-DS, 6=Export, 7=Contingency T03, 8=Contingency T04, 9=POS, 10=POS Adjustment |
| transmit | boolean | No | true to transmit to DIAN immediately |
| async | boolean | No | true = 202 Accepted response + background processing via BullMQ. false (default) = synchronous. |
| customer | object | Yes | Customer data (see sub-table) |
| invoice_lines | array | Yes | Document lines (FE & DS). For NC use credit_note_lines, for ND use debit_note_lines |
| legal_monetary_totals | object | No | Monetary totals |
| tax_totals | array | No | Tax summary |
| payment_form | object | No | Payment form |
| notes | string | No | Notes |
| id_documento_referencia | integer | No | NC/ND only: ID of the original document it applies to |
| id_concepto_nota | string | No | NC/ND only: Concept/reason code |
| referencia_externa | string | No | Unique reference from your system (e.g., "ORD-001"). Prevents duplicates — if it exists, returns 409 |
Customer Sub-table
| Field | Type | Required | Description |
|---|---|---|---|
| identification_number | string | Yes | Customer NIT or CC |
| name | string | Yes | Business name |
| string | Yes | Email for document delivery | |
| type_document_identification.code | string | No | 13=CC, 31=NIT, 22=CE, 41=Pasaporte |
| type_organization.code | string | No | 1=Legal Entity, 2=Natural Person |
| address | string | No | Address |
| municipality.code | string | No | DANE municipality code |
| municipality.name | string | No | Municipality name |
Invoice Lines Sub-table
| Field | Type | Required | Description |
|---|---|---|---|
| description | string | Yes | Product/service description |
| invoiced_quantity | number | Yes | Quantity |
| line_extension_amount | number | Yes | Line subtotal (without taxes) |
| price_amount | number | Yes | Unit price |
| unit_measure.code | string | No | Unit of measure code (94=Unit) |
| tax_totals | array | No | Taxes for this line |
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
}
]
}Sync Response (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
}
}
}Async Response (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}]}'- Synchronous Transmission: In the production environment (or when using production API keys sk_live_...), document transmission is always processed synchronously (SendBillSync) to prevent rejections due to lack of authorization for asynchronous batch processing.
- Suppression of Empty Taxes: To avoid restrictive warnings (such as FAX05 and FAX14 notifications) on the DIAN portal, the system dynamically suppresses empty ICA (03) and INC (04) blocks with base/percentage at 0.00 when operating in production.
- Date and Signature Alignment: The emission date and time in the XML document are automatically synchronized in real-time with the digital signature timestamp (using Colombia time zone -05:00), completely eliminating rejections caused by rule FAD09e.
- Transactional Recalculation of CUFE/CUDE: The CUFE/CUDE code is dynamically recalculated and injected, integrating the official time offset of -05:00 in both the mathematical calculation and the IssueTime tag of the XML, ensuring exact consistency.
Check Status (Polling)
/v1/api/facturacion/:id/statusCheck the current status of a document. Useful for polling when using async mode.
Query Parameters
| Field | Type | Required | Description |
|---|---|---|---|
| id_empresa | integer | Yes | Company ID (query param) |
| check_dian | boolean | No | true = Query DIAN GetStatus live if doc is In Queue |
| ambiente | string | No | 1=Production, 2=Testing (default: 2) |
Document States
| Code | State | Description |
|---|---|---|
| 1 | Borrador | Saved, not transmitted |
| 2 | Enviado/Aceptado | DIAN accepted the document |
| 3 | En Cola | Processing in background (async mode) |
| 4 | Rechazado | DIAN rejected the document |
| 5 | Waiting DIAN | Circuit Breaker open — DIAN unavailable. Will be resent automatically. |
| 6 | Dead Letter | Exhausted 5 retries. Recovery Cron will re-queue automatically when DIAN is back. |
{
"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"
}
}Contingency Batch Send
/v1/api/facturacion/contingencia/enviarSends all pending contingency documents (T03/T04) to DIAN. Documents are queued in BullMQ for async processing.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| id_empresa | integer | Yes | Company ID |
| documento_ids | array | No | Specific IDs to send. If empty, sends ALL pending. |
{
"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" }
]
}
}Utility endpoints
/v1/api/facturacion/reenviar/:idResend a draft or failed document to DIAN. Regenerates XML, signs and transmits.
/v1/api/facturacion/consecutivo/:tipoGets the next available consecutive number for a document type.
/v1/api/facturacion/suscripcionChecks subscription status: documents used, available, and limit.
🌐 Export Invoices (Multi-currency & Incoterms)
To issue export invoices (Type 02 / Operation 10), specify the foreign currency (USD, EUR), daily TRM exchange rate and 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
}🏥 Sectoral Invoicing (Health RIPS, Transport RNDC, Fuels)
Health Sector (RIPS)
Operation 11. Validates MinSalud sectoral fields, provider code, copays and moderator fees.
Cargo Transport (RNDC)
Operation 12. Integrates cargo dispatch and official MinTransporte cargo manifest.
Fuels & Gas Stations
Automatic support for Fuel Tax (24), Surcharge (25) and Sordicom (26).
WebSocket Events (Real-time)
facturacion:update — Document accepted/rejected by DIAN (status, errors, zipKey)
facturacion:error — Max retries exhausted. Document will be marked as recoverable and resent automatically.
contingencia:batch — Contingency batch send started
Rooms: empresa_{id}, user_{id}
🛡️ DIAN Resilience Engine
| Layer | Mechanism | Detail |
|---|---|---|
| Circuit Breaker | Outage detection | 5 consecutive failures → pause sends 60s → automatic test → resume if DIAN responds |
| Exponential Backoff | Progressive retries | 5 attempts: 10s → 20s → 40s → 80s → 160s |
| Dead Letter Queue | Failed queue | After 5 attempts → state 6 (automatically recoverable) |
| Recovery Cron | Auto recovery | Every 5 min searches for state 5/6 docs and re-queues them if DIAN is available |
| Rate Limiter | Speed control | Max 10 req/sec to DIAN WS, 3 concurrent workers |
Circuit Breaker
CLOSED ──(5 failures)──▸ OPEN ──(60s)──▸ HALF_OPEN ──(2 successes)──▸ CLOSED
▲ │ fail
└─────────────────┘ (escalating timeout: 60s → 120s → 5min)Document States
| State | ID | Description |
|---|---|---|
| Borrador | 1 | Generated, not transmitted to DIAN |
| Accepted | 2 | DIAN accepted and validated the document |
| In Queue | 3 | Processing via BullMQ (async mode) |
| Rejected | 4 | DIAN rejected the document (business error) |
| Waiting DIAN | 5 | Circuit Breaker open — will be resent automatically |
| Dead Letter | 6 | Exhausted 5 retries — Recovery Cron will re-queue |
📊 Performance (Benchmark)
Stress test results on a local server with 500 electronic invoices burst-processed with 25 concurrent connections (without DIAN transmission).
Latency Distribution
| Metric | Value |
|---|---|
| Total requests | 500 |
| Concurrency | 25 |
| Total time | 1.78s |
| Throughput | 281 req/s |
| Avg Latency | 82ms |
| Median (P50) | 75ms |
| P95 | 162ms |
| P99 | 178ms |
| Max | 179ms |