Réponses et erreurs

Contrat des réponses et des erreurs de l’API d’administration

Ce fichier complète le contrat de réponse de chaque point de terminaison de Référence des points de terminaison. Consultez la ligne du point de terminaison pour le corps de réussite et les tableaux ci-dessous pour chaque corps d’échec commun ou spécifique. Par défaut, les erreurs utilisent plusieurs structures de compatibilité ; les appelants peuvent choisir une enveloppe universelle.

Enveloppe d’erreur structurée facultative

Envoyez cet en-tête de requête sur n’importe quel point de terminaison :

X-Error-Format: envelope

La comparaison de valeur ignore les espaces en début et en fin et ne tient pas compte de la casse. Avec cette valeur exacte, toute réponse JSON dont le statut est 400 ou supérieur est convertie en :

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

Exemple de conversion d’un corps de validation par défaut :

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

Les règles de conversion sont précises :

  • validationErrors devient details.fields, et code devient VALIDATION_FAILED, même si le corps par défaut avait aussi un code métier.
  • La valeur code par défaut au premier niveau est conservée en l’absence de champs de validation.
  • Les autres propriétés de premier niveau, à l’exception de error, message, validationErrors et code, sont déplacées dans details ; par exemple, limit d’un export de rapport devient details.limit.
  • Un champ error de type chaîne au premier niveau devient message. S’il n’existe pas, le message de repli associé au statut est utilisé.
  • Les codes de repli sont AUTH_REQUIRED (401), PERMISSION_DENIED (403), RESOURCE_NOT_FOUND (404), CONFLICT (409), VALIDATION_FAILED (422 et autres 4xx non classés), RATE_LIMITED (429), EXTERNAL_PROVIDER_FAILED (502) et INTERNAL_ERROR (autres 5xx, y compris 503).
  • requestId est l’en-tête de réponse X-Request-Id exact. Un ID de requête fourni par l’appelant n’est utilisé que s’il correspond à [A-Za-z0-9._:-]{1,128} après suppression des espaces de début et de fin ; sinon, le serveur génère un UUID.

Cette transformation ne change ni le statut ni les en-têtes non liés au corps. Elle s’applique aussi aux répétitions idempotentes selon l’en-tête X-Error-Format de la requête de répétition. Les réponses binaires de réussite restent binaires ; leurs erreurs JSON sont enveloppées. Les tableaux restants montrent les corps par défaut ; appliquer les règles ci-dessus donne l’autre corps de réponse possible pour chaque ligne.

Notation des réponses

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

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

PlainError = { error: string }

error et le texte des messages de validation sont descriptifs, pas des discriminants programmatiques stables. Fondez les branchements sur code lorsqu’il est présent. La validation de requête renvoie 422 ValidationError ; la validation d’un objet entier peut produire { "validationErrors": {} } lorsqu’aucun champ individuel n’est identifié. Le JSON invalide et les erreurs inattendues renvoient le 500 PlainError global ci-dessous.

Tous les exemples JSON montrent la structure exacte du corps. Le texte représenté par <message> est le message de validation ou d’opération renvoyé : il s’agit d’une chaîne JSON, pas d’une valeur littérale entre chevrons.

Ordre de traitement des requêtes

Les requêtes sont traitées dans cet ordre :

  1. la configuration et l’authentification des jetons d’espace de travail ;
  2. la politique de l’hôte et les limites de fréquence du jeton/de l’espace de travail ;
  3. le filtrage des droits actuels ;
  4. pour chaque mutation, validation et réservation de la clé d’idempotence ;
  5. les contrôles de portées du point de terminaison, la validation de la requête et l’opération demandée.

Une mutation avec un jeton valide mais aux portées insuffisantes doit donc quand même envoyer Idempotency-Key. Une réponse terminée à une mutation 403, 404, 409 ou 422 peut être répétée pour la même clé et la même requête.

Réponses d’authentification, de politique et de limitation des requêtes

Ces réponses peuvent survenir sur chaque point de terminaison /v2/admin enregistré avant son traitement spécifique.

StatutQuandCorps exactEn-têtes pertinents
401Jeton d’espace de travail absent, dupliqué, joint par des virgules, autre que Bearer, mal formé, inconnu, expiré, révoqué ou invalide pour une autre raison{ "error": "Unauthorized", "code": "INVALID_WORKSPACE_TOKEN" }WWW-Authenticate: Bearer, Cache-Control: no-store
404Le jeton est valide, mais l’hôte de son espace de travail ne dispose pas de adminApiEnabled{ "error": "Not Found" }Cache-Control: no-store
429Le quota de requêtes du jeton ou de l’espace de travail est épuisé{ "error": "Too many attempts. Please try again later." }Retry-After: <seconds>
503L’authentification par jeton d’espace de travail est temporairement indisponible{ "error": "Admin API workspace-token configuration is unavailable", "code": "WORKSPACE_API_CONFIG_UNAVAILABLE" }—
503La recherche de politique de l’hôte ou l’autorisation des droits actuels échoue{ "error": "Workspace authorization is temporarily unavailable", "code": "WORKSPACE_AUTHORIZATION_UNAVAILABLE" }—

L’accès à l’API est inclus dans toutes les offres. Désactiver le paramètre adminApiEnabled de l’hôte de l’espace de travail renvoie 404 ; perdre un droit supplémentaire à une fonctionnalité retire uniquement les portées concernées. Le refus de portée qui en résulte utilise la réponse ci-dessous, et non un mécanisme de renouvellement du jeton.

Erreurs de portée, d’idempotence, d’analyse, d’appartenance et erreurs inattendues

S’applique àStatutCorps exactEn-têtes/remarques
Chaque route après l’authentification403{ "error": "Insufficient workspace-token scope", "code": "INSUFFICIENT_SCOPE" }Renvoyé lorsqu’une portée requise est absente.
Chaque mutation400{ "error": "Idempotency-Key is required for this operation", "code": "IDEMPOTENCY_KEY_REQUIRED" }Aucune clé fournie.
Chaque mutation400{ "error": "Exactly one Idempotency-Key is required", "code": "INVALID_IDEMPOTENCY_KEY" }En-tête en double ou valeurs jointes par des virgules.
Chaque mutation400{ "error": "Idempotency-Key must contain 1 to 255 visible characters", "code": "INVALID_IDEMPOTENCY_KEY" }Vide, trop long ou contenant un caractère de contrôle.
Chaque mutation409{ "error": "Idempotency-Key was already used with a different request", "code": "IDEMPOTENCY_CONFLICT" }Même jeton/méthode/chemin/clé, mais URL ou corps différent.
Chaque mutation409{ "error": "Request is already processing", "code": "IDEMPOTENT_REQUEST_PROCESSING" }Retry-After: 5.
Chaque mutation409{ "error": "Previous request outcome is unknown; verify its effects before attempting the operation again", "code": "IDEMPOTENCY_OUTCOME_UNKNOWN" }Le bail de traitement précédent a expiré, la connexion s’est fermée ou la requête s’est terminée avec 5xx.
Chaque mutation503{ "error": "Idempotency storage unavailable", "code": "IDEMPOTENCY_UNAVAILABLE" }L’API ne peut pas vérifier ou enregistrer l’entrée d’idempotence.
Tout point de terminaison avec un schéma de requête, de corps ou de chemin invalide422{ "validationErrors": { "<field>": ["<message>"] } }Plusieurs champs ou messages peuvent être présents. Les appelants ne peuvent pas fournir cpoId ; l’espace de travail provient toujours du jeton.
Toute ressource imbriquée introuvable dans l’espace de travail ou tout ID d’un autre espace de travail404{ "error": "Workspace resource not found", "code": "RESOURCE_NOT_FOUND" }Utilisé de façon cohérente, sauf indication contraire dans un tableau ci-dessous.
Tout point de terminaison rencontrant une erreur inattendue500{ "error": "Something went wrong" }Pour les mutations, réessayer plus tard avec la même clé produit 409 IDEMPOTENCY_OUTCOME_UNKNOWN.

Les ID de ressources dans le chemin doivent être des nombres positifs. Un :siteId, :chargerId, :portId, :tariffId, :profileId, :assignmentId, :userId, :rfidId, :accessId, :limitId ou :localUserId non positif ou non numérique renvoie 422 ValidationError, et non 400.

Erreurs des sites et de gestion de la puissance

Points de terminaisonStatutCorps exact
Création/mise à jour d’un site ; validation des champs de l’espace de travail422{ "validationErrors": { "<field>": ["<message>"] } }
DELETE /v2/admin/sites/:siteId lorsque le site a des dépendances409{ "error": "<message>", "code": "SITE_NOT_EMPTY" }
GET /v2/admin/sites/geocode recherche normalisée invalide400{ "error": "<message>", "code": "INVALID_GEOCODE_QUERY" }
Identique, file d’attente limitée du fournisseur pleine429{ "error": "<message>", "code": "GEOCODING_BUSY" } ; inclut Retry-After lorsque le géocodeur le fournit
Identique, délai dépassé/défaillance du fournisseur ou erreur inattendue du géocodeur502{ "error": "<message>", "code": "GEOCODING_UNAVAILABLE" } ; une erreur inattendue utilise Address search is temporarily unavailable
PUT /v2/admin/sites/:siteId/power-management configuration de topologie/métier invalide422{ "error": "<message>", "code": "INVALID_POWER_MANAGEMENT_CONFIGURATION" }
Identique, refus OCPP/délai dépassé, concurrence ou conflit de rapprochement409{ "error": "<message>", "code": "POWER_MANAGEMENT_CONFLICT" }

Erreurs des bornes

mapChargerErrors() est utilisé pour la création/mise à jour des bornes, les identifiants, les paramètres de connecteur, la publication publique, la résolution des données QR, la modification/le rechargement de configuration, le lancement du micrologiciel, les quatre commandes de base et la demande de programmation composite.

Points de terminaisonStatutCorps exact
Toute opération ci-dessus présentant un échec de validation métier422{ "validationErrors": { "<field>": ["<message>"] } }
Toute opération ci-dessus présentant un conflit d’état, d’unicité, hors ligne/OCPP, de facturation, de mode sans badge, de connecteur ou de préparation409{ "error": "<message>", "code": "CHARGER_CONFLICT" }
GET /chargers/:chargerId/sessions, plage temporelle par défaut ou explicite invalide422{ "validationErrors": { "from": ["from must be before or equal to to"] } } ou { "validationErrors": { "from": ["Session range cannot exceed 90 days"] } }

Les simples lectures renvoient uniquement les réponses communes 401/403/404/429/500/503, ainsi que 422 pour la validation des paramètres ou du chemin. La suppression d’une borne peut renvoyer le 500 PlainError commun si elle échoue sans réponse d’erreur plus précise.

Erreurs des rapports

Points de terminaisonStatutCorps exact
Plage de données/d’export où from >= to422{ "validationErrors": { "range": ["from must be earlier than to"] } }
Plage de données/d’export supérieure à 90 jours422{ "validationErrors": { "range": ["Report ranges cannot exceed 90 days"] } }
Curseur opaque invalide pour les données/mesures422{ "validationErrors": { "cursor": ["<message>"] } }
GET /reports/export, le résultat dépasse 2 000 lignes422{ "error": "<message>", "code": "REPORT_EXPORT_ROW_LIMIT", "limit": 2000 }
POST /reports/send, aucune programmation enregistrée409{ "error": "A workspace report schedule must be saved before sending", "code": "REPORT_SCHEDULE_REQUIRED" }
Identique, refus ou défaillance du service d’e-mail502{ "error": "Report delivery failed", "code": "REPORT_DELIVERY_FAILED" }
Ressource de programmation/mesures absente du périmètre404corps commun RESOURCE_NOT_FOUND

L’export réussi est binaire ; toutes les erreurs d’export restent en JSON.

Erreurs des tarifs

Points de terminaisonStatutCorps exact
Validation métier de création/mise à jour/composants/prix du marché/attribution422{ "validationErrors": { "<field>": ["<message>"] } }
Conflit de suppression de tarif ou d’état/dépendance/unicité d’une attribution409{ "error": "<message>", "code": "TARIFF_CONFLICT" }
Tarif, zone de marché, borne, connecteur, attribution de tarif ou autre ressource imbriquée introuvable dans le périmètre404corps commun RESOURCE_NOT_FOUND

Erreurs des profils de recharge

Points de terminaisonStatutCorps exact
Validation métier de création/mise à jour/programmation/attribution422{ "validationErrors": { "<field>": ["<message>"] } }
Le profil est référencé par une utilisation protégée409{ "error": "<message>", "code": "CHARGING_PROFILE_IN_USE" }
Conflit de synchronisation OCPP, d’attribution, de concurrence ou autre conflit de profil409{ "error": "<message>", "code": "CHARGING_PROFILE_CONFLICT" }
Profil, borne, connecteur, attribution ou autre ressource imbriquée introuvable dans le périmètre404corps commun RESOURCE_NOT_FOUND

Erreurs métier des utilisateurs

Les erreurs de validation utilisateur qui identifient un champ utilisent ValidationError et code ; les autres erreurs utilisateur utilisent CodedError. Tous les cas de ressources absentes utilisent la réponse commune RESOURCE_NOT_FOUND, qui ne révèle pas l’existence des ressources.

StatutCode(s)Corps
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" } ; inclut 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 peut aussi renvoyer le 403 INSUFFICIENT_SCOPE commun après analyse du corps si users:access est absent, ou si un RFID a été fourni et que users:rfid est absent. Les points de terminaison d’utilisateur local répertorient chaque portée requise dans Référence des points de terminaison.

Les codes d’erreur utilisateur s’appliquent comme suit :

Famille de points de terminaisonCodes métier utilisateur autres que 404, en plus des réponses communes
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)
Détail utilisateur, véhicules et lectures RFID/accès/limitesaucun code métier autre que 404
Création d’un RFIDCUSTOMER_CONTRACT_MISSING, RFID_ALREADY_EXISTS, TAGLESS_USER_PROTECTED (409); INVALID_RFID (422)
Mise à jour/suppression d’un RFIDTAGLESS_USER_PROTECTED (409)
Remplacement des accèsTAGLESS_USER_PROTECTED (409); NO_CHARGERS_AVAILABLE (422)
Révocation d’un accèsTAGLESS_USER_PROTECTED (409)
Création/mise à jour d’une limiteTAGLESS_USER_PROTECTED, LIMIT_ALREADY_EXISTS (409); INVALID_LIMIT_TYPE, INVALID_LIMIT_VALUE (422)
Suppression d’une limiteTAGLESS_USER_PROTECTED (409)
Création d’une invitation d’espace de travailCUSTOMER_CONTRACT_MISSING, INVITATION_EMAIL_IN_USE, RFID_ALREADY_EXISTS, TAGLESS_USER_PROTECTED (409) ; INVALID_EMAIL/INVALID_RFID (422) ; INVITATION_RESEND_THROTTLED (429) lorsqu’un délai minimal entre envois s’applique
Renvoi d’une invitation d’espace de travailINVALID_EMAIL (422), INVITATION_RESEND_THROTTLED (429)
Annulation d’une invitation d’espace de travailINVALID_EMAIL (422)
Création d’un utilisateur local de borne pour un client existantLOCAL_USER_ALREADY_EXISTS, TAGLESS_USER_PROTECTED (409)
Invitation d’un utilisateur local de borneLOCAL_USER_ALREADY_EXISTS, INVITATION_EMAIL_IN_USE, TAGLESS_USER_PROTECTED (409) ; INVALID_EMAIL (422) ; INVITATION_RESEND_THROTTLED (429) lorsqu’un délai minimal entre envois s’applique
Annulation d’une invitation d’utilisateur localINVALID_EMAIL (422)
Mise à jour/suppression d’un utilisateur localTAGLESS_USER_PROTECTED (409)

Tous les résultats liés à l’appartenance et aux ressources absentes dans ces familles, y compris un e-mail non enregistré sur POST /users, utilisent le corps commun 404 RESOURCE_NOT_FOUND.

Réponses sans corps et réponses répétées

Une réponse 204 réussie n’a pas de corps. Cela vaut pour toute suppression documentée mentionnant 204 empty. Une répétition idempotente terminée définit Idempotency-Replayed: true et utilise le statut et le corps enregistrés ; pour 204, la réponse HTTP reste sans corps. L’API ne renvoie jamais d’objet JSON de réussite pour une opération 204 documentée.