Contrato de respuestas y errores de Admin API
Este archivo completa el contrato de respuesta de cada endpoint de la Referencia de endpoints. Consulta en la fila del endpoint el cuerpo correcto y en las tablas siguientes todos los cuerpos compartidos o específicos de respuestas no satisfactorias. Por defecto, los errores utilizan varias estructuras de compatibilidad; los clientes pueden optar por una envoltura universal.
Envoltura de error estructurada opcional
Envía esta cabecera de solicitud a cualquier endpoint:
X-Error-Format: envelope
La comparación del valor elimina espacios de los extremos y no distingue mayúsculas de minúsculas. Con ese valor exacto, toda respuesta JSON cuyo estado sea 400 o superior se convierte en:
ErrorEnvelope = {
error: {
code: string,
message: string,
details: Record<string, unknown>,
requestId: string
}
}
Ejemplo de conversión de un cuerpo de validación predeterminado:
{
"error": {
"code": "VALIDATION_FAILED",
"message": "Invalid request",
"details": {
"fields": {
"name": ["String must contain at least 1 character(s)"]
}
},
"requestId": "integration-42"
}
}
Las reglas de conversión son exactas:
validationErrorsse convierte endetails.fieldsycodeenVALIDATION_FAILED, incluso cuando el cuerpo predeterminado ya tenía un código de dominio.- El
codede nivel superior predeterminado se conserva cuando no hay campos de validación. - Las demás propiedades de nivel superior, excepto
error,message,validationErrorsycode, se trasladan adetails; por ejemplo,limitde la exportación de informes se convierte endetails.limit. - Un
errorde nivel superior de tipo cadena se convierte enmessage. Si no existe, se utiliza el texto de respaldo del estado. - Los códigos de respaldo son
AUTH_REQUIRED(401),PERMISSION_DENIED(403),RESOURCE_NOT_FOUND(404),CONFLICT(409),VALIDATION_FAILED(422y otros4xxsin clasificar),RATE_LIMITED(429),EXTERNAL_PROVIDER_FAILED(502) yINTERNAL_ERROR(otros5xx, incluido503). requestIdes la cabecera de respuestaX-Request-Idexacta. Un ID de solicitud proporcionado por el cliente solo se utiliza si coincide con[A-Za-z0-9._:-]{1,128}tras eliminar los espacios de los extremos; de lo contrario, el servidor genera un UUID.
Esta transformación no cambia el estado ni las cabeceras ajenas al cuerpo. También se aplica a las repeticiones idempotentes según la cabecera X-Error-Format de la solicitud de repetición. Las respuestas correctas binarias siguen siendo binarias; sus errores JSON se envuelven. Las tablas restantes muestran los cuerpos predeterminados; aplicar las reglas anteriores proporciona el otro cuerpo posible para cada fila.
Notación de respuestas
ValidationError = {
validationErrors: Record<string, string[]>,
code?: string
}
CodedError = {
error: string,
code: string,
// a route may add fields explicitly listed below
}
PlainError = { error: string }
error y el texto de los mensajes de validación son descriptivos, no un discriminador programático estable. Basa la lógica en code cuando esté presente. La validación de solicitudes devuelve 422 ValidationError; validar un objeto completo puede producir { "validationErrors": {} } si no se identifica un campo individual. El JSON no válido y los fallos inesperados devuelven el 500 PlainError global mostrado a continuación.
Todos los ejemplos JSON muestran las estructuras exactas de los cuerpos. El texto indicado como <message> es el mensaje de validación u operación devuelto y es una cadena JSON, no un valor literal entre signos de menor y mayor.
Orden de procesamiento de solicitudes
Las solicitudes se procesan en este orden:
- configuración y autenticación de tokens de espacios de trabajo;
- políticas del host y límites de solicitudes del token/espacio de trabajo;
- filtrado según los derechos actuales;
- validación y reserva de idempotencia para cada modificación;
- comprobación de ámbitos del endpoint, validación de la solicitud y operación solicitada.
Por tanto, una solicitud de modificación con un token válido pero con ámbitos insuficientes sigue teniendo que enviar Idempotency-Key. Una respuesta de modificación completada con 403, 404, 409 o 422 se puede repetir con la misma clave y solicitud.
Respuestas de autenticación, políticas y límites de solicitudes
Estas respuestas pueden aparecer en cualquier endpoint /v2/admin registrado antes del procesamiento específico del endpoint.
| Estado | Cuándo | Cuerpo exacto | Cabeceras relevantes |
|---|---|---|---|
401 | Token de espacio de trabajo ausente, duplicado, unido por comas, no Bearer, mal formado, desconocido, caducado, revocado o no válido por otro motivo | { "error": "Unauthorized", "code": "INVALID_WORKSPACE_TOKEN" } | WWW-Authenticate: Bearer, Cache-Control: no-store |
404 | El token es válido, pero el host de su espacio de trabajo no tiene adminApiEnabled | { "error": "Not Found" } | Cache-Control: no-store |
429 | Se ha agotado la cuota de solicitudes del token o del espacio de trabajo | { "error": "Too many attempts. Please try again later." } | Retry-After: <seconds> |
503 | La autenticación de tokens de espacios de trabajo no está disponible temporalmente | { "error": "Admin API workspace-token configuration is unavailable", "code": "WORKSPACE_API_CONFIG_UNAVAILABLE" } | — |
503 | Falla la consulta de políticas del host o la autorización de derechos actuales | { "error": "Workspace authorization is temporarily unavailable", "code": "WORKSPACE_AUTHORIZATION_UNAVAILABLE" } | — |
El acceso a la API está incluido en todos los planes. Desactivar el ajuste adminApiEnabled del host del espacio de trabajo devuelve 404; perder el derecho a una función adicional solo elimina los ámbitos afectados. La denegación del ámbito resultante utiliza la respuesta siguiente, no un proceso de renovación del token.
Fallos de ámbitos, idempotencia, análisis, propiedad e imprevistos
| Se aplica a | Estado | Cuerpo exacto | Cabeceras/notas |
|---|---|---|---|
| Toda ruta después de la autenticación | 403 | { "error": "Insufficient workspace-token scope", "code": "INSUFFICIENT_SCOPE" } | Se devuelve cuando falta algún ámbito obligatorio. |
| Toda operación de modificación | 400 | { "error": "Idempotency-Key is required for this operation", "code": "IDEMPOTENCY_KEY_REQUIRED" } | No se ha proporcionado ninguna clave. |
| Toda operación de modificación | 400 | { "error": "Exactly one Idempotency-Key is required", "code": "INVALID_IDEMPOTENCY_KEY" } | Cabecera duplicada o valores unidos por comas. |
| Toda operación de modificación | 400 | { "error": "Idempotency-Key must contain 1 to 255 visible characters", "code": "INVALID_IDEMPOTENCY_KEY" } | Vacío, demasiado largo o contiene un carácter de control. |
| Toda operación de modificación | 409 | { "error": "Idempotency-Key was already used with a different request", "code": "IDEMPOTENCY_CONFLICT" } | Mismo token, método, ruta y clave, pero URL o cuerpo diferentes. |
| Toda operación de modificación | 409 | { "error": "Request is already processing", "code": "IDEMPOTENT_REQUEST_PROCESSING" } | Retry-After: 5. |
| Toda operación de modificación | 409 | { "error": "Previous request outcome is unknown; verify its effects before attempting the operation again", "code": "IDEMPOTENCY_OUTCOME_UNKNOWN" } | La concesión de procesamiento anterior ha caducado, la conexión se ha cerrado o la solicitud ha terminado con un 5xx. |
| Toda operación de modificación | 503 | { "error": "Idempotency storage unavailable", "code": "IDEMPOTENCY_UNAVAILABLE" } | La API no puede comprobar ni guardar el registro de idempotencia. |
| Cualquier endpoint con un esquema de consulta, cuerpo o ruta no válido | 422 | { "validationErrors": { "<field>": ["<message>"] } } | Puede haber varios campos o mensajes. Los clientes no pueden proporcionar cpoId; el espacio de trabajo siempre procede del token. |
| Cualquier recurso anidado del espacio de trabajo no encontrado o ID de otro espacio de trabajo | 404 | { "error": "Workspace resource not found", "code": "RESOURCE_NOT_FOUND" } | Se utiliza de forma uniforme salvo que una tabla posterior indique lo contrario. |
| Cualquier endpoint con un fallo inesperado | 500 | { "error": "Something went wrong" } | En las operaciones de modificación, reintentar la misma clave más adelante devuelve 409 IDEMPOTENCY_OUTCOME_UNKNOWN. |
Los ID de recursos de la ruta deben ser números positivos. Un :siteId, :chargerId, :portId, :tariffId, :profileId, :assignmentId, :userId, :rfidId, :accessId, :limitId o :localUserId no positivo o no numérico devuelve 422 ValidationError, no 400.
Errores de emplazamientos y gestión de potencia
| Endpoints | Estado | Cuerpo exacto |
|---|---|---|
| Creación/actualización de emplazamiento; validación de campos del espacio de trabajo | 422 | { "validationErrors": { "<field>": ["<message>"] } } |
DELETE /v2/admin/sites/:siteId cuando el emplazamiento tiene dependencias | 409 | { "error": "<message>", "code": "SITE_NOT_EMPTY" } |
GET /v2/admin/sites/geocode búsqueda normalizada no válida | 400 | { "error": "<message>", "code": "INVALID_GEOCODE_QUERY" } |
| Lo mismo, cola acotada del proveedor llena | 429 | { "error": "<message>", "code": "GEOCODING_BUSY" }; incluye Retry-After cuando lo proporciona el geocodificador |
| Lo mismo, tiempo de espera o fallo del proveedor o error inesperado de geocodificación | 502 | { "error": "<message>", "code": "GEOCODING_UNAVAILABLE" }; un error inesperado utiliza Address search is temporarily unavailable |
PUT /v2/admin/sites/:siteId/power-management configuración de topología/dominio no válida | 422 | { "error": "<message>", "code": "INVALID_POWER_MANAGEMENT_CONFIGURATION" } |
| Lo mismo, rechazo o tiempo de espera OCPP, condición de carrera o conflicto de conciliación | 409 | { "error": "<message>", "code": "POWER_MANAGEMENT_CONFLICT" } |
Errores de cargadores
mapChargerErrors() se utiliza para crear/actualizar cargadores, credenciales, ajustes de conectores, publicación, resolución de datos QR, modificación/recarga de configuración, inicio de firmware, los cuatro comandos básicos y la solicitud de programación compuesta.
| Endpoints | Estado | Cuerpo exacto |
|---|---|---|
| Cualquier operación anterior con un fallo de validación del dominio | 422 | { "validationErrors": { "<field>": ["<message>"] } } |
| Cualquier operación anterior con un conflicto de estado, unicidad, conexión/OCPP, facturación, Tagless, conector o disponibilidad | 409 | { "error": "<message>", "code": "CHARGER_CONFLICT" } |
GET /chargers/:chargerId/sessions, intervalo de tiempo predeterminado o explícito no válido | 422 | { "validationErrors": { "from": ["from must be before or equal to to"] } } o { "validationErrors": { "from": ["Session range cannot exceed 90 days"] } } |
Las operaciones de lectura simples solo devuelven las respuestas compartidas 401/403/404/429/500/503, además de 422 para la validación de consultas y rutas. La eliminación de un cargador puede devolver la respuesta compartida 500 PlainError si falla sin un error más específico.
Errores de informes
| Endpoints | Estado | Cuerpo exacto |
|---|---|---|
Intervalo de datos/exportación en el que from >= to | 422 | { "validationErrors": { "range": ["from must be earlier than to"] } } |
| Intervalo de datos/exportación superior a 90 días | 422 | { "validationErrors": { "range": ["Report ranges cannot exceed 90 days"] } } |
| Cursor opaco no válido de datos/mediciones | 422 | { "validationErrors": { "cursor": ["<message>"] } } |
GET /reports/export, el resultado supera 2.000 filas | 422 | { "error": "<message>", "code": "REPORT_EXPORT_ROW_LIMIT", "limit": 2000 } |
POST /reports/send, sin programación guardada | 409 | { "error": "A workspace report schedule must be saved before sending", "code": "REPORT_SCHEDULE_REQUIRED" } |
| Lo mismo, rechazo o fallo del servicio de correo | 502 | { "error": "Report delivery failed", "code": "REPORT_DELIVERY_FAILED" } |
| No existe el recurso propio de programación/mediciones | 404 | cuerpo compartido RESOURCE_NOT_FOUND |
La exportación correcta es binaria; todos los errores de exportación siguen siendo JSON.
Errores de tarifas
| Endpoints | Estado | Cuerpo exacto |
|---|---|---|
| Validación de dominio para creación/actualización/componentes/precio de mercado/asignación | 422 | { "validationErrors": { "<field>": ["<message>"] } } |
| Conflicto de eliminación de tarifa o de estado, dependencia o unicidad de asignación | 409 | { "error": "<message>", "code": "TARIFF_CONFLICT" } |
| Tarifa, zona de oferta, cargador, conector, asignación de tarifa u otro recurso anidado fuera de la propiedad del espacio de trabajo | 404 | cuerpo compartido RESOURCE_NOT_FOUND |
Errores de perfiles de carga
| Endpoints | Estado | Cuerpo exacto |
|---|---|---|
| Validación de dominio para creación/actualización/programación/asignación | 422 | { "validationErrors": { "<field>": ["<message>"] } } |
| Un uso protegido hace referencia al perfil | 409 | { "error": "<message>", "code": "CHARGING_PROFILE_IN_USE" } |
| Conflicto de sincronización OCPP, asignación, concurrencia u otro conflicto de perfil | 409 | { "error": "<message>", "code": "CHARGING_PROFILE_CONFLICT" } |
| Perfil, cargador, conector, asignación u otro recurso anidado fuera de la propiedad del espacio de trabajo | 404 | cuerpo compartido RESOURCE_NOT_FOUND |
Errores del dominio de usuarios
Los errores de validación de usuarios que identifican un campo utilizan ValidationError más code; los demás errores de usuarios utilizan CodedError. Todos los casos de recursos no encontrados utilizan la respuesta compartida RESOURCE_NOT_FOUND, que no revela la existencia del recurso.
| Estado | Código(s) | Cuerpo |
|---|---|---|
400 | INVALID_USER_CURSOR | { "validationErrors": { "cursor": ["The user-list cursor is invalid for the selected status"] }, "code": "INVALID_USER_CURSOR" } |
409 | USER_ALREADY_EXISTS, CUSTOMER_CONTRACT_MISSING, INVITATION_EMAIL_IN_USE, RFID_ALREADY_EXISTS, ACCESS_ALREADY_EXISTS, ACCESS_ALL_ALREADY_EXISTS, LIMIT_ALREADY_EXISTS, LOCAL_USER_ALREADY_EXISTS, PROTECTED_WORKSPACE_USER, TAGLESS_USER_PROTECTED, USER_RELATED_DATA | { "error": "<message>", "code": "<listed code>" } |
422 | INVALID_EMAIL, INVALID_RFID, INVALID_LIMIT_TYPE, INVALID_LIMIT_VALUE | { "validationErrors": { "<field>": ["<message>"] }, "code": "<listed code>" } |
422 | NO_CHARGERS_AVAILABLE | { "error": "No chargers are available", "code": "NO_CHARGERS_AVAILABLE" } |
429 | INVITATION_RESEND_THROTTLED | { "error": "Invitation resend is temporarily unavailable", "code": "INVITATION_RESEND_THROTTLED" }; incluye Retry-After |
503 | USER_CURSOR_UNAVAILABLE | { "error": "User pagination is temporarily unavailable", "code": "USER_CURSOR_UNAVAILABLE" } |
404 | RESOURCE_NOT_FOUND | { "error": "Workspace resource not found", "code": "RESOURCE_NOT_FOUND" } |
POST /users/invitations también puede devolver la respuesta compartida 403 INSUFFICIENT_SCOPE tras analizar el cuerpo si falta users:access, o si se proporcionó un RFID y falta users:rfid. Los endpoints de usuarios locales enumeran todos los ámbitos obligatorios en la Referencia de endpoints.
Los códigos de error de usuarios se aplican así:
| Familia de endpoints | Códigos del dominio de usuarios distintos de 404, además de las respuestas compartidas |
|---|---|
GET /users | INVALID_USER_CURSOR (400), USER_CURSOR_UNAVAILABLE (503) |
POST /users | USER_ALREADY_EXISTS, TAGLESS_USER_PROTECTED (409) |
PATCH /users/:userId | TAGLESS_USER_PROTECTED (409) |
DELETE /users/:userId | TAGLESS_USER_PROTECTED, PROTECTED_WORKSPACE_USER, USER_RELATED_DATA (409) |
| Lecturas de detalles del usuario, vehículos, RFID, accesos y límites | ningún código de dominio distinto de 404 |
| Creación de RFID | CUSTOMER_CONTRACT_MISSING, RFID_ALREADY_EXISTS, TAGLESS_USER_PROTECTED (409); INVALID_RFID (422) |
| Actualización/eliminación de RFID | TAGLESS_USER_PROTECTED (409) |
| Sustitución del acceso | TAGLESS_USER_PROTECTED (409); NO_CHARGERS_AVAILABLE (422) |
| Revocación del acceso | TAGLESS_USER_PROTECTED (409) |
| Creación/actualización de límite | TAGLESS_USER_PROTECTED, LIMIT_ALREADY_EXISTS (409); INVALID_LIMIT_TYPE, INVALID_LIMIT_VALUE (422) |
| Eliminación de límite | TAGLESS_USER_PROTECTED (409) |
| Creación de invitación al espacio de trabajo | CUSTOMER_CONTRACT_MISSING, INVITATION_EMAIL_IN_USE, RFID_ALREADY_EXISTS, TAGLESS_USER_PROTECTED (409); INVALID_EMAIL/INVALID_RFID (422); INVITATION_RESEND_THROTTLED (429) cuando se aplica un tiempo de espera de entrega |
| Reenvío de invitación al espacio de trabajo | INVALID_EMAIL (422), INVITATION_RESEND_THROTTLED (429) |
| Cancelación de invitación al espacio de trabajo | INVALID_EMAIL (422) |
| Creación de usuario local del cargador para un cliente existente | LOCAL_USER_ALREADY_EXISTS, TAGLESS_USER_PROTECTED (409) |
| Invitación de usuario local del cargador | LOCAL_USER_ALREADY_EXISTS, INVITATION_EMAIL_IN_USE, TAGLESS_USER_PROTECTED (409); INVALID_EMAIL (422); INVITATION_RESEND_THROTTLED (429) cuando se aplica un tiempo de espera de entrega |
| Cancelación de invitación de usuario local | INVALID_EMAIL (422) |
| Actualización/eliminación de usuario local | TAGLESS_USER_PROTECTED (409) |
Todos los resultados de propiedad y recurso no encontrado de esas familias, incluido un correo no registrado en POST /users, utilizan el cuerpo compartido 404 RESOURCE_NOT_FOUND.
Respuestas sin cuerpo y de repetición
Una respuesta 204 correcta no tiene cuerpo. Esto se aplica a todas las eliminaciones documentadas que indican 204 empty. Una repetición idempotente completada establece Idempotency-Replayed: true y utiliza el estado y el cuerpo guardados; para 204, la respuesta HTTP sigue sin cuerpo. La API nunca devuelve un objeto JSON de éxito para una operación 204 documentada.