Entrega DDEX
Envie lançamentos em DDEX ERN: teste um lote com POST /ddex/validate, entregue com POST /ddex ou uploads diretos, use SFTP e leia o relatório de entrega.
Atualizado em
Os lançamentos entram na HILLS Music em lotes DDEX ERN. A API não cria nem edita lançamentos avulsos campo a campo. Você envia o mesmo lote que enviaria a uma plataforma, pela API ou por SFTP. Cada lançamento do lote vira um rascunho no seu catálogo e passa pela revisão e pela entrega às plataformas como de costume.
Versões do ERN
| Versão | Status |
|---|---|
ERN 4.3 (http://ddex.net/xml/ern/43) |
Recomendada |
| 4.2, 4.1 | Aceitas |
| 3.8.2, 3.8.1, 3.8, 3.7 | Aceitas. O relatório avisa que a versão é legada. |
| Qualquer outra | Rejeitada |
Todas as versões aceitas passam pelas mesmas verificações e pela mesma importação. Um lote é um zip com um ou mais arquivos XML NewReleaseMessage e o áudio, as capas e os vídeos a que eles se referem.
Escopos
| Escopo | Permite |
|---|---|
ddex:validate |
Apenas testes. Bom para CI. |
ddex:write |
Testes, entregas, uploads diretos e status das entregas. |
1. Teste primeiro
POST /ddex/validate executa todas as verificações de uma entrega: o XML, as regras da HILLS, os arquivos de áudio, capa e vídeo, os UPCs e ISRCs em relação ao seu catálogo, gêneros, territórios e contratos (deals). Nada é criado: nenhum lançamento, gravação, artista, código ou entrega. Envie um .zip ou um ú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 é o artista ou gravadora a que o lote se destina. Omita-o para o seu próprio catálogo. Para um arquivo XML, envie Content-Type: application/xml. Você também pode enviar multipart/form-data com o campo file (até 512 MB).
A resposta traz a versão do ERN, um resumo, cada verificação por etapa (pass, warning, error, skipped) e um veredito:
| Veredito | Significa |
|---|---|
would_import |
Sem problemas. Viraria um rascunho. |
would_import_with_warnings |
Seria importado. Leia os avisos. |
would_be_flagged |
Aguardaria a equipe da HILLS: uma remoção, ou uma atualização de um lançamento em revisão ou no ar. |
would_be_rejected |
Tem erros. Nada seria criado para esse lançamento. |
Um lote com erros também responde 200. O veredito diz o que deu errado. Um lote grande demais para teste responde 413 too_large, e muitos testes ao mesmo tempo podem responder 429 busy. Todo teste também aparece na página DDEX do app web, em Test reports, por 90 dias.
2. Entregue
POST /ddex recebe o zip como corpo bruto (Content-Type: application/zip, até 20 GB) ou no campo multipart file (até 512 MB). Ele responde 202 na hora:
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 arquivos grandes, prefira um upload direto.
Uploads diretos para lotes grandes
Um upload direto envia o arquivo direto para o armazenamento, sem passar pela API.
- Inicie.
POST /ddex/uploadscomnameesizeem bytes (até 20 GB), emember_idse necessário. - Envie. Até 64 MB, você recebe uma única
upload.url: façaPUTdo arquivo inteiro nela. Acima de 64 MB, você recebeupload.part_sizee uma URL por parte. FaçaPUTde cada fatia depart_sizebytes na URL correspondente (a última fatia é menor). As partes podem ir em qualquer ordem, e em paralelo. Essas URLs são assinadas: não envie o headerAuthorizationpara elas. - Confirme.
POST /ddex/uploads/{id}/commit. Ele verifica se todas as partes chegaram com o tamanho certo e então coloca o lote na fila comoPOST /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
As URLs das partes valem por 6 horas. GET /ddex/uploads/{id} gera URLs novas para as partes que ainda faltam, com received_parts e parts_total. Uma confirmação com partes faltando responde 409 upload_incomplete e lista missing e wrong_size: envie essas partes e confirme de novo. DELETE /ddex/uploads/{id} descarta um upload que você não vai concluir. Uploads não confirmados são removidos após 7 dias.
Via SFTP
Cada caixa de entrada DDEX é um login SFTP com duas pastas. Você recebe o login junto com a caixa de entrada, na página DDEX do app web.
| Pasta | O que acontece |
|---|---|
/production/<batch>/ |
Entregue. Quando o marcador chega, o lote é importado. |
/test/<batch>/ |
Testado, como em POST /ddex/validate. Nada é criado. O relatório é gravado ao lado: /test/<batch>.report.txt e .report.json. |
Envie o XML e os arquivos dele para a pasta do lote e, por último, o marcador: BatchComplete_*.xml, ou qualquer arquivo *.complete. Um /test/<file>.xml ou .zip avulso também é testado. Qualquer outro arquivo em /test, como ping.txt, é um teste de conexão. Uma pasta de lote de produção que nunca recebe o marcador é removida após 7 dias. Tudo o que estiver em /test sai após o mesmo prazo. Veja Pasta de teste.
3. Leia o relatório de entrega
Consulte GET /ddex/{id} a cada 10 a 30 segundos, ou assine o webhook ddex.import.imported. O status passa por queued → parsing → validating → importing e termina como:
done: todos os lançamentos entraram;partial: alguns lançamentos ficaram de fora;failed: nada foi importado.
curl "https://api.hillsmusic.com/v1/ddex/311" \
-H "Authorization: Bearer $HILLS_API_KEY"
A resposta traz contagens e um item por lançamento, cada um com outcome, release_id e errors (cada erro indica o seu campo DDEX). GET /ddex lista as suas últimas 100 entregas.
O que é criado ou sinalizado
| Resultado | Quando |
|---|---|
created |
Um lançamento novo. Ele vira um rascunho no catálogo de member_id. |
updated |
O UPC já é um rascunho ali (ou um lançamento devolvido para alterações). Esse rascunho é atualizado. |
flagged |
Uma remoção, ou uma atualização de um lançamento em revisão ou no ar. Não é aplicada. A equipe da HILLS analisa. |
left_out |
O lançamento tinha erros. Nada foi criado para ele. Corrija e entregue de novo. |
test |
Uma mensagem marcada como TestMessage: verificada, nada criado. |
Um ISRC que você já tem reaproveita a gravação correspondente. Um ISRC que pertence a outra conta deixa o lançamento de fora. Os rascunhos então passam pela revisão como de costume: envie-os pelo app web, ou peça à HILLS Music para ativar o envio automático na sua caixa de entrada. Acompanhe-os com GET /releases e com webhooks como release.approved e release.live.
Os parâmetros completos estão na referência de Entregas DDEX.