Skip to content

Conceptos

Lo que hay detrás de los campos. Está ordenado por lo que se necesita entender antes: ambiente, identificadores, ciclo de vida, y los dos casos raros —contingencia y lotes— que solo importan cuando algo se sale de lo normal.

Ambiente: 00 pruebas, 01 producción

Hacienda tiene dos ambientes y son mundos separados: distintas credenciales, distintos correlativos, distintos sellos. Un documento de pruebas no existe en producción y viceversa.

El ambiente lo fija la configuración del contribuyente, no la petición. Lo que sí te dice en cuál estás es el prefijo de tu API key: sk_test_ o sk_live_. Es deliberado — si una llave se filtra en un log, se ve de un vistazo si el problema es grave.

Todo lo que emitas contra sk_live_ tiene valor fiscal, aunque haya sido sin querer. Se anula con una nota de crédito, un evento de retorno o una invalidación, no borrándolo.

Los dos identificadores de un documento

Un DTE tiene dos números y hacen cosas distintas. Confundirlos cuesta tiempo.

Código de generación

2F380579-2A15-42E8-9ADF-4EA97AE4DA3A

Un UUID en mayúsculas. Lo genera el emisor, es único en todo el sistema de Hacienda, y es la clave con la que se consulta todo: el estado, el PDF, el JSON, la línea de tiempo, y el documento que ajusta una nota de crédito.

Guárdalo en tu base junto a tu propia venta. Es el enlace entre tu sistema y el fiscal.

Número de control

DTE-01-M001P001-000000000000042
 │   │     │         └── correlativo, 15 dígitos
 │   │     └── establecimiento (M001) y punto de venta (P001)
 │   └── tipo de documento (CAT-002)
 └── prefijo fijo

Es el correlativo: una secuencia sin huecos por cada combinación de tipo, establecimiento y punto de venta. Es lo que revisa un auditor.

Dos consecuencias prácticas:

  • Un correlativo consumido no se recupera. Si emites un documento por error, el número queda usado y hay que justificar qué pasó con él. Por eso Idempotency-Key es obligatoria.
  • Un correlativo no retrocede. Si vienes de otro proveedor y ya ibas por el 1500, se posiciona la serie con PUT /api/v1/dte/series. Hacia atrás, nunca: serían dos documentos con el mismo número.

El ciclo de un documento

                          ┌──────────────┐
  POST /documentos ──────▶│ TRANSMITIENDO│
                          └──────┬───────┘

                 ┌───────────────┼────────────────┐
                 ▼               ▼                ▼
           ┌──────────┐   ┌────────────┐   ┌──────────────────┐
           │ SELLADO  │   │ RECHAZADO  │   │ EN_CONTINGENCIA  │
           └────┬─────┘   └────────────┘   └──────────────────┘


          ┌─────────────┐
          │ INVALIDADO  │
          └─────────────┘
EstadoQué significa
TRANSMITIENDOFirmado y en camino a Hacienda. Todavía no existe fiscalmente.
SELLADOHacienda lo aceptó. selloRecibido trae los 40 caracteres del sello. Este es el único estado que cuenta.
RECHAZADOHacienda lo rechazó. codigoMsg y descripcionMsg dicen por qué. El correlativo queda consumido igual.
EN_CONTINGENCIAHacienda no respondió y el documento quedó acumulado. Ver abajo.
INVALIDADOEstaba sellado y se anuló con un evento de invalidación.
FIRMADO, BORRADOR, ERROR_FIRMAEstados internos. Si ves ERROR_FIRMA de forma persistente, el certificado del contribuyente tiene un problema.

Cómo enterarte de que pasó a SELLADO

Tres caminos, de mejor a peor:

  1. Webhook. Te avisan. Es lo correcto para un sistema que factura a diario. → Webhooks
  2. ?esperar=8s al emitir. Para una caja que tiene que imprimir el ticket ahora. Máximo 20 segundos.
  3. Sondear GET /api/v1/dte/documentos/{cg}. Funciona, pero si lo haces cada segundo para cada documento acabarás limitado por peticiones. Úsalo como red de seguridad del webhook, no como mecanismo principal.

Qué hacer si un documento sale RECHAZADO

Un rechazo no se reintenta tal cual: Hacienda ya dijo que ese contenido no le sirve. Lo que se hace es corregir y emitir uno nuevo, que consumirá el siguiente correlativo.

descripcionMsg trae el motivo textual de Hacienda y observaciones el detalle. Los rechazos más comunes son datos del receptor incompletos en un CCF y códigos de catálogo que no existen.

El documento rechazado no se invalida: no llegó a existir, así que no hay nada que anular.

Contingencia

Cuando Hacienda no responde —se cae, o hay mantenimiento—, el sistema no deja de facturar. Los documentos se firman igual y quedan EN_CONTINGENCIA.

Lo importante para ti: el documento es válido y se le puede entregar al cliente. La normativa lo contempla. Cuando Hacienda vuelve, se declara el evento de contingencia y los acumulados se transmiten.

Del lado del integrador no hay nada especial que hacer, salvo no interpretar EN_CONTINGENCIA como un error. Si tu sistema bloquea la venta cuando el documento no está SELLADO, en una contingencia dejas de vender sin necesidad.

Lotes

Para cargas masivas —una migración, el cierre de un mes acumulado— está POST /api/v1/dte/lotes, que recibe muchos documentos de una vez y los procesa en segundo plano.

No lo uses para la operación normal. Un lote no te da el sello de un documento concreto rápido, y el punto de venta necesita justo eso.

Catálogos

Hacienda define 33 catálogos de códigos: unidades de medida, actividades económicas, departamentos, formas de pago. Están servidos en GET /api/v1/dte/catalogos y GET /api/v1/dte/catalogos/{cat}.

Los que más se usan:

CatálogoPara quéValor típico
CAT-002Tipo de documento01 Factura, 03 CCF, 04 NR, 11 FEX, 14 FSE…
CAT-011Tipo de ítem1 bien, 2 servicio
CAT-014Unidad de medida59 unidad
CAT-016Condición de la operación1 contado, 2 crédito
CAT-017Forma de pago01 efectivo, 02 débito, 03 crédito, 05 transferencia
CAT-019Actividad económicadel receptor, en el CCF
CAT-022Tipo de documento de identidad36 NIT, 13 DUI
CAT-012 / 013 / 036Departamento / municipio / distritodirección

Trampa con los municipios (CAT-013): el código no es único por sí solo, se repite entre departamentos. El municipio 23 existe en varios. Solo tiene sentido junto a su departamento, y por eso el endpoint acepta ?padre=06.

Emisor, establecimientos y puntos de venta

Un contribuyente tiene uno o varios establecimientos (sucursales) y cada uno tiene uno o varios puntos de venta (cajas). El correlativo es por combinación, así que dos cajas de la misma sucursal llevan series separadas.

Al emitir puedes elegir desde dónde con codEstable y codPuntoVenta. Si los omites se usa el primero activo — quien tiene una sola caja no necesita saber que esto existe.

Si tu sistema tiene varias sucursales, mándalos siempre: dejar que el sistema elija hace que dos sucursales compartan correlativo y eso es un problema de auditoría, no de software.