Errores
Forma de un error
Sección titulada «Forma de un error»{ "success": false, "message": "API key inválida o expirada."}Siempre success: false y un message en español, pensado para que puedas
mostrarlo o registrarlo tal cual. Un error nunca trae data.
success es el campo a mirar primero: en las respuestas correctas es true.
Códigos
Sección titulada «Códigos»| Código | Significa | Qué hacer |
|---|---|---|
| 200 | Todo bien | — |
| 401 | Falta la key, o es inválida o expiró | Revisa el header. No reintentes: no se va a arreglar solo |
| 402 | Sin saldo de consultas | Compra una bolsa. No reintentes hasta recargar |
| 403 | La key es válida pero le falta el scope, o el plan no incluye API | Marca el scope o sube de plan. No reintentes |
| 404 | El recurso no existe en tu organización | Verifica el identificador |
| 422 | Un parámetro no pasó validación | Corrige el formato. No reintentes |
| 429 | Excediste el límite de peticiones | Espera y reintenta con backoff |
| 503 | El RUNT no respondió, o /health detectó una dependencia caída |
Reintenta más tarde |
Regla corta: 401, 402, 403 y 422 son tuyos —no reintentar sin cambiar algo—. 429 y 503 son transitorios —reintentar con espera—.
402 y 403 se parecen y no son lo mismo: 402 dice “recarga y vuelve”, 403 dice “tu llave no puede hacer esto”. Tratarlos igual te deja reintentando en vano o alertando a un humano que no hacía falta.
402 · Sin saldo
Sección titulada «402 · Sin saldo»{ "success": false, "message": "Sin saldo de consultas. Compra una bolsa para seguir usando el API."}El saldo es de la organización, no de la llave: todas tus llaves gastan del mismo. Se recarga en el panel, en Facturación → Consultas. Ver Límites de uso.
401 · No autenticado
Sección titulada «401 · No autenticado»Dos mensajes distintos, y la diferencia importa:
{ "success": false, "message": "API key requerida. Proporciónala en el header X-API-Key o como Bearer token." }No llegó ninguna key. Casi siempre es el header mal escrito, o un cliente HTTP que no lo está enviando.
{ "success": false, "message": "API key inválida o expirada." }La key llegó pero no sirve: no existe, está desactivada o pasó su fecha de expiración. Revisa en el panel que siga activa.
403 · Sin scope
Sección titulada «403 · Sin scope»{ "success": false, "message": "No tienes el scope necesario: vehicles.read" }El mensaje nombra el scope exacto que falta, así que no hay que adivinar. Si tu key no tiene ningún scope marcado, todos los endpoints devuelven 403: una lista de scopes vacía niega todo. Ver Autenticación y scopes.
404 · No encontrado
Sección titulada «404 · No encontrado»Solo lo devuelve GET /vehicles/{plate}:
{ "success": false, "message": "Vehículo no encontrado en tu organización." }El mensaje es literal: puede que la placa exista en el RUNT, y hasta en NotiAuto, pero no está registrada en tu organización. La API de flota nunca devuelve datos de otras organizaciones.
Si lo que quieres son datos de un vehículo que no es tuyo, eso es
POST /consults/vehicle, que consulta al RUNT.
422 · Validación
Sección titulada «422 · Validación»Formato estándar de Laravel:
{ "message": "The plate field format is invalid.", "errors": { "plate": ["The plate field format is invalid."] }}Lo devuelven los endpoints de consulta RUNT. Los formatos que exigen:
| Campo | Regla |
|---|---|
plate |
ABC123, 123ABC o ABC12D. No distingue mayúsculas |
document |
Solo dígitos, entre 6 y 10 |
type_document |
Uno de los códigos válidos, distintos para vehículo y persona |
first_surname |
Primer apellido de la persona, obligatorio en consultas de licencia |
Los códigos de documento están en Consultas RUNT.
429 · Límite excedido
Sección titulada «429 · Límite excedido»Sin cuerpo útil. La respuesta trae el header Retry-After con los segundos que
faltan.
if (res.status === 429) { const espera = Number(res.headers.get('Retry-After') ?? 60); await new Promise((r) => setTimeout(r, espera * 1000)); // reintentar}Ver Límites de uso.
503 · Servicio no disponible
Sección titulada «503 · Servicio no disponible»En los endpoints de consulta significa que el RUNT no respondió o rechazó la
consulta. El message trae lo que reportó el RUNT:
{ "success": false, "message": "El RUNT no respondió a la consulta del vehículo." }Un fallo del RUNT no se cachea nunca, así que el reintento sí puede dar otro resultado. Aun así, espera: si el RUNT está caído, reintentar de inmediato solo gasta tu límite de peticiones.
En GET /health un 503 significa que alguna dependencia está caída; mira
dependencies para saber cuál.
Un caso que no es error: secciones en null
Sección titulada «Un caso que no es error: secciones en null»POST /consults/vehicle puede responder 200 con soat o rtm en null:
{ "success": true, "cached": false, "data": { "plate": "ABC123", "marca": "CHEVROLET" }, "soat": null, "rtm": { "numero": "...", "vigente": true }}Eso no significa “el vehículo no tiene SOAT”. Significa que esa sección del RUNT no respondió. Son cosas distintas y la API no las puede distinguir por ti.
Cuando pasa, la consulta no se cachea, así que volver a pedirla más tarde
puede traer la sección completa. Nunca interpretes soat: null como “sin
seguro”.