# Phân phối DDEX > Gửi bản phát hành dạng DDEX ERN: kiểm thử lô với POST /ddex/validate, phân phối bằng POST /ddex hoặc tải lên trực tiếp, dùng SFTP và đọc báo cáo phân phối. Bản phát hành vào HILLS Music dưới dạng các lô DDEX ERN. API không tạo hay sửa từng bản phát hành theo từng trường. Bạn gửi đúng lô mà bạn vẫn gửi cho một nền tảng, qua API hoặc SFTP. Mỗi bản phát hành trong lô trở thành một bản nháp trong danh mục của bạn, rồi đi qua kiểm duyệt và phân phối đến các nền tảng như thường lệ. ## Các phiên bản ERN | Phiên bản | Trạng thái | | --- | --- | | ERN 4.3.2 (`http://ddex.net/xml/ern/432`), ERN 3.8.2 (`http://ddex.net/xml/ern/382`) | Khuyến nghị | | 4.3, 3.8.1, 3.8 | Được chấp nhận | | 4.2, 4.1, 3.7 | Được chấp nhận. Báo cáo cảnh báo rằng đây là phiên bản cũ. | | Mọi phiên bản khác | Bị từ chối | Mọi phiên bản được chấp nhận đều đi qua cùng các bước kiểm tra và nhập. Một lô là một tệp zip chứa một hoặc nhiều tệp XML `NewReleaseMessage` cùng audio, ảnh bìa và video mà chúng tham chiếu. ## Scope | Scope | Cho phép | | --- | --- | | `ddex:validate` | Chỉ kiểm thử. Phù hợp cho CI. | | `ddex:write` | Kiểm thử, phân phối, tải lên trực tiếp và trạng thái phân phối. | ## 1. Kiểm thử trước `POST /ddex/validate` chạy mọi bước kiểm tra như một lần phân phối thật: XML, các quy tắc của HILLS, tệp audio, ảnh bìa và video, UPC và ISRC so với danh mục của bạn, thể loại, vùng lãnh thổ và điều khoản phát hành (deal). **Không có gì được tạo ra**: không bản phát hành, bản ghi âm, nghệ sĩ, mã hay lần phân phối nào. Hãy gửi một tệp `.zip` hoặc một tệp `.xml` đơn lẻ. ```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` là nghệ sĩ hoặc hãng đĩa mà lô này dành cho. Bỏ trống nếu là danh mục của chính bạn. Với tệp XML, hãy gửi `Content-Type: application/xml`. Bạn cũng có thể gửi `multipart/form-data` với trường `file` (tối đa 512 MB). Phản hồi gồm phiên bản ERN, phần tóm tắt, mọi bước kiểm tra theo từng giai đoạn (`pass`, `warning`, `error`, `skipped`) và một kết luận: | Kết luận | Ý nghĩa | | --- | --- | | `would_import` | Sạch lỗi. Bản phát hành sẽ trở thành bản nháp. | | `would_import_with_warnings` | Sẽ được nhập. Hãy đọc các cảnh báo. | | `would_be_flagged` | Sẽ chờ đội ngũ HILLS xử lý: một yêu cầu gỡ, hoặc cập nhật một bản phát hành đang kiểm duyệt hay đã lên kệ. | | `would_be_rejected` | Có lỗi. Không có gì được tạo cho bản phát hành đó. | Một lô có lỗi vẫn trả về `200`. Kết luận cho biết sự cố là gì. Một lô quá lớn để kiểm thử trả về `413 too_large`, và quá nhiều lần kiểm thử cùng lúc có thể trả về `429 busy`. Mọi lần kiểm thử cũng được liệt kê trên trang DDEX của ứng dụng web, trong mục **Test reports**, trong 90 ngày. ## 2. Phân phối `POST /ddex` nhận tệp zip dưới dạng body thô (`Content-Type: application/zip`, tối đa 20 GB) hoặc trường multipart `file` (tối đa 512 MB). Endpoint trả về `202` ngay lập tức: ```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"}} ``` Với tệp lớn, nên dùng tải lên trực tiếp. ## Tải lên trực tiếp cho lô lớn Tải lên trực tiếp gửi tệp thẳng vào kho lưu trữ thay vì đi qua API. 1. **Bắt đầu.** `POST /ddex/uploads` với `name` và `size` tính bằng byte (tối đa 20 GB), và `member_id` nếu cần. 2. **Tải lên.** Với tệp đến 64 MB, bạn nhận một `upload.url`: `PUT` toàn bộ tệp lên đó. Trên 64 MB, bạn nhận `upload.part_size` và một URL cho mỗi phần. `PUT` từng đoạn `part_size` byte lên URL của nó (đoạn cuối ngắn hơn). Các phần có thể gửi theo thứ tự bất kỳ, và song song. Các URL này đã có chữ ký: đừng gửi header `Authorization` đến chúng. 3. **Commit.** `POST /ddex/uploads/{id}/commit`. Endpoint kiểm tra mọi phần đã đến đủ và đúng kích thước, rồi đưa lô vào hàng đợi như `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 ``` URL của các phần có hiệu lực trong 6 giờ. `GET /ddex/uploads/{id}` cấp URL mới cho các phần còn thiếu, kèm `received_parts` và `parts_total`. Một lần commit khi còn thiếu phần sẽ trả về `409 upload_incomplete` và liệt kê `missing` và `wrong_size`: hãy gửi các phần đó, rồi commit lại. `DELETE /ddex/uploads/{id}` hủy một bản tải lên mà bạn sẽ không hoàn tất. Bản tải lên chưa commit sẽ bị xóa sau 7 ngày. ## Qua SFTP Mỗi hộp thư DDEX là một tài khoản đăng nhập SFTP với hai thư mục. Bạn nhận thông tin đăng nhập cùng hộp thư, trên trang DDEX của ứng dụng web. | Thư mục | Điều gì xảy ra | | --- | --- | | `/production//` | Phân phối thật. Khi tệp đánh dấu đến nơi, lô sẽ được nhập. | | `/test//` | Kiểm thử, giống `POST /ddex/validate`. Không có gì được tạo ra. Báo cáo được ghi ngay cạnh lô: `/test/.report.txt` và `.report.json`. | Hãy tải XML và các tệp của nó vào thư mục lô, rồi tải tệp đánh dấu sau cùng: `BatchComplete_*.xml`, hoặc bất kỳ tệp `*.complete` nào. Một tệp `/test/.xml` hoặc `.zip` đơn lẻ cũng được kiểm thử. Mọi tệp khác trong `/test`, như `ping.txt`, là một lần kiểm tra kết nối. Thư mục lô production không bao giờ nhận được tệp đánh dấu sẽ bị xóa sau 7 ngày. Mọi thứ nằm trong `/test` cũng bị xóa sau cùng khoảng thời gian đó. Xem [Thư mục test](https://developer.hillsmusic.com/vi/reference/test-folder/). ## 3. Đọc báo cáo phân phối Hãy poll `GET /ddex/{id}` mỗi 10–30 giây, hoặc đăng ký [webhook](https://developer.hillsmusic.com/vi/guides/webhooks/) `ddex.import.imported`. Trạng thái chuyển từ `queued` → `parsing` → `validating` → `importing`, rồi kết thúc ở một trong các trạng thái: - `done`: mọi bản phát hành đã được nhập; - `partial`: một số bản phát hành bị bỏ qua; - `failed`: không có gì được nhập. ```bash curl "https://api.hillsmusic.com/v1/ddex/311" \ -H "Authorization: Bearer $HILLS_API_KEY" ``` Phản hồi gồm các số đếm và một mục cho mỗi bản phát hành, mỗi mục có `outcome`, `release_id` và `errors` (mỗi lỗi nêu trường DDEX liên quan). `GET /ddex` liệt kê 100 lần phân phối gần nhất của bạn. ## Những gì được tạo hoặc gắn cờ | Kết quả | Khi nào | | --- | --- | | `created` | Một bản phát hành mới. Bản phát hành trở thành bản nháp trong danh mục của `member_id`. | | `updated` | UPC đã là một bản nháp (hoặc một bản phát hành bị trả lại để chỉnh sửa) ở đó. Bản nháp đó được cập nhật. | | `flagged` | Một yêu cầu gỡ, hoặc cập nhật một bản phát hành đang kiểm duyệt hay đã lên kệ. Thay đổi chưa được áp dụng. Đội ngũ HILLS sẽ xem xét. | | `left_out` | Bản phát hành có lỗi. Không có gì được tạo cho nó. Hãy sửa rồi phân phối lại. | | `test` | Một message được đánh dấu là `TestMessage`: đã kiểm tra, không tạo gì. | Một ISRC bạn đã có sẽ dùng lại bản ghi âm đó. Một ISRC thuộc về tài khoản khác sẽ khiến bản phát hành bị bỏ qua. Sau đó các bản nháp đi qua kiểm duyệt như thường lệ: gửi duyệt chúng trong ứng dụng web, hoặc đề nghị HILLS Music bật tự động gửi duyệt cho hộp thư của bạn. Theo dõi chúng bằng [GET /releases](https://developer.hillsmusic.com/vi/reference/releases/) và các webhook như `release.approved` và `release.live`. Đầy đủ parameter có trong [tài liệu tham chiếu Phân phối DDEX](https://developer.hillsmusic.com/vi/reference/ddex-deliveries/). Nguồn: https://developer.hillsmusic.com/vi/guides/ddex/