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.
Ví dụ request và response
Readiness check · GET /readyz
Dùng cho load balancer, Kubernetes readiness probe hoặc hệ thống giám sát: 200 nghĩa là sẵn sàng nhận traffic, 503 kèm reason/reasons và danh sách check khi chưa sẵn sàng. Hỗ trợ cả HEAD.
curl --request GET \
--url 'https://xunibox.vn/api/public/readyz' \
--header 'Accept: application/json'HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Cache-Control: no-store
{
"status": "ready",
"ready": true,
"api_version": "1.0.0",
"timestamp": "2026-08-05T15:08:54.464Z",
"response_time_ms": 24,
"checks": [
{ "name": "backend_config", "ready": true, "duration_ms": 0, "reason": null },
{ "name": "database_read", "ready": true, "duration_ms": 12, "reason": null },
{ "name": "catalog_read", "ready": true, "duration_ms": 10, "reason": null }
]
}
// Khi chưa sẵn sàng:
HTTP/1.1 503 Service Unavailable
{
"status": "not_ready",
"ready": false,
"timestamp": "2026-08-05T15:08:08.988Z",
"reason": "Cơ sở dữ liệu trả về HTTP 500 khi đọc thử bảng tracks.",
"reasons": ["Cơ sở dữ liệu trả về HTTP 500 khi đọc thử bảng tracks."]
}Readiness probe siêu nhẹ · HEAD /readyz
HEAD chạy đúng các check như GET nhưng không trả body — hợp với health check của load balancer, uptime monitor hoặc bước kiểm tra trước khi deploy. Chỉ cần đọc status code: 200 là sẵn sàng, 503 là chưa.
curl --head \
--url 'https://xunibox.vn/api/public/readyz'HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Access-Control-Allow-Origin: *
Cache-Control: no-store
// Khi chưa sẵn sàng (không có body, chỉ dùng status code):
HTTP/1.1 503 Service Unavailable// Node.js / trình duyệt: kiểm tra readiness trước khi gửi traffic
export async function isXuniBoxReady(timeoutMs = 3000) {
const controller = new AbortController();
const timer = setTimeout(() => controller.abort(), timeoutMs);
try {
const response = await fetch('https://xunibox.vn/api/public/readyz', {
headers: { Accept: 'application/json' },
signal: controller.signal,
});
const payload = await response.json();
if (!payload.ready) {
const failed = payload.checks.filter((check) => !check.ready);
console.warn('XuniBOX chưa sẵn sàng:', payload.reason, failed);
}
return payload.ready === true;
} catch (error) {
console.warn('Không gọi được /readyz:', error);
return false;
} finally {
clearTimeout(timer);
}
}
// Probe siêu nhẹ cho load balancer: chỉ cần status code, không tải body
export async function readyProbe() {
const response = await fetch('https://xunibox.vn/api/public/readyz', { method: 'HEAD' });
return response.status === 200;
}# Kubernetes readiness probe
readinessProbe:
httpGet:
path: /api/public/readyz
port: 443
scheme: HTTPS
initialDelaySeconds: 5
periodSeconds: 30
timeoutSeconds: 3
# Shell: dừng deploy nếu upstream chưa sẵn sàng
if [ "$(curl -s -o /dev/null -w '%{http_code}' -I https://xunibox.vn/api/public/readyz)" != "200" ]; then
echo "XuniBOX chưa sẵn sàng, tạm hoãn gửi traffic" && exit 1
fiHealth check · GET /healthz
Dùng để kiểm tra kết nối khi tích hợp. Không cần API key, không tốn hạn mức rate limit.
curl --request GET \
--url 'https://xunibox.vn/api/public/healthz' \
--header 'Accept: application/json'HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Cache-Control: no-store
{
"status": "ok",
"api_version": "1.0.0",
"response_time_ms": 12,
"timestamp": "2026-08-05T10:03:00.000Z",
"db_connected": true,
"db_response_time_ms": 8
}1. Danh sách bài nhạc · GET /tracks
Lấy bài mới nhất theo thể loại, có phân trang. meta.total là tổng số bản ghi khớp bộ lọc, không phải số phần tử trong data.
curl --request GET \
--url 'https://xunibox.vn/api/public/tracks?genre=Pop&sort=newest&page=1&limit=2' \
--header 'Accept: application/json' \
--header 'X-API-Key: xnb_live_your_key'HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
X-Total-Count: 128
X-Page: 1
X-Limit: 2
X-Offset: 0
{
"data": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"title": "Mùa hè rực rỡ",
"artist": "Minh Anh",
"genre": "Pop",
"duration": "3:24",
"audio_url": "https://...signed-preview-url...",
"preview_start_seconds": 42,
"preview_duration_seconds": 30,
"cover_url": "https://...signed-url...",
"play_count": 1240,
"created_at": "2026-08-05T01:30:00.000Z"
},
{
"id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"title": "Đêm thành phố",
"artist": "Hoàng Nam",
"genre": "Pop",
"duration": "2:58",
"audio_url": "https://...signed-preview-url...",
"preview_start_seconds": 30,
"preview_duration_seconds": 15,
"cover_url": null,
"play_count": 318,
"created_at": "2026-08-04T09:12:00.000Z"
}
],
"meta": { "total": 128, "page": 1, "limit": 2 }
}2. Chi tiết một bài · GET /tracks/:id
Trả thẳng object bài hát, không bọc trong data. Dùng để làm mới audio_url trước khi render video.
curl --request GET \
--url 'https://xunibox.vn/api/public/tracks/550e8400-e29b-41d4-a716-446655440000' \
--header 'X-API-Key: xnb_live_your_key'{
"id": "550e8400-e29b-41d4-a716-446655440000",
"title": "Tên bài hát",
"artist": "Tên nghệ sĩ",
"genre": "Pop",
"duration": "3:24",
"audio_url": "https://...signed-preview-url...",
"preview_start_seconds": 42,
"preview_duration_seconds": 30,
"cover_url": "https://...signed-url...",
"play_count": 1240,
"created_at": "2026-08-05T01:30:00.000Z"
}HTTP/1.1 404 Not Found
{
"error": "Không tìm thấy bài hát."
}3. Làm mới link nghe thử · GET /tracks/:id/audio-url
Endpoint gọn nhất để lấy link media còn hạn: chỉ trả audio_url, cover_url, độ dài preview và thời điểm hết hạn. Gọi ngay trước khi phát hoặc trước khi render video, không lưu link vào database.
curl --request GET \
--url 'https://xunibox.vn/api/public/tracks/550e8400-e29b-41d4-a716-446655440000/audio-url' \
--header 'X-API-Key: xnb_live_your_key'HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Cache-Control: no-store
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"audio_url": "https://...signed-preview-url...",
"cover_url": "https://...signed-url...",
"preview_duration_seconds": 30,
"media_expires_in": 3600,
"expires_at": "2026-08-05T11:03:00.000Z"
}
// 400 nếu ID sai định dạng UUID.
// 404 nếu bài hát không tồn tại hoặc chưa có đoạn nghe thử.// Gọi ngay trước khi bấm play hoặc trước khi render video.
// Nhẹ hơn /tracks/:id vì chỉ trả đúng phần media.
async function getFreshAudio(trackId) {
const res = await fetch(
`https://xunibox.vn/api/public/tracks/${trackId}/audio-url`,
{ headers: { "X-API-Key": process.env.XUNIBOX_API_KEY } }
);
if (res.status === 404) return null; // bài đã bị gỡ
if (!res.ok) throw new Error(`XuniBOX ${res.status}`);
const media = await res.json();
// Hết hạn sau media_expires_in giây — xin lại nếu vượt quá.
return media;
}4. Lấy nhiều bài theo ID · GET /tracks/by-ids
Khôi phục playlist đã lưu chỉ bằng một request thay vì gọi /tracks/:id nhiều lần. Cũng là cách làm mới link media hàng loạt (tối đa 50 ID/lượt).
curl --request GET \
--url 'https://xunibox.vn/api/public/tracks/by-ids?ids=550e8400-e29b-41d4-a716-446655440000,7c9e6679-7425-40de-944b-e07fc1f90ae7' \
--header 'X-API-Key: xnb_live_your_key'HTTP/1.1 200 OK
{
"data": [
{ "id": "550e8400-e29b-41d4-a716-446655440000", "title": "Mùa hè rực rỡ", "...": "..." },
{ "id": "7c9e6679-7425-40de-944b-e07fc1f90ae7", "title": "Đêm thành phố", "...": "..." }
],
"meta": { "total": 2, "page": 1, "limit": 50 }
}
// ID không tồn tại sẽ bị bỏ qua, không gây lỗi 404.
// ID trùng lặp được gộp lại, thứ tự trả về bám theo thứ tự bạn gửi lên.5. Danh sách thể loại · GET /genres
data là mảng chuỗi, không phải mảng object. Dùng để dựng bộ lọc thể loại trong UI của bạn.
curl --request GET \
--url 'https://xunibox.vn/api/public/genres?page=1&limit=20' \
--header 'X-API-Key: xnb_live_your_key'HTTP/1.1 200 OK
{
"data": ["Acoustic", "Ballad", "EDM", "Lo-fi", "Pop", "Rap"],
"meta": { "total": 6, "page": 1, "limit": 20 }
}6. Danh sách nghệ sĩ · GET /artists
Kèm tiểu sử, ảnh đại diện ký tạm thời và track_count. Lấy id ở đây để gọi tiếp /artists/:id/tracks hoặc lọc /tracks?artist_id=.
curl --request GET \
--url 'https://xunibox.vn/api/public/artists?sort=name_asc&page=1&limit=2' \
--header 'Accept: application/json' \
--header 'X-API-Key: xnb_live_your_key'HTTP/1.1 200 OK
X-Total-Count: 24
{
"data": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "Hoàng Nam",
"biography": "Nghệ sĩ indie đến từ Đà Nẵng.",
"avatar_url": "https://...signed-url...",
"track_count": 12,
"created_at": "2026-07-21T04:00:00.000Z",
"media_expires_in": 3600
},
{
"id": "b3f1c2d4-5a6b-4c7d-8e9f-0a1b2c3d4e5f",
"name": "Minh Anh",
"biography": null,
"avatar_url": null,
"track_count": 5,
"created_at": "2026-07-02T08:15:00.000Z",
"media_expires_in": 3600
}
],
"meta": { "total": 24, "page": 1, "limit": 2 }
}7. Nhạc của một nghệ sĩ · GET /artists/:id/tracks
Response có thêm khóa artist ở cấp ngoài cùng, tiện dựng trang nghệ sĩ chỉ bằng một request.
curl --request GET \
--url 'https://xunibox.vn/api/public/artists/550e8400-e29b-41d4-a716-446655440000/tracks?sort=popular&limit=20' \
--header 'X-API-Key: xnb_live_your_key'HTTP/1.1 200 OK
{
"artist": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "Hoàng Nam",
"biography": "Nghệ sĩ indie đến từ Đà Nẵng.",
"avatar_url": "https://...signed-url...",
"created_at": "2026-07-21T04:00:00.000Z",
"media_expires_in": 3600
},
"data": [ { "id": "...", "title": "...", "...": "..." } ],
"meta": { "total": 12, "page": 1, "limit": 20 }
}8. Tìm kiếm · GET /tracks?q=
q quét đồng thời tên bài hát, nghệ sĩ và thể loại. Kết hợp được với genre, artist_id, sort và phân trang. Không có kết quả vẫn là 200 với data rỗng — đừng coi đó là lỗi.
const params = new URLSearchParams({
q: "mùa hè", // tìm trong tên bài hát, nghệ sĩ và thể loại
sort: "popular",
page: "1",
limit: "20"
});
const response = await fetch(`https://xunibox.vn/api/public/tracks?${params}`, {
headers: {
"X-API-Key": process.env.XUNIBOX_API_KEY,
"Accept": "application/json"
}
});
const { data, meta } = await response.json();HTTP/1.1 200 OK
{
"data": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"title": "Mùa hè rực rỡ",
"artist": "Minh Anh",
"genre": "Pop",
"duration": "3:24",
"audio_url": "https://...signed-preview-url...",
"preview_start_seconds": 42,
"preview_duration_seconds": 30,
"cover_url": "https://...signed-url...",
"play_count": 1240,
"created_at": "2026-08-05T01:30:00.000Z"
}
],
"meta": { "total": 1, "page": 1, "limit": 20 }
}HTTP/1.1 200 OK
{
"data": [],
"meta": { "total": 0, "page": 1, "limit": 20 }
}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.