# 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. 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`. ```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-0001.zip ``` ```js 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: ```bash 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. 1. **Inicie.** `POST /ddex/uploads` com `name` e `size` em bytes (até 20 GB), e `member_id` se necessário. 2. **Envie.** Até 64 MB, você recebe uma única `upload.url`: faça `PUT` do arquivo inteiro nela. Acima de 64 MB, você recebe `upload.part_size` e uma URL por parte. Faça `PUT` de cada fatia de `part_size` bytes 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 header `Authorization` para elas. 3. **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 como `POST /ddex` (`202`). ```js 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//` | Entregue. Quando o marcador chega, o lote é importado. | | `/test//` | Testado, como em `POST /ddex/validate`. Nada é criado. O relatório é gravado ao lado: `/test/.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/.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](https://developer.hillsmusic.com/pt/reference/test-folder/). ## 3. Leia o relatório de entrega Consulte `GET /ddex/{id}` a cada 10 a 30 segundos, ou assine o [webhook](https://developer.hillsmusic.com/pt/guides/webhooks/) `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. ```bash 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](https://developer.hillsmusic.com/pt/reference/releases/) e com webhooks como `release.approved` e `release.live`. Os parâmetros completos estão na [referência de Entregas DDEX](https://developer.hillsmusic.com/pt/reference/ddex-deliveries/). Fonte: https://developer.hillsmusic.com/pt/guides/ddex/