Răspunsuri și erori

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:

  • validationErrors devine details.fields, iar code devine VALIDATION_FAILED chiar dacă corpul implicit avea și un cod de domeniu.
  • Un code implicit 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 și code, sunt mutate în details; de exemplu, limit al exportului de rapoarte devine details.limit.
  • Un error de tip șir la nivel superior devine message. 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 alte 4xx neclasificate), RATE_LIMITED (429), EXTERNAL_PROVIDER_FAILED (502) și INTERNAL_ERROR (alte 5xx, inclusiv 503).
  • requestId este antetul de răspuns exact X-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:

  1. configurarea și autentificarea tokenurilor spațiului de lucru;
  2. politica gazdei și limitele de rată ale tokenului/spațiului de lucru;
  3. filtrarea drepturilor curente;
  4. pentru fiecare modificare, validare/rezervare de idempotență;
  5. 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.

StareCândCorp exactAntete relevante
401Token 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
404Tokenul este valid, dar gazda spațiului său de lucru nu are adminApiEnabled{ "error": "Not Found" }Cache-Control: no-store
429Cota de cereri per token sau per spațiu de lucru este epuizată{ "error": "Too many attempts. Please try again later." }Retry-After: <seconds>
503Autentificarea tokenurilor de spațiu de lucru este temporar indisponibilă{ "error": "Admin API workspace-token configuration is unavailable", "code": "WORKSPACE_API_CONFIG_UNAVAILABLE" }—
503Consultarea 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ă laStareCorp exactAntete/note
Fiecare rută după autentificare403{ "error": "Insufficient workspace-token scope", "code": "INSUFFICIENT_SCOPE" }Returnat când lipsește orice domeniu de acces obligatoriu.
Fiecare modificare400{ "error": "Idempotency-Key is required for this operation", "code": "IDEMPOTENCY_KEY_REQUIRED" }Nu a fost furnizată o cheie.
Fiecare modificare400{ "error": "Exactly one Idempotency-Key is required", "code": "INVALID_IDEMPOTENCY_KEY" }Antet duplicat sau unit prin virgule.
Fiecare modificare400{ "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 modificare409{ "error": "Idempotency-Key was already used with a different request", "code": "IDEMPOTENCY_CONFLICT" }Același token/metodă/cale/cheie, URL sau corp diferit.
Fiecare modificare409{ "error": "Request is already processing", "code": "IDEMPOTENT_REQUEST_PROCESSING" }Retry-After: 5.
Fiecare modificare409{ "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 modificare503{ "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 lucru404{ "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

EndpointuriStareCorp exact
Crearea/actualizarea locației; validarea câmpurilor spațiului de lucru422{ "validationErrors": { "<field>": ["<message>"] } }
DELETE /v2/admin/sites/:siteId când locația are dependențe409{ "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 geocodificare502{ "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 reconciliere409{ "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.

EndpointuriStareCorp exact
Orice operațiune de mai sus cu o eroare de validare a domeniului422{ "validationErrors": { "<field>": ["<message>"] } }
Orice operațiune de mai sus cu un conflict de stare, unicitate, offline/OCPP, facturare, Tagless, conector sau pregătire409{ "error": "<message>", "code": "CHARGER_CONFLICT" }
GET /chargers/:chargerId/sessions, interval de timp implicit/explicit nevalid422{ "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

EndpointuriStareCorp exact
Interval de date/export în care from >= to422{ "validationErrors": { "range": ["from must be earlier than to"] } }
Interval de date/export de peste 90 de zile422{ "validationErrors": { "range": ["Report ranges cannot exceed 90 days"] } }
Cursor opac nevalid pentru date/măsurători422{ "validationErrors": { "cursor": ["<message>"] } }
GET /reports/export, rezultatul depășește 2.000 de rânduri422{ "error": "<message>", "code": "REPORT_EXPORT_ROW_LIMIT", "limit": 2000 }
POST /reports/send, niciun program salvat409{ "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ă404corp comun RESOURCE_NOT_FOUND

Exportul reușit este binar; toate erorile de export rămân JSON.

Erori ale tarifelor

EndpointuriStareCorp exact
Validarea domeniului pentru creare/actualizare/componente/prețuri de piață/atribuire422{ "validationErrors": { "<field>": ["<message>"] } }
Conflict de stare/dependență/unicitate la ștergerea sau atribuirea tarifului409{ "error": "<message>", "code": "TARIFF_CONFLICT" }
Tarif, zonă de ofertare, stație, conector, atribuire de tarif sau altă resursă imbricată care nu este deținută404corp comun RESOURCE_NOT_FOUND

Erori ale profilurilor de încărcare

EndpointuriStareCorp exact
Validarea domeniului pentru creare/actualizare/program/atribuire422{ "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 profil409{ "error": "<message>", "code": "CHARGING_PROFILE_CONFLICT" }
Profil, stație, conector, atribuire sau altă resursă imbricată care nu este deținută404corp 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.

StareCod/CoduriCorp
400INVALID_USER_CURSOR{ "validationErrors": { "cursor": ["The user-list cursor is invalid for the selected status"] }, "code": "INVALID_USER_CURSOR" }
409USER_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>" }
422INVALID_EMAIL, INVALID_RFID, INVALID_LIMIT_TYPE, INVALID_LIMIT_VALUE{ "validationErrors": { "<field>": ["<message>"] }, "code": "<listed code>" }
422NO_CHARGERS_AVAILABLE{ "error": "No chargers are available", "code": "NO_CHARGERS_AVAILABLE" }
429INVITATION_RESEND_THROTTLED{ "error": "Invitation resend is temporarily unavailable", "code": "INVITATION_RESEND_THROTTLED" }; include Retry-After
503USER_CURSOR_UNAVAILABLE{ "error": "User pagination is temporarily unavailable", "code": "USER_CURSOR_UNAVAILABLE" }
404RESOURCE_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 endpointuriCoduri non-404 ale domeniului utilizatorilor, pe lângă răspunsurile comune
GET /usersINVALID_USER_CURSOR (400), USER_CURSOR_UNAVAILABLE (503)
POST /usersUSER_ALREADY_EXISTS, TAGLESS_USER_PROTECTED (409)
PATCH /users/:userIdTAGLESS_USER_PROTECTED (409)
DELETE /users/:userIdTAGLESS_USER_PROTECTED, PROTECTED_WORKSPACE_USER, USER_RELATED_DATA (409)
Detalii utilizator, vehicule, citiri RFID/acces/limităniciun cod de domeniu non-404
Crearea unui RFIDCUSTOMER_CONTRACT_MISSING, RFID_ALREADY_EXISTS, TAGLESS_USER_PROTECTED (409); INVALID_RFID (422)
Actualizarea/ștergerea unui RFIDTAGLESS_USER_PROTECTED (409)
Înlocuirea accesuluiTAGLESS_USER_PROTECTED (409); NO_CHARGERS_AVAILABLE (422)
Revocarea accesuluiTAGLESS_USER_PROTECTED (409)
Crearea/actualizarea limiteiTAGLESS_USER_PROTECTED, LIMIT_ALREADY_EXISTS (409); INVALID_LIMIT_TYPE, INVALID_LIMIT_VALUE (422)
Ștergerea limiteiTAGLESS_USER_PROTECTED (409)
Crearea invitației în spațiul de lucruCUSTOMER_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 lucruINVALID_EMAIL (422), INVITATION_RESEND_THROTTLED (429)
Anularea invitației în spațiul de lucruINVALID_EMAIL (422)
Crearea unui utilizator local al stației pentru un client existentLOCAL_USER_ALREADY_EXISTS, TAGLESS_USER_PROTECTED (409)
Invitație de utilizator local al stațieiLOCAL_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 localINVALID_EMAIL (422)
Actualizarea/ștergerea unui utilizator localTAGLESS_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ă.