# Entregas DDEX > Entrega lotes DDEX ERN (se recomienda 4.3) a producción, pruébalos antes (sin crear nada), usa subidas directas para los grandes y consulta su estado. Entrega lotes DDEX ERN (se recomienda 4.3) a producción, pruébalos antes (sin crear nada), usa subidas directas para los grandes y consulta su estado. URL base `https://api.hillsmusic.com/v1`. Cada solicitud envía una clave de API: `Authorization: Bearer hm_live_…`. - Probar un mensaje o lote DDEX - Entregar un lote DDEX (se recomienda ERN 4.3) - Listar entregas - Iniciar una subida directa (lotes grandes) - Estado de una subida directa - Descartar una subida directa - Confirmar una subida directa - Estado de la entrega ## Probar un mensaje o lote DDEX `POST /v1/ddex/validate` · Ámbito: `ddex:validate` o `ddex:write` La vía de pruebas: un .xml (Content-Type: application/xml) o un .zip, que se comprueba como una entrega (el XML, las reglas de HILLS, los archivos de audio, portada y video, los UPC e ISRC frente al catálogo). No se crea nada: ni lanzamientos, ni grabaciones, ni artistas, ni códigos, ni entregas. La prueba aparece en la página DDEX del panel (Test reports). Devuelve cada comprobación por fase (pass / warning / error / skipped), lo que HILLS crearía y el veredicto: would_import, would_import_with_warnings, would_be_flagged o would_be_rejected. También funciona con ddex:write. ### Parámetros | Parámetro | Ubicación | Tipo | Obligatorio | Descripción | | --- | --- | --- | --- | --- | | `member_id` | query | integer | No | El artista o sello al que corresponde (tu propia cuenta si se omite). | | `name` | query | string | No | Nombre de archivo para un cuerpo en bruto (predeterminado: batch.zip, o message.xml para XML). | ### Cuerpo de la solicitud El lote: el zip que entregas a las plataformas (XML del ERN + los recursos a los que remite) como cuerpo en bruto, un .xml suelto o el campo multipart file (con member_id como campo). Tipos de contenido: `application/zip`, `application/xml`, `multipart/form-data`. ### Ejemplo de solicitud ```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 ``` ### Respuesta `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" } ] } } ``` ### Errores | Estado | Cuándo | | --- | --- | | 400 | invalid: un parámetro es incorrecto; field indica cuál. | | 401 | unauthenticated, invalid_key, key_revoked, key_expired o test_keys_retired. | | 403 | insufficient_scope: a la clave le falta el ámbito; scope indica cuál. account_inactive o api_not_in_plan. | | 413 | too_large: supera el tamaño que admite una prueba; entrégalo con POST /ddex. | | 429 | busy: demasiadas pruebas a la vez; vuelve a intentarlo en breve. rate_limited: espera los segundos que indique Retry-After. | ## Entregar un lote DDEX (se recomienda ERN 4.3) `POST /v1/ddex` · Ámbito: `ddex:write` Envía el zip que entregas a las plataformas: uno o varios XML NewReleaseMessage del ERN con el audio, la portada y los videos a los que remiten. Como cuerpo en bruto (Content-Type: application/zip, hasta 20 GB) o en el campo multipart file (hasta 512 MB). Cada lanzamiento se convierte en un borrador en member_id (tu propio catálogo si se omite); un UPC que ya existe actualiza su borrador; las retiradas y las actualizaciones de lanzamientos publicados esperan al equipo de HILLS. Se recomienda ERN 4.3 (espacio de nombres http://ddex.net/xml/ern/43); 4.2, 4.1, 3.8.x (3.8.2, 3.8.1, 3.8) y 3.7 se aceptan y se leen de la misma forma (el informe advierte de que la versión es antigua); las demás versiones se rechazan. 202 con el id de la entrega: consulta GET /ddex/{id}. ### Parámetros | Parámetro | Ubicación | Tipo | Obligatorio | Descripción | | --- | --- | --- | --- | --- | | `member_id` | query | integer | No | El artista o sello al que corresponde (tu propia cuenta si se omite). | | `name` | query | string | No | Nombre de archivo para un cuerpo en bruto (predeterminado: batch.zip). | ### Cuerpo de la solicitud El lote: el zip que entregas a las plataformas (XML del ERN + los recursos a los que remite) como cuerpo en bruto, un .xml suelto o el campo multipart file (con member_id como campo). Tipos de contenido: `application/zip`, `application/xml`, `multipart/form-data`. ### Ejemplo de solicitud ```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 ``` ### Respuesta `202` ```json { "data": { "id": 311, "status": "queued", "environment": "production", "status_url": "/v1/ddex/311" } } ``` ### Errores | Estado | Cuándo | | --- | --- | | 400 | invalid: un parámetro es incorrecto; field indica cuál. | | 401 | unauthenticated, invalid_key, key_revoked, key_expired o test_keys_retired. | | 403 | insufficient_scope: a la clave le falta el ámbito; scope indica cuál. account_inactive o api_not_in_plan. | | 413 | too_large: más de 20 GB (cuerpo en bruto) o de 512 MB (multipart). | | 429 | rate_limited: espera los segundos que indique Retry-After. | ## Listar entregas `GET /v1/ddex` · Ámbito: `ddex:write` o `ddex:validate` Tus últimas 100 entregas DDEX, de la más reciente a la más antigua (no incluye las subidas aún sin confirmar). ### Ejemplo de solicitud ```bash curl "https://api.hillsmusic.com/v1/ddex" \ -H "Authorization: Bearer $HILLS_API_KEY" ``` ### Respuesta `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" } ] } ``` ### Errores | Estado | Cuándo | | --- | --- | | 401 | unauthenticated, invalid_key, key_revoked, key_expired o test_keys_retired. | | 403 | insufficient_scope: a la clave le falta el ámbito; scope indica cuál. account_inactive o api_not_in_plan. | | 429 | rate_limited: espera los segundos que indique Retry-After. | ## Iniciar una subida directa (lotes grandes) `POST /v1/ddex/uploads` · Ámbito: `ddex:write` Recomendado para zips grandes: el archivo va directamente al almacenamiento en lugar de pasar por la API. Envía el nombre del archivo y su tamaño en bytes (hasta 20 GB). Hasta 64 MB recibes una sola URL a la que enviar el archivo completo con PUT; por encima, un tamaño de parte y una URL por parte: envía con PUT cada fragmento de part_size bytes (el último, más corto) a su URL, en cualquier orden y en paralelo. Las URL funcionan durante 6 horas; GET /ddex/uploads/{id} da URL nuevas para las partes que aún faltan. Después, POST /ddex/uploads/{id}/commit. DELETE /ddex/uploads/{id} descarta una subida que no vayas a terminar; las subidas sin confirmar se eliminan a los 7 días. ### Cuerpo de la solicitud JSON. | Campo | Tipo | Obligatorio | Descripción | | --- | --- | --- | --- | | `name` | string | Sí | El nombre del archivo (.zip o .xml). | | `size` | integer | Sí | El tamaño del archivo en bytes. | | `member_id` | integer | No | El artista o sello al que corresponde (tu propia cuenta si se omite). | ### Ejemplo de solicitud ```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}' ``` ### Respuesta `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" } } ``` ### Errores | Estado | Cuándo | | --- | --- | | 400 | invalid: un parámetro es incorrecto; field indica cuál. | | 401 | unauthenticated, invalid_key, key_revoked, key_expired o test_keys_retired. | | 403 | insufficient_scope: a la clave le falta el ámbito; scope indica cuál. account_inactive o api_not_in_plan. | | 429 | rate_limited: espera los segundos que indique Retry-After. | ## Estado de una subida directa `GET /v1/ddex/uploads/{id}` · Ámbito: `ddex:write` Si la subida aún no está confirmada: URL nuevas para las partes que faltan (las primeras caducan a las 6 horas), received_parts y parts_total. Una vez confirmada: el id de su entrega y status_url. ### Parámetros | Parámetro | Ubicación | Tipo | Obligatorio | Descripción | | --- | --- | --- | --- | --- | | `id` | path | integer | Sí | El id de la subida. | ### Ejemplo de solicitud ```bash curl "https://api.hillsmusic.com/v1/ddex/uploads/312" \ -H "Authorization: Bearer $HILLS_API_KEY" ``` ### Respuesta `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 } } ``` ### Errores | Estado | Cuándo | | --- | --- | | 401 | unauthenticated, invalid_key, key_revoked, key_expired o test_keys_retired. | | 403 | insufficient_scope: a la clave le falta el ámbito; scope indica cuál. account_inactive o api_not_in_plan. | | 404 | not_found: no existe o no es tuyo. | | 429 | rate_limited: espera los segundos que indique Retry-After. | ## Descartar una subida directa `DELETE /v1/ddex/uploads/{id}` · Ámbito: `ddex:write` Descarta una subida que no vas a terminar, junto con las partes ya enviadas. 409 si ya se confirmó. ### Parámetros | Parámetro | Ubicación | Tipo | Obligatorio | Descripción | | --- | --- | --- | --- | --- | | `id` | path | integer | Sí | El id de la subida. | ### Ejemplo de solicitud ```bash curl -X DELETE "https://api.hillsmusic.com/v1/ddex/uploads/312" \ -H "Authorization: Bearer $HILLS_API_KEY" ``` ### Respuesta `200` ```json { "data": { "id": 312, "deleted": true } } ``` ### Errores | Estado | Cuándo | | --- | --- | | 401 | unauthenticated, invalid_key, key_revoked, key_expired o test_keys_retired. | | 403 | insufficient_scope: a la clave le falta el ámbito; scope indica cuál. account_inactive o api_not_in_plan. | | 404 | not_found: no existe o no es tuyo. | | 409 | already_committed: ya está confirmada y no se puede descartar. | | 429 | rate_limited: espera los segundos que indique Retry-After. | ## Confirmar una subida directa `POST /v1/ddex/uploads/{id}/commit` · Ámbito: `ddex:write` Comprueba que todas las partes llegaron con el tamaño correcto y pone el lote en cola exactamente igual que POST /ddex. 409 upload_incomplete enumera las partes que faltan o cuyo tamaño es incorrecto (súbelas y vuelve a confirmar). 202 con el id de la entrega; consulta GET /ddex/{id}. ### Parámetros | Parámetro | Ubicación | Tipo | Obligatorio | Descripción | | --- | --- | --- | --- | --- | | `id` | path | integer | Sí | El id de la subida. | ### Ejemplo de solicitud ```bash curl -X POST "https://api.hillsmusic.com/v1/ddex/uploads/312/commit" \ -H "Authorization: Bearer $HILLS_API_KEY" ``` ### Respuesta `202` ```json { "data": { "id": 312, "status": "queued", "environment": "production", "status_url": "/v1/ddex/312" } } ``` ### Errores | Estado | Cuándo | | --- | --- | | 401 | unauthenticated, invalid_key, key_revoked, key_expired o test_keys_retired. | | 403 | insufficient_scope: a la clave le falta el ámbito; scope indica cuál. account_inactive o api_not_in_plan. | | 404 | not_found: no existe o no es tuyo. | | 409 | upload_incomplete: faltan partes o su tamaño es incorrecto (missing y wrong_size las enumeran). already_committed: ya se confirmó (status_url apunta a la entrega). commit_in_progress: hay otra confirmación de esta subida en curso. | | 429 | rate_limited: espera los segundos que indique Retry-After. | ## Estado de la entrega `GET /v1/ddex/{id}` · Ámbito: `ddex:write` o `ddex:validate` queued → parsing → validating → importing → done / partial / failed, con un elemento por lanzamiento (creado, actualizado, marcado para el equipo de HILLS, excluido, prueba) y cada error con su campo DDEX. GET /ddex enumera tus últimas 100. ### Parámetros | Parámetro | Ubicación | Tipo | Obligatorio | Descripción | | --- | --- | --- | --- | --- | | `id` | path | integer | Sí | El id de la entrega (de POST /ddex o de la confirmación). | ### Ejemplo de solicitud ```bash curl "https://api.hillsmusic.com/v1/ddex/311" \ -H "Authorization: Bearer $HILLS_API_KEY" ``` ### Respuesta `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": [] } ] } } ``` ### Errores | Estado | Cuándo | | --- | --- | | 401 | unauthenticated, invalid_key, key_revoked, key_expired o test_keys_retired. | | 403 | insufficient_scope: a la clave le falta el ámbito; scope indica cuál. account_inactive o api_not_in_plan. | | 404 | not_found: no existe o no es tuyo. | | 429 | rate_limited: espera los segundos que indique Retry-After. | Fuente: https://developer.hillsmusic.com/es/reference/ddex-deliveries/