Errores
El formato de los errores y qué hacer con cada uno.
Todos los fallos tienen la misma forma:
{
"error": "issuer_not_found",
"message": "The issuer profile does not exist"
}error es una clave estable; message es texto en inglés para quien
desarrolla y puede cambiar de redacción. Decidí sobre el código, no sobre el
mensaje, y traducilo vos: enganchar tu interfaz a esa prosa es enganchartela a
algo que va a cambiar.
En un fallo de validación se agrega issues con qué campo falló y por qué.
Por código HTTP
| HTTP | Qué pasó | Qué hacer |
|---|---|---|
400 | El cuerpo o un parámetro no cumple el esquema | Corregir la petición; mirá issues |
401 | Llave ausente, mal formada, inexistente o revocada | Revisar Authorization |
404 | No existe, o no es tuyo | No reintentar |
409 | Conflicto: duplicado, o un límite alcanzado | Depende del código |
422 | El documento no se puede emitir como viene | Corregir los datos |
429 | Superaste un límite —de peticiones o de documentos | Con Retry-After, esperalo; sin él, es el tope mensual |
503 | Una dependencia no respondió | Reintentar con espera creciente |
Los que vas a ver
invalid_payload y invalid_path_parameter son de forma: algo no cumple el
esquema.
issuer_not_found y issuer_id_required son de configuración: el emisor no
existe, o no dijiste cuál cuando hay más de uno.
issuer_limit_reached significa que la cuenta llegó a su tope de emisores. Es
un límite técnico del motor, no una licencia. El tope cuenta solo los activos,
así que desactivar uno libera su espacio —y reactivarlo
después puede devolver este mismo código, si ese espacio ya lo ocupa otro.
document_limit_reached es otro límite, y no es el de peticiones por
segundo: es cuántos documentos podés finalizar este mes en producción.
Sandbox no tiene tope. Se revisa solo al finalizar, nunca al crear un
borrador, y un reintento con la misma Idempotency-Key de un documento que
ya finalizaste nunca lo dispara —no es una emisión nueva. El mes se cuenta en
hora de Costa Rica. Podés ver cuánto llevás y cuál es tu tope con
curl https://api.timbre.cr/internal/v1/usage \
-H "Authorization: Bearer timbre_sk_…"que responde documentsThisMonth, monthlyDocumentLimit —null es sin
tope— y periodStart, el mismo número contra el que el motor te va a
rechazar si lo alcanzás.
Los certificate_* son del .p12 que cargaste y todos son 400:
certificate_password_invalid es un PIN que no lo abre,
certificate_expired y certificate_not_yet_valid son fechas, y
certificate_identification_mismatch es un certificado que no corresponde a la
cédula que declaraste.
duplicate_branch_code y duplicate_terminal_code son códigos ya registrados:
el de sucursal es único por contribuyente y el de terminal, único dentro de su
sucursal.
tariff_ambiguous significa que Timbre no supo qué tarifa corresponde y
prefirió negarse a adivinar. Hoy pasa con el 8 %. Un motor fiscal que adivina
produce documentos que parecen correctos y no lo son.
cabys_unknown es un código CAByS que no está en la versión del catálogo
vigente en la fecha de la venta —no lo confundas con tariff_ambiguous: acá
el código ni siquiera existe, ahí existe pero su tarifa no tiene código legal.
tax_supplied_by_caller pasa si una línea trae campos de impuesto que le
corresponden a Timbre derivar. No se reconcilian ni se ignoran: se rechazan,
para que nunca circule un documento cuyo impuesto lo puso quien lo mandó y no
el catálogo.
regime_unsupported es un contribuyente en un régimen que la derivación
todavía no modela —hoy, zona_franca. El alta lo acepta como taxRegime,
pero emitir a su nombre se rechaza hasta que ese régimen esté implementado.
expected_total_mismatch solo aparece si mandaste expectedTotal: es una
aserción tuya sobre el total, y si no coincide con lo que Timbre calculó,
rechaza en vez de firmar un documento que ya sabe que no es el que
esperabas.
Los exoneration_* son de la exoneración del comprador
(exoneration.authorizationNumber), y cada uno distingue una causa distinta
para no convertir una duda en una línea a precio completo sin decírtelo:
exoneration_not_found es un número que Hacienda no reconoce,
exoneration_expired es uno real pero fuera de vigencia en la fecha del
documento, exoneration_cabys_not_covered es uno vigente que no cubre
ninguno de los CAByS del documento, y exoneration_unavailable es que no se
pudo verificar con Hacienda —Timbre prefiere rechazar antes que cobrarle IVA
de más a alguien exonerado.
rate_limit_exceeded viene con Retry-After.
service_unavailable es del lado de Timbre o de Hacienda. Reintentá; no
cambies el documento.
Reintentar, y cuándo no
429 y 503 se reintentan con espera creciente. 400, 401, 403, 404 y
422 no: el resultado va a ser el mismo hasta que cambie algo tuyo.
Un documento en permanent_error o rejected no se reintenta: se corrige el
problema y se emite uno nuevo. Reencolar solo aplica a un
documento que quedó en finalized sin llegar a la cola.
Reintentar una emisión siempre con la misma Idempotency-Key. Sin ella,
el reintento de una petición que no viste responder emite un segundo documento
y gasta otro consecutivo.