Errores
El catálogo completo, qué se reintenta y qué no, y para qué sirve el requestId.
Todos los errores tienen la misma forma:
{
"error": {
"code": "SCOPE_REQUIRED",
"message": "Esta API key no tiene permiso para esta operación.",
"details": { "scope": "expenses.read" },
"requestId": "req_b0b926d7fbe34e53be33d869981cc9b9",
"docUrl": "https://docs.verifika.tech/guias/errores"
}
}Ramifica por code, nunca por message. Los códigos son parte del contrato; los mensajes
están en español para humanos y pueden cambiar de redacción.
Catálogo
| HTTP | code | Qué pasó | ¿Reintentar? |
|---|---|---|---|
| 400 | BAD_REQUEST | Cuerpo o parámetros inválidos. details trae el detalle. También sale si tu llave entra a varios negocios y no mandaste companyId. | No, hasta corregir |
| 401 | UNAUTHORIZED | Falta la llave, o es inválida, revocada, vencida, o viene de una IP no permitida. | No |
| 403 | SCOPE_REQUIRED | La llave no tiene ese permiso. details.scope dice cuál. | No |
| 403 | PLAN_FEATURE_REQUIRED | El plan no incluye la función. details.requiredPlanName dice cuál la trae. | No |
| 403 | FORBIDDEN | El companyId no es de esta llave, o la llave no sirve para esta API. | No |
| 404 | NOT_FOUND | El recurso no existe o no es tuyo. | No |
| 409 | IDEMPOTENCY_IN_PROGRESS | Esa Idempotency-Key se está procesando. | Sí, en unos segundos |
| 409 | IDEMPOTENCY_KEY_REUSED | Misma llave con cuerpo distinto. | No, usa una llave nueva |
| 429 | RATE_LIMITED | Te pasaste del límite. | Sí, respetando Retry-After |
| 500 | INTERNAL_ERROR | Nos falló algo. | Sí, con espera creciente |
404 y 403 no se distinguen a propósito
Pedir un ingreso de otro negocio devuelve 404, no 403. Si respondiéramos "no tienes
permiso", estaríamos confirmando que ese id existe — y eso convierte el endpoint en una forma
de descubrir datos ajenos probando ids.
Qué reintentar
Regla corta: 429 y 5xx se reintentan con espera creciente; el resto, no. Un 403 no
se arregla insistiendo, y un 400 tampoco.
const REINTENTABLE = (status) => status === 429 || status >= 500;El requestId
Va en el cuerpo de todo error y en la cabecera X-Request-Id de toda respuesta, incluidas
las exitosas.
Guárdalo en tus logs. Con ese id, soporte encuentra tu petición exacta; sin él, un reporte de "a veces me da error" no se puede investigar.
Si tu sistema ya genera ids de traza, mándalo tú en X-Request-Id y lo respetamos, así tu
traza no se parte al entrar a Verifika.