Electronic Invoicing

POST/v1/api/facturacion

Unified endpoint — issues all 10 electronic document types (FE, NC, ND, DS, NC-DS, Export, Contingency T03/T04, POS, POS Adjustment Note).

POST/v1/api/facturacion/fast

Fast asynchronous emission (~30-50ms) — atomic consecutive reservation, CUFE and QR calculation, XAdES digital signing, and BullMQ queueing for DIAN transmission.

⚡ Fast Emission / Async Mode: Use POST /facturacion/fast or send async: true in /facturacion to get a 202 Accepted in ~40ms with CUFE and QR ready for your customer. SOAP transmission to DIAN runs in background.
🔒 Idempotency with Idempotency-Key: Send the Idempotency-Key: <UUID> header to prevent duplicates on retries or repeated clicks. Protected with distributed Redis lock (409 EMISION_EN_CURSO) and 24h Replay Cache.

Request Body

FieldTypeRequiredDescription
id_tipo_documentointegerYes1=FE, 2=NC, 3=ND, 4=DS, 5=NC-DS, 6=Export, 7=Contingency T03, 8=Contingency T04, 9=POS, 10=POS Adjustment
transmitbooleanNotrue to transmit to DIAN immediately
asyncbooleanNotrue = 202 Accepted response + background processing via BullMQ. false (default) = synchronous.
customerobjectYesCustomer data (see sub-table)
invoice_linesarrayYesDocument lines (FE & DS). For NC use credit_note_lines, for ND use debit_note_lines
legal_monetary_totalsobjectNoMonetary totals
tax_totalsarrayNoTax summary
payment_formobjectNoPayment form
notesstringNoNotes
id_documento_referenciaintegerNoNC/ND only: ID of the original document it applies to
id_concepto_notastringNoNC/ND only: Concept/reason code
referencia_externastringNoUnique reference from your system (e.g., "ORD-001"). Prevents duplicates — if it exists, returns 409

Customer Sub-table

FieldTypeRequiredDescription
identification_numberstringYesCustomer NIT or CC
namestringYesBusiness name
emailstringYesEmail for document delivery
type_document_identification.codestringNo13=CC, 31=NIT, 22=CE, 41=Pasaporte
type_organization.codestringNo1=Legal Entity, 2=Natural Person
addressstringNoAddress
municipality.codestringNoDANE municipality code
municipality.namestringNoMunicipality name

Invoice Lines Sub-table

FieldTypeRequiredDescription
descriptionstringYesProduct/service description
invoiced_quantitynumberYesQuantity
line_extension_amountnumberYesLine subtotal (without taxes)
price_amountnumberYesUnit price
unit_measure.codestringNoUnit of measure code (94=Unit)
tax_totalsarrayNoTaxes for this line

Request Example

JSON
{
  "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 OK)

JSON
{
  "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
    }
  }
}

Fast / Async Emission Response (202 Accepted)

JSON
{
  "success": true,
  "estado": "PENDIENTE_DIAN",
  "id_documento": 10452,
  "prefijo": "FE",
  "numero": 1001,
  "cufe": "a1b2c3d4e5f67890123456789abcdef0123456789abcdef0123456789abcdef...",
  "qr_url": "https://catalogo-vpfe.dian.gov.co/document/searchqr?documentkey=a1b2c3...",
  "consultar_en": "/v1/api/facturacion/10452/estado",
  "mensaje": "Factura creada y encolada para transmisión DIAN"
}
Code Examples
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}]}'
Try EndpointPOST /facturacion
⚙️ Automatic Rules in Production (DIAN Annex 1.8):
  • 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.
✅ CUFE/CUDE (Verified): Generated with SHA-384 per DIAN Technical Annex v1.8, Ch. 11.1.2. Verified byte-by-byte against the official DIAN example (CUFE: 8bb918b1...). CUFE for Invoices (resolution technical key), CUDE for Notes and Contingency (software PIN).
ℹ️ QR Code: The DIAN verification URL is generated automatically based on the environment (testing/production).
ℹ️ Pre-emission Validation: The system automatically validates company, DIAN software, resolution (validity + range), digital certificate, customer, and totals before generating the XML.
ℹ️ Email: The document is automatically sent via email to the customer with the XML attached.

Check Status (Polling)

GET/v1/api/facturacion/:id/status

Check the current status of a document. Useful for polling when using async mode.

Query Parameters

FieldTypeRequiredDescription
id_empresaintegerYesCompany ID (query param)
check_dianbooleanNotrue = Query DIAN GetStatus live if doc is In Queue
ambientestringNo1=Production, 2=Testing (default: 2)

Document States

CodeStateDescription
1BorradorSaved, not transmitted
2Enviado/AceptadoDIAN accepted the document
3En ColaProcessing in background (async mode)
4RechazadoDIAN rejected the document
5Waiting DIANCircuit Breaker open — DIAN unavailable. Will be resent automatically.
6Dead LetterExhausted 5 retries. Recovery Cron will re-queue automatically when DIAN is back.
JSON
{
  "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

POST/v1/api/facturacion/contingencia/enviar

Sends all pending contingency documents (T03/T04) to DIAN. Documents are queued in BullMQ for async processing.

Request Body

FieldTypeRequiredDescription
id_empresaintegerYesCompany ID
documento_idsarrayNoSpecific IDs to send. If empty, sends ALL pending.
JSON
{
  "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

POST/v1/api/facturacion/reenviar/:id

Resend a draft or failed document to DIAN. Regenerates XML, signs and transmits.

GET/v1/api/facturacion/consecutivo/:tipo

Gets the next available consecutive number for a document type.

GET/v1/api/facturacion/suscripcion

Checks 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.):

JSON
{
  "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 SS-SinAporte / SS-Recaudo (MinSalud Res. 2275/2023). Emits the Interoperabilidad block: provider code, payment modality, coverage, contract, 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

The system protects against DIAN Web Service outages with multiple resilience layers. No document is lost — all are automatically resent.
LayerMechanismDetail
Circuit BreakerOutage detection5 consecutive failures → pause sends 60s → automatic test → resume if DIAN responds
Exponential BackoffProgressive retries5 attempts: 10s → 20s → 40s → 80s → 160s
Dead Letter QueueFailed queueAfter 5 attempts → state 6 (automatically recoverable)
Recovery CronAuto recoveryEvery 5 min searches for state 5/6 docs and re-queues them if DIAN is available
Rate LimiterSpeed controlMax 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

StateIDDescription
Borrador1Generated, not transmitted to DIAN
Accepted2DIAN accepted and validated the document
In Queue3Processing via BullMQ (async mode)
Rejected4DIAN rejected the document (business error)
Waiting DIAN5Circuit Breaker open — will be resent automatically
Dead Letter6Exhausted 5 retries — Recovery Cron will re-queue
✅ No document loss: States 5 and 6 are recoverable. The Recovery Cron (every 5 min) automatically re-queues all pending documents when DIAN becomes available again.

📊 Performance (Benchmark)

Stress test results on a local server with 500 electronic invoices burst-processed with 25 concurrent connections (without DIAN transmission).

100%
Success Rate
281req/s
Throughput
75ms
Median Latency
162ms
P95 Latency

Latency Distribution

< 100ms87%
100–200ms13%
> 200ms0%
MetricValue
Total requests500
Concurrency25
Total time1.78s
Throughput281 req/s
Avg Latency82ms
Median (P50)75ms
P95162ms
P99178ms
Max179ms
⚠️ Note: In production with transmit=true, DIAN transmission latency (1-5s) is processed in background via BullMQ. The client response remains ~150ms (202 Accepted).