# Erreurs > Le format des erreurs, tous les statuts et codes renvoyés par l’API, les erreurs à retenter, et un gestionnaire d’erreurs Node prêt à copier. Quand une requête échoue, l’API renvoie un statut 4xx ou 5xx et un corps JSON avec un `code` stable. Basez votre logique sur `code`. Le texte de `error` s’adresse à des personnes et peut changer. ## Le format ```json { "error": "This API key doesn't have the earnings:read scope.", "code": "insufficient_scope", "scope": "earnings:read" } ``` | Champ | Toujours présent | Signification | | --- | --- | --- | | `error` | Oui | Ce qui s’est mal passé, en toutes lettres. Peut être journalisé ou affiché à un opérateur sans risque. | | `code` | Oui | Un code stable. Voir les tableaux ci-dessous. | | `field` | Avec `invalid` | Le paramètre ou le champ du corps en cause. | | `scope` | Avec `insufficient_scope` | Le scope dont la clé a besoin. | Quelques erreurs ajoutent leurs propres champs. Par exemple, `409 upload_incomplete` liste les parties `missing` et `wrong_size`. ## Erreurs possibles sur tous les endpoints | Statut | `code` | Signification | Retenter ? | | --- | --- | --- | --- | | 400 | `invalid` | Un paramètre est incorrect. `field` l’indique. | Non. Corrigez la requête. | | 401 | `unauthenticated` | Aucun en-tête `Authorization: Bearer`. | Non | | 401 | `invalid_key` | La clé n’existe pas. | Non | | 401 | `key_revoked` | La clé a été révoquée. Créez-en une nouvelle. | Non | | 401 | `key_expired` | La clé a expiré. Créez-en une nouvelle. | Non | | 401 | `test_keys_retired` | Une clé `hm_test_`, retirée le 12 octobre 2026. Utilisez une clé `hm_live_`. | Non | | 403 | `insufficient_scope` | La clé n’a pas le scope requis par cet endpoint. `scope` l’indique. | Non | | 403 | `account_inactive` | Votre compte n’est pas actif. | Non | | 403 | `api_not_in_plan` | Votre offre n’inclut pas l’API. Elle est incluse dans Enterprise et Custom. | Non | | 404 | `not_found` | Endpoint inexistant, ou ressource qui ne vous appartient pas. | Non | | 429 | `rate_limited` | Limite par minute de cette clé dépassée. | Oui, après `Retry-After` secondes | | 500 | `server_error` | Un problème est survenu de notre côté. | Oui, avec un délai croissant | `404 not_found` couvre à la fois « n’existe pas » et « appartient à un autre compte ». L’API ne vous révèle jamais l’existence de la sortie de quelqu’un d’autre. ## Erreurs propres à certains endpoints | Statut | `code` | Où | Signification | | --- | --- | --- | --- | | 409 | `exists` | `POST /members/invite` | Un compte existe déjà avec cette adresse e-mail. | | 413 | `too_large` | `POST /ddex/validate` | Trop volumineux pour un test. Livrez-le avec `POST /ddex`. | | 413 | `too_large` | `POST /ddex` | Plus de 20 Go (corps brut) ou de 512 Mo (multipart). Utilisez un envoi direct. | | 429 | `busy` | `POST /ddex/validate` | Trop de tests simultanés. Réessayez dans un instant. | | 409 | `upload_incomplete` | `POST /ddex/uploads/{id}/commit` | Parties manquantes ou de mauvaise taille. Envoyez-les, puis finalisez à nouveau. | | 409 | `already_committed` | Envois directs | Déjà finalisé. `status_url` pointe vers la livraison. | | 409 | `commit_in_progress` | `POST /ddex/uploads/{id}/commit` | Une autre finalisation de cet envoi est en cours. | | 400 | `invalid_url` | `POST /webhooks`, `PATCH /webhooks/{id}` | Pas une URL https publique sur le port 443. | | 409 | `too_many` | `POST /webhooks` | Vous avez déjà 20 endpoints. | | 409 | `endpoint_disabled` | Test et nouvelle tentative de webhook | L’endpoint est désactivé. Réactivez-le d’abord. | Chaque [page de la référence](https://developer.hillsmusic.com/fr/reference/releases/) liste les erreurs de chaque endpoint. [Scopes et erreurs](https://developer.hillsmusic.com/fr/reference/scopes-and-errors/) regroupe les erreurs communes. ## Erreurs de validation Une `400 invalid` désigne le premier problème rencontré : ```json { "error": "updated_since is an ISO date or time.", "code": "invalid", "field": "updated_since" } ``` Un seul champ est signalé à la fois. Corrigez-le et renvoyez la requête. Si vous construisez un formulaire au-dessus de l’API, affichez `error` à côté du champ désigné par `field`. Les fichiers DDEX fonctionnent autrement. Un lot DDEX qui pose problème ne renvoie pas de `400`. Le test renvoie `200` avec toutes les vérifications et un verdict, et une livraison renvoie `202` puis signale les problèmes sortie par sortie. Voir [Livraison DDEX](https://developer.hillsmusic.com/fr/guides/ddex/). ## Quoi retenter - **Retentez** les `429` et les `5xx`, ainsi que les erreurs réseau comme les délais dépassés et les connexions réinitialisées. - **Ne retentez pas** les autres `4xx`. La même requête obtiendra la même réponse. Corrigez d’abord la requête, la clé ou ses scopes. Pour une `429`, attendez le nombre de secondes indiqué dans `Retry-After`. Pour une `5xx`, attendez plus longtemps après chaque essai (1 s, 2 s, 4 s…) et abandonnez au bout de quelques tentatives. Voir [Limites de débit](https://developer.hillsmusic.com/fr/guides/rate-limits/). Les lectures peuvent être retentées sans risque. Réfléchissez avant de retenter une écriture : un `POST /ddex` relancé après une réponse perdue peut mettre le lot deux fois en file d’attente. Vérifiez d’abord sa présence avec `GET /ddex`. ## Un gestionnaire d’erreurs Node ```js export class HillsError extends Error { constructor(status, body, headers) { super(body.error ?? `HTTP ${status}`); this.status = status; this.code = body.code; this.field = body.field; this.scope = body.scope; this.retryAfter = Number(headers.get("Retry-After")) || null; } } const sleep = (ms) => new Promise((r) => setTimeout(r, ms)); export async function hills(path, init = {}, tries = 4) { for (let i = 1; ; i++) { const res = await fetch("https://api.hillsmusic.com/v1" + path, { ...init, headers: { ...init.headers, Authorization: `Bearer ${process.env.HILLS_API_KEY}` }, }); const body = await res.json().catch(() => ({})); if (res.ok) return body; const err = new HillsError(res.status, body, res.headers); const retryable = res.status === 429 || res.status >= 500; if (!retryable || i >= tries) throw err; await sleep(err.retryAfter ? err.retryAfter * 1000 : 1000 * 2 ** (i - 1)); } } try { await hills("/earnings"); } catch (err) { if (err.code === "insufficient_scope") console.error(`Add ${err.scope} to this key.`); else if (err.code === "api_not_in_plan") console.error("The plan doesn't include the API."); else throw err; } ``` Avec curl, ajoutez `-w '%{http_code}'` pour voir le statut, ou `-i` pour voir les en-têtes : ```bash curl -i "https://api.hillsmusic.com/v1/releases/999999" \ -H "Authorization: Bearer $HILLS_API_KEY" # HTTP/2 404 # {"error":"…","code":"not_found"} ``` Source: https://developer.hillsmusic.com/fr/guides/errors/