Manual técnico completo
Guía maestra de integración externa REST/JSON para FE y DSE, versión 1.0.0.
Quantum Nube API - Facturación Electrónica y Documento Soporte Electrónico#
Guía maestra de integración externa REST/JSON
Versión: 1.0.0
Fecha de referencia: 07 de octubre de 2026
Base URL de producción: https://nomina.quantumpos.com.co/api/ext/v1
Autenticación: Bearer Token
Formato: JSON UTF-8
Este documento describe la API externa v1 de Quantum Nube para Facturación Electrónica (FE) y Documento Soporte Electrónico (DSE). Está diseñado para equipos de desarrollo, integradores ERP/POS/e-commerce y para publicar la documentación dentro del portal web de Quantum. Los ejemplos usan datos ficticios. Nunca publique tokens reales, contraseñas, certificados, claves técnicas ni credenciales DIAN.
1. Cómo se documenta profesionalmente una API#
Una documentación profesional no debería vivir únicamente en Postman ni únicamente en una página escrita a mano. La recomendación para Quantum Nube es usar cuatro capas complementarias, con una sola fuente técnica de verdad:
| Capa | Propósito | Entregable recomendado |
|---|---|---|
| Contrato de API | Define rutas, métodos, seguridad, parámetros, esquemas y respuestas | openapi/quantum-api-v1.yaml |
| Portal humano | Explica conceptos, flujos, reglas fiscales, ejemplos y errores | Sección /developers/api en la web |
| Cliente de pruebas | Permite probar peticiones sin construir código desde cero | Colección y environment de Postman |
| Ejemplos y guías | Aceleran la integración en distintos lenguajes y sistemas | cURL, JavaScript, Python, PHP y JSON |
La recomendación es que OpenAPI 3.1 sea la fuente contractual, que el sitio web la renderice con un visor como Scalar, Redoc o Swagger UI, y que alrededor de esa referencia se publiquen guías manuales más explicativas. Postman debe mantenerse como complemento de pruebas y onboarding, no como única documentación.
1.1 Estructura recomendada del portal de desarrolladores#
La web debería exponer una sección similar a:
/developers
/developers/api
/developers/api/quickstart
/developers/api/authentication
/developers/api/fe
/developers/api/dse
/developers/api/errors
/developers/api/idempotency
/developers/api/reference
/developers/api/changelog
/developers/downloads/openapi.yaml
/developers/downloads/postman-collection.json
La navegación ideal tiene un menú lateral fijo en escritorio, buscador, contenido central, tabla de contenidos a la derecha y pestañas de código cURL / JavaScript / Python / PHP. En móvil, el menú lateral debe convertirse en drawer y el código debe permitir desplazamiento horizontal sin romper el layout.
1.2 Qué NO debe hacer la página pública#
La documentación pública nunca debe guardar un Bearer Token real en HTML, JavaScript, variables públicas de build, localStorage, repositorios o ejemplos. Si se ofrece una función de Try it, debe estar detrás de un portal autenticado y, preferiblemente, ejecutarse mediante un backend/proxy de Quantum. Un token de integración de larga duración no debe viajar a un navegador público.
2. Resumen de la API externa v1#
Todas las rutas descritas en este manual cuelgan de:
https://nomina.quantumpos.com.co/api/ext/v1
El identificador de empresa forma parte de la URL:
/companies/{company_id}/...
Cada token queda asociado a una empresa. Quantum valida que el company_id de la ruta corresponda a la empresa del token; intentar acceder a otra empresa produce una respuesta 403.
2.1 Endpoints FE y DSE disponibles#
| Método | Ruta | Scope | Uso |
|---|---|---|---|
| GET | /companies/{company_id}/fe/docs |
fe.read |
Lista documentos FE de producción |
| GET | /companies/{company_id}/fe/docs/{doc_id} |
fe.read |
Obtiene detalle de un documento FE |
| GET | /companies/{company_id}/fe/terceros |
fe.read |
Lista terceros/receptores registrados |
| GET | /companies/{company_id}/fe/payment-methods |
fe.read |
Consulta métodos de pago configurados para la empresa |
| POST | /companies/{company_id}/dian/get-acquirer |
fe.read |
Consulta datos de adquirente mediante el flujo DIAN soportado |
| POST | /companies/{company_id}/fe/facturas |
fe.write |
Crea, firma y procesa/envía una FE |
| POST | /companies/{company_id}/dse/documentos |
dse.write |
Crea, firma y transmite un DSE con idempotencia obligatoria |
| GET | /companies/{company_id}/dse/documentos/{doc_id} |
dse.read |
Consulta el estado y detalle de un DSE |
Este paquete se concentra deliberadamente en FE y DSE. La API externa también puede contener otros módulos/versiones, pero no forman parte del contrato documentado aquí.
3. Autenticación Bearer y aislamiento multiempresa#
3.1 Header obligatorio#
Authorization: Bearer YOUR_API_TOKEN
Accept: application/json
Content-Type: application/json
Para solicitudes GET sin body, Content-Type puede omitirse. El token debe almacenarse en un gestor de secretos o variable de entorno del servidor consumidor.
3.2 Scopes#
Los permisos se asignan al cliente API y los tokens de ese cliente heredan sus scopes. Los scopes relevantes son:
| Scope | Permite |
|---|---|
fe.read |
Consultar FE, terceros, métodos de pago y GetAcquirer |
fe.write |
Crear/procesar facturas electrónicas |
dse.read |
Consultar DSE por ID |
dse.write |
Crear, firmar y transmitir DSE |
Un token válido sin el scope necesario recibe 403.
3.3 Respuestas típicas de seguridad#
Sin token o token inválido:
{
"ok": false,
"error": "Authorization Bearer faltante o inválido."
}
Token de otra empresa:
{
"ok": false,
"error": "El token no tiene acceso a la empresa solicitada."
}
Scope insuficiente:
{
"ok": false,
"error": "Scopes insuficientes. Faltan: dse.write"
}
3.4 Reglas operativas de seguridad#
- Trate el token como una contraseña de máquina a máquina.
- No lo incluya en capturas, tickets, logs compartidos ni documentación pública.
- No use un token de producción desde JavaScript del navegador.
- Separe clientes API cuando existan terceros o integraciones con responsabilidades diferentes.
- Rote/revoque credenciales cuando cambie el proveedor o exista sospecha de exposición.
- Mantenga
company_idconfigurable; no mezcle IDs entre clientes. - Aplique timeout, registro de respuesta y control de reintentos del lado integrador.
4. Convenciones generales#
4.1 JSON#
Las peticiones con body usan:
Content-Type: application/json
Use JSON válido, números sin separadores de miles y fechas en ISO YYYY-MM-DD salvo que un campo indique otro formato.
4.2 Dinero y redondeo#
Enviar valores monetarios como números JSON. Para conciliación, el sistema consumidor debe usar aritmética decimal, no float binario, y redondear a dos decimales cuando corresponda.
4.3 HTTP#
| Código | Interpretación recomendada |
|---|---|
| 200 | Consulta o operación exitosa; también puede representar replay idempotente |
| 201 | Documento nuevo creado/procesado exitosamente |
| 202 | Solicitud idempotente ya reservada y aún no terminal |
| 400 | Payload inválido/regla de negocio incumplida |
| 401 | Bearer ausente, inválido, expirado o revocado |
| 403 | Empresa incorrecta o scope insuficiente |
| 404 | Recurso no encontrado dentro de la empresa |
| 409 | Conflicto de idempotencia DSE: misma llave con payload diferente |
| 422 | DSE procesado pero clasificado como rechazado |
| 500 | Error interno inesperado |
| 502 | Resultado de transporte/DIAN incierto; revisar pending antes de reintentar |
4.4 Regla de reintentos#
Nunca asuma que un timeout equivale a “el documento no llegó”. Una conexión puede cortarse después de que Quantum haya recibido o transmitido el documento. FE y DSE tienen mecanismos de trazabilidad diferentes y deben respetarse:
- FE: conservar y reutilizar el mismo
draft_keypara la operación original. - DSE: conservar y reutilizar el mismo header
Idempotency-Keyy el mismo payload. - En DSE, si la respuesta indica
pending: true, no cree una segunda operación con una llave nueva.
5. Quickstart - validar conectividad sin emitir un documento#
5.1 Probar autenticación con métodos de pago FE#
curl -sS \
-H "Authorization: Bearer $QUANTUM_API_TOKEN" \
-H "Accept: application/json" \
"https://nomina.quantumpos.com.co/api/ext/v1/companies/$COMPANY_ID/fe/payment-methods"
Esta petición permite comprobar token, empresa y fe.read sin crear un documento fiscal.
5.2 Variables mínimas recomendadas#
QUANTUM_API_BASE=https://nomina.quantumpos.com.co/api/ext/v1
QUANTUM_COMPANY_ID=<ID_EMPRESA>
QUANTUM_API_TOKEN=<SECRETO>
PARTE I - FACTURACIÓN ELECTRÓNICA (FE)#
6. Flujo FE de extremo a extremo#
La ruta de creación FE reutiliza el flujo operativo probado de Quantum Nube: recibe la venta, crea la factura, genera XML, firma y ejecuta el procesamiento/envío DIAN según la configuración de la empresa.
Flujo recomendado del integrador:
Venta confirmada en ERP/POS
|
v
Consultar/mantener mapeos de pago
|
v
Construir payload FE + draft_key
|
v
POST /fe/facturas
|
+---- 2xx ---> persistir factura_id / CUFE / estado
|
+---- timeout/error incierto ---> NO generar otra venta; conservar draft_key
|
v
GET /fe/docs/{doc_id} para detalle/seguimiento cuando se disponga del ID
7. Crear Factura Electrónica#
7.1 Endpoint#
POST /api/ext/v1/companies/{company_id}/fe/facturas
Authorization: Bearer <token con fe.write>
Content-Type: application/json
7.2 Campos de primer nivel#
| Campo | Tipo | Recomendación | Descripción |
|---|---|---|---|
receptor |
object | Requerido para integración | Datos del adquirente |
items |
array | Requerido | Líneas comerciales |
subtotal |
number | Recomendado | Base total antes de impuestos |
impuestos |
number | Recomendado | Total de impuestos |
total |
number | Recomendado | Total bruto del documento |
es_contingencia |
boolean | Opcional, default normal | false normal; true cuando aplique contingencia |
fecha_emision |
string/date | Recomendado | Fecha YYYY-MM-DD |
payment |
object | Recomendado | Forma y medio de pago |
aiu |
object | Opcional | AIU cuando aplique |
withholdings |
array | Opcional | Retenciones configuradas |
currency |
object | Opcional | Moneda comercial/tasa cuando aplique |
observaciones |
string | Opcional | Texto libre, UI actual admite hasta 4000 caracteres |
attachment_tokens |
array | Opcional | Tokens de adjuntos previamente cargados |
draft_key |
string | Muy recomendado | Identificador estable de la operación; máximo operativo actual 80 caracteres |
7.3 Receptor#
Ejemplo mínimo de integración:
{
"receptor": {
"tipo_doc": "13",
"numero_doc": "1000000000",
"nombre": "CLIENTE DE PRUEBA",
"email": "cliente@example.com",
"direccion": "Bogotá D.C."
}
}
| Campo | Tipo | Uso |
|---|---|---|
tipo_doc |
string | Código de tipo de identificación |
numero_doc |
string | Documento/NIT del adquirente |
nombre |
string | Nombre o razón social |
email |
string | Correo del receptor |
direccion |
string | Dirección informada |
No use un tipo de documento únicamente porque aparece en un ejemplo; valide el tipo fiscal real del adquirente.
7.4 Ítems FE#
Forma de payload actualmente utilizada por el flujo FE:
{
"desc": "Servicio de prueba",
"cant": 1,
"unit": 100000,
"iva": 19,
"iva_incluido": true,
"unit_input": 119000
}
| Campo | Tipo | Descripción |
|---|---|---|
desc |
string | Descripción comercial |
cant |
number | Cantidad |
unit |
number | Valor unitario base |
iva |
number | Tarifa tributaria usada por el flujo FE |
iva_incluido |
boolean | Señala si el valor de entrada incluye impuesto |
unit_input |
number | Valor unitario original/de entrada |
codigo_impuesto / tax_code |
string | Campo avanzado para identificar el tributo cuando el flujo lo requiera |
7.5 Regla crítica FE: 8% se trata como INC#
En el flujo FE actual, la tarifa exactamente 8% se clasifica como INC - Impuesto Nacional al Consumo, código DIAN 04. Otros porcentajes positivos sin código explícito se tratan como IVA código 01; 0% no genera impuesto en esta normalización.
Base 100,000
INC 8% 8,000
Total 108,000
Ejemplo:
{
"desc": "Producto sujeto a INC 8%",
"cant": 1,
"unit": 100000,
"iva": 8,
"iva_incluido": true,
"unit_input": 108000
}
[!WARNING] No replique esta regla de FE en DSE. En DSE la semántica de impuestos es distinta y se documenta en su propia sección.
7.6 Totales#
{
"subtotal": 100000,
"impuestos": 19000,
"total": 119000
}
El integrador debe calcular y validar que los totales sean consistentes con las líneas enviadas. No envíe totales de 19% cuando las líneas están marcadas con 8%, ni mezcle bases con valores impuestos incluidos sin normalización previa.
8. Formas y métodos de pago FE#
payment.form, method_id y means_code son conceptos diferentes.
8.1 Forma de pago#
payment.form |
Identificador fiscal resultante | Uso |
|---|---|---|
contado |
1 | Pago de contado |
credito |
2 | Venta a crédito |
Para crédito, informe due_date en YYYY-MM-DD cuando corresponda.
8.2 Descubrir métodos configurados#
GET /api/ext/v1/companies/{company_id}/fe/payment-methods
Scope: fe.read
No hardcodee method_id entre empresas. Es un ID interno de Quantum y pertenece a la configuración de cada compañía. La integración debe consultar el catálogo y construir un mapeo estable en el ERP/POS.
Ejemplo conceptual de registro:
{
"id": 19,
"payment_form": "contado",
"label": "Efectivo",
"payment_means_code": "10",
"payment_means_name": "Efectivo",
"is_active": true,
"is_default": true
}
Los IDs del ejemplo no son portables a otra empresa.
8.3 Códigos observados en una configuración operativa#
means_code |
Medio |
|---|---|
10 |
Efectivo |
42 |
Transferencia / consignación |
48 |
Tarjeta crédito |
49 |
Tarjeta débito |
Estos códigos sirven como referencia; la fuente operativa para cada cliente es GET /fe/payment-methods.
8.4 Pago contado#
{
"payment": {
"form": "contado",
"method_id": 19,
"means_code": "10",
"due_date": ""
}
}
8.5 Pago crédito#
{
"payment": {
"form": "credito",
"method_id": 123,
"means_code": "42",
"due_date": "2026-11-06"
}
}
Use un method_id real devuelto para la empresa; 123 es únicamente ilustrativo.
9. AIU, retenciones, moneda, observaciones y adjuntos FE#
9.1 AIU#
La UI vigente envía la siguiente estructura:
{
"aiu": {
"enabled": false,
"contract_base": 100000,
"administracion_percent": 0,
"imprevistos_percent": 0,
"utilidad_percent": 0,
"tax_rate": 19,
"iva_base_mode": "AIU_TOTAL"
}
}
iva_base_mode puede representar la base total AIU o, cuando corresponda al flujo, la utilidad. Si su integración no usa AIU, envíe enabled: false.
9.2 Retenciones FE#
La estructura de la UI vigente utiliza:
{
"withholdings": [
{
"type": "<tipo-configurado>",
"base_mode": "<base-configurada>",
"percent": 2.5
}
]
}
Los tipos/base válidos dependen de la configuración FE de la empresa. No invente códigos de retención en una integración externa. Si no aplican, envíe [].
9.3 Moneda comercial#
El flujo FE contempla una estructura como:
{
"currency": {
"commercial_currency": "COP",
"applied_rate": null,
"official_trm": null,
"rate_date": "2026-10-07"
}
}
La implementación actual maneja COP y USD en el flujo comercial. Si usa USD, conserve la tasa aplicada y fecha como parte de la trazabilidad del sistema origen.
9.4 Observaciones#
{
"observaciones": "Servicio correspondiente al período octubre de 2026."
}
9.5 Adjuntos#
{
"attachment_tokens": []
}
La API externa v1 documentada aquí no expone un endpoint público para subir adjuntos. Por tanto, un integrador server-to-server debería enviar [] salvo que Quantum haya proporcionado específicamente un mecanismo compatible que genere esos tokens. No intente enviar rutas locales ni archivos base64 dentro de attachment_tokens.
10. draft_key e idempotencia operativa FE#
draft_key identifica el borrador/operación de negocio en el flujo FE y la capa de metadatos mantiene unicidad por empresa para esa llave.
Recomendación:
{
"draft_key": "venta-ERP-2026-00018451"
}
Buenas prácticas:
- Genere una llave estable a partir del ID inmutable de la venta o un UUID.
- Persístala antes de llamar a Quantum.
- Ante timeout, conserve la misma llave y el mismo contexto comercial.
- No genere otra llave solo para “probar otra vez”.
- Persista
factura_id, CUFE, estado y respuesta cuando estén disponibles.
[!IMPORTANT] FE usa
draft_keyen el body. DSE usaIdempotency-Keyen el header. No son el mismo contrato y no deben mezclarse.
11. Ejemplo FE completo - contado IVA 19%#
{
"receptor": {
"tipo_doc": "13",
"numero_doc": "1000000000",
"nombre": "CLIENTE DE PRUEBA",
"email": "cliente@example.com",
"direccion": "Bogotá D.C."
},
"items": [
{
"desc": "Servicio de integración",
"cant": 1,
"unit": 100000,
"iva": 19,
"iva_incluido": true,
"unit_input": 119000
}
],
"subtotal": 100000,
"impuestos": 19000,
"total": 119000,
"es_contingencia": false,
"fecha_emision": "2026-10-07",
"payment": {
"form": "contado",
"method_id": 19,
"means_code": "10",
"due_date": ""
},
"aiu": {
"enabled": false,
"contract_base": 100000,
"administracion_percent": 0,
"imprevistos_percent": 0,
"utilidad_percent": 0,
"tax_rate": 19,
"iva_base_mode": "AIU_TOTAL"
},
"withholdings": [],
"currency": {
"commercial_currency": "COP",
"applied_rate": null,
"official_trm": null,
"rate_date": "2026-10-07"
},
"observaciones": "Ejemplo de integración FE",
"attachment_tokens": [],
"draft_key": "venta-demo-000001"
}
cURL:
curl -X POST \
"https://nomina.quantumpos.com.co/api/ext/v1/companies/COMPANY_ID/fe/facturas" \
-H "Authorization: Bearer API_TOKEN" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d @fe-contado.json
11.1 Respuesta de creación FE#
La ruta externa reutiliza directamente el flujo de creación/procesamiento FE. El consumidor debe interpretar el contrato por HTTP status, ok y campos retornados. El campo factura_id es el identificador de factura utilizado por la UI actual después de crear/procesar.
Ejemplo representativo:
{
"ok": true,
"factura_id": 12345,
"cufe": "<CUFE>",
"estado": "aceptado",
"enviado": true
}
El response puede contener datos adicionales de envío/contabilidad según el resultado. No haga un parser que falle por campos adicionales.
12. Listar y consultar FE#
12.1 Listado#
GET /api/ext/v1/companies/{company_id}/fe/docs
Scope: fe.read
Parámetros de consulta soportados por el listado actual:
| Parámetro | Regla |
|---|---|
page |
Página, mínimo 1 |
per_page |
Tamaño de página; el servidor limita el rango operativo |
tipo |
01 factura, 91 nota crédito |
estado |
aprobado, rechazado, pendiente |
q |
Búsqueda por ID/número/CUFE/tercero/documento |
El listado externo reutiliza el listado FE de producción; no incluye documentos de habilitación.
12.2 Detalle FE por ID#
GET /api/ext/v1/companies/{company_id}/fe/docs/{doc_id}
Scope: fe.read
Respuesta estructural:
{
"ok": true,
"doc": {
"id": 12345,
"company_id": 11,
"tipo_dian": "01",
"prefijo": "FV",
"consecutivo": 123,
"estado_dian": "aceptado",
"cufe": "<CUFE>",
"es_habilitacion": false,
"subtotal": "100000.00",
"impuestos": "19000.00",
"total": "119000.00",
"moneda": "COP",
"fecha_emision": "2026-10-07T10:30:00",
"fecha_vencimiento": null,
"xml_path": "<ruta-interna>",
"track_id": null,
"zip_key": "<clave-si-aplica>",
"tercero": {
"id": 1,
"nombre": "CLIENTE DE PRUEBA",
"tipo_documento": "13",
"numero_documento": "1000000000",
"email": "cliente@example.com"
},
"items": [
{
"id": 1,
"descripcion": "Servicio de integración",
"cantidad": "1.00",
"valor_unitario": "100000.00",
"descuento": "0.00",
"base_imponible": "100000.00",
"impuesto": "19000.00",
"tipo_impuesto": "IVA",
"codigo_impuesto": "01"
}
]
}
}
xml_path es metadato de implementación y no debe tratarse como URL pública de descarga ni persistirse como contrato permanente del consumidor.
13. Terceros FE#
GET /api/ext/v1/companies/{company_id}/fe/terceros
Scope: fe.read
Respuesta:
{
"ok": true,
"terceros": [
{
"id": 1,
"nombre": "CLIENTE DE PRUEBA",
"tipo_documento": "13",
"numero_documento": "1000000000",
"email": "cliente@example.com",
"direccion": "Bogotá D.C."
}
]
}
14. GetAcquirer DIAN#
14.1 Endpoint#
POST /api/ext/v1/companies/{company_id}/dian/get-acquirer
Scope: fe.read
Request recomendado:
{
"identification_type": "31",
"identification_number": "900000000",
"force_refresh": false
}
Se aceptan alias de compatibilidad para identificación (tipo_doc / tipo_documento y numero_doc / numero_documento). Para nuevas integraciones use los nombres en inglés mostrados arriba para mantener un contrato claro.
Si el servicio DIAN/flujo subyacente no produce respuesta satisfactoria, el endpoint puede responder 502.
PARTE II - DOCUMENTO SOPORTE ELECTRÓNICO (DSE)#
15. Objetivo del endpoint DSE externo#
La API DSE externa v1 está diseñada como un flujo create + sign + send en una sola operación lógica, con control de idempotencia obligatorio y una barrera de envío antes de la llamada de red a DIAN.
ERP / sistema cliente
|
| POST + Idempotency-Key
v
Reserva idempotente
|
v
Crear DSE + numeración servidor
|
v
Firmar XML
|
v
Estado sending (fence)
|
v
Transmitir DIAN
|
+--> aceptado / rechazado
|
+--> pendiente / transporte incierto -> NO reenviar ciegamente
16. Crear, firmar y enviar DSE#
16.1 Endpoint y headers#
POST /api/ext/v1/companies/{company_id}/dse/documentos
Authorization: Bearer <token con dse.write>
Idempotency-Key: <llave-estable>
Accept: application/json
Content-Type: application/json
16.2 Idempotency-Key es obligatorio#
La llave:
- Es obligatoria para creación DSE externa.
- Máximo 120 caracteres.
- Se evalúa junto con empresa y cliente API.
- La API calcula un hash canónico del payload.
- Misma llave + mismo payload: devuelve el documento/reserva existente, no crea otro.
- Misma llave + payload diferente:
409.
Ejemplo recomendado:
Idempotency-Key: ERP-CXP-2026-00009182
Aunque existen aliases de compatibilidad request_key y draft_key en el body, las nuevas integraciones deben usar el header estándar Idempotency-Key.
16.3 Campos de primer nivel DSE#
| Campo | Tipo | Regla |
|---|---|---|
fecha_documento |
string | YYYY-MM-DD; por operación debe ser la fecha actual |
fecha |
string | Alias compatible de fecha_documento |
hora |
string | Opcional; se genera hora -05:00 si se omite |
moneda |
string | Default COP |
proveedor |
object | Datos reales del proveedor/no obligado |
items |
array | Obligatorio, mínimo 1 |
forma_generacion |
string | 1 por operación, 2 acumulado semanal |
fecha_inicio_periodo |
string | Requerido en modo 2 |
fecha_fin_periodo |
string | Requerido en modo 2 |
forma_pago |
string | 1 contado, 2 crédito |
medio_pago_codigo |
string | Código numérico 1 a 3 dígitos; default 10 |
fecha_vencimiento |
string | Fecha de pago; en contado se fuerza a emisión |
fecha_vencimiento_contable |
string | Opcional; no puede ser anterior a emisión |
retenciones |
array | Retenciones DSE normalizadas |
withholdings |
array | Alias compatible de retenciones |
tipo_dian |
string | No configurable; si se envía debe ser 05 |
Campos internos cuyo nombre empiece por _ son rechazados por la API externa.
17. Proveedor DSE#
Ejemplo recomendado con información explícita:
{
"proveedor": {
"tipo_documento": "31",
"nit": "900000001",
"dv": "1",
"nombre": "PROVEEDOR DE PRUEBA SAS",
"nombre_comercial": "PROVEEDOR DE PRUEBA",
"regimen": "O-49",
"dian_tax_scheme_code": "ZZ",
"direccion": "Calle 1 # 2-3",
"municipio": "Bogotá",
"codigo_municipio": "11001",
"departamento": "Cundinamarca",
"codigo_departamento": "11",
"pais": "CO",
"email": "proveedor@example.com",
"telefono": "3000000000",
"codigo_postal": "111711"
}
}
| Campo | Observación |
|---|---|
nit |
Identificación principal; numero_documento funciona como alias |
dv |
Dígito de verificación cuando aplique |
nombre |
Nombre/razón social real |
nombre_comercial |
Opcional; si falta se deriva de nombre |
tipo_documento |
Default interno actual 13; envíe el tipo real |
regimen |
Default técnico actual O-49; envíe el dato real cuando corresponda |
dian_tax_scheme_code |
Default técnico ZZ; debe corresponder al proveedor |
direccion |
Dirección real recomendada |
municipio / codigo_municipio |
Nombre y código |
departamento / codigo_departamento |
Nombre y código |
pais |
Default CO |
email |
Correo del proveedor |
telefono |
Teléfono |
codigo_postal |
Código postal |
[!IMPORTANT] El backend tiene algunos defaults de compatibilidad para evitar campos vacíos, pero una integración profesional debe enviar datos fiscales reales, no depender de valores dummy/default.
18. Ítems DSE#
18.1 Estructura recomendada#
{
"items": [
{
"codigo": "81112100",
"descripcion": "Servicio de prueba",
"cantidad": 1,
"unidad_medida": "EA",
"precio_unitario": 100000,
"porcentaje_iva": 19
}
]
}
18.2 Reglas exactas relevantes#
| Campo | Regla |
|---|---|
cantidad |
Debe ser mayor a 0 |
unidad_medida |
Default EA; NIU se normaliza a EA |
precio_unitario |
No negativo |
base_imponible / base |
Si falta precio_unitario, puede derivarse precio a partir de base/cantidad |
codigo |
UNSPSC numérico de exactamente 8 dígitos |
descripcion |
Si falta, el backend tiene fallback, pero debe enviarse una descripción real |
porcentaje_iva |
Tarifa porcentual recomendada en DSE |
impuesto |
Valor monetario absoluto del impuesto |
iva |
Alias histórico tratado como valor monetario, no como porcentaje |
cost_center_id |
Metadato contable opcional; debe pertenecer a la empresa |
cost_center_code / centro_costo_codigo |
Alternativa para resolver centro de costo |
18.3 Diferencia crítica entre FE y DSE respecto a iva#
En FE, el payload operativo usa "iva": 19 como tarifa. En DSE, la lógica actual interpreta iva como valor monetario de impuesto cuando viene informado.
Por eso, para DSE se recomienda:
{
"precio_unitario": 100000,
"porcentaje_iva": 19
}
No:
{
"precio_unitario": 100000,
"iva": 19
}
El segundo ejemplo se interpretaría como 19 unidades monetarias de impuesto, no como 19%.
18.4 Totales DSE se calculan en servidor#
Para cada ítem:
base = cantidad * precio_unitario
impuesto = base * porcentaje_iva / 100 (si se usa porcentaje)
Y para el documento:
subtotal = suma de bases
impuestos = suma de impuestos
total = subtotal + impuestos
neto_pagar = total - total_retenciones
No dependa de enviar subtotal, impuestos o total como autoridad en DSE; el backend los calcula desde las líneas.
19. Forma de generación DSE#
19.1 Por operación - forma_generacion: "1"#
- Es el default.
fecha_documentodebe ser la fecha actual.- El período inicial y final queda igual a la fecha del documento.
{
"fecha_documento": "2026-10-07",
"forma_generacion": "1"
}
19.2 Acumulado semanal - forma_generacion: "2"#
Requiere:
{
"fecha_documento": "2026-10-07",
"forma_generacion": "2",
"fecha_inicio_periodo": "2026-10-01",
"fecha_fin_periodo": "2026-10-07"
}
Reglas:
- Inicio no puede ser posterior al fin.
- Máximo 7 días calendario.
- Fin del período no puede ser posterior a
fecha_documento. period_start_dateyperiod_end_dateson aliases compatibles.
20. Forma y medio de pago DSE#
20.1 Contado#
{
"forma_pago": "1",
"medio_pago_codigo": "10"
}
En contado, la fecha de vencimiento fiscal se iguala a la fecha del documento.
20.2 Crédito#
{
"forma_pago": "2",
"medio_pago_codigo": "42",
"fecha_vencimiento": "2026-11-06"
}
La fecha de vencimiento no puede ser anterior a fecha_documento.
Aliases soportados:
forma_pago <-> payment_type
medio_pago_codigo <-> payment_means_code
fecha_vencimiento <-> payment_due_date
medio_pago_codigo debe ser un código numérico de 1 a 3 dígitos.
21. Retenciones DSE#
21.1 Códigos canónicos soportados#
| Código DIAN | Nombre canónico |
|---|---|
05 |
ReteIVA |
06 |
ReteRenta |
07 |
ReteICA |
21.2 Ejemplo por porcentaje#
{
"retenciones": [
{
"retention_key": "rete_renta",
"dian_tax_code": "06",
"tax_name": "ReteRenta",
"base_mode": "subtotal",
"percent": 2.5
}
]
}
21.3 Campos y aliases#
| Concepto | Campos aceptados |
|---|---|
| Llave | retention_key, type, tipo, tax_name, nombre |
| Código DIAN | dian_tax_code, codigo_dian |
| Nombre | tax_name, nombre, label |
| Modo base | base_mode, modo_base |
| Base explícita | base_amount, base |
| Porcentaje | percent, porcentaje |
| Valor | amount, valor |
| Activación | enabled, activa |
| Orden | display_order |
21.4 Modos de base#
| Valor normalizado | Aliases |
|---|---|
subtotal |
subtotal, base |
impuestos |
impuestos, iva |
total |
total, bruto |
21.5 Validaciones#
retencionesdebe ser lista.- Elementos con
enabled:falseoactiva:falsese omiten. - No se permiten llaves de retención duplicadas.
- Debe existir código DIAN y nombre.
- La base debe ser mayor a cero y no superar el total.
- El porcentaje no puede ser negativo.
- Si se envía
amountypercent, el valor debe coincidir conbase x porcentajedentro de tolerancia monetaria de un centavo. - Si se envía amount sin porcentaje, el porcentaje puede derivarse.
- La suma de retenciones no puede superar el total del documento.
22. Numeración, certificado y secretos DSE#
La API externa no necesita ni debe recibir:
software_id
software_pin
clave_tecnica
resolucion
prefijo asignado manualmente
consecutivo manual
ruta de certificado
password P12
credenciales DIAN
Quantum obtiene numeración, configuración, certificado y datos técnicos desde la configuración segura de la empresa. El consumidor envía datos de negocio, no secretos fiscales internos.
tipo_dian está fijado a 05 por el servicio externo.
23. Ejemplo DSE completo - por operación, contado#
Header:
Idempotency-Key: ERP-CXP-2026-00009182
Body:
{
"fecha_documento": "2026-10-07",
"forma_generacion": "1",
"forma_pago": "1",
"medio_pago_codigo": "10",
"moneda": "COP",
"proveedor": {
"tipo_documento": "31",
"nit": "900000001",
"dv": "1",
"nombre": "PROVEEDOR DE PRUEBA SAS",
"regimen": "O-49",
"dian_tax_scheme_code": "ZZ",
"direccion": "Calle 1 # 2-3",
"municipio": "Bogotá",
"codigo_municipio": "11001",
"departamento": "Cundinamarca",
"codigo_departamento": "11",
"pais": "CO",
"email": "proveedor@example.com"
},
"items": [
{
"codigo": "81112100",
"descripcion": "Servicio de soporte tecnológico",
"cantidad": 1,
"unidad_medida": "EA",
"precio_unitario": 100000,
"porcentaje_iva": 19
}
],
"retenciones": []
}
cURL:
curl -X POST \
"https://nomina.quantumpos.com.co/api/ext/v1/companies/COMPANY_ID/dse/documentos" \
-H "Authorization: Bearer API_TOKEN" \
-H "Idempotency-Key: ERP-CXP-2026-00009182" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d @dse-contado.json
24. Respuestas DSE e idempotencia#
24.1 Documento nuevo procesado#
HTTP 201 cuando el flujo nuevo se procesa sin clasificación rechazado:
{
"ok": true,
"pending": false,
"idempotent": false,
"documento": {
"id": 7423,
"company_id": 30,
"prefijo": "DS",
"consecutivo": 4238,
"document_date": "2026-10-07",
"moneda": "COP",
"subtotal": "100000.00",
"impuestos": "19000.00",
"total": "119000.00",
"total_retenciones": "0.00",
"estado_dian": "aceptado",
"cuds": "<CUDS>"
},
"dian": {
"is_valid": true,
"status_code": "00",
"status_description": "<descripcion>",
"status_message": "<mensaje>"
}
}
24.2 Replay idempotente#
Misma llave + mismo payload, si ya existe documento:
{
"ok": true,
"idempotent": true,
"pending": false,
"documento": {
"id": 7423,
"estado_dian": "aceptado"
}
}
HTTP usual 200 (o 422 si el documento existente está rechazado).
24.3 Reserva aún sin documento terminal#
{
"ok": true,
"idempotent": true,
"pending": true,
"message": "La solicitud ya está reservada. No se creará ni enviará un segundo DSE.",
"request_status": "creating"
}
HTTP 202.
24.4 Misma llave, payload diferente#
HTTP 409:
{
"ok": false,
"error": "Idempotency-Key ya fue usado con un payload diferente."
}
24.5 Transporte/DIAN incierto#
HTTP 502 puede representar un estado incierto, no un permiso para duplicar:
{
"ok": false,
"pending": true,
"idempotent": false,
"error": "La transmisión no confirmó un estado terminal. El DSE quedó reservado y no se reenviará automáticamente.",
"documento": {
"id": 7423,
"estado_dian": "en_proceso_http"
}
}
Acción del cliente:
- Persistir el
doc_id. - No crear otra llave.
- Consultar
GET /dse/documentos/{doc_id}. - Si requiere reintentar el POST por recuperación de conexión, usar exactamente la misma
Idempotency-Keyy el mismo payload. - Escalar a soporte si el estado permanece incierto según el SLA operativo acordado.
25. Consultar DSE por ID#
GET /api/ext/v1/companies/{company_id}/dse/documentos/{doc_id}
Scope: dse.read
Respuesta:
{
"ok": true,
"pending": false,
"documento": {
"id": 7423,
"company_id": 30,
"prefijo": "DS",
"consecutivo": 4238,
"document_date": "2026-10-07",
"accounting_due_date": null,
"moneda": "COP",
"subtotal": "100000.00",
"impuestos": "19000.00",
"total": "119000.00",
"total_retenciones": "0.00",
"es_habilitacion": 0,
"xml_path": "<ruta-interna>",
"estado_dian": "aceptado",
"cuds": "<CUDS>",
"zip_key": "<ZIP_KEY>",
"last_status_error": null,
"accounting_status": "posted",
"third_party_id": 123,
"cost_center_id": 1,
"created_at": "2026-10-07 21:00:00",
"updated_at": "2026-10-07 21:00:10"
}
}
xml_path y last_status_error son metadatos de implementación/diagnóstico. No los use como URL pública ni como campos indispensables para que el ERP funcione.
26. Estados DSE que el integrador debe entender#
| Estado | Significado operativo |
|---|---|
firmado |
XML firmado; etapa anterior a transmisión |
sending |
Quantum reservó el documento para transmisión; no duplicar |
enviado |
Enviado, resultado aún no terminal |
en_proceso |
DIAN/proceso aún pendiente |
en_proceso_http |
Resultado de transporte/correlación pendiente o incierto |
send_unknown |
Resultado de envío no concluyente |
aceptado |
Resultado terminal exitoso |
rechazado |
Resultado terminal rechazado |
El booleano pending resume los estados no terminales de transmisión en la API externa.
27. Ejemplo DSE acumulado semanal + crédito + retención#
{
"fecha_documento": "2026-10-07",
"forma_generacion": "2",
"fecha_inicio_periodo": "2026-10-01",
"fecha_fin_periodo": "2026-10-07",
"forma_pago": "2",
"medio_pago_codigo": "42",
"fecha_vencimiento": "2026-11-06",
"fecha_vencimiento_contable": "2026-11-06",
"moneda": "COP",
"proveedor": {
"tipo_documento": "31",
"nit": "900000001",
"dv": "1",
"nombre": "PROVEEDOR DE PRUEBA SAS",
"regimen": "O-49",
"dian_tax_scheme_code": "ZZ",
"direccion": "Bogotá",
"municipio": "Bogotá",
"codigo_municipio": "11001",
"departamento": "Cundinamarca",
"codigo_departamento": "11",
"pais": "CO"
},
"items": [
{
"codigo": "81112100",
"descripcion": "Servicios semana 1",
"cantidad": 1,
"unidad_medida": "EA",
"precio_unitario": 1000000,
"porcentaje_iva": 0
}
],
"retenciones": [
{
"retention_key": "rete_renta",
"dian_tax_code": "06",
"tax_name": "ReteRenta",
"base_mode": "subtotal",
"percent": 2.5
}
]
}
PARTE III - DISEÑO DE LA INTEGRACIÓN#
28. Patrón recomendado: Outbox/Queue#
Para POS/ERP con transacciones críticas, no conviene que el cierre de una venta espere indefinidamente a servicios externos. El patrón recomendado es:
Transacción de negocio local
|
+--> guardar venta/documento local
+--> guardar trabajo OUTBOX con clave estable
|
v
Worker asíncrono
|
+--> Quantum API
|
+--> persistir HTTP + respuesta
+--> reprogramar consultas/reintentos seguros
Esto desacopla el tiempo de respuesta del POS de la transmisión fiscal y permite trazabilidad, reintentos y recuperación controlada.
28.1 Registro mínimo por operación#
| Campo local | Por qué guardarlo |
|---|---|
source_id |
ID de venta/compra en ERP/POS |
company_id |
Evita mezcla multiempresa |
document_type |
FE o DSE |
draft_key / idempotency_key |
Evita duplicados |
payload_hash |
Detecta cambios entre intentos |
attempt_count |
Auditoría de reintentos |
last_http_status |
Diagnóstico |
last_response |
Evidencia técnica |
quantum_document_id |
Consulta posterior |
cufe / cuds |
Identificador fiscal |
estado_dian |
Estado sincronizado |
created_at / updated_at |
Trazabilidad temporal |
29. Algoritmo de reintento recomendado#
29.1 FE#
1. Generar/persistir draft_key antes del POST.
2. POST FE.
3. Si 2xx -> guardar factura_id/CUFE/estado.
4. Si 4xx de validación -> no reintentar automáticamente; corregir datos.
5. Si timeout/5xx -> conservar draft_key; no crear una venta nueva.
6. Aplicar revisión/consulta operativa antes de un reenvío destructivo.
29.2 DSE#
1. Generar/persistir Idempotency-Key antes del POST.
2. POST con la misma llave y payload.
3. 201 -> guardar documento.id y estado.
4. 200/202 con idempotent:true -> usar el documento/reserva existente.
5. 409 -> error de programación: se reutilizó una llave con otro payload.
6. 422 -> documento rechazado; no crear un duplicado para ocultar el rechazo.
7. 502 + pending:true -> estado incierto; consultar GET. NO cambiar llave.
8. Timeout -> repetir únicamente con misma llave y mismo payload o consultar por ID si ya se obtuvo.
Backoff sugerido del lado cliente para consultas no terminales: 5s, 15s, 30s, 60s, luego intervalos mayores según SLA. Evite loops de alta frecuencia.
30. Errores y diagnóstico#
30.1 Matriz de tratamiento#
| Clase | Ejemplo | Reintento automático |
|---|---|---|
| Autenticación | 401 | No; corregir token |
| Autorización | 403 | No; corregir empresa/scopes |
| Validación | 400 | No; corregir payload |
| No encontrado | 404 | No, salvo carrera de sincronización conocida |
| Idempotencia | 409 | No; investigar llave/payload |
| Rechazo fiscal DSE | 422 | No duplicar; revisar rechazo |
| Pendiente transporte | 502 + pending:true |
Consultar; no crear nueva llave |
| Error interno | 500 | Reintento cauteloso manteniendo clave de idempotencia/trazabilidad |
30.2 Qué adjuntar a soporte#
Sin exponer secretos:
- Fecha/hora y zona horaria.
company_id.- Endpoint y método.
- HTTP status.
draft_keyFE oIdempotency-KeyDSE.factura_id/documento.idsi existe.- CUFE/CUDS si existe.
estado_dian.- Response body sanitizado.
- Hash del payload, no necesariamente el payload completo si contiene información sensible.
Nunca adjunte el Bearer Token.
31. Ejemplos de código#
31.1 cURL FE#
curl -X POST "$QUANTUM_API_BASE/companies/$COMPANY_ID/fe/facturas" \
-H "Authorization: Bearer $QUANTUM_API_TOKEN" \
-H "Content-Type: application/json" \
-d @fe-contado.json
31.2 cURL DSE#
curl -X POST "$QUANTUM_API_BASE/companies/$COMPANY_ID/dse/documentos" \
-H "Authorization: Bearer $QUANTUM_API_TOKEN" \
-H "Idempotency-Key: $IDEMPOTENCY_KEY" \
-H "Content-Type: application/json" \
-d @dse-contado.json
31.3 JavaScript / Node.js#
const response = await fetch(
`${process.env.QUANTUM_API_BASE}/companies/${companyId}/dse/documentos`,
{
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.QUANTUM_API_TOKEN}`,
'Content-Type': 'application/json',
'Accept': 'application/json',
'Idempotency-Key': idempotencyKey,
},
body: JSON.stringify(payload),
}
);
const body = await response.json();
if (response.status === 502 && body.pending) {
// No crear otro DSE. Persistir ID/llave y consultar estado.
}
31.4 Python#
import os
import requests
url = f"{os.environ['QUANTUM_API_BASE']}/companies/{company_id}/dse/documentos"
headers = {
"Authorization": f"Bearer {os.environ['QUANTUM_API_TOKEN']}",
"Accept": "application/json",
"Content-Type": "application/json",
"Idempotency-Key": idempotency_key,
}
response = requests.post(url, json=payload, headers=headers, timeout=60)
body = response.json()
if response.status_code == 502 and body.get("pending"):
# Conservar la misma llave y consultar el documento; no duplicar.
pass
31.5 PHP#
$ch = curl_init($baseUrl . "/companies/" . $companyId . "/dse/documentos");
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
"Authorization: Bearer " . getenv("QUANTUM_API_TOKEN"),
"Accept: application/json",
"Content-Type: application/json",
"Idempotency-Key: " . $idempotencyKey,
],
CURLOPT_POSTFIELDS => json_encode($payload, JSON_UNESCAPED_UNICODE),
CURLOPT_TIMEOUT => 60,
]);
$result = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
PARTE IV - POSTMAN, OPENAPI Y WEB#
32. Cómo usar la colección Postman incluida#
El paquete incluye:
postman/Quantum_Nube_FE_DSE_v1.postman_collection.json
postman/Quantum_Nube_FE_DSE_v1.postman_environment.json
Procedimiento:
- Importar ambos archivos en Postman.
- Seleccionar el environment.
- Definir
company_id. - Definir
api_tokenlocalmente; no guardar el environment con el secreto en Git. - Ejecutar primero
FE > Listar métodos de pago. - Guardar un
fe_payment_method_idyfe_payment_means_codeválidos. - Ejecutar las consultas de lectura.
- Solo cuando se quiera emitir realmente, ejecutar los POST FE/DSE.
- Para DSE, mantener la misma
dse_idempotency_keysi se repite la prueba de la misma operación.
La colección calcula por defecto la fecha de Colombia y genera claves solo cuando las variables están vacías, para que un retry conserve la misma llave.
33. OpenAPI 3.1 incluido#
Archivo:
openapi/quantum-api-v1.yaml
Debe convertirse en la fuente contractual del portal web. Beneficios:
- Referencia de endpoints navegable.
- Generación de clientes/SDKs si se decide más adelante.
- Validación automatizada del contrato.
- Importación directa en Postman/Insomnia/Bruno y herramientas de pruebas.
- Renderizado con Scalar, Redoc o Swagger UI.
- Control de versiones en Git.
33.1 Política recomendada de actualización#
Cada cambio de API debe modificar en la misma entrega:
1. Código backend
2. OpenAPI
3. Ejemplos/Postman
4. Changelog
5. Pruebas de contrato
No se debe permitir que la página web describa un payload distinto al que realmente acepta producción.
34. Integración dentro del sitio web de Quantum#
34.1 Arquitectura propuesta#
Web Quantum
|
+-- /developers/api -> Landing / Quickstart
+-- /developers/api/fe -> Guía FE
+-- /developers/api/dse -> Guía DSE
+-- /developers/api/reference -> OpenAPI renderizado
+-- /developers/api/errors -> Errores / retries
+-- /developers/api/changelog -> Historial
+-- /developers/downloads -> OpenAPI + Postman
34.2 Componentes visuales#
- Header del ecosistema Quantum.
- Sidebar por secciones.
- Buscador local.
- Breadcrumbs.
- Títulos con anclas copiables.
- Tablas responsivas.
- Bloques de código con botón copiar.
- Tabs por lenguaje.
- Callouts
Importante / Advertencia / Nota. - Etiquetas
GET,POST,fe.read,dse.write. - Sección “Respuesta” junto a cada request.
- Links descargables a OpenAPI y Postman.
- Changelog visible con versión y fecha.
34.3 Fuente de contenido#
No duplique manualmente el contrato de endpoints en varias páginas. Use:
- Markdown para guías conceptuales.
- OpenAPI para referencia técnica.
- JSON de navegación para construir sidebar.
- Postman como descarga.
La carpeta incluida docs/ ya está fragmentada de esa forma para que el proyecto web pueda copiarla o convertirla a MDX.
35. Seguridad específica del portal web#
Si la documentación es pública:
OpenAPI público -> sí, sin secretos
Ejemplos JSON/cURL -> sí, usando API_TOKEN ficticio
Postman collection -> sí, sin token
Postman environment -> sí, api_token vacío
Try it con token real -> NO en página pública
Si se desea “Try it” real, cree un portal autenticado y un mecanismo seguro que no exponga credenciales persistentes al frontend.
36. Checklist de salida a producción para un integrador#
Credenciales y aislamiento#
- [ ]
company_idconfirmado. - [ ] Cliente API activo.
- [ ] Token guardado como secreto.
- [ ] Scopes mínimos asignados.
- [ ] Prueba de token contra endpoint de lectura.
- [ ] Prueba de empresa incorrecta produce 403.
FE#
- [ ] Mapeo de receptor validado.
- [ ] Mapeo de items e impuestos validado.
- [ ] Caso 0%, 19% y, si aplica, INC 8% probado.
- [ ] Métodos de pago obtenidos desde catálogo de la empresa.
- [ ]
draft_keypersistido antes de enviar. - [ ] Timeout probado sin generar duplicidad.
- [ ] GET de detalle integrado.
DSE#
- [ ] Scope
dse.ready/odse.writeconfirmado. - [ ]
Idempotency-Keypersistida antes de enviar. - [ ] UNSPSC de 8 dígitos validado.
- [ ]
porcentaje_ivausado correctamente. - [ ] Proveedor real validado.
- [ ] Forma generación 1/2 probada según negocio.
- [ ] Retenciones probadas si aplican.
- [ ] Caso 409 probado.
- [ ] Caso retry misma llave probado.
- [ ] Caso
pending:truetratado sin duplicar. - [ ] GET DSE integrado.
Observabilidad#
- [ ] HTTP status persistido.
- [ ] Response body persistido/sanitizado.
- [ ] ID Quantum persistido.
- [ ] CUFE/CUDS persistido.
- [ ] Métricas de errores/reintentos.
- [ ] Alerta por pendientes prolongados.
37. Matriz mínima de QA / pruebas de contrato#
| Caso | FE | DSE | Resultado esperado |
|---|---|---|---|
| Sin token | Sí | Sí | 401 |
| Token empresa distinta | Sí | Sí | 403 |
| Scope insuficiente | Sí | Sí | 403 |
| Payload mal formado | Sí | Sí | 400 |
| Documento inexistente | Sí | Sí | 404 |
| Efectivo/contado | Sí | Sí | Procesamiento válido |
| Crédito | Sí | Sí | Vencimiento válido |
| Impuesto 0% | Sí | Sí | Cálculo consistente |
| IVA 19% | Sí | Sí | Cálculo consistente |
| INC 8% | Sí | No aplicar regla FE | FE código 04 |
| UNSPSC inválido | N/A | Sí | 400 |
| DSE sin Idempotency-Key | N/A | Sí | 400 |
| DSE replay misma llave/payload | N/A | Sí | idempotent true / sin duplicado |
| DSE misma llave/payload distinto | N/A | Sí | 409 |
| DSE rechazo DIAN | N/A | Sí | 422 |
| DSE transporte incierto | N/A | Sí | 502 + pending true / sin duplicar |
38. Recomendaciones de evolución de la API#
Para llevar el producto a un estándar de developer platform más completo, priorizar:
- Añadir un
request_id/correlation ID oficial en headers y respuestas. - Publicar endpoints externos de descarga XML/PDF mediante URLs autorizadas, en vez de exponer
xml_pathinterno. - Publicar endpoint externo de adjuntos FE si el caso de uso lo exige.
- Normalizar envelopes y nombres de estado FE/DSE.
- Incorporar rate-limit explícito y headers de cuota si se requiere.
- Publicar webhooks firmados para
aceptado/rechazadoy reducir polling. - Agregar sandbox/habilitación separado del endpoint productivo si se quiere onboarding autónomo.
- Generar SDKs desde OpenAPI cuando el contrato se estabilice.
- Ejecutar pruebas de contrato OpenAPI en CI.
- Mantener changelog por versión y política de deprecación.
Estas son mejoras de plataforma; no cambian el contrato productivo documentado actualmente.
39. Changelog de documentación#
v1.0.0 - 2026-10-07#
- Consolidación de API externa FE y DSE.
- Documentación de autenticación Bearer y scopes
fe.*/dse.*. - Documentación de aislamiento por empresa.
- FE: catálogo de pagos, creación, listado, detalle, terceros y GetAcquirer.
- FE: regla 8% -> INC código 04.
- DSE: create + sign + send externo.
- DSE:
Idempotency-Keyobligatorio, replay seguro y conflicto 409. - DSE: estados pending y tratamiento de 502 incierto.
- DSE: proveedor, UNSPSC, impuestos, acumulado semanal y retenciones.
- Paquete OpenAPI + Postman + guías web.
40. Resumen ejecutivo para el equipo web#
La implementación profesional recomendada para la página de Quantum es:
OpenAPI 3.1 = contrato técnico principal
Markdown/MDX = guías humanas y tutoriales
Scalar/Redoc/Swagger UI = referencia interactiva generada
Postman = colección descargable para pruebas
Changelog = control de versión visible
Backend/BFF = cualquier prueba autenticada real desde la web
Copie el contenido de este paquete al proyecto web, publique las guías Markdown dentro de /developers/api, renderice openapi/quantum-api-v1.yaml en la página de referencia y permita descargar los archivos Postman. No exponga credenciales reales en el frontend.
