# Livraison DDEX > Livrez en DDEX ERN : testez un lot avec POST /ddex/validate, livrez avec POST /ddex ou l’envoi direct, passez par le SFTP et lisez le rapport. Les sorties entrent dans HILLS Music sous forme de lots DDEX ERN. L’API ne crée ni ne modifie de sorties à l’unité, champ par champ. Vous envoyez le même lot que celui que vous enverriez à une plateforme, via l’API ou en SFTP. Chaque sortie qu’il contient devient un brouillon dans votre catalogue, puis passe par la vérification et la livraison aux plateformes comme d’habitude. ## Versions ERN | Version | Statut | | --- | --- | | ERN 4.3 (`http://ddex.net/xml/ern/43`) | Recommandée | | 4.2, 4.1 | Acceptées | | 3.8.2, 3.8.1, 3.8, 3.7 | Acceptées. Le rapport signale que la version est ancienne. | | Toute autre version | Refusée | Toutes les versions acceptées passent par les mêmes vérifications et le même import. Un lot est un zip contenant un ou plusieurs fichiers XML `NewReleaseMessage` ainsi que l’audio, les pochettes et les vidéos qu’ils référencent. ## Scopes | Scope | Autorise | | --- | --- | | `ddex:validate` | Les tests uniquement. Idéal pour la CI. | | `ddex:write` | Les tests, les livraisons, les envois directs et le statut des livraisons. | ## 1. Tester d’abord `POST /ddex/validate` exécute toutes les vérifications d’une livraison : le XML, les règles HILLS, les fichiers audio, pochettes et vidéos, les UPC et ISRC comparés à votre catalogue, les genres, les territoires et les accords. **Rien n’est créé** : ni sortie, ni enregistrement, ni artiste, ni code, ni livraison. Envoyez un `.zip` ou un seul `.xml`. ```bash curl -X POST "https://api.hillsmusic.com/v1/ddex/validate?member_id=41" \ -H "Authorization: Bearer $HILLS_API_KEY" \ -H "Content-Type: application/zip" \ --data-binary @batch-0001.zip ``` ```js import { readFile } from "node:fs/promises"; const res = await fetch("https://api.hillsmusic.com/v1/ddex/validate?member_id=41", { method: "POST", headers: { Authorization: `Bearer ${process.env.HILLS_API_KEY}`, "Content-Type": "application/zip" }, body: await readFile("batch-0001.zip"), }); const { data } = await res.json(); console.log(data.verdict, data.summary); for (const c of data.checks.filter((c) => c.status === "error")) console.log(c.field, c.message); ``` `member_id` désigne l’artiste ou le label auquel le lot est destiné. Omettez-le pour votre propre catalogue. Pour un fichier XML, envoyez `Content-Type: application/xml`. Vous pouvez aussi envoyer du `multipart/form-data` avec le champ `file` (jusqu’à 512 Mo). La réponse contient la version ERN, un résumé, chaque vérification par étape (`pass`, `warning`, `error`, `skipped`) et un verdict : | Verdict | Signification | | --- | --- | | `would_import` | Aucun problème. La sortie deviendrait un brouillon. | | `would_import_with_warnings` | La sortie serait importée. Lisez les avertissements. | | `would_be_flagged` | La sortie attendrait l’équipe HILLS : un retrait, ou une mise à jour d’une sortie en vérification ou en ligne. | | `would_be_rejected` | La sortie comporte des erreurs. Rien ne serait créé pour elle. | Un lot qui comporte des erreurs renvoie quand même `200` : c’est le verdict qui indique le problème. Un lot trop volumineux pour être testé renvoie `413 too_large`, et un trop grand nombre de tests simultanés peut renvoyer `429 busy`. Chaque test est aussi listé sur la page DDEX de l’application web, sous **Test reports**, pendant 90 jours. ## 2. Livrer `POST /ddex` accepte le zip en corps brut (`Content-Type: application/zip`, jusqu’à 20 Go) ou dans le champ multipart `file` (jusqu’à 512 Mo). Il renvoie immédiatement `202` : ```bash curl -X POST "https://api.hillsmusic.com/v1/ddex?member_id=41&name=batch-0001.zip" \ -H "Authorization: Bearer $HILLS_API_KEY" \ -H "Content-Type: application/zip" \ --data-binary @batch-0001.zip # {"data":{"id":311,"status":"queued","environment":"production","status_url":"/v1/ddex/311"}} ``` Pour les gros fichiers, préférez l’envoi direct. ## Envoi direct pour les lots volumineux Avec l’envoi direct, le fichier va directement dans le stockage au lieu de transiter par l’API. 1. **Démarrer.** `POST /ddex/uploads` avec `name` et `size` en octets (jusqu’à 20 Go), et `member_id` si nécessaire. 2. **Envoyer.** Jusqu’à 64 Mo, vous recevez une seule `upload.url` : envoyez-y le fichier entier en `PUT`. Au-delà de 64 Mo, vous recevez `upload.part_size` et une URL par partie. Envoyez en `PUT` chaque tranche de `part_size` octets vers son URL (la dernière tranche est plus courte). Les parties peuvent arriver dans n’importe quel ordre, et en parallèle. Ces URL sont signées : n’y envoyez aucun en-tête `Authorization`. 3. **Finaliser.** `POST /ddex/uploads/{id}/commit`. L’appel vérifie que chaque partie est arrivée avec la bonne taille, puis met le lot en file d’attente comme `POST /ddex` (`202`). ```js import { open, stat } from "node:fs/promises"; const H = { Authorization: `Bearer ${process.env.HILLS_API_KEY}`, "Content-Type": "application/json" }; const API = "https://api.hillsmusic.com/v1"; const file = "batch-0001.zip"; const { size } = await stat(file); const start = await fetch(`${API}/ddex/uploads`, { method: "POST", headers: H, body: JSON.stringify({ name: file, size, member_id: 41 }), }).then((r) => r.json()); const { id, upload } = start.data; const fh = await open(file); if (upload.url) { await fetch(upload.url, { method: "PUT", body: await fh.readFile() }); } else { for (const p of upload.parts) { const offset = (p.part_number - 1) * upload.part_size; const buf = Buffer.alloc(Math.min(upload.part_size, size - offset)); await fh.read(buf, 0, buf.length, offset); const r = await fetch(p.url, { method: "PUT", body: buf }); if (!r.ok) throw new Error(`part ${p.part_number}: ${r.status}`); } } await fh.close(); const commit = await fetch(`${API}/ddex/uploads/${id}/commit`, { method: "POST", headers: H }); console.log(commit.status, await commit.json()); // 202, then poll status_url ``` Les URL des parties sont valables 6 heures. `GET /ddex/uploads/{id}` fournit de nouvelles URL pour les parties encore manquantes, avec `received_parts` et `parts_total`. Une finalisation alors que des parties manquent renvoie `409 upload_incomplete` et liste `missing` et `wrong_size` : envoyez ces parties, puis finalisez à nouveau. `DELETE /ddex/uploads/{id}` abandonne un envoi que vous ne terminerez pas. Les envois non finalisés sont supprimés au bout de 7 jours. ## Par SFTP Chaque boîte de dépôt DDEX correspond à un identifiant SFTP avec deux dossiers. Vous recevez l’identifiant avec votre boîte de dépôt, sur la page DDEX de l’application web. | Dossier | Ce qui se passe | | --- | --- | | `/production//` | Livraison. Dès l’arrivée du marqueur, le lot est importé. | | `/test//` | Test, comme avec `POST /ddex/validate`. Rien n’est créé. Le rapport est écrit à côté : `/test/.report.txt` et `.report.json`. | Déposez le XML et ses fichiers dans le dossier du lot, puis le marqueur en dernier : `BatchComplete_*.xml`, ou n’importe quel fichier `*.complete`. Un fichier `/test/.xml` ou `.zip` seul est également testé. Tout autre fichier déposé dans `/test`, comme `ping.txt`, sert de test de connexion. Un dossier de lot de production qui ne reçoit jamais son marqueur est supprimé au bout de 7 jours. Tout ce qui se trouve dans `/test` est supprimé après le même délai. Voir [Dossier de test](https://developer.hillsmusic.com/fr/reference/test-folder/). ## 3. Lire le rapport de livraison Interrogez `GET /ddex/{id}` toutes les 10 à 30 secondes, ou abonnez-vous au [webhook](https://developer.hillsmusic.com/fr/guides/webhooks/) `ddex.import.imported`. Le statut passe par `queued` → `parsing` → `validating` → `importing`, puis se termine par : - `done` : toutes les sorties ont été importées ; - `partial` : certaines sorties ont été écartées ; - `failed` : rien n’a été importé. ```bash curl "https://api.hillsmusic.com/v1/ddex/311" \ -H "Authorization: Bearer $HILLS_API_KEY" ``` La réponse contient des compteurs et un élément par sortie, chacun avec son `outcome`, son `release_id` et ses `errors` (chaque erreur indique son champ DDEX). `GET /ddex` liste vos 100 dernières livraisons. ## Ce qui est créé ou signalé | Résultat | Quand | | --- | --- | | `created` | Une nouvelle sortie. Elle devient un brouillon dans le catalogue de `member_id`. | | `updated` | L’UPC correspond déjà à un brouillon (ou à une sortie renvoyée pour modifications) dans ce catalogue. Ce brouillon est mis à jour. | | `flagged` | Un retrait, ou une mise à jour d’une sortie en vérification ou en ligne. Elle n’est pas appliquée : l’équipe HILLS l’examine. | | `left_out` | La sortie comportait des erreurs. Rien n’a été créé pour elle. Corrigez-la et livrez-la à nouveau. | | `test` | Un message marqué `TestMessage` : vérifié, rien n’est créé. | Un ISRC que vous possédez déjà réutilise l’enregistrement correspondant. Un ISRC qui appartient à un autre compte entraîne l’exclusion de la sortie. Les brouillons passent ensuite par la vérification comme d’habitude : soumettez-les dans l’application web, ou demandez à HILLS Music d’activer la soumission automatique pour votre boîte de dépôt. Suivez-les avec [GET /releases](https://developer.hillsmusic.com/fr/reference/releases/) et des webhooks comme `release.approved` et `release.live`. Tous les paramètres figurent dans la [référence Livraisons DDEX](https://developer.hillsmusic.com/fr/reference/ddex-deliveries/). Source: https://developer.hillsmusic.com/fr/guides/ddex/