REST API · v1
Tài liệu API XuniBOX
API chỉ đọc để lấy danh sách nhạc, nghệ sĩ và thể loại từ kho XuniBOX. Mỗi chủ đề dưới đây là một trang riêng, có đường dẫn riêng để bạn chia sẻ cho đội kỹ thuật.
Mã lỗi và cách retry
| HTTP | Ý nghĩa | Nên làm gì |
|---|---|---|
| 400 | Tham số hoặc UUID không hợp lệ | Đọc body — nó liệt kê đúng giới hạn của từng tham số. Không retry. |
| 401 | Thiếu header X-API-Key | Gắn key vào request. |
| 403 | Key sai, bị vô hiệu hóa, hoặc URL media hết hạn | Kiểm tra key; nếu là media thì gọi lại API lấy URL mới. |
| 404 | Không tìm thấy bài hát hoặc nghệ sĩ | Xóa khỏi cache/UI. Có thể admin đã gỡ nội dung. |
| 429 | Vượt hạn mức request | Chờ theo Retry-After rồi thử lại. |
| 502 | Lỗi khi đọc dữ liệu từ hạ tầng lưu trữ | Retry với backoff, thường tự hết trong vài giây. |
| 503 | Dịch vụ đang bảo trì cấu hình | Retry sau vài phút. |
| 500 | Lỗi ngoài dự kiến | Retry một lần; còn lỗi thì gửi cho chúng tôi thời điểm và endpoint. |
Error response · mặc định
{
"error": "API key không hợp lệ hoặc đã bị vô hiệu hóa."
}Error response · 400 có chi tiết
HTTP/1.1 400 Bad Request
{
"error": "Tham số truy vấn không hợp lệ.",
"allowed_sort": ["newest", "oldest", "popular", "title_asc", "title_desc"],
"pagination": {
"limit": "Số nguyên từ 1 đến 100; mặc định 20.",
"page": "Số nguyên từ 1 đến 5000; mặc định 1."
},
"filters": {
"title": "Tìm một phần tên bài hát, tối đa 160 ký tự.",
"genre": "Tìm một phần thể loại, tối đa 80 ký tự.",
"artist": "Tìm một phần tên nghệ sĩ, tối đa 120 ký tự.",
"artist_id": "UUID nghệ sĩ.",
"q": "Tìm đồng thời trong title, artist và genre, tối đa 100 ký tự."
}
}Helper retry có backoff
async function xuniboxFetch(path, { retries = 3 } = {}) {
for (let attempt = 0; attempt <= retries; attempt++) {
const res = await fetch(`https://xunibox.vn/api/public${path}`, {
headers: { "X-API-Key": process.env.XUNIBOX_API_KEY, Accept: "application/json" }
});
if (res.ok) return res.json();
// 4xx là lỗi phía bạn — retry cũng vô ích, trừ 429.
if (res.status !== 429 && res.status < 500) {
const body = await res.json().catch(() => ({}));
throw new Error(body.error ?? `XuniBOX ${res.status}`);
}
if (attempt === retries) throw new Error(`XuniBOX ${res.status} sau ${retries} lần thử`);
const retryAfter = Number(res.headers.get("Retry-After"));
const waitMs = Number.isFinite(retryAfter) && retryAfter > 0
? retryAfter * 1000
: 2 ** attempt * 500 + Math.random() * 250; // backoff + jitter
await new Promise((resolve) => setTimeout(resolve, waitMs));
}
}Body lỗi luôn có khóa
error dạng chuỗi tiếng Việt. Log nguyên body khi debug — riêng 400 của /tracks còn kèm bảng giới hạn nên thường đọc là biết sai chỗ nào.Sẵn sàng tích hợp?
Gửi thông tin sản phẩm để admin XuniBOX xét duyệt và cấp API key.