FacEPro Cloud API v1

Documentación API REST

FacEPro Cloud · v1 · Facturación electrónica DIAN Colombia

El API de FacEPro Cloud te permite emitir facturas electrónicas, notas crédito y notas débito ante la DIAN desde cualquier aplicación (PHP, VB.NET, C#, Java, JavaScript, Python). Tú envías un JSON simple con los datos de la operación; nosotros nos encargamos de generar el XML UBL 2.1, firmarlo digitalmente (XAdES BES + WS-Security), calcular el CUFE y enviarlo a la DIAN.

Antes de empezar

Necesitas: (1) tu empresa registrada en el portal, (2) el certificado digital cargado, (3) la configuración DIAN completada (SoftwareID, PIN, Clave Técnica, Resolución), y (4) un Token API generado desde el portal.

Quick start — tu primera factura en 3 pasos

  1. 1

    Genera un Token API

    Entra al portal, ve a Tokens API, haz clic en Generar Token y copia el valor (solo se muestra una vez).

  2. 2

    Verifica el token con GET /me

    Confirma que tu token responde y que la empresa asociada es la correcta antes de enviar facturas reales.

  3. 3

    Envía tu primera factura con POST /documentos

    Recibirás un tracking_id, el cufe y el estado DIAN en una sola respuesta.

Ejemplos JSON descargables

Descarga estos archivos como punto de partida para tu integración. Cada ejemplo incluye todos los campos disponibles con valores reales que puedes adaptar.

Factura electrónica — contado
POST /api/v1/documentos · Pago al contado, IVA 19% + exento
factura-contado.json ↓
Factura electrónica — crédito
POST /api/v1/documentos · Crédito con fecha vencimiento + descuento
factura-credito.json ↓
Factura con retenciones · B2B
POST /api/v1/documentos · ReteIVA + ReteRenta + ReteICA (Gran Contribuyente)
factura-con-retenciones.json ↓
Factura con anticipo + descuento
POST /api/v1/documentos · Descuento global + anticipo previo
factura-con-anticipo-descuento.json ↓
Factura con ICA + INC
POST /api/v1/documentos · Impuestos al consumo (bar) + ICA (Bogotá)
factura-con-ica-inc.json ↓
Factura con propina
POST /api/v1/documentos · Bar/restaurante · Propina 10% (DIAN code 03, no gravable)
factura-con-propina.json ↓
Factura con producto regalo
POST /api/v1/documentos · FreeOfChargeIndicator · 2x1 / muestra (precio_referencia)
factura-con-regalo.json ↓
Factura con bolsas plásticas
POST /api/v1/documentos · Impuesto bolsas Ley 1819 (TaxScheme 22, per-unidad)
factura-con-bolsas.json ↓
Factura con IBUA
POST /api/v1/documentos · Bebidas azucaradas (TaxScheme 34, por volumen ml)
factura-con-ibua.json ↓
Factura con ICUI
POST /api/v1/documentos · Comestibles ultraprocesados (TaxScheme 35, porcentual)
factura-con-icui.json ↓
Factura con Imp. Carbono
POST /api/v1/documentos · Combustibles (TaxScheme 23, por galón)
factura-con-carbono.json ↓
Factura con licores (ICL)
POST /api/v1/documentos · ICL específico (32) + AD VALOREM (ZZ)
factura-con-licor.json ↓
Nota crédito
POST /api/v1/notas-credito · Referencia a factura previa
nota-credito.json ↓
Nota débito
POST /api/v1/notas-debito · Interés por mora
nota-debito.json ↓
Evento 030 — Acuse de recibo
POST /api/v1/eventos · Confirmar recepción de factura
evento-030-acuse-recibo.json ↓
Evento 032 — Recibo del bien
POST /api/v1/eventos · Confirmar bien entregado
evento-032-recibo-bien.json ↓
Evento 033 — Aceptación expresa
POST /api/v1/eventos · Aceptar como título valor
evento-033-aceptacion-expresa.json ↓
Evento 031 — Reclamo
POST /api/v1/eventos · Rechazar factura recibida
evento-031-reclamo.json ↓
Tip: Estos ejemplos son ilustrativos. Cuando integres, reemplaza los CUFE de los eventos por el CUFE real de tu factura recibida, y los datos del adquirente/emisor con los de tu operación.

Autenticación

Todas las peticiones (excepto GET /health) requieren un Bearer Token en el header Authorization:

Authorization: Bearer 7|aBcDeFgHiJkLmNoPqRsTuVwXyZ0123456789...
  • El token identifica a tu empresa (tenant).
  • Está hasheado en base de datos: si lo pierdes, debes generar uno nuevo.
  • Lo puedes revocar en cualquier momento desde el portal.
  • Cada petición se valida y se registra en los logs de auditoría del API.

No expongas tu token

Nunca lo incluyas en código del lado del navegador, en repositorios públicos, ni en capturas de pantalla. Si sospechas que se filtró, revócalo de inmediato.

Convenciones

Base URL https://facepro.cdpconsultores.com/api/v1
Formato JSON (UTF-8) en request y response
Content-Type application/json
Accept application/json
Zona horaria America/Bogota (UTC-5)
Decimales punto como separador (19000.50, no 19000,50)
Fechas YYYY-MM-DD

Forma de las respuestas

Toda respuesta JSON incluye un campo ok booleano que indica si la operación fue exitosa.

// Éxito
{
  "ok": true,
  "data": { ... }
}

// Error
{
  "ok": false,
  "error": "Mensaje legible",
  "codigo": "identificador_estable"
}

CUFE y CUDE

El CUFE (Código Único de Factura Electrónica) y el CUDE (Código Único de Documento Electrónico) son hashes SHA-384 que identifican inequívocamente cada documento ante la DIAN.

CampoAplica aLargoAlgoritmo
CUFEFactura electrónica96 hexSHA-384
CUDENC, ND, eventos (ApplicationResponse)96 hexSHA-384

Cálculo del CUFE (factura)

CUFE = SHA-384(
  NumFac + FecFac + HorFac + ValFac
  + "01" + ValImpIVA
  + "04" + ValImpICA
  + "03" + ValImpINC
  + ValTot + NitOFE + NumAdq + ClTec + TipoAmb
)

Cálculo del CUDE (evento / ApplicationResponse)

CUDE = SHA-384(
  Num_DE + Fec_Emi + Hor_Emi + NitFE + DocAdq
  + ResponseCode + ID + DocumentTypeCode + Software-PIN
)
FacEPro lo calcula automáticamente. Solo recibes el CUFE/CUDE en la respuesta del API — no necesitas calcularlo en tu app.

Validar un documento en el catálogo DIAN

Cualquier persona puede verificar un documento por su CUFE en:

https://catalogo-vpfe.dian.gov.co/document/searchqr?documentkey={CUFE}

Ambiente habilitación: catalogo-vpfe-hab.dian.gov.co

Impuestos avanzados, retenciones, descuentos y anticipos

Para coberturas B2B reales en Colombia, FacEPro soporta todos los conceptos exigidos por DIAN. Todos son opcionales: si no los envías, la factura es simple como antes.

Retenciones (ReteIVA / ReteRenta / ReteICA)

Aplican cuando el adquirente es Gran Contribuyente o Autoretenedor. El comprador retiene impuestos al pagar la factura.

CódigoNombreBase por defectoTarifa típica
05ReteIVAMonto del IVA15% del IVA
06ReteRenta (Retefuente)Subtotal2.5% servicios · 3.5% compras
07ReteICASubtotal0.7% a 11.04‰ según municipio
"retenciones": [
  { "codigo": "05", "porcentaje": 15.00 },
  { "codigo": "06", "porcentaje": 2.50 },
  { "codigo": "07", "porcentaje": 0.70 }
]

La respuesta del API incluye total_retencion_iva, total_retencion_renta, total_retencion_ica, total_retenciones y total_neto (lo que el cliente realmente paga).

ICA e INC por línea

Impuestos adicionales que aplican según la línea:

  • ICA (Impuesto de Industria y Comercio): por municipio, ~0.7% a 1% según actividad
  • INC (Impuesto al Consumo): 8% en bares/restaurantes, 4% en telefonía móvil
"lineas": [
  {
    "codigo": "M-001",
    "descripcion": "Cena gourmet",
    "cantidad": 1,
    "precio": 250000,
    "iva_pct": 0,
    "inc_pct": 8      // INC 8% para bares/restaurantes
  }
]

Propina (bares y restaurantes)

La propina es un incremento al total pero NO entra a la base imponible — no se le calcula IVA. DIAN la identifica con AllowanceChargeReasonCode = 03.

"factura": {
  ...
  "propina_pct": 10.00      // 10% del subtotal · o usar:
  "propina_valor": 25000      // monto fijo (mutuamente excluyente con pct)
}

Cálculo: Subtotal $250.000 · IVA $0 · INC 8% = $20.000 · Propina 10% = $25.000 → Total a pagar = $295.000. La propina aparece en ChargeTotalAmount del XML, fuera del TaxInclusiveAmount.

Descuentos y recargos globales

A diferencia de lineas[].descuento_pct (por línea), el global aplica al documento entero.

"factura": {
  ...
  "descuento_global_valor": 50000,
  "descuento_global_razon": "Cliente frecuente",

  "recargo_global_valor": 10000,
  "recargo_global_razon": "Costo de envío"
}

Anticipos (pagos previos)

Si el cliente ya pagó algo antes de la factura, declara los anticipos. Se restan del total a pagar.

"anticipos": [
  {
    "id": "ANT-001",
    "valor": 200000,
    "fecha_recibido": "2026-05-01"
  }
]

Productos de regalo (FreeOfChargeIndicator)

Para promociones 2x1, muestras, regalos comerciales o degustaciones. La línea lleva "es_regalo": true y precio_referencia con el valor de mercado del producto regalado. El cliente paga $0 por esa línea (LineExtensionAmount = 0) pero queda trazable para DIAN con el indicador <cbc:FreeOfChargeIndicator>true</cbc:FreeOfChargeIndicator> y el bloque PricingReference en el XML.

"lineas": [
  {
    "codigo": "SHAMPOO-500",
    "descripcion": "Shampoo Hidratante 500ml",
    "cantidad": 1,
    "precio": 35000,
    "iva_pct": 19
  },
  {
    "codigo": "ACOND-300",
    "descripcion": "Acondicionador 300ml (REGALO)",
    "cantidad": 1,
    "precio": 0,
    "iva_pct": 0,
    "es_regalo": true,
    "precio_referencia": 28000     // valor de mercado del producto
  }
]

Bolsas plásticas (Ley 1819 / TaxScheme 22)

Impuesto al uso de bolsas plásticas (Reforma Tributaria 2016, Art. 207). A diferencia de IVA/ICA/INC, es per-unidad (no porcentual): se cobra un valor fijo por cada bolsa entregada. Para 2026 el valor por bolsa es de $80 COP (actualizar anualmente según UVT).

"bolsas": {
  "cantidad": 3,
  "valor_unitario": 80
}

Se emite un <cac:TaxTotal> dedicado con TaxScheme/ID = 22, PerUnitAmount y BaseUnitMeasure. El total (cantidad × valor_unitario) suma al total a pagar y queda guardado en el campo total_bolsas del documento.

Impuestos sectoriales (Nivel 2)

Para sectores específicos (bebidas, comestibles ultraprocesados, combustibles, licores). Todos son opcionales y por línea: solo la empresa que vende ese producto los envía. Las tarifas las calcula y envía tu sistema (cambian cada año por UVT); FacEPro solo arma el XML. Códigos confirmados contra los XML de ejemplo del toolkit DIAN.

ImpuestoTaxSchemeTipoCampo en la línea
IBUA (bebidas azucaradas)34por volumen (ml)ibua: {volumen_ml, tarifa_por_100ml}
ICUI (comestibles ultraprocesados)35porcentualicui_pct
INCarbono (combustibles)23por unidadcarbono: {cantidad, unidad, tarifa}
ICL (licor, específico)32por grados alcohollicor: {grados, tarifa_especifico, ad_valorem_pct}
AD VALOREM (licor, 2º comp.)ZZporcentual
// Bebida azucarada (IBUA): tax = (volumen_ml / 100) × tarifa_por_100ml
{ "codigo": "COCA1L", "cantidad": 10, "precio": 1000, "iva_pct": 19,
  "ibua": { "volumen_ml": 10000, "tarifa_por_100ml": 18 } }

// Ultraprocesado (ICUI): porcentual, como el IVA
{ "codigo": "SNACK", "cantidad": 5, "precio": 20000, "iva_pct": 19, "icui_pct": 20 }

// Combustible (Carbono): tax = cantidad × tarifa
{ "codigo": "ACPM", "cantidad": 100, "precio": 9500, "iva_pct": 0,
  "carbono": { "cantidad": 100, "unidad": "GLL", "tarifa": 238 } }

// Licor: ICL específico (grados × tarifa) + AD VALOREM (% sobre base) + IVA
{ "codigo": "AGUARD", "cantidad": 1, "precio": 53000, "iva_pct": 19,
  "licor": { "grados": 37, "tarifa_especifico": 295, "ad_valorem_pct": 25 } }

Cada impuesto se emite como un <cac:TaxTotal> adicional, tanto a nivel de línea como agregado en la cabecera. Los montos suman al total a pagar y quedan en total_ibua, total_icui, total_carbono, total_icl y total_advalorem del documento.

Tipo de operación DIAN

CódigoTipoAplica a
10Estándar (default)Mayoría de facturas
09AIUConstrucción, vigilancia, aseo
11MandatosFacturación por cuenta de terceros
12ExportaciónVentas internacionales
13Cambio de divisasCasas de cambio
"factura": { ..., "tipo_operacion": "10" }
Todo es opcional. Tu integración actual NO se rompe: si no envías estos campos, la factura sale exactamente como antes.

Entrega automática al adquirente

Según el Anexo Técnico DIAN sección 9.1, el facturador electrónico debe enviar al adquirente, vía correo electrónico, un AttachedDocument (ZIP) con la factura XML firmada + el ApplicationResponse de DIAN. FacEPro lo hace automáticamente cuando incluyes adquiriente.email en el payload.

Flujo automático

  1. 1. Tu app envía POST /api/v1/documentos con adquiriente.email
  2. 2. FacEPro firma, envía a DIAN, espera veredicto
  3. 3. Si DIAN acepta → FacEPro construye el AttachedDocument, lo firma, empaqueta en ZIP
  4. 4. Envía el correo al adquiriente.email con asunto formato DIAN

Asunto del correo (formato DIAN)

NIT_FACTURADOR;RAZON_SOCIAL;NUMERO_DOC;CODIGO_TIPO_DOC;NOMBRE_COMERCIAL;LINEA_NEGOCIO

# Ejemplo:
901259449;UP MOTOS S.A.S;SETP990000023;01;UP MOTOS;Comercializadora

Adjuntos

  • entrega_{numero}.zip — AttachedDocument firmado + factura.xml + ApplicationResponse.xml
  • {numero}.pdf — Representación gráfica con QR DIAN
Reintentos automáticos: Si el envío del correo falla (SMTP caído, email inválido, etc.), FacEPro reintenta cada 5 minutos hasta 5 veces. El estado de la entrega es visible en /portal/documentos/{uuid}.

Catálogos DIAN

Estos códigos vienen de las tablas oficiales del Anexo Técnico 1.9 DIAN. Tu aplicación debe enviar exactamente estos valores.

Tipo de persona tipo_persona

CódigoDescripción
1Persona Jurídica
2Persona Natural

Tipo de documento tipo_documento

CódigoDescripción
11Registro civil
12Tarjeta de identidad
13Cédula de ciudadanía
21Tarjeta de extranjería
22Cédula de extranjería
31NIT
41Pasaporte
42Documento extranjero
50NIT otro país

Responsabilidad fiscal responsabilidad_fiscal

CódigoDescripción
O-13Gran contribuyente
O-15Autorretenedor
O-23Agente de retención IVA
O-47Régimen simple de tributación
R-99-PNNo responsable (lo más común para personas naturales y régimen simplificado)

Motivo nota crédito motivo.codigo (NC)

CódigoDescripción
1Devolución parcial de bienes y/o no aceptación parcial del servicio
2Anulación de factura electrónica
3Rebaja o descuento parcial o total
4Ajuste de precios
5Otros
6Devolución total de bienes y/o no aceptación total del servicio

Motivo nota débito motivo.codigo (ND)

CódigoDescripción
1Intereses
2Gastos por cobrar
3Cambio del valor
4Otros

Unidad de medida unidad (línea)

CódigoDescripción
94Unidad (default)
EAEach (cada uno)
KGMKilogramo
LTRLitro
MTRMetro
HURHora

Catálogo completo en el Anexo Técnico 1.9 DIAN.

GET /health público · sin autenticación

Estado del servicio

Devuelve un OK simple. Útil para monitorear que el servicio responde.

Respuesta 200

{
  "status": "ok",
  "service": "FacEPro Cloud",
  "version": "v1",
  "time": "2026-05-10T15:30:00-05:00"
}
GET /me requiere Bearer Token

Información de la empresa autenticada

Verifica que tu token funciona y a qué empresa apunta. Llámalo siempre antes de enviar el primer documento para asegurarte de que estás operando contra la empresa correcta.

Respuesta 200

{
  "user": {
    "id": 3,
    "name": "Luis Alberto",
    "email": "luis@empresa.com"
  },
  "tenant": {
    "id": 2,
    "uuid": "6a2f1c4e-...",
    "nit": "901234567",
    "dv": "1",
    "razon_social": "MI EMPRESA SAS",
    "estado": "activo"
  }
}
curl -H "Authorization: Bearer YOUR_TOKEN" \
  https://facepro.cdpconsultores.com/api/v1/me
<?php
$ch = curl_init('https://facepro.cdpconsultores.com/api/v1/me');
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'Authorization: Bearer YOUR_TOKEN',
    'Accept: application/json',
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);

$data = json_decode($response, true);
print_r($data['tenant']);
Imports System.Net.Http
Imports System.Net.Http.Headers
Imports Newtonsoft.Json.Linq

Dim cliente As New HttpClient()
cliente.DefaultRequestHeaders.Authorization =
    New AuthenticationHeaderValue("Bearer", "YOUR_TOKEN")

Dim respuesta = Await cliente.GetAsync("https://facepro.cdpconsultores.com/api/v1/me")
Dim cuerpo = Await respuesta.Content.ReadAsStringAsync()
Dim json = JObject.Parse(cuerpo)

Console.WriteLine("Empresa: " & json("tenant")("razon_social").ToString())
using var client = new HttpClient();
client.DefaultRequestHeaders.Authorization =
    new AuthenticationHeaderValue("Bearer", "YOUR_TOKEN");

var response = await client.GetAsync("https://facepro.cdpconsultores.com/api/v1/me");
var body = await response.Content.ReadAsStringAsync();
var data = JsonSerializer.Deserialize<JsonElement>(body);

Console.WriteLine(data.GetProperty("tenant").GetProperty("razon_social"));
const response = await fetch('https://facepro.cdpconsultores.com/api/v1/me', {
  headers: { 'Authorization': 'Bearer YOUR_TOKEN' }
});
const data = await response.json();
console.log(data.tenant.razon_social);
POST /documentos crea factura · permite_facturas

Emitir factura electrónica

Genera el XML UBL 2.1, lo firma con XAdES BES, calcula el CUFE, lo empaqueta en ZIP, firma el SOAP envelope con WS-Security y lo envía a la DIAN. Devuelve el documento completo con el estado DIAN incluido.

Cuerpo del request

CampoTipoRequeridoDescripción
factura.fechadatenoFecha emisión YYYY-MM-DD (default: hoy)
factura.horastringnoHora HH:mm:ss-05:00 (default: ahora)
factura.forma_pagostringnoNUEVO · 1=Contado (default), 2=Crédito
factura.metodo_pagostringnoNUEVO · 10=Efectivo, 41=Transferencia, 47=Transf. bancaria, 48=TC, 49=TD
factura.fecha_vencimientodatesi créditoNUEVO · Fecha vence (obligatoria si forma_pago=2)
factura.tipo_operacionstringnoNUEVO · Default 10=Estándar · 09=AIU · 11=Mandatos · 12=Exportación · etc.
factura.descuento_global_valornumbernoNUEVO · Descuento a nivel documento (en $)
factura.descuento_global_razonstringnoNUEVO · Texto del descuento (ej. "Cliente frecuente")
factura.recargo_global_valornumbernoNUEVO · Recargo a nivel documento (ej. flete, propina)
factura.recargo_global_razonstringnoNUEVO · Texto del recargo
adquiriente.tipo_personastring1=Jurídica, 2=Natural
adquiriente.tipo_documentostringVer tabla de tipos de documento
adquiriente.numero_documentostringNIT sin DV, o número de cédula
adquiriente.dvstringnoDígito verificación NIT (solo si tipo_documento = 31)
adquiriente.razon_socialstringNombre de la empresa o persona
adquiriente.nombre_comercialstringnoNUEVO · Nombre comercial (DIAN seccion 9.1)
adquiriente.responsabilidad_fiscalstringEj: R-99-PN
adquiriente.emailstringrecomendadoSi está presente, FacEPro envía automáticamente el AttachedDocument por correo al adquirente (obligación DIAN 9.1)
adquiriente.direccionstringnoDirección física
adquiriente.codigo_municipiostringnoCódigo DANE municipio (ej: 05001)
adquiriente.codigo_departamentostringnoCódigo DANE depto (ej: 05)
lineas[]arrayMínimo 1, máximo 200 ítems
lineas[].codigostringCódigo interno del producto
lineas[].descripcionstringDescripción del bien o servicio
lineas[].cantidadnumberCantidad (admite decimales)
lineas[].unidadstringnoUnidad de medida (default: 94)
lineas[].precionumberPrecio unitario sin IVA
lineas[].iva_pctnumberPorcentaje IVA (0, 5, 19)
lineas[].descuento_pctnumbernoDescuento % sobre la línea
lineas[].descuento_valornumbernoAlternativa: descuento en $ fijo
lineas[].ica_pctnumbernoNUEVO · % ICA línea (ej. 0.966 para Bogotá 9.66‰)
lineas[].inc_pctnumbernoNUEVO · % Impuesto al Consumo (ej. 8 bares, 4 telefonía)
lineas[].notastringnoNUEVO · Nota libre por línea
Retenciones — opcionales, para B2B con Gran Contribuyente / Autoretenedor
retenciones[].codigostringsí (si retenciones)05=ReteIVA · 06=ReteRenta · 07=ReteICA
retenciones[].porcentajenumbersí (si retenciones)% de retención (ej. 15 para 15% ReteIVA)
retenciones[].base_calculostringnoiva (default ReteIVA), subtotal (default otras), manual
retenciones[].base_manualnumbersi manualBase custom si base_calculo=manual
Anticipos — opcionales, pagos recibidos previos
anticipos[].valornumbersí (si anticipos)Monto recibido previamente
anticipos[].idstringnoIdentificador del anticipo (ej. recibo)
anticipos[].fecha_recibidodatenoFecha del pago anticipado
Propina — bares/restaurantes, no genera IVA (ver sección Impuestos avanzados)
factura.propina_pct / propina_valornumberno% del subtotal, o monto fijo (excluyentes)
Producto regalo (FreeOfChargeIndicator) — 2x1 / muestras
lineas[].es_regaloboolnotrue = producto gratis (precio 0)
lineas[].precio_referencianumbersi regaloValor de mercado del producto regalado
Bolsas plásticas (TaxScheme 22) — a nivel documento
bolsas.cantidad / valor_unitarioint / numbernoNº de bolsas × valor por bolsa del año
Impuestos sectoriales por línea (ver sección Impuestos sectoriales) — opcionales
lineas[].icui_pctnumbernoICUI ultraprocesados (35) · porcentual
lineas[].ibuaobjectnoIBUA bebidas (34) · {volumen_ml, tarifa_por_100ml}
lineas[].carbonoobjectnoImp. Carbono (23) · {cantidad, unidad, tarifa}
lineas[].licorobjectnoLicores ICL (32) + AdV (ZZ) · {grados, tarifa_especifico, ad_valorem_pct}

Ejemplo de request

{
  "adquiriente": {
    "tipo_persona": "2",
    "tipo_documento": "13",
    "numero_documento": "71234567",
    "razon_social": "JUAN PEREZ",
    "responsabilidad_fiscal": "R-99-PN",
    "email": "juan@correo.com",
    "direccion": "Calle 50 # 30-20",
    "codigo_municipio": "05001",
    "codigo_departamento": "05"
  },
  "lineas": [
    {
      "codigo": "PROD-001",
      "descripcion": "Repuesto motocicleta XYZ",
      "cantidad": 2,
      "precio": 50000,
      "iva_pct": 19
    },
    {
      "codigo": "SERV-010",
      "descripcion": "Mano de obra instalación",
      "cantidad": 1,
      "precio": 25000,
      "iva_pct": 19,
      "descuento_pct": 10
    }
  ]
}

Respuesta 201 Created

{
  "ok": true,
  "data": {
    "tracking_id": "550e8400-e29b-41d4-a716-446655440000",
    "numero_completo": "SETP990000011",
    "tipo_documento": "factura",
    "prefijo": "SETP",
    "consecutivo": 990000011,
    "fecha_emision": "2026-05-10T15:30:00-05:00",
    "adquirente": {
      "documento": "71234567",
      "razon_social": "JUAN PEREZ"
    },
    "totales": {
      "subtotal": 122500,
      "iva": 23275,
      "total": 145775
    },
    "cufe": "a1b2c3d4...96 chars hex...",
    "zip_key": "abcdef1234...",
    "estado": "aceptado",
    "estado_dian_codigo": "00",
    "estado_dian_mensaje": "Procesado correctamente",
    "links": {
      "self":      "https://facepro.cdpconsultores.com/api/v1/documentos/550e8400-...",
      "consultar": "https://facepro.cdpconsultores.com/api/v1/documentos/550e8400-.../consultar",
      "xml":       "https://facepro.cdpconsultores.com/api/v1/documentos/550e8400-.../xml"
    }
  }
}

Ejemplos de código

curl -X POST https://facepro.cdpconsultores.com/api/v1/documentos \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "adquiriente": {
      "tipo_persona": "2",
      "tipo_documento": "13",
      "numero_documento": "71234567",
      "razon_social": "JUAN PEREZ",
      "responsabilidad_fiscal": "R-99-PN"
    },
    "lineas": [
      { "codigo": "P1", "descripcion": "Producto 1",
        "cantidad": 2, "precio": 50000, "iva_pct": 19 }
    ]
  }'
<?php
$datos = [
    'adquiriente' => [
        'tipo_persona'           => '2',
        'tipo_documento'         => '13',
        'numero_documento'       => '71234567',
        'razon_social'           => 'JUAN PEREZ',
        'responsabilidad_fiscal' => 'R-99-PN',
    ],
    'lineas' => [
        [
            'codigo'      => 'P1',
            'descripcion' => 'Producto 1',
            'cantidad'    => 2,
            'precio'      => 50000,
            'iva_pct'     => 19,
        ],
    ],
];

$ch = curl_init('https://facepro.cdpconsultores.com/api/v1/documentos');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($datos));
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'Authorization: Bearer YOUR_TOKEN',
    'Content-Type: application/json',
    'Accept: application/json',
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
$status   = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

$result = json_decode($response, true);
if ($status === 201) {
    echo "CUFE: " . $result['data']['cufe'] . "\n";
    echo "Estado: " . $result['data']['estado'] . "\n";
} else {
    echo "Error: " . $result['error'] . "\n";
}
Imports System.Net.Http
Imports System.Net.Http.Headers
Imports System.Text
Imports Newtonsoft.Json
Imports Newtonsoft.Json.Linq

Dim datos = New With {
    .adquiriente = New With {
        .tipo_persona = "2",
        .tipo_documento = "13",
        .numero_documento = "71234567",
        .razon_social = "JUAN PEREZ",
        .responsabilidad_fiscal = "R-99-PN"
    },
    .lineas = {
        New With {
            .codigo = "P1",
            .descripcion = "Producto 1",
            .cantidad = 2,
            .precio = 50000,
            .iva_pct = 19
        }
    }
}

Dim json = JsonConvert.SerializeObject(datos)
Dim contenido As New StringContent(json, Encoding.UTF8, "application/json")

Dim cliente As New HttpClient()
cliente.DefaultRequestHeaders.Authorization =
    New AuthenticationHeaderValue("Bearer", "YOUR_TOKEN")

Dim respuesta = Await cliente.PostAsync("https://facepro.cdpconsultores.com/api/v1/documentos", contenido)
Dim cuerpo = Await respuesta.Content.ReadAsStringAsync()
Dim resultado = JObject.Parse(cuerpo)

If respuesta.IsSuccessStatusCode Then
    Console.WriteLine("CUFE: " & resultado("data")("cufe").ToString())
    Console.WriteLine("Estado: " & resultado("data")("estado").ToString())
Else
    Console.WriteLine("Error: " & resultado("error").ToString())
End If
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Text.Json;

var datos = new {
    adquiriente = new {
        tipo_persona = "2",
        tipo_documento = "13",
        numero_documento = "71234567",
        razon_social = "JUAN PEREZ",
        responsabilidad_fiscal = "R-99-PN"
    },
    lineas = new[] {
        new {
            codigo = "P1",
            descripcion = "Producto 1",
            cantidad = 2,
            precio = 50000,
            iva_pct = 19
        }
    }
};

var json = JsonSerializer.Serialize(datos);
var content = new StringContent(json, Encoding.UTF8, "application/json");

using var client = new HttpClient();
client.DefaultRequestHeaders.Authorization =
    new AuthenticationHeaderValue("Bearer", "YOUR_TOKEN");

var response = await client.PostAsync("https://facepro.cdpconsultores.com/api/v1/documentos", content);
var body = await response.Content.ReadAsStringAsync();
var result = JsonDocument.Parse(body).RootElement;

if (response.IsSuccessStatusCode) {
    Console.WriteLine("CUFE: " + result.GetProperty("data").GetProperty("cufe"));
    Console.WriteLine("Estado: " + result.GetProperty("data").GetProperty("estado"));
} else {
    Console.WriteLine("Error: " + result.GetProperty("error"));
}
const datos = {
  adquiriente: {
    tipo_persona: '2',
    tipo_documento: '13',
    numero_documento: '71234567',
    razon_social: 'JUAN PEREZ',
    responsabilidad_fiscal: 'R-99-PN'
  },
  lineas: [
    { codigo: 'P1', descripcion: 'Producto 1',
      cantidad: 2, precio: 50000, iva_pct: 19 }
  ]
};

const response = await fetch('https://facepro.cdpconsultores.com/api/v1/documentos', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_TOKEN',
    'Content-Type': 'application/json',
    'Accept': 'application/json'
  },
  body: JSON.stringify(datos)
});

const result = await response.json();
if (response.ok) {
  console.log('CUFE:', result.data.cufe);
  console.log('Estado:', result.data.estado);
} else {
  console.error('Error:', result.error);
}
GET /documentos requiere Bearer Token

Listar documentos

Lista paginada de documentos del tenant.

Query params

ParámetroTipoDescripción
estadostringFiltrar por estado: aceptado, rechazado, pendiente, fallido
desdedateFecha emisión >= (YYYY-MM-DD)
hastadateFecha emisión <= (YYYY-MM-DD)
per_pageintItems por página (default 20, max 100)
pageintNúmero de página
curl -H "Authorization: Bearer YOUR_TOKEN" \
  "https://facepro.cdpconsultores.com/api/v1/documentos?estado=aceptado&desde=2026-05-01&per_page=50"
<?php
$query = http_build_query([
    'estado'   => 'aceptado',
    'desde'    => '2026-05-01',
    'per_page' => 50,
]);

$ch = curl_init('https://facepro.cdpconsultores.com/api/v1/documentos?' . $query);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'Authorization: Bearer YOUR_TOKEN',
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);

$data = json_decode($response, true);
foreach ($data['data'] as $doc) {
    echo $doc['numero_completo'] . ' - ' . $doc['estado'] . PHP_EOL;
}
Dim cliente As New HttpClient()
cliente.DefaultRequestHeaders.Authorization =
    New AuthenticationHeaderValue("Bearer", "YOUR_TOKEN")

Dim url = "https://facepro.cdpconsultores.com/api/v1/documentos?estado=aceptado&desde=2026-05-01&per_page=50"
Dim respuesta = Await cliente.GetAsync(url)
Dim cuerpo = Await respuesta.Content.ReadAsStringAsync()
Dim json = JObject.Parse(cuerpo)

For Each doc In json("data")
    Console.WriteLine(doc("numero_completo") & " - " & doc("estado"))
Next
using var client = new HttpClient();
client.DefaultRequestHeaders.Authorization =
    new AuthenticationHeaderValue("Bearer", "YOUR_TOKEN");

var url = "https://facepro.cdpconsultores.com/api/v1/documentos?estado=aceptado&desde=2026-05-01&per_page=50";
var response = await client.GetAsync(url);
var body = await response.Content.ReadAsStringAsync();
var data = JsonDocument.Parse(body).RootElement;

foreach (var doc in data.GetProperty("data").EnumerateArray())
{
    Console.WriteLine(doc.GetProperty("numero_completo") + " - " + doc.GetProperty("estado"));
}
const params = new URLSearchParams({
  estado: 'aceptado',
  desde: '2026-05-01',
  per_page: 50
});

const response = await fetch(`https://facepro.cdpconsultores.com/api/v1/documentos?${params}`, {
  headers: { 'Authorization': 'Bearer YOUR_TOKEN' }
});
const data = await response.json();

data.data.forEach(doc => {
  console.log(`${doc.numero_completo} - ${doc.estado}`);
});
GET /documentos/{uuid} requiere Bearer Token

Detalle de documento

Devuelve un documento por su tracking_id (UUID). El formato de respuesta es idéntico al campo data de POST /documentos.

curl -H "Authorization: Bearer YOUR_TOKEN" \
  https://facepro.cdpconsultores.com/api/v1/documentos/550e8400-e29b-41d4-a716-446655440000
<?php
$trackingId = '550e8400-e29b-41d4-a716-446655440000';

$ch = curl_init("https://facepro.cdpconsultores.com/api/v1/documentos/{$trackingId}");
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Authorization: Bearer YOUR_TOKEN']);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);

$doc = json_decode($response, true);
echo "Estado: " . $doc['estado'];
Dim trackingId = "550e8400-e29b-41d4-a716-446655440000"
Dim cliente As New HttpClient()
cliente.DefaultRequestHeaders.Authorization =
    New AuthenticationHeaderValue("Bearer", "YOUR_TOKEN")

Dim respuesta = Await cliente.GetAsync("https://facepro.cdpconsultores.com/api/v1/documentos/" & trackingId)
Dim cuerpo = Await respuesta.Content.ReadAsStringAsync()
Dim doc = JObject.Parse(cuerpo)

Console.WriteLine("Estado: " & doc("estado"))
var trackingId = "550e8400-e29b-41d4-a716-446655440000";
using var client = new HttpClient();
client.DefaultRequestHeaders.Authorization =
    new AuthenticationHeaderValue("Bearer", "YOUR_TOKEN");

var response = await client.GetAsync($"https://facepro.cdpconsultores.com/api/v1/documentos/{trackingId}");
var body = await response.Content.ReadAsStringAsync();
var doc = JsonDocument.Parse(body).RootElement;

Console.WriteLine("Estado: " + doc.GetProperty("estado"));
const trackingId = '550e8400-e29b-41d4-a716-446655440000';

const response = await fetch(`https://facepro.cdpconsultores.com/api/v1/documentos/${trackingId}`, {
  headers: { 'Authorization': 'Bearer YOUR_TOKEN' }
});
const doc = await response.json();
console.log('Estado:', doc.estado);
GET /documentos/{uuid}/consultar requiere Bearer Token

Consultar estado en DIAN (GetStatusZip)

Llama el método GetStatusZip del WS DIAN con el zip_key guardado y devuelve el estado actual del documento según la DIAN. Útil cuando el envío inicial quedó pendiente o hubo un timeout.

Respuesta 200

{
  "ok": true,
  "documento": { /* DocumentoResource actualizado */ },
  "dian": {
    "is_valid": true,
    "status_code": "00",
    "status_description": "Procesado correctamente",
    "errors": []
  }
}
curl -H "Authorization: Bearer YOUR_TOKEN" \
  https://facepro.cdpconsultores.com/api/v1/documentos/550e8400-.../consultar
<?php
$ch = curl_init("https://facepro.cdpconsultores.com/api/v1/documentos/{$trackingId}/consultar");
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Authorization: Bearer YOUR_TOKEN']);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);

$res = json_decode($response, true);
echo $res['dian']['status_description'];
Dim respuesta = Await cliente.GetAsync("https://facepro.cdpconsultores.com/api/v1/documentos/" & trackingId & "/consultar")
Dim cuerpo = Await respuesta.Content.ReadAsStringAsync()
Dim json = JObject.Parse(cuerpo)
Console.WriteLine(json("dian")("status_description"))
var response = await client.GetAsync($"https://facepro.cdpconsultores.com/api/v1/documentos/{trackingId}/consultar");
var body = await response.Content.ReadAsStringAsync();
var res = JsonDocument.Parse(body).RootElement;
Console.WriteLine(res.GetProperty("dian").GetProperty("status_description"));
const response = await fetch(`https://facepro.cdpconsultores.com/api/v1/documentos/${trackingId}/consultar`, {
  headers: { 'Authorization': 'Bearer YOUR_TOKEN' }
});
const res = await response.json();
console.log(res.dian.status_description);
GET /documentos/{uuid}/xml requiere Bearer Token

Descargar XML firmado

Descarga el XML UBL 2.1 ya firmado con XAdES BES (incluye el CUFE, la firma digital, la cadena de certificados y los QR del Anexo Técnico). Devuelve application/xml en el body.

curl -H "Authorization: Bearer YOUR_TOKEN" \
  https://facepro.cdpconsultores.com/api/v1/documentos/550e8400-.../xml \
  -o factura.xml
<?php
$ch = curl_init("https://facepro.cdpconsultores.com/api/v1/documentos/{$trackingId}/xml");
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Authorization: Bearer YOUR_TOKEN']);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$xml = curl_exec($ch);
curl_close($ch);

file_put_contents('factura.xml', $xml);
Dim respuesta = Await cliente.GetAsync("https://facepro.cdpconsultores.com/api/v1/documentos/" & trackingId & "/xml")
Dim xml = Await respuesta.Content.ReadAsStringAsync()
File.WriteAllText("factura.xml", xml)
var response = await client.GetAsync($"https://facepro.cdpconsultores.com/api/v1/documentos/{trackingId}/xml");
var xml = await response.Content.ReadAsStringAsync();
File.WriteAllText("factura.xml", xml);
const response = await fetch(`https://facepro.cdpconsultores.com/api/v1/documentos/${trackingId}/xml`, {
  headers: { 'Authorization': 'Bearer YOUR_TOKEN' }
});
const xml = await response.text();
// xml contiene el UBL firmado
POST /notas-credito crea NC · permite_notas_credito

Emitir nota crédito

Igual a POST /documentos pero con dos campos extra obligatorios: factura_referencia (la factura que se acredita) y motivo.

Campos adicionales

CampoRequeridoDescripción
factura_referencia.numeroNúmero completo de la factura original (ej: SETP990000011)
factura_referencia.cufeCUFE de 96 caracteres hex de la factura original
factura_referencia.fechaFecha emisión de la factura original (YYYY-MM-DD)
motivo.codigo1, 2, 3, 4, 5 o 6 (ver tabla)
motivo.descripcionTexto libre describiendo el motivo

Ejemplo de request

{
  "factura_referencia": {
    "numero": "SETP990000011",
    "cufe":   "a1b2c3d4...96 hex chars...",
    "fecha":  "2026-05-10"
  },
  "motivo": {
    "codigo":      "2",
    "descripcion": "Anulación por error en valor unitario"
  },
  "adquiriente": { /* mismo cliente que la factura original */ },
  "lineas": [ /* lo que se acredita */ ]
}
curl -X POST https://facepro.cdpconsultores.com/api/v1/notas-credito \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "factura_referencia": {
      "numero": "SETP990000011",
      "cufe":   "a1b2c3...",
      "fecha":  "2026-05-10"
    },
    "motivo": { "codigo": "2", "descripcion": "Anulación" },
    "adquiriente": { ... },
    "lineas": [ ... ]
  }'
<?php
$datos = [
    'factura_referencia' => [
        'numero' => 'SETP990000011',
        'cufe'   => 'a1b2c3d4...',
        'fecha'  => '2026-05-10',
    ],
    'motivo' => [
        'codigo'      => '2',
        'descripcion' => 'Anulación por error en valor unitario',
    ],
    'adquiriente' => [ /* ... */ ],
    'lineas'      => [ /* ... */ ],
];

$ch = curl_init('https://facepro.cdpconsultores.com/api/v1/notas-credito');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($datos));
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'Authorization: Bearer YOUR_TOKEN',
    'Content-Type: application/json',
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
Dim datos = New With {
    .factura_referencia = New With {
        .numero = "SETP990000011",
        .cufe   = "a1b2c3d4...",
        .fecha  = "2026-05-10"
    },
    .motivo = New With { .codigo = "2", .descripcion = "Anulación" },
    .adquiriente = New With { },
    .lineas = { }
}

Dim json = JsonConvert.SerializeObject(datos)
Dim contenido As New StringContent(json, Encoding.UTF8, "application/json")
Dim respuesta = Await cliente.PostAsync("https://facepro.cdpconsultores.com/api/v1/notas-credito", contenido)
var datos = new {
    factura_referencia = new {
        numero = "SETP990000011",
        cufe   = "a1b2c3d4...",
        fecha  = "2026-05-10"
    },
    motivo = new { codigo = "2", descripcion = "Anulación" },
    adquiriente = new { /* ... */ },
    lineas = new[] { /* ... */ }
};

var json = JsonSerializer.Serialize(datos);
var content = new StringContent(json, Encoding.UTF8, "application/json");
var response = await client.PostAsync("https://facepro.cdpconsultores.com/api/v1/notas-credito", content);
const datos = {
  factura_referencia: {
    numero: 'SETP990000011',
    cufe:   'a1b2c3d4...',
    fecha:  '2026-05-10'
  },
  motivo: { codigo: '2', descripcion: 'Anulación' },
  adquiriente: { /* ... */ },
  lineas: [ /* ... */ ]
};

const response = await fetch('https://facepro.cdpconsultores.com/api/v1/notas-credito', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_TOKEN',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify(datos)
});
const result = await response.json();
POST /notas-debito crea ND · permite_notas_debito

Emitir nota débito

Estructura idéntica a la nota crédito pero con motivos distintos (1=Intereses, 2=Gastos por cobrar, 3=Cambio del valor, 4=Otros).

{
  "factura_referencia": {
    "numero": "SETP990000011",
    "cufe":   "a1b2c3d4...",
    "fecha":  "2026-05-10"
  },
  "motivo": {
    "codigo":      "1",
    "descripcion": "Intereses por mora"
  },
  "adquiriente": { ... },
  "lineas": [ ... ]
}
curl -X POST https://facepro.cdpconsultores.com/api/v1/notas-debito \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "factura_referencia": { "numero": "SETP990000011", "cufe": "...", "fecha": "2026-05-10" },
    "motivo": { "codigo": "1", "descripcion": "Intereses por mora" },
    "adquiriente": { ... },
    "lineas": [ ... ]
  }'
<?php
$datos = [
    'factura_referencia' => [ 'numero'=>'SETP990000011', 'cufe'=>'...', 'fecha'=>'2026-05-10' ],
    'motivo'             => [ 'codigo'=>'1', 'descripcion'=>'Intereses por mora' ],
    'adquiriente'        => [ /* ... */ ],
    'lineas'             => [ /* ... */ ],
];

$ch = curl_init('https://facepro.cdpconsultores.com/api/v1/notas-debito');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($datos));
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'Authorization: Bearer YOUR_TOKEN',
    'Content-Type: application/json',
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
Dim datos = New With {
    .factura_referencia = New With { .numero = "SETP990000011", .cufe = "...", .fecha = "2026-05-10" },
    .motivo = New With { .codigo = "1", .descripcion = "Intereses por mora" },
    .adquiriente = New With { },
    .lineas = { }
}

Dim json = JsonConvert.SerializeObject(datos)
Dim contenido As New StringContent(json, Encoding.UTF8, "application/json")
Dim respuesta = Await cliente.PostAsync("https://facepro.cdpconsultores.com/api/v1/notas-debito", contenido)
var datos = new {
    factura_referencia = new { numero = "SETP990000011", cufe = "...", fecha = "2026-05-10" },
    motivo = new { codigo = "1", descripcion = "Intereses por mora" },
    adquiriente = new { /* ... */ },
    lineas = new[] { /* ... */ }
};

var json = JsonSerializer.Serialize(datos);
var content = new StringContent(json, Encoding.UTF8, "application/json");
var response = await client.PostAsync("https://facepro.cdpconsultores.com/api/v1/notas-debito", content);
const datos = {
  factura_referencia: { numero: 'SETP990000011', cufe: '...', fecha: '2026-05-10' },
  motivo: { codigo: '1', descripcion: 'Intereses por mora' },
  adquiriente: { /* ... */ },
  lineas: [ /* ... */ ]
};

const response = await fetch('https://facepro.cdpconsultores.com/api/v1/notas-debito', {
  method: 'POST',
  headers: { 'Authorization': 'Bearer YOUR_TOKEN', 'Content-Type': 'application/json' },
  body: JSON.stringify(datos)
});
const result = await response.json();
POST /eventos acuse · aceptación · reclamo

Emitir evento DIAN sobre una factura recibida

Permite emitir los 4 eventos DIAN (Anexo Técnico sección 8.5) sobre facturas que tu empresa recibió de un proveedor. Genera el ApplicationResponse XML, lo firma con XAdES BES, calcula el CUDE y lo envía a DIAN vía SendEventUpdateStatus (sincrónico).

Códigos de evento

CódigoEventoPara qué sirve
030Acuse de reciboConfirmas que recibiste la factura. Inicia conteo de 3 días para aceptación tácita.
032Recibo del bien o servicioConfirmas que recibiste el bien o servicio facturado.
033Aceptación expresaAceptas formalmente la factura. La factura se convierte en título valor negociable.
031ReclamoRechazas la factura. Requiere concepto_reclamo.

Cuerpo del request

CampoTipoRequeridoDescripción
codigo_eventostring030, 031, 032 o 033
concepto_reclamostringsi 03101=Inconsistencias, 02=Mercancía no entregada totalmente, 03=No entregada, 04=Servicio no prestado
factura.numerostringNúmero completo de la factura recibida (ej. FV-12345)
factura.cufestringCUFE de la factura, 96 caracteres hex
factura.fecha_emisiondateFecha de emisión YYYY-MM-DD
factura.tipo_doc_codestringno01=Factura (default), 91=NC, 92=ND
factura.emisor_nitstringNIT del proveedor (sin guiones)
factura.emisor_dvstringnoDV del NIT proveedor
factura.emisor_razon_socialstringRazón social del proveedor
persona.idstringrecomendadoCédula del firmante (DIAN exige)
persona.nombrestringrecomendadoNombres del firmante
persona.apellidostringrecomendadoApellidos del firmante
persona.cargostringnoCargo (ej. "Administrador")
persona.areastringnoÁrea (ej. "Compras")

Ejemplo de request (030 Acuse de recibo)

{
  "codigo_evento": "030",
  "factura": {
    "numero": "FV-12345",
    "cufe": "8736be4825ce83da9327df...96 chars...",
    "fecha_emision": "2026-05-10",
    "tipo_doc_code": "01",
    "emisor_nit": "800123456",
    "emisor_dv": "1",
    "emisor_razon_social": "Llantas y Repuestos SA"
  },
  "persona": {
    "id": "71234567",
    "nombre": "Luis Alberto",
    "apellido": "Perez Gomez",
    "cargo": "Administrador",
    "area": "Compras"
  }
}

Respuesta 201 Created

{
  "ok": true,
  "data": {
    "uuid": "...",
    "codigo_evento": "030",
    "descripcion": "Acuse de Recibo de la Factura Electronica",
    "cude": "...96 chars hex...",
    "estado": "aceptado",
    "estado_dian_codigo": "00",
    "estado_dian_mensaje": "Procesado correctamente"
  }
}
Regla LGC62: Los eventos 033 (Aceptación expresa) y 034 (Tácita) solo se pueden emitir sobre facturas a crédito (forma_pago=2). DIAN rechaza con regla LGC62 si la factura es de contado.
GET /eventos

Listar eventos del tenant

Devuelve los eventos que tu empresa ha emitido o recibido, paginados de 20 en 20.

Query params (filtros)

ParamValores
direccionemitido | recibido
codigo_evento030 | 031 | 032 | 033
cufeCUFE específico
estadoaceptado | rechazado | enviado | fallido

También disponible GET /eventos/{uuid} para ver el detalle de un evento específico.

Códigos de error

HTTPSignificadoAcción recomendada
200OKOperación exitosa (GET).
201CreatedDocumento creado (POST).
401UnauthenticatedToken inválido o ausente. Verifica el header Authorization.
403Forbidden / permiso no concedidoTu empresa no tiene habilitado este endpoint. Contacta a CDP.
404Not foundEl tracking_id no existe (o no pertenece a tu empresa).
422Datos inválidosRevisa el campo errors de la respuesta.
429Quota excedidaLlegaste al límite mensual/anual. Espera al próximo periodo o pide ampliación.
500Error internoEl cuerpo trae el detalle. Si persiste, reintenta más tarde.

Ejemplo: 422 Validación

{
  "ok": false,
  "error": "Datos invalidos",
  "errors": {
    "adquiriente.numero_documento": ["El número de documento es requerido."],
    "lineas.0.iva_pct": ["El IVA % debe ser un número entre 0 y 100."]
  }
}

Ejemplo: 429 Quota

{
  "ok": false,
  "error": "Cuota excedida para el periodo.",
  "codigo": "quota_excedida",
  "consumidos": 100,
  "limite": 100,
  "periodo": "mensual"
}

Ejemplo: 403 Permiso

{
  "ok": false,
  "error": "Tu empresa no tiene permitido emitir este tipo de documento.",
  "codigo": "permiso_no_concedido",
  "permiso": "permite_notas_credito"
}

Mejores prácticas

  • Guarda siempre el tracking_id y el cufe en tu sistema. Son tus identificadores estables; el numero_completo sirve para reportes humanos pero el cufe es lo que te exigirán para una nota crédito o auditoría.
  • Revisa estado en la respuesta. Solo aceptado significa que la DIAN validó la factura. Cualquier otro valor (rechazado, fallido, pendiente) requiere atención: lee estado_dian_mensaje y ultimo_error.
  • Usa /consultar para reintentar cuando el estado quedó pendiente por timeout. Llamarlo no genera un nuevo envío, solo re-pregunta a la DIAN por el zip_key original.
  • Implementa idempotencia en tu lado: antes de POST, verifica si ya enviaste esa venta. La DIAN rechaza duplicados (mismo prefijo + consecutivo).
  • Maneja el 429 con un retry-after. Si llegas a la cuota, frena los envíos automáticos y avisa al usuario humano para que pida ampliación.
  • Logs locales: guarda el JSON enviado y la respuesta completa al menos 90 días. Te servirá para soporte si hay un problema con la DIAN.
  • Pruebas: usa el ambiente habilitacion (configurado en el portal) hasta que tu integración sea estable. Cuando pases a produccion, los documentos van a tener efecto fiscal real.

¿Necesitas ayuda?

Escríbenos a soporte@cdpconsultores.com con el tracking_id y el JSON que enviaste. CDP Consultores · Rionegro, Antioquia, Colombia.