Entrega DDEX
Envía lanzamientos como DDEX ERN: prueba un lote con POST /ddex/validate, entrégalo con POST /ddex o subidas directas, usa SFTP y lee el informe.
Actualizado el
Los lanzamientos entran en HILLS Music como lotes DDEX ERN. La API no crea ni edita lanzamientos sueltos campo a campo. Envías el mismo lote que enviarías a una plataforma, por la API o por SFTP. Cada lanzamiento del lote se convierte en un borrador de tu catálogo y pasa por la revisión y la entrega a las plataformas como de costumbre.
Versiones de ERN
| Versión | Estado |
|---|---|
ERN 4.3 (http://ddex.net/xml/ern/43) |
Recomendada |
| 4.2, 4.1 | Aceptadas |
| 3.8.2, 3.8.1, 3.8, 3.7 | Aceptadas. El informe advierte de que la versión es antigua. |
| Cualquier otra | Rechazada |
Todas las versiones aceptadas pasan por las mismas comprobaciones y la misma importación. Un lote es un zip con uno o varios archivos XML NewReleaseMessage y el audio, las portadas y los videos a los que remiten.
Ámbitos
| Ámbito | Permite |
|---|---|
ddex:validate |
Solo pruebas. Ideal para CI. |
ddex:write |
Pruebas, entregas, subidas directas y estado de las entregas. |
1. Prueba primero
POST /ddex/validate ejecuta todas las comprobaciones de una entrega: el XML, las reglas de HILLS, los archivos de audio, portada y video, los UPC e ISRC frente a tu catálogo, los géneros, los territorios y los acuerdos. No se crea nada: ni lanzamientos, ni grabaciones, ni artistas, ni códigos, ni entregas. Envía un .zip o un único .xml.
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
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 es el artista o sello al que corresponde el lote. Omítelo para tu propio catálogo. Para un archivo XML, envía Content-Type: application/xml. También puedes enviar multipart/form-data con el campo file (hasta 512 MB).
La respuesta incluye la versión del ERN, un resumen, cada comprobación por fase (pass, warning, error, skipped) y un veredicto:
| Veredicto | Significa |
|---|---|
would_import |
Sin problemas. Se convertiría en un borrador. |
would_import_with_warnings |
Se importaría. Lee las advertencias. |
would_be_flagged |
Quedaría a la espera del equipo de HILLS: una retirada, o una actualización de un lanzamiento en revisión o publicado. |
would_be_rejected |
Tiene errores. No se crearía nada para ese lanzamiento. |
Un lote con errores responde igualmente 200. El veredicto indica qué ha fallado. Un lote demasiado grande para probarlo responde 413 too_large, y muchas pruebas a la vez pueden responder 429 busy. Además, cada prueba aparece durante 90 días en la página DDEX de la aplicación web, en Test reports.
2. Entrega
POST /ddex acepta el zip como cuerpo en bruto (Content-Type: application/zip, hasta 20 GB) o en el campo multipart file (hasta 512 MB). Responde 202 de inmediato:
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"}}
Para archivos grandes, es preferible una subida directa.
Subidas directas para lotes grandes
Una subida directa envía el archivo directamente al almacenamiento en lugar de pasar por la API.
- Inicia.
POST /ddex/uploadsconnameysizeen bytes (hasta 20 GB), ymember_idsi hace falta. - Sube. Hasta 64 MB recibes una sola
upload.url: envía a ella el archivo completo conPUT. Por encima de 64 MB recibesupload.part_sizey una URL por parte. Envía conPUTcada fragmento depart_sizebytes a su URL (el último fragmento es más corto). Las partes pueden ir en cualquier orden y en paralelo. Estas URL están firmadas: no envíes ninguna cabeceraAuthorizationa ellas. - Confirma.
POST /ddex/uploads/{id}/commit. Comprueba que todas las partes llegaron con el tamaño correcto y después pone el lote en cola igual quePOST /ddex(202).
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
Las URL de las partes funcionan durante 6 horas. GET /ddex/uploads/{id} da URL nuevas para las partes que aún faltan, con received_parts y parts_total. Una confirmación con partes que faltan responde 409 upload_incomplete y enumera missing y wrong_size: envíalas y vuelve a confirmar. DELETE /ddex/uploads/{id} descarta una subida que no vayas a terminar. Las subidas sin confirmar se eliminan a los 7 días.
Por SFTP
Cada buzón DDEX es un único acceso SFTP con dos carpetas. Recibes el acceso con tu buzón, en la página DDEX de la aplicación web.
| Carpeta | Qué ocurre |
|---|---|
/production/<batch>/ |
Se entrega. En cuanto llega el marcador, se importa el lote. |
/test/<batch>/ |
Se prueba, como con POST /ddex/validate. No se crea nada. El informe se escribe a su lado: /test/<batch>.report.txt y .report.json. |
Sube el XML y sus archivos a la carpeta del lote y, al final, el marcador: BatchComplete_*.xml o cualquier archivo *.complete. También se prueba un único /test/<file>.xml o .zip. Cualquier otro archivo en /test, como ping.txt, es una prueba de conexión. Una carpeta de lote de producción que nunca recibe su marcador se elimina a los 7 días. Lo que haya en /test se elimina en el mismo plazo. Consulta Carpeta de pruebas.
3. Lee el informe de entrega
Consulta GET /ddex/{id} cada 10–30 segundos, o suscríbete al webhook ddex.import.imported. El estado pasa por queued → parsing → validating → importing y termina en:
done: todos los lanzamientos se importaron;partial: algunos lanzamientos quedaron excluidos;failed: no se importó nada.
curl "https://api.hillsmusic.com/v1/ddex/311" \
-H "Authorization: Bearer $HILLS_API_KEY"
La respuesta incluye recuentos y un elemento por lanzamiento, cada uno con su outcome, su release_id y sus errors (cada error indica su campo DDEX). GET /ddex enumera tus últimas 100 entregas.
Qué se crea o se marca
| Resultado | Cuándo |
|---|---|
created |
Un lanzamiento nuevo. Se convierte en un borrador del catálogo de member_id. |
updated |
El UPC ya es un borrador (o un lanzamiento devuelto para cambios) en ese catálogo. Se actualiza ese borrador. |
flagged |
Una retirada, o una actualización de un lanzamiento en revisión o publicado. No se aplica. Lo revisa el equipo de HILLS. |
left_out |
El lanzamiento tenía errores. No se creó nada para él. Corrígelo y vuelve a entregarlo. |
test |
Un mensaje marcado como TestMessage: se comprueba y no se crea nada. |
Un ISRC que ya tienes reutiliza esa grabación. Un ISRC que pertenece a otra cuenta deja el lanzamiento excluido. Después, los borradores pasan por la revisión como de costumbre: envíalos desde la aplicación web o pide a HILLS Music que active el envío automático para tu buzón. Síguelos con GET /releases y con webhooks como release.approved y release.live.
Todos los parámetros están en la referencia de Entregas DDEX.