</>Quantum DevelopersAPI v1

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#

  1. Trate el token como una contraseña de máquina a máquina.
  2. No lo incluya en capturas, tickets, logs compartidos ni documentación pública.
  3. No use un token de producción desde JavaScript del navegador.
  4. Separe clientes API cuando existan terceros o integraciones con responsabilidades diferentes.
  5. Rote/revoque credenciales cuando cambie el proveedor o exista sospecha de exposición.
  6. Mantenga company_id configurable; no mezcle IDs entre clientes.
  7. 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:


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:

  1. Genere una llave estable a partir del ID inmutable de la venta o un UUID.
  2. Persístala antes de llamar a Quantum.
  3. Ante timeout, conserve la misma llave y el mismo contexto comercial.
  4. No genere otra llave solo para “probar otra vez”.
  5. Persista factura_id, CUFE, estado y respuesta cuando estén disponibles.

[!IMPORTANT] FE usa draft_key en el body. DSE usa Idempotency-Key en 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:

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"#

{
  "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:


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#


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:

  1. Persistir el doc_id.
  2. No crear otra llave.
  3. Consultar GET /dse/documentos/{doc_id}.
  4. Si requiere reintentar el POST por recuperación de conexión, usar exactamente la misma Idempotency-Key y el mismo payload.
  5. 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:

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:

  1. Importar ambos archivos en Postman.
  2. Seleccionar el environment.
  3. Definir company_id.
  4. Definir api_token localmente; no guardar el environment con el secreto en Git.
  5. Ejecutar primero FE > Listar métodos de pago.
  6. Guardar un fe_payment_method_id y fe_payment_means_code válidos.
  7. Ejecutar las consultas de lectura.
  8. Solo cuando se quiera emitir realmente, ejecutar los POST FE/DSE.
  9. Para DSE, mantener la misma dse_idempotency_key si 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:

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#

34.3 Fuente de contenido#

No duplique manualmente el contrato de endpoints en varias páginas. Use:

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#

FE#

DSE#

Observabilidad#


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:

  1. Añadir un request_id/correlation ID oficial en headers y respuestas.
  2. Publicar endpoints externos de descarga XML/PDF mediante URLs autorizadas, en vez de exponer xml_path interno.
  3. Publicar endpoint externo de adjuntos FE si el caso de uso lo exige.
  4. Normalizar envelopes y nombres de estado FE/DSE.
  5. Incorporar rate-limit explícito y headers de cuota si se requiere.
  6. Publicar webhooks firmados para aceptado/rechazado y reducir polling.
  7. Agregar sandbox/habilitación separado del endpoint productivo si se quiere onboarding autónomo.
  8. Generar SDKs desde OpenAPI cuando el contrato se estabilice.
  9. Ejecutar pruebas de contrato OpenAPI en CI.
  10. 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#


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.

DocumentaciónPrecios API