Contractul de răspunsuri și erori al API-ului de administrare
Acest fișier completează contractul de răspuns pentru fiecare endpoint din Referința endpointurilor. Citește rândul endpointului pentru corpul său de succes și tabelele de mai jos pentru fiecare corp de nereușită comun sau specific endpointului. Implicit, erorile folosesc mai multe structuri de compatibilitate; apelanții pot opta pentru o singură anvelopă universală.
Anvelopă structurată opțională pentru erori
Trimite acest antet de cerere la orice endpoint:
X-Error-Format: envelope
Comparația valorii elimină spațiile de la capete și nu distinge literele mari de cele mici. Cu acea valoare exactă, fiecare răspuns JSON cu starea 400 sau mai mare este convertit în:
ErrorEnvelope = {
error: {
code: string,
message: string,
details: Record<string, unknown>,
requestId: string
}
}
Exemplu de conversie a unui corp de validare implicit:
{
"error": {
"code": "VALIDATION_FAILED",
"message": "Invalid request",
"details": {
"fields": {
"name": ["String must contain at least 1 character(s)"]
}
},
"requestId": "integration-42"
}
}
Regulile de conversie sunt exacte:
validationErrorsdevinedetails.fields, iarcodedevineVALIDATION_FAILEDchiar dacă corpul implicit avea și un cod de domeniu.- Un
codeimplicit la nivel superior este păstrat când nu există câmpuri de validare. - Celelalte proprietăți de nivel superior, în afară de
error,message,validationErrorsșicode, sunt mutate îndetails; de exemplu,limital exportului de rapoarte devinedetails.limit. - Un
errorde tip șir la nivel superior devinemessage. Dacă nu există, este folosită valoarea de rezervă a stării. - Codurile de rezervă sunt
AUTH_REQUIRED(401),PERMISSION_DENIED(403),RESOURCE_NOT_FOUND(404),CONFLICT(409),VALIDATION_FAILED(422și alte4xxneclasificate),RATE_LIMITED(429),EXTERNAL_PROVIDER_FAILED(502) șiINTERNAL_ERROR(alte5xx, inclusiv503). requestIdeste antetul de răspuns exactX-Request-Id. Un ID de cerere furnizat de apelant este folosit doar dacă se potrivește cu[A-Za-z0-9._:-]{1,128}după eliminarea spațiilor de la capete; altfel serverul generează un UUID.
Această transformare nu modifică starea sau antetele care nu țin de corp. Se aplică și reluărilor idempotente conform antetului X-Error-Format al cererii de reluare. Răspunsurile binare de succes rămân binare; erorile lor JSON sunt încapsulate. Tabelele rămase afișează corpurile implicite; aplicarea regulilor de mai sus produce celălalt corp de răspuns posibil pentru fiecare rând.
Notația răspunsurilor
ValidationError = {
validationErrors: Record<string, string[]>,
code?: string
}
CodedError = {
error: string,
code: string,
// a route may add fields explicitly listed below
}
PlainError = { error: string }
error și textul mesajelor de validare sunt descriptive, nu un discriminator programatic stabil. Diferențiază cazurile pe baza lui code când este prezent. Validarea cererii returnează 422 ValidationError; validarea unui obiect întreg poate produce { "validationErrors": {} } când nu este identificat un câmp individual. JSON-ul nevalid și erorile neașteptate returnează răspunsul global 500 PlainError afișat mai jos.
Toate exemplele JSON reprezintă structurile exacte ale corpului. Textul afișat ca <message> este mesajul de validare sau de operare returnat și este un șir JSON, nu o valoare literală între paranteze unghiulare.
Ordinea de procesare a cererilor
Cererile sunt procesate în această ordine:
- configurarea și autentificarea tokenurilor spațiului de lucru;
- politica gazdei și limitele de rată ale tokenului/spațiului de lucru;
- filtrarea drepturilor curente;
- pentru fiecare modificare, validare/rezervare de idempotență;
- verificările domeniilor de acces ale endpointului, validarea cererii și operațiunea solicitată.
Prin urmare, o modificare cu un token valid, dar cu domenii de acces insuficiente, trebuie în continuare să trimită Idempotency-Key. Răspunsul unei modificări 403, 404, 409 sau 422 finalizate poate fi reluat pentru aceeași cheie/cerere.
Răspunsuri de autentificare, politică și limitare a ratei
Aceste răspunsuri pot apărea la fiecare endpoint /v2/admin înregistrat, înainte de procesarea specifică endpointului.
| Stare | Când | Corp exact | Antete relevante |
|---|---|---|---|
401 | Token al spațiului de lucru lipsă, duplicat, unit prin virgule, non-Bearer, malformat, necunoscut, expirat, revocat sau nevalid din alte motive | { "error": "Unauthorized", "code": "INVALID_WORKSPACE_TOKEN" } | WWW-Authenticate: Bearer, Cache-Control: no-store |
404 | Tokenul este valid, dar gazda spațiului său de lucru nu are adminApiEnabled | { "error": "Not Found" } | Cache-Control: no-store |
429 | Cota de cereri per token sau per spațiu de lucru este epuizată | { "error": "Too many attempts. Please try again later." } | Retry-After: <seconds> |
503 | Autentificarea tokenurilor de spațiu de lucru este temporar indisponibilă | { "error": "Admin API workspace-token configuration is unavailable", "code": "WORKSPACE_API_CONFIG_UNAVAILABLE" } | — |
503 | Consultarea politicii gazdei sau autorizarea drepturilor curente eșuează | { "error": "Workspace authorization is temporarily unavailable", "code": "WORKSPACE_AUTHORIZATION_UNAVAILABLE" } | — |
Accesul API este inclus în fiecare plan. Dezactivarea setării adminApiEnabled a gazdei spațiului de lucru returnează 404; pierderea dreptului la o funcție suplimentară elimină doar domeniile de acces afectate. Refuzul domeniului de acces rezultat folosește răspunsul de mai jos, nu un flux de reîmprospătare a tokenului.
Erori de domeniu de acces, idempotență, parsare, proprietate și erori neașteptate
| Se aplică la | Stare | Corp exact | Antete/note |
|---|---|---|---|
| Fiecare rută după autentificare | 403 | { "error": "Insufficient workspace-token scope", "code": "INSUFFICIENT_SCOPE" } | Returnat când lipsește orice domeniu de acces obligatoriu. |
| Fiecare modificare | 400 | { "error": "Idempotency-Key is required for this operation", "code": "IDEMPOTENCY_KEY_REQUIRED" } | Nu a fost furnizată o cheie. |
| Fiecare modificare | 400 | { "error": "Exactly one Idempotency-Key is required", "code": "INVALID_IDEMPOTENCY_KEY" } | Antet duplicat sau unit prin virgule. |
| Fiecare modificare | 400 | { "error": "Idempotency-Key must contain 1 to 255 visible characters", "code": "INVALID_IDEMPOTENCY_KEY" } | Gol, prea lung sau conține un caracter de control. |
| Fiecare modificare | 409 | { "error": "Idempotency-Key was already used with a different request", "code": "IDEMPOTENCY_CONFLICT" } | Același token/metodă/cale/cheie, URL sau corp diferit. |
| Fiecare modificare | 409 | { "error": "Request is already processing", "code": "IDEMPOTENT_REQUEST_PROCESSING" } | Retry-After: 5. |
| Fiecare modificare | 409 | { "error": "Previous request outcome is unknown; verify its effects before attempting the operation again", "code": "IDEMPOTENCY_OUTCOME_UNKNOWN" } | Rezervarea precedentă de procesare a expirat, conexiunea s-a închis sau cererea s-a încheiat cu 5xx. |
| Fiecare modificare | 503 | { "error": "Idempotency storage unavailable", "code": "IDEMPOTENCY_UNAVAILABLE" } | API-ul nu poate verifica sau salva înregistrarea de idempotență. |
| Orice endpoint cu schemă de interogare/corp/cale nevalidă | 422 | { "validationErrors": { "<field>": ["<message>"] } } | Pot exista mai multe câmpuri/mesaje. Apelanții nu pot furniza cpoId; spațiul de lucru provine întotdeauna din token. |
| Orice resursă imbricată a spațiului de lucru negăsită sau ID din alt spațiu de lucru | 404 | { "error": "Workspace resource not found", "code": "RESOURCE_NOT_FOUND" } | Folosit consecvent, cu excepția cazului în care un tabel de mai jos precizează altfel. |
| Orice endpoint cu o eroare neașteptată | 500 | { "error": "Something went wrong" } | Pentru modificări, reîncercarea aceleiași chei ulterior produce 409 IDEMPOTENCY_OUTCOME_UNKNOWN. |
ID-urile din căile resurselor trebuie să fie numere pozitive. Un :siteId, :chargerId, :portId, :tariffId, :profileId, :assignmentId, :userId, :rfidId, :accessId, :limitId sau :localUserId nepozitiv ori nenumeric returnează 422 ValidationError, nu 400.
Erori pentru locații și gestionarea puterii
| Endpointuri | Stare | Corp exact |
|---|---|---|
| Crearea/actualizarea locației; validarea câmpurilor spațiului de lucru | 422 | { "validationErrors": { "<field>": ["<message>"] } } |
DELETE /v2/admin/sites/:siteId când locația are dependențe | 409 | { "error": "<message>", "code": "SITE_NOT_EMPTY" } |
GET /v2/admin/sites/geocode căutare normalizată nevalidă | 400 | { "error": "<message>", "code": "INVALID_GEOCODE_QUERY" } |
| La fel, coada limitată a furnizorului este plină | 429 | { "error": "<message>", "code": "GEOCODING_BUSY" }; include Retry-After când este furnizat de geocodificator |
| La fel, expirare/eroare a furnizorului sau eroare neașteptată de geocodificare | 502 | { "error": "<message>", "code": "GEOCODING_UNAVAILABLE" }; o eroare neașteptată folosește Address search is temporarily unavailable |
PUT /v2/admin/sites/:siteId/power-management configurație de topologie/domeniu nevalidă | 422 | { "error": "<message>", "code": "INVALID_POWER_MANAGEMENT_CONFIGURATION" } |
| La fel, refuz/expirare OCPP, conflict concurent sau de reconciliere | 409 | { "error": "<message>", "code": "POWER_MANAGEMENT_CONFLICT" } |
Erori ale stațiilor
mapChargerErrors() este folosit de crearea/actualizarea stațiilor, credențiale, setări de conector, listare publică, rezolvarea conținutului QR, modificarea/reîncărcarea configurației, pornirea firmware-ului, toate cele patru comenzi de bază și cererea de program compozit.
| Endpointuri | Stare | Corp exact |
|---|---|---|
| Orice operațiune de mai sus cu o eroare de validare a domeniului | 422 | { "validationErrors": { "<field>": ["<message>"] } } |
| Orice operațiune de mai sus cu un conflict de stare, unicitate, offline/OCPP, facturare, Tagless, conector sau pregătire | 409 | { "error": "<message>", "code": "CHARGER_CONFLICT" } |
GET /chargers/:chargerId/sessions, interval de timp implicit/explicit nevalid | 422 | { "validationErrors": { "from": ["from must be before or equal to to"] } } sau { "validationErrors": { "from": ["Session range cannot exceed 90 days"] } } |
Operațiunile simple de citire returnează doar răspunsurile comune 401/403/404/429/500/503, plus validarea interogării/căii 422. Ștergerea unei stații poate returna răspunsul comun 500 PlainError dacă ștergerea eșuează fără un răspuns de eroare mai specific.
Erori ale rapoartelor
| Endpointuri | Stare | Corp exact |
|---|---|---|
Interval de date/export în care from >= to | 422 | { "validationErrors": { "range": ["from must be earlier than to"] } } |
| Interval de date/export de peste 90 de zile | 422 | { "validationErrors": { "range": ["Report ranges cannot exceed 90 days"] } } |
| Cursor opac nevalid pentru date/măsurători | 422 | { "validationErrors": { "cursor": ["<message>"] } } |
GET /reports/export, rezultatul depășește 2.000 de rânduri | 422 | { "error": "<message>", "code": "REPORT_EXPORT_ROW_LIMIT", "limit": 2000 } |
POST /reports/send, niciun program salvat | 409 | { "error": "A workspace report schedule must be saved before sending", "code": "REPORT_SCHEDULE_REQUIRED" } |
| La fel, serviciul de email respinge/eșuează | 502 | { "error": "Report delivery failed", "code": "REPORT_DELIVERY_FAILED" } |
| Resursă de program/măsurători deținută absentă | 404 | corp comun RESOURCE_NOT_FOUND |
Exportul reușit este binar; toate erorile de export rămân JSON.
Erori ale tarifelor
| Endpointuri | Stare | Corp exact |
|---|---|---|
| Validarea domeniului pentru creare/actualizare/componente/prețuri de piață/atribuire | 422 | { "validationErrors": { "<field>": ["<message>"] } } |
| Conflict de stare/dependență/unicitate la ștergerea sau atribuirea tarifului | 409 | { "error": "<message>", "code": "TARIFF_CONFLICT" } |
| Tarif, zonă de ofertare, stație, conector, atribuire de tarif sau altă resursă imbricată care nu este deținută | 404 | corp comun RESOURCE_NOT_FOUND |
Erori ale profilurilor de încărcare
| Endpointuri | Stare | Corp exact |
|---|---|---|
| Validarea domeniului pentru creare/actualizare/program/atribuire | 422 | { "validationErrors": { "<field>": ["<message>"] } } |
| Profilul este referit de o utilizare protejată | 409 | { "error": "<message>", "code": "CHARGING_PROFILE_IN_USE" } |
| Conflict de sincronizare OCPP, atribuire, concurență sau alt conflict de profil | 409 | { "error": "<message>", "code": "CHARGING_PROFILE_CONFLICT" } |
| Profil, stație, conector, atribuire sau altă resursă imbricată care nu este deținută | 404 | corp comun RESOURCE_NOT_FOUND |
Erori ale domeniului utilizatorilor
Erorile de validare ale utilizatorilor care identifică un câmp folosesc ValidationError plus code; celelalte erori ale utilizatorilor folosesc CodedError. Toate cazurile de resurse lipsă folosesc răspunsul comun RESOURCE_NOT_FOUND, care nu permite enumerarea.
| Stare | Cod/Coduri | Corp |
|---|---|---|
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" }; include 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 poate returna și răspunsul comun 403 INSUFFICIENT_SCOPE după parsarea corpului dacă lipsește users:access sau dacă a fost furnizat un RFID și lipsește users:rfid. Endpointurile pentru utilizatori locali enumeră fiecare domeniu de acces obligatoriu în Referința endpointurilor.
Codurile de eroare ale utilizatorilor se aplică astfel:
| Familie de endpointuri | Coduri non-404 ale domeniului utilizatorilor, pe lângă răspunsurile comune |
|---|---|
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) |
| Detalii utilizator, vehicule, citiri RFID/acces/limită | niciun cod de domeniu non-404 |
| Crearea unui RFID | CUSTOMER_CONTRACT_MISSING, RFID_ALREADY_EXISTS, TAGLESS_USER_PROTECTED (409); INVALID_RFID (422) |
| Actualizarea/ștergerea unui RFID | TAGLESS_USER_PROTECTED (409) |
| Înlocuirea accesului | TAGLESS_USER_PROTECTED (409); NO_CHARGERS_AVAILABLE (422) |
| Revocarea accesului | TAGLESS_USER_PROTECTED (409) |
| Crearea/actualizarea limitei | TAGLESS_USER_PROTECTED, LIMIT_ALREADY_EXISTS (409); INVALID_LIMIT_TYPE, INVALID_LIMIT_VALUE (422) |
| Ștergerea limitei | TAGLESS_USER_PROTECTED (409) |
| Crearea invitației în spațiul de lucru | CUSTOMER_CONTRACT_MISSING, INVITATION_EMAIL_IN_USE, RFID_ALREADY_EXISTS, TAGLESS_USER_PROTECTED (409); INVALID_EMAIL/INVALID_RFID (422); INVITATION_RESEND_THROTTLED (429) când se aplică intervalul de așteptare pentru livrare |
| Retrimiterea invitației în spațiul de lucru | INVALID_EMAIL (422), INVITATION_RESEND_THROTTLED (429) |
| Anularea invitației în spațiul de lucru | INVALID_EMAIL (422) |
| Crearea unui utilizator local al stației pentru un client existent | LOCAL_USER_ALREADY_EXISTS, TAGLESS_USER_PROTECTED (409) |
| Invitație de utilizator local al stației | LOCAL_USER_ALREADY_EXISTS, INVITATION_EMAIL_IN_USE, TAGLESS_USER_PROTECTED (409); INVALID_EMAIL (422); INVITATION_RESEND_THROTTLED (429) când se aplică intervalul de așteptare pentru livrare |
| Anularea invitației unui utilizator local | INVALID_EMAIL (422) |
| Actualizarea/ștergerea unui utilizator local | TAGLESS_USER_PROTECTED (409) |
Toate rezultatele privind proprietatea și resursele lipsă din acele familii, inclusiv o adresă de email neînregistrată pe POST /users, folosesc corpul comun 404 RESOURCE_NOT_FOUND.
Răspunsuri fără corp și de reluare
Un răspuns 204 reușit nu are corp. Acest lucru se aplică fiecărei ștergeri documentate care enumeră 204 empty. O reluare idempotentă finalizată setează Idempotency-Replayed: true și folosește starea/corpul stocat; pentru 204, răspunsul HTTP rămâne fără corp. API-ul nu returnează niciodată un obiect JSON de succes pentru o operațiune 204 documentată.