# Livraisons DDEX
> Livrez des lots DDEX ERN (4.3 recommandée) en production, testez-les d’abord (rien n’est créé), envoi direct pour les gros lots, et leur statut.
Livrez des lots DDEX ERN (4.3 recommandée) en production, testez-les d’abord (rien n’est créé), envoi direct pour les gros lots, et leur statut.
URL de base `https://api.hillsmusic.com/v1`. Chaque requête envoie une clé d’API : `Authorization: Bearer hm_live_…`.
- Tester un message ou un lot DDEX
- Livrer un lot DDEX (ERN 4.3 recommandée)
- Lister les livraisons
- Démarrer un envoi direct (lots volumineux)
- État d’un envoi direct
- Abandonner un envoi direct
- Finaliser un envoi direct
- Statut de livraison
## Tester un message ou un lot DDEX
`POST /v1/ddex/validate` · Scope : `ddex:validate` ou `ddex:write`
Le circuit de test : un .xml (Content-Type: application/xml) ou un .zip, vérifié comme une livraison (XML, règles HILLS, fichiers audio, pochettes et vidéos, UPC et ISRC comparés au catalogue). Rien n’est créé : ni sortie, ni enregistrement, ni artiste, ni code, ni livraison. Le test est listé sur la page DDEX du tableau de bord (Test reports). La réponse donne chaque vérification par étape (pass / warning / error / skipped), ce que HILLS créerait, et le verdict : would_import, would_import_with_warnings, would_be_flagged ou would_be_rejected. ddex:write fonctionne aussi.
### Paramètres
| Paramètre | Emplacement | Type | Obligatoire | Description |
| --- | --- | --- | --- | --- |
| `member_id` | query | integer | Non | L’artiste ou le label concerné (votre propre compte s’il est omis). |
| `name` | query | string | Non | Nom de fichier pour un corps brut (batch.zip par défaut, ou message.xml pour du XML). |
### Corps de la requête
Le lot : le zip que vous livrez aux plateformes (XML ERN + les ressources qu’il référence) en corps brut, un .xml seul, ou le champ multipart file (avec member_id comme champ). Types de contenu : `application/zip`, `application/xml`, `multipart/form-data`.
### Exemple de requête
```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.zip
```
### Réponse `200`
```json
{
"data": {
"ern_version": "4.3",
"verdict": "would_be_rejected",
"summary": {
"messages": 1,
"releases": 1,
"pass": 41,
"warnings": 1,
"errors": 2,
"skipped": 1
},
"checks": [
{
"stage": "release",
"label": "Label",
"status": "error",
"message": "ReleaseLabelReference is required…",
"field": "Release/ReleaseLabelReference"
}
]
}
}
```
### Erreurs
| Statut | Quand |
| --- | --- |
| 400 | invalid : un paramètre est incorrect ; field l’indique. |
| 401 | unauthenticated, invalid_key, key_revoked, key_expired ou test_keys_retired. |
| 403 | insufficient_scope : la clé n’a pas le scope requis ; scope l’indique. account_inactive ou api_not_in_plan. |
| 413 | too_large : trop volumineux pour un test ; livrez-le avec POST /ddex. |
| 429 | busy : trop de tests simultanés ; réessayez dans un instant. rate_limited : attendez le nombre de secondes indiqué par Retry-After. |
## Livrer un lot DDEX (ERN 4.3 recommandée)
`POST /v1/ddex` · Scope : `ddex:write`
Envoyez le zip que vous livrez aux plateformes : le ou les XML ERN NewReleaseMessage avec l’audio, la pochette et les vidéos qu’ils référencent. En corps brut (Content-Type: application/zip, jusqu’à 20 Go) ou dans le champ multipart file (jusqu’à 512 Mo). Chaque sortie devient un brouillon sur member_id (votre propre catalogue s’il est omis) ; un UPC déjà présent met à jour son brouillon ; les retraits et les mises à jour de sorties en ligne attendent l’équipe HILLS. ERN 4.3 (espace de noms http://ddex.net/xml/ern/43) est recommandée ; 4.2, 4.1, 3.8.x (3.8.2, 3.8.1, 3.8) et 3.7 sont acceptées et lues de la même façon (le rapport signale que la version est ancienne) ; les autres versions sont refusées. 202 avec l’identifiant de la livraison — interrogez ensuite GET /ddex/{id}.
### Paramètres
| Paramètre | Emplacement | Type | Obligatoire | Description |
| --- | --- | --- | --- | --- |
| `member_id` | query | integer | Non | L’artiste ou le label concerné (votre propre compte s’il est omis). |
| `name` | query | string | Non | Nom de fichier pour un corps brut (batch.zip par défaut). |
### Corps de la requête
Le lot : le zip que vous livrez aux plateformes (XML ERN + les ressources qu’il référence) en corps brut, un .xml seul, ou le champ multipart file (avec member_id comme champ). Types de contenu : `application/zip`, `application/xml`, `multipart/form-data`.
### Exemple de requête
```bash
curl -X POST "https://api.hillsmusic.com/v1/ddex?member_id=41" \
-H "Authorization: Bearer $HILLS_API_KEY" \
-H "Content-Type: application/zip" \
--data-binary @batch.zip
```
### Réponse `202`
```json
{
"data": {
"id": 311,
"status": "queued",
"environment": "production",
"status_url": "/v1/ddex/311"
}
}
```
### Erreurs
| Statut | Quand |
| --- | --- |
| 400 | invalid : un paramètre est incorrect ; field l’indique. |
| 401 | unauthenticated, invalid_key, key_revoked, key_expired ou test_keys_retired. |
| 403 | insufficient_scope : la clé n’a pas le scope requis ; scope l’indique. account_inactive ou api_not_in_plan. |
| 413 | too_large : plus de 20 Go (corps brut) ou de 512 Mo (multipart). |
| 429 | rate_limited : attendez le nombre de secondes indiqué par Retry-After. |
## Lister les livraisons
`GET /v1/ddex` · Scope : `ddex:write` ou `ddex:validate`
Vos 100 dernières livraisons DDEX, de la plus récente à la plus ancienne (les envois pas encore finalisés n’y figurent pas).
### Exemple de requête
```bash
curl "https://api.hillsmusic.com/v1/ddex" \
-H "Authorization: Bearer $HILLS_API_KEY"
```
### Réponse `200`
```json
{
"data": [
{
"id": 311,
"member_id": 41,
"environment": "production",
"batch_name": "batch-0001.zip",
"status": "done",
"error": null,
"message_id": "MSG-2026-0001",
"ern_version": "4.3",
"message_count": 1,
"release_count": 1,
"track_count": 12,
"created_count": 1,
"updated_count": 0,
"flagged_count": 0,
"left_out_count": 0,
"release_ids": [
912
],
"created_at": "2026-10-07T09:00:00Z",
"started_at": "2026-10-07T09:00:02Z",
"finished_at": "2026-10-07T09:01:10Z"
}
]
}
```
### Erreurs
| Statut | Quand |
| --- | --- |
| 401 | unauthenticated, invalid_key, key_revoked, key_expired ou test_keys_retired. |
| 403 | insufficient_scope : la clé n’a pas le scope requis ; scope l’indique. account_inactive ou api_not_in_plan. |
| 429 | rate_limited : attendez le nombre de secondes indiqué par Retry-After. |
## Démarrer un envoi direct (lots volumineux)
`POST /v1/ddex/uploads` · Scope : `ddex:write`
Recommandé pour les gros zips : le fichier va directement dans le stockage au lieu de transiter par l’API. Envoyez le nom du fichier et sa taille en octets (jusqu’à 20 Go). Jusqu’à 64 Mo, vous recevez une seule URL vers laquelle envoyer tout le fichier en PUT ; au-delà, une taille de partie et une URL par partie : envoyez en PUT chaque tranche de part_size octets (la dernière est plus courte) vers son URL, dans n’importe quel ordre et en parallèle. Les URL sont valables 6 heures ; GET /ddex/uploads/{id} en fournit de nouvelles pour les parties encore manquantes. Appelez ensuite POST /ddex/uploads/{id}/commit. 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.
### Corps de la requête
JSON.
| Champ | Type | Obligatoire | Description |
| --- | --- | --- | --- |
| `name` | string | Oui | Le nom du fichier (.zip ou .xml). |
| `size` | integer | Oui | La taille du fichier en octets. |
| `member_id` | integer | Non | L’artiste ou le label concerné (votre propre compte s’il est omis). |
### Exemple de requête
```bash
curl -X POST "https://api.hillsmusic.com/v1/ddex/uploads" \
-H "Authorization: Bearer $HILLS_API_KEY" \
-H "Content-Type: application/json" \
-d '{"name":"batch-0001.zip","size":1073741824,"member_id":41}'
```
### Réponse `201`
```json
{
"data": {
"id": 312,
"status": "uploading",
"environment": "production",
"name": "batch-0001.zip",
"size": 1073741824,
"expires_in": 21600,
"upload": {
"method": "multipart",
"url": null,
"part_size": 16777216,
"parts": [
{
"part_number": 1,
"url": "https://…"
}
]
},
"commit_url": "/v1/ddex/uploads/312/commit"
}
}
```
### Erreurs
| Statut | Quand |
| --- | --- |
| 400 | invalid : un paramètre est incorrect ; field l’indique. |
| 401 | unauthenticated, invalid_key, key_revoked, key_expired ou test_keys_retired. |
| 403 | insufficient_scope : la clé n’a pas le scope requis ; scope l’indique. account_inactive ou api_not_in_plan. |
| 429 | rate_limited : attendez le nombre de secondes indiqué par Retry-After. |
## État d’un envoi direct
`GET /v1/ddex/uploads/{id}` · Scope : `ddex:write`
Pour un envoi pas encore finalisé : de nouvelles URL pour les parties encore manquantes (les premières expirent au bout de 6 heures), received_parts et parts_total. Une fois finalisé : l’identifiant de sa livraison et status_url.
### Paramètres
| Paramètre | Emplacement | Type | Obligatoire | Description |
| --- | --- | --- | --- | --- |
| `id` | path | integer | Oui | L’identifiant de l’envoi. |
### Exemple de requête
```bash
curl "https://api.hillsmusic.com/v1/ddex/uploads/312" \
-H "Authorization: Bearer $HILLS_API_KEY"
```
### Réponse `200`
```json
{
"data": {
"id": 312,
"status": "uploading",
"environment": "production",
"name": "batch-0001.zip",
"size": 1073741824,
"expires_in": 21600,
"upload": {
"method": "multipart",
"url": null,
"part_size": 16777216,
"parts": [
{
"part_number": 7,
"url": "https://…"
}
]
},
"commit_url": "/v1/ddex/uploads/312/commit",
"received_parts": 63,
"parts_total": 64
}
}
```
### Erreurs
| Statut | Quand |
| --- | --- |
| 401 | unauthenticated, invalid_key, key_revoked, key_expired ou test_keys_retired. |
| 403 | insufficient_scope : la clé n’a pas le scope requis ; scope l’indique. account_inactive ou api_not_in_plan. |
| 404 | not_found : la ressource n’existe pas ou ne vous appartient pas. |
| 429 | rate_limited : attendez le nombre de secondes indiqué par Retry-After. |
## Abandonner un envoi direct
`DELETE /v1/ddex/uploads/{id}` · Scope : `ddex:write`
Abandonne un envoi que vous ne terminerez pas, avec les parties déjà envoyées. 409 s’il a déjà été finalisé.
### Paramètres
| Paramètre | Emplacement | Type | Obligatoire | Description |
| --- | --- | --- | --- | --- |
| `id` | path | integer | Oui | L’identifiant de l’envoi. |
### Exemple de requête
```bash
curl -X DELETE "https://api.hillsmusic.com/v1/ddex/uploads/312" \
-H "Authorization: Bearer $HILLS_API_KEY"
```
### Réponse `200`
```json
{
"data": {
"id": 312,
"deleted": true
}
}
```
### Erreurs
| Statut | Quand |
| --- | --- |
| 401 | unauthenticated, invalid_key, key_revoked, key_expired ou test_keys_retired. |
| 403 | insufficient_scope : la clé n’a pas le scope requis ; scope l’indique. account_inactive ou api_not_in_plan. |
| 404 | not_found : la ressource n’existe pas ou ne vous appartient pas. |
| 409 | already_committed : déjà finalisé, il ne peut plus être abandonné. |
| 429 | rate_limited : attendez le nombre de secondes indiqué par Retry-After. |
## Finaliser un envoi direct
`POST /v1/ddex/uploads/{id}/commit` · Scope : `ddex:write`
Vérifie que chaque partie est arrivée avec la bonne taille et met le lot en file d’attente exactement comme POST /ddex. 409 upload_incomplete liste les parties manquantes ou de mauvaise taille (envoyez-les, puis finalisez à nouveau). 202 avec l’identifiant de la livraison ; interrogez ensuite GET /ddex/{id}.
### Paramètres
| Paramètre | Emplacement | Type | Obligatoire | Description |
| --- | --- | --- | --- | --- |
| `id` | path | integer | Oui | L’identifiant de l’envoi. |
### Exemple de requête
```bash
curl -X POST "https://api.hillsmusic.com/v1/ddex/uploads/312/commit" \
-H "Authorization: Bearer $HILLS_API_KEY"
```
### Réponse `202`
```json
{
"data": {
"id": 312,
"status": "queued",
"environment": "production",
"status_url": "/v1/ddex/312"
}
}
```
### Erreurs
| Statut | Quand |
| --- | --- |
| 401 | unauthenticated, invalid_key, key_revoked, key_expired ou test_keys_retired. |
| 403 | insufficient_scope : la clé n’a pas le scope requis ; scope l’indique. account_inactive ou api_not_in_plan. |
| 404 | not_found : la ressource n’existe pas ou ne vous appartient pas. |
| 409 | upload_incomplete : parties manquantes ou de mauvaise taille (listées dans missing et wrong_size). already_committed : déjà finalisé (status_url pointe vers la livraison). commit_in_progress : une autre finalisation de cet envoi est en cours. |
| 429 | rate_limited : attendez le nombre de secondes indiqué par Retry-After. |
## Statut de livraison
`GET /v1/ddex/{id}` · Scope : `ddex:write` ou `ddex:validate`
queued → parsing → validating → importing → done / partial / failed, avec un élément par sortie (créée, mise à jour, signalée à l’équipe HILLS, écartée, test) et chaque erreur avec son champ DDEX. GET /ddex liste vos 100 dernières livraisons.
### Paramètres
| Paramètre | Emplacement | Type | Obligatoire | Description |
| --- | --- | --- | --- | --- |
| `id` | path | integer | Oui | L’identifiant de la livraison (renvoyé par POST /ddex ou par la finalisation). |
### Exemple de requête
```bash
curl "https://api.hillsmusic.com/v1/ddex/311" \
-H "Authorization: Bearer $HILLS_API_KEY"
```
### Réponse `200`
```json
{
"data": {
"id": 311,
"member_id": 41,
"environment": "production",
"status": "partial",
"message_id": "MSG-2026-0001",
"ern_version": "4.3",
"created_count": 1,
"left_out_count": 1,
"items": [
{
"ref": "R0",
"title": "Midnight Run",
"upc": "0602600000017",
"outcome": "created",
"release_id": 912,
"errors": []
}
]
}
}
```
### Erreurs
| Statut | Quand |
| --- | --- |
| 401 | unauthenticated, invalid_key, key_revoked, key_expired ou test_keys_retired. |
| 403 | insufficient_scope : la clé n’a pas le scope requis ; scope l’indique. account_inactive ou api_not_in_plan. |
| 404 | not_found : la ressource n’existe pas ou ne vous appartient pas. |
| 429 | rate_limited : attendez le nombre de secondes indiqué par Retry-After. |
Source: https://developer.hillsmusic.com/fr/reference/ddex-deliveries/