Trifaco API

Errores, idempotencia y reintentos

Formato de error, qué hacer con cada código, cómo reintentar sin duplicar documentos y los límites de tasa de la API.

Formato Problem

Todos los errores usan el mismo cuerpo:

{
  "code": "FISCAL_VALIDATION_FAILED",
  "message": "…",
  "request_id": "…",
  "retryable": false,
  "action": "fix_request",
  "errors": [{ "…": "errores por campo" }]
}
  • action: fix_request, check_credentials, check_permissions, consult_operation, retry_same_key, top_up, contact_support o none.
  • Puede incluir operation_id, resource_id y resource_type.
  • Guarda el cuerpo de forma privada junto con request_id. No registres la clave ni material de firma.

El cliente de ejemplo (integration.ts) lanza ApiFailure con estado, problema y Retry-After, y nunca reintenta por su cuenta.

Qué hacer con cada respuesta

RespuestaQué hacer
401 INVALID_API_KEYRevisa la credencial del ambiente. No envíes otra factura.
403 PERMISSION_DENIED / ENVIRONMENT_DISABLEDRevisa permisos y capacidades. Producción sigue bloqueada.
404El recurso no existe para tu empresa y ambiente (ver aislamiento).
400 IDEMPOTENCY_KEY_REQUIREDPrepara una clave válida antes de enviar.
422 FISCAL_VALIDATION_FAILEDCorrige los errores publicados. Confirma que no hubo admisión antes de preparar otra identidad.
422 UNSUPPORTED_OPERATIONLa ruta está pendiente; no está en la referencia.
409 IDEMPOTENCY_CONFLICT / EXTERNAL_REFERENCE_CONFLICTNo cambies la identidad para eludir el conflicto. Compara con la solicitud original.
409 VERSION_CONFLICT / 428 PRECONDITION_REQUIREDVuelve a consultar el recurso y decide con su ETag actual.
409 SECRET_ALREADY_DELIVEREDEl secreto ya se entregó. Usa resource_id para consultar el recurso; rota o sustituye si lo perdiste.
429 SANDBOX_DAILY_LIMITTu cuenta del sandbox agotó sus facturas del día. Retry-After dice cuántos segundos faltan para la medianoche de Colombia.
403 SANDBOX_RECIPIENT_NOT_ALLOWEDEl sandbox solo envía correo al de la persona dueña de la cuenta. Usa esa dirección o prueba la entrega con webhooks.
429 / 503, timeout o pérdida de conexiónNo supongas que no hubo admisión. Sigue la sección siguiente.

Idempotencia

Toda mutación exige Idempotency-Key: de 8 a 128 caracteres, A-Z a-z 0-9 . _ : -, empezando por letra o dígito.

  • La clave vale dentro de empresa, ambiente, operación y recurso destino. Se retiene al menos 90 días y mientras haya trabajo pendiente.
  • Misma clave y mismo contenido → devuelve el resultado original (202 con el mismo document_id).
  • Misma clave y contenido distinto409 IDEMPOTENCY_CONFLICT.
  • Misma referencia externa y contenido distinto409 EXTERNAL_REFERENCE_CONFLICT.
  • Los decimales se comparan como texto: "1.0" y "1.00" son contenidos distintos.
  • No dependas del encabezado Idempotency-Replayed (el servicio no lo emite). Compara el ID devuelto y consulta el recurso.

Reintentar sin duplicar

Antes del primer envío, guarda de forma durable los bytes exactos del cuerpo, la referencia externa y la clave de idempotencia.

Si la respuesta no llega (timeout, conexión perdida, 429, 503), no generes una factura nueva. Si ya tienes un document_id, consúltalo.

Si no lo tienes, decide explícitamente repetir el envío con los mismos bytes y la misma clave. Si la primera solicitud se había admitido, recibirás esa misma admisión.

Nunca cambies issued_at, decimales, referencia ni clave de una solicitud incierta. Si agotas el presupuesto de consultas, continúa más tarde con el mismo ID.

prepareInvoice, prepareCredit y prepareDebit del cliente de ejemplo fijan los bytes para un proceso, pero no los guardan: tu integración debe persistirlos antes del primer envío. submit hace un solo intento.

Un documento con dian.status: unknown exige conciliación. No es un rechazo y no autoriza otra emisión.

Recursos versionados

Los recursos que lo implementan devuelven ETag. Las acciones que exigen If-Match rechazan versiones antiguas con 409 VERSION_CONFLICT. Vuelve a consultar y evalúa la acción con la versión actual.

Límites de tasa

La API aplica límites antes de leer el cuerpo o autenticar, y otros después de identificar empresa y clave. También cuentan las consultas, las credenciales inválidas y las rutas inexistentes. Son independientes del saldo.

ÁmbitoSolicitudes/sRáfagaSimultáneas
Servicio API10020064
IP (IPv6 agrupada por /64)5010016
Empresa y ambiente30608
Clave verificada20404
Escrituras por empresa y ambiente10504
Cuenta del sandbox1604
Salud (presupuesto separado)5102

Son valores iniciales por proceso, no capacidad fiscal garantizada. Varias claves comparten el límite de su empresa; varios clientes detrás de una IP comparten el de la red.

Un rechazo devuelve HTTP_RATE_LIMIT o HTTP_CONCURRENCY_LIMIT (429 para límites de cliente, 503 por saturación) o HTTP_STATE_CAPACITY (503), con retryable: true, action: retry_same_key y Retry-After en segundos.

  • Espera al menos Retry-After y añade variación aleatoria.
  • Repite con la misma clave y el mismo cuerpo.
  • Una solicitud rechazada por estos límites no reserva numeración ni consume crédito.

Límites del sandbox

Una cuenta del sandbox público es gratuita y emite con el emisor compartido de habilitación, así que además de lo anterior tiene tres límites propios:

LímiteValorQué pasa al superarlo
Facturas por día50429 SANDBOX_DAILY_LIMIT, con la espera hasta la medianoche de Colombia
Peticiones por minuto60429 HTTP_RATE_LIMIT, con su Retry-After
Destinos de webhook3429 WEBHOOK_ENDPOINT_LIMIT al registrar el cuarto

Ninguna factura rechazada por un límite consume numeración: reintenta con la misma Idempotency-Key cuando pase la espera. El correo del sandbox solo llega a la dirección de la persona dueña de la cuenta; para probar notificaciones a tu sistema, usa webhooks. Una empresa real no tiene estos límites.

Los operadores ajustan los límites con HTTP_<SCOPE>_RATE, HTTP_<SCOPE>_BURST y HTTP_<SCOPE>_CONCURRENCY (SCOPE: GLOBAL, IP, TENANT, KEY, WRITE, SANDBOX, HEALTH) HTTP_MAX_ENTRIES (10.000 por defecto) y SANDBOX_DAILY_DOCUMENTS (50). Las entradas inactivas vencen a los cinco minutos, y los valores inválidos impiden arrancar. Los eventos agregados http.protection publican cada minuto los rechazos por ámbito y motivo, sin claves, IP, empresa ni cuerpo. El servidor solo confía en direcciones reenviadas por el proxy local de loopback (Caddy); no expongas un proxy que acepte cabeceras de origen sin validar, y revisa esta confianza si cambia la topología de red. Antes de ejecutar varios procesos API hay que coordinar los presupuestos, porque los contadores son locales a cada proceso.

En esta página