Ir al contenido

Errores

{
"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ó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.

{
"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.

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.

{ "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.

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.

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.

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.

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.

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”.