Отговори и грешки

Договор за отговори и грешки на Admin API

Този файл допълва договора за отговори за всяка крайна точка в Справочник за крайни точки. Прочетете реда на крайната точка за успешното тяло и таблиците по-долу за всички общи или специфични неуспешни тела. По подразбиране грешките използват няколко съвместими структури; клиентите могат да изберат една универсална обвивка.

Незадължителна структурирана обвивка за грешки

Изпратете тази заглавка на заявката към която и да е крайна точка:

X-Error-Format: envelope

Стойността се сравнява след премахване на крайните интервали, без значение на регистъра. При точно тази стойност всеки JSON отговор със състояние 400 или по-високо се преобразува в:

ErrorEnvelope = {
  error: {
    code: string,
    message: string,
    details: Record<string, unknown>,
    requestId: string
  }
}

Примерно преобразуване на стандартно тяло за валидация:

{
  "error": {
    "code": "VALIDATION_FAILED",
    "message": "Invalid request",
    "details": {
      "fields": {
        "name": ["String must contain at least 1 character(s)"]
      }
    },
    "requestId": "integration-42"
  }
}

Правилата за преобразуване са точни:

  • validationErrors става details.fields, а code става VALIDATION_FAILED, дори когато стандартното тяло има и домейн код.
  • При липса на полета за валидация се запазва code по подразбиране на най-горно ниво.
  • Другите свойства на най-горно ниво, освен error, message, validationErrors и code, се преместват в details; например limit при експорт на отчет става details.limit.
  • Текстово error на най-горно ниво става message. Ако липсва, се използва резервната стойност за състоянието.
  • Резервните кодове са AUTH_REQUIRED (401), PERMISSION_DENIED (403), RESOURCE_NOT_FOUND (404), CONFLICT (409), VALIDATION_FAILED (422 и други некласифицирани 4xx), RATE_LIMITED (429), EXTERNAL_PROVIDER_FAILED (502) и INTERNAL_ERROR (други 5xx, включително 503).
  • requestId е точната заглавка X-Request-Id на отговора. Подаден от клиента ID на заявка се използва само ако след премахване на крайните интервали съответства на [A-Za-z0-9._:-]{1,128}; иначе сървърът генерира UUID.

Преобразуването не променя състоянието или заглавките, несвързани с тялото. То важи и за идемпотентни повторения според заглавката X-Error-Format на повторената заявка. Двоичните успешни отговори остават двоични; JSON грешките им се обвиват. Останалите таблици показват стандартните тела; правилата по-горе дават другото възможно тяло за всеки ред.

Нотация на отговорите

ValidationError = {
  validationErrors: Record<string, string[]>,
  code?: string
}

CodedError = {
  error: string,
  code: string,
  // a route may add fields explicitly listed below
}

PlainError = { error: string }

error и текстът на съобщението за валидация са описателни, а не стабилен програмен разграничител. Разграничавайте по code, когато присъства. Валидацията на заявката връща 422 ValidationError; валидацията на цял обект може да даде { "validationErrors": {} }, когато не е посочено отделно поле. Невалиден JSON и неочаквани грешки връщат глобалното 500 PlainError, показано по-долу.

Всички JSON примери показват точната структура на тялото. Текстът <message> е върнатото съобщение за валидация или операция и представлява JSON низ, а не буквална стойност в ъглови скоби.

Ред на обработка на заявки

Заявките се обработват в този ред:

  1. конфигурация и удостоверяване с токен на работно пространство;
  2. политика на хоста и лимити на заявки за токен/работно пространство;
  3. филтриране по текущи права;
  4. за всяка промяна — валидация/заявяване на идемпотентност;
  5. проверки на обхвата на крайната точка, валидация на заявката и заявената операция.

Следователно промяна с валиден токен, но недостатъчен обхват, все пак трябва да изпрати Idempotency-Key. Завършен отговор за промяна 403, 404, 409 или 422 може да бъде повторен със същия ключ/заявка.

Отговори за удостоверяване, политики и ограничаване на заявки

Тези отговори могат да възникнат на всяка регистрирана крайна точка /v2/admin преди специфичната ѝ обработка.

СъстояниеКогаТочно тялоПриложими заглавки
401Липсващ, дублиран, съединен със запетая, не-Bearer, неправилно оформен, непознат, изтекъл, отнет или иначе невалиден токен на работното пространство{ "error": "Unauthorized", "code": "INVALID_WORKSPACE_TOKEN" }WWW-Authenticate: Bearer, Cache-Control: no-store
404Токенът е валиден, но хостът на работното му пространство няма adminApiEnabled{ "error": "Not Found" }Cache-Control: no-store
429Лимитът на заявките за токен или работно пространство е изчерпан{ "error": "Too many attempts. Please try again later." }Retry-After: <seconds>
503Удостоверяването с токен на работно пространство временно не е достъпно{ "error": "Admin API workspace-token configuration is unavailable", "code": "WORKSPACE_API_CONFIG_UNAVAILABLE" }—
503Проверката на политиката на хоста или оторизацията на текущите права е неуспешна{ "error": "Workspace authorization is temporarily unavailable", "code": "WORKSPACE_AUTHORIZATION_UNAVAILABLE" }—

API достъпът е включен във всеки план. Изключването на adminApiEnabled за хоста на работното пространство връща 404; загубата на допълнително право за функция премахва само засегнатите обхвати. Полученият отказ за обхват използва отговора по-долу, а не процес за обновяване на токен.

Обхват, идемпотентност, парсване, собственост и неочаквани грешки

Прилага се заСъстояниеТочно тялоЗаглавки/бележки
Всеки маршрут след удостоверяване403{ "error": "Insufficient workspace-token scope", "code": "INSUFFICIENT_SCOPE" }Връща се, когато липсва който и да е задължителен обхват.
Всяка промяна400{ "error": "Idempotency-Key is required for this operation", "code": "IDEMPOTENCY_KEY_REQUIRED" }Не е подаден ключ.
Всяка промяна400{ "error": "Exactly one Idempotency-Key is required", "code": "INVALID_IDEMPOTENCY_KEY" }Дублирана или съединена със запетая заглавка.
Всяка промяна400{ "error": "Idempotency-Key must contain 1 to 255 visible characters", "code": "INVALID_IDEMPOTENCY_KEY" }Празно, твърде дълго или съдържа контролен знак.
Всяка промяна409{ "error": "Idempotency-Key was already used with a different request", "code": "IDEMPOTENCY_CONFLICT" }Същите токен/метод/път/ключ, различни URL или тяло.
Всяка промяна409{ "error": "Request is already processing", "code": "IDEMPOTENT_REQUEST_PROCESSING" }Retry-After: 5.
Всяка промяна409{ "error": "Previous request outcome is unknown; verify its effects before attempting the operation again", "code": "IDEMPOTENCY_OUTCOME_UNKNOWN" }Предишният наем за обработка е изтекъл, връзката е затворена или заявката е приключила с 5xx.
Всяка промяна503{ "error": "Idempotency storage unavailable", "code": "IDEMPOTENCY_UNAVAILABLE" }API не може да провери или запази записа за идемпотентност.
Всяка крайна точка с невалидна схема на заявката/тялото/пътя422{ "validationErrors": { "<field>": ["<message>"] } }Може да има няколко полета/съобщения. Клиентите не могат да подават cpoId; работното пространство винаги идва от токена.
Всеки липсващ вложен ресурс или идентификатор от друго работно пространство404{ "error": "Workspace resource not found", "code": "RESOURCE_NOT_FOUND" }Използва се последователно, освен ако таблица по-долу не посочва друго.
Всяка крайна точка с неочаквана грешка500{ "error": "Something went wrong" }При промени повторен опит със същия ключ по-късно дава 409 IDEMPOTENCY_OUTCOME_UNKNOWN.

ID на ресурсите в пътя трябва да са положителни числа. Неположително или нечислово :siteId, :chargerId, :portId, :tariffId, :profileId, :assignmentId, :userId, :rfidId, :accessId, :limitId или :localUserId връща 422 ValidationError, а не 400.

Грешки на обекти и управление на мощността

Крайни точкиСъстояниеТочно тяло
Създаване/актуализация на обект; валидация на полета на работното пространство422{ "validationErrors": { "<field>": ["<message>"] } }
DELETE /v2/admin/sites/:siteId, когато обектът има зависимости409{ "error": "<message>", "code": "SITE_NOT_EMPTY" }
GET /v2/admin/sites/geocode невалидно нормализирано търсене400{ "error": "<message>", "code": "INVALID_GEOCODE_QUERY" }
Същото, ограничената опашка на доставчика е пълна429{ "error": "<message>", "code": "GEOCODING_BUSY" }; включва Retry-After, когато е предоставено от геокодера
Същото, изтекло време/грешка на доставчика или неочаквана грешка на геокодера502{ "error": "<message>", "code": "GEOCODING_UNAVAILABLE" }; неочаквана грешка използва Address search is temporarily unavailable
PUT /v2/admin/sites/:siteId/power-management невалидна топология/домейн конфигурация422{ "error": "<message>", "code": "INVALID_POWER_MANAGEMENT_CONFIGURATION" }
Същото, отказ/изтекло време на OCPP, паралелна промяна или конфликт при съгласуване409{ "error": "<message>", "code": "POWER_MANAGEMENT_CONFLICT" }

Грешки на станции

mapChargerErrors() се използва за създаване/актуализация на станция, данни за достъп, настройки на конектор, публично показване, разрешаване на QR съдържание, промяна/презареждане на конфигурация, стартиране на фърмуер, всичките четири основни команди и заявка за съставен график.

Крайни точкиСъстояниеТочно тяло
Всяка горна операция с грешка при валидация на домейна422{ "validationErrors": { "<field>": ["<message>"] } }
Всяка горна операция с конфликт на състояние, уникалност, офлайн/OCPP, плащане, Tagless, конектор или готовност409{ "error": "<message>", "code": "CHARGER_CONFLICT" }
GET /chargers/:chargerId/sessions, невалиден стандартен/изричен времеви период422{ "validationErrors": { "from": ["from must be before or equal to to"] } } или { "validationErrors": { "from": ["Session range cannot exceed 90 days"] } }

Обикновените операции за четене връщат само общите отговори 401/403/404/429/500/503 и валидация 422 на заявката/пътя. Изтриването на станция може да върне общото 500 PlainError, ако е неуспешно без по-конкретен отговор за грешка.

Грешки на отчети

Крайни точкиСъстояниеТочно тяло
Период на данни/експорт, при който from >= to422{ "validationErrors": { "range": ["from must be earlier than to"] } }
Период на данни/експорт над 90 дни422{ "validationErrors": { "range": ["Report ranges cannot exceed 90 days"] } }
Невалиден непрозрачен курсор за данни/измервания422{ "validationErrors": { "cursor": ["<message>"] } }
GET /reports/export, резултатът надхвърля 2000 реда422{ "error": "<message>", "code": "REPORT_EXPORT_ROW_LIMIT", "limit": 2000 }
POST /reports/send, няма запазен график409{ "error": "A workspace report schedule must be saved before sending", "code": "REPORT_SCHEDULE_REQUIRED" }
Същото, пощенската услуга отказва/е неуспешна502{ "error": "Report delivery failed", "code": "REPORT_DELIVERY_FAILED" }
Липсва собствен ресурс за график/измервания404общо тяло RESOURCE_NOT_FOUND

Успешният експорт е двоичен; всички грешки при експорт остават JSON.

Грешки на тарифи

Крайни точкиСъстояниеТочно тяло
Домейн валидация при създаване/актуализация/компоненти/пазарни цени/присвояване422{ "validationErrors": { "<field>": ["<message>"] } }
Конфликт на състояние/зависимост/уникалност при изтриване или присвояване на тарифа409{ "error": "<message>", "code": "TARIFF_CONFLICT" }
Тарифа, ценова зона, станция, конектор, присвояване на тарифа или друг вложен ресурс не принадлежи на собственика404общо тяло RESOURCE_NOT_FOUND

Грешки на профили за зареждане

Крайни точкиСъстояниеТочно тяло
Домейн валидация при създаване/актуализация/график/присвояване422{ "validationErrors": { "<field>": ["<message>"] } }
Профилът се използва от защитена употреба409{ "error": "<message>", "code": "CHARGING_PROFILE_IN_USE" }
Конфликт на OCPP синхронизация, присвояване, паралелна промяна или друг конфликт на профил409{ "error": "<message>", "code": "CHARGING_PROFILE_CONFLICT" }
Профил, станция, конектор, присвояване или друг вложен ресурс не принадлежи на собственика404общо тяло RESOURCE_NOT_FOUND

Грешки в потребителския домейн

Грешките при валидация на потребител, посочващи поле, използват ValidationError и code; останалите потребителски грешки използват CodedError. Всички случаи на липсващ ресурс използват общия отговор RESOURCE_NOT_FOUND, който не разкрива съществуването на ресурси.

СъстояниеКод(ове)Тяло
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" }; включва 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 може да върне и общото 403 INSUFFICIENT_SCOPE след парсване на тялото, ако липсва users:access, или ако е подаден RFID и липсва users:rfid. Крайните точки за локални потребители изброяват всеки задължителен обхват в Справочник за крайни точки.

Кодовете за потребителски грешки се прилагат така:

Група крайни точкиДомейн кодове за потребители, различни от 404, в допълнение към общите отговори
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)
Четене на детайли на потребител, автомобили, RFID/достъп/лимитиняма домейн код, различен от 404
Създаване на RFIDCUSTOMER_CONTRACT_MISSING, RFID_ALREADY_EXISTS, TAGLESS_USER_PROTECTED (409); INVALID_RFID (422)
Актуализация/изтриване на RFIDTAGLESS_USER_PROTECTED (409)
Замяна на достъпTAGLESS_USER_PROTECTED (409); NO_CHARGERS_AVAILABLE (422)
Отнемане на достъпTAGLESS_USER_PROTECTED (409)
Създаване/актуализация на лимитTAGLESS_USER_PROTECTED, LIMIT_ALREADY_EXISTS (409); INVALID_LIMIT_TYPE, INVALID_LIMIT_VALUE (422)
Изтриване на лимитTAGLESS_USER_PROTECTED (409)
Създаване на покана за работно пространствоCUSTOMER_CONTRACT_MISSING, INVITATION_EMAIL_IN_USE, RFID_ALREADY_EXISTS, TAGLESS_USER_PROTECTED (409); INVALID_EMAIL/INVALID_RFID (422); INVITATION_RESEND_THROTTLED (429), когато важи изчакване за доставка
Повторно изпращане на покана за работно пространствоINVALID_EMAIL (422), INVITATION_RESEND_THROTTLED (429)
Отмяна на покана за работно пространствоINVALID_EMAIL (422)
Създаване на локален потребител на станция за съществуващ клиентLOCAL_USER_ALREADY_EXISTS, TAGLESS_USER_PROTECTED (409)
Покана за локален потребител на станцияLOCAL_USER_ALREADY_EXISTS, INVITATION_EMAIL_IN_USE, TAGLESS_USER_PROTECTED (409); INVALID_EMAIL (422); INVITATION_RESEND_THROTTLED (429), когато важи изчакване за доставка
Отмяна на покана за локален потребителINVALID_EMAIL (422)
Актуализация/изтриване на локален потребителTAGLESS_USER_PROTECTED (409)

Всички резултати за собственост и липсващи ресурси в тези групи, включително нерегистриран имейл при POST /users, използват общото тяло 404 RESOURCE_NOT_FOUND.

Отговори без тяло и при повторение

Успешният отговор 204 няма тяло. Това важи за всяко документирано изтриване с 204 empty. Завършено идемпотентно повторение задава Idempotency-Replayed: true и използва запазените състояние/тяло; за 204 HTTP отговорът остава без тяло. API никога не връща успешен JSON обект за документирана операция 204.