Ir al contenido
HILLS API v1 Acceso anticipado

Guías

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.

  1. Inicia. POST /ddex/uploads con name y size en bytes (hasta 20 GB), y member_id si hace falta.
  2. Sube. Hasta 64 MB recibes una sola upload.url: envía a ella el archivo completo con PUT. Por encima de 64 MB recibes upload.part_size y una URL por parte. Envía con PUT cada fragmento de part_size bytes 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 cabecera Authorization a ellas.
  3. 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 que POST /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.

¿Listo para integrar?

Solicita acceso a la API y te respondemos en 1 a 3 días hábiles.