Tài liệu tham khảo REST API
Các SDK chỉ là client mỏng bên trên API HTTPS + JSON này, nên mọi engine, công cụ hay máy chủ đều có thể dùng trực tiếp.
Chú thích trong mã và tên API được giữ nguyên tiếng Anh để khớp với SDK.
Cơ bản#
Base URL: https://majacloud.majanite.com/v1. Bắt buộc dùng HTTPS, trừ khi gọi từ localhost. Phần thân yêu cầu là JSON với Content-Type: application/json.
Tải bản mô tả OpenAPI 3.1 để sinh client hoặc nhập vào Postman hay Insomnia.
Header#
| Header | Ý nghĩa |
|---|---|
X-Project-ID | ID dự án lấy từ bảng điều khiển (luôn bắt buộc). |
X-Client-Key | Khóa client công khai (luôn bắt buộc, an toàn khi đưa vào bản build). |
X-Secret-Key | Khóa bí mật của máy chủ, thay cho khóa client (chỉ dùng giữa các máy chủ). |
Authorization | Bearer <access_token> cho các endpoint của người chơi. |
X-Device-ID | ID cài đặt, không bắt buộc (dùng làm nhãn thiết bị của tài khoản khách). |
X-Majacloud-SDK | Client và phiên bản, không bắt buộc, ví dụ unity/2.0.0. |
Phản hồi#
Mọi phản hồi đều là JSON có ok. Lỗi còn kèm code ổn định, message, request_id và đôi khi details:
var top = await Majacloud.Leaderboards.GetTopAsync("coins", 10);
if (top.Ok)
{
foreach (var entry in top.Value.Entries)
Debug.Log($"#{entry.Rank} {entry.PlayerName} {entry.Score}");
}
else if (top.Error.IsRetryable)
{
// Network, timeout, 5xx or rate limit: try again later
Debug.Log("Retry in " + top.Error.RetryAfterSeconds + " s");
}
else
{
Debug.LogWarning(top.Error.Code + ": " + top.Error.Message + " (" + top.Error.RequestId + ")");
}var top := await Majacloud.leaderboards.get_top("coins", 10)
if top.ok:
for entry in top.value.entries:
print("#%d %s %d" % [entry.rank, entry.player_name, entry.score])
elif top.is_retryable():
# Network, timeout, 5xx or rate limit: try again later
print("Retry in ", top.retry_after, " s")
else:
push_warning("%s: %s (%s)" % [top.error, top.message, top.request_id])const top = await mc.leaderboards.getTop('coins', { limit: 10 });
if (top.ok) {
for (const entry of top.value.entries) {
console.log(`#${entry.rank} ${entry.player_name} ${entry.score}`);
}
} else if (top.error.retryable) {
// Network, timeout, 5xx or rate limit: try again later
console.log('Retry in', top.error.retryAfter, 's');
} else {
console.warn(`${top.error.code}: ${top.error.message} (${top.error.requestId})`);
}// Success
{ "ok": true, "entries": [ … ], "total": 42 }
// Error (HTTP 4xx/5xx)
{
"ok": false,
"error": {
"code": "rate_limited",
"message": "Project rate limit reached. Try again in a minute.",
"request_id": "6f1c2a9e-…",
"details": { "limit": 120, "window": "minute" }
}
}Ví dụ#
export PROJECT_ID="<project id>" CLIENT_KEY="pk_live_…"
curl https://majacloud.majanite.com/v1/project -H "X-Project-ID: $PROJECT_ID" -H "X-Client-Key: $CLIENT_KEY"
curl -X POST https://majacloud.majanite.com/v1/auth/guest -H "X-Project-ID: $PROJECT_ID" -H "X-Client-Key: $CLIENT_KEY" \
-H "Content-Type: application/json" -d '{}'Endpoint#
Dự án#
GET/projectThông tin dự án, gói và khóa công khai của cấu hình từ xaKhóa client
Phản hồi 200
{
"ok": true,
"project": {
"id": "8f3c…",
"name": "Space Runner",
"plan": "free",
"config_version": 12,
"config_public_key_xml": "<RSAKeyValue>…</RSAKeyValue>",
"config_public_key_pem": "-----BEGIN PUBLIC KEY-----\n…\n-----END PUBLIC KEY-----\n",
"services": {
"player_auth": true,
"leaderboards": true,
"remote_config": true,
"cloud_save": true,
"rewards": true
}
}
}
Xác thực người chơi#
POST/auth/guestTạo người chơi khách và một phiênKhóa client
Phần thân
{
"device_id": "optional installation id"
}
Phản hồi 201
{
"ok": true,
"auth_method": "guest",
"access_token": "eyJ2IjoyLCJ0IjoiYWNjZXNz…",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "2d0f…",
"refresh_expires_in": 2592000,
"player": {
"id": "c7a1…",
"player_id": "player_3f9c…",
"display_name": "Guest 4821",
"auth_type": "guest",
"email_verified": false
}
}
POST/auth/refreshXoay vòng refresh token và nhận access token mớiKhóa client
Phần thân
{
"refresh_token": "…"
}
Phản hồi 200
{
"ok": true,
"auth_method": "guest",
"access_token": "eyJ2IjoyLCJ0IjoiYWNjZXNz…",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "2d0f…",
"refresh_expires_in": 2592000,
"player": {
"id": "c7a1…",
"player_id": "player_3f9c…",
"display_name": "Guest 4821",
"auth_type": "guest",
"email_verified": false
}
}
Lỗi
unauthorized (reason: invalid | expired | revoked | reused)
POST/auth/logoutThu hồi phiênKhóa client
Phần thân
{
"refresh_token": "optional"
}
Phản hồi 200
{
"ok": true,
"revoked": true
}
POST/auth/link/startBắt đầu đăng nhập qua web (liên kết tài khoản khách với email hoặc Google)Token người chơi
Phần thân
{
"code_challenge": "base64url(sha256(verifier))",
"code_challenge_method": "S256",
"return_url": "optional, https on this host or an allowlisted scheme"
}
Phản hồi 201
{
"ok": true,
"flow_id": "uuid",
"flow_token": "…",
"auth_url": "https://majacloud.majanite.com/player-auth.php?flow_id=…&flow_token=…",
"expires_at": "2026-10-09T08:27:00Z",
"poll_interval_seconds": 3
}
GET/auth/link/statusThăm dò trạng thái luồng đăng nhậpKhóa client
Truy vấn
flow_id— uuidflow_token— …
Phản hồi 200
{
"ok": true,
"status": "pending | completed | consumed | expired",
"exchange_code": "(only when completed)",
"expires_at": "…"
}
POST/auth/link/exchangeĐổi luồng đã hoàn tất lấy một phiênKhóa client
Phần thân
{
"flow_id": "uuid",
"exchange_code": "…",
"code_verifier": "the original verifier"
}
Phản hồi 200
{
"ok": true,
"auth_method": "guest",
"access_token": "eyJ2IjoyLCJ0IjoiYWNjZXNz…",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "2d0f…",
"refresh_expires_in": 2592000,
"player": {
"id": "c7a1…",
"player_id": "player_3f9c…",
"display_name": "Guest 4821",
"auth_type": "guest",
"email_verified": false
},
"merged_guest": true
}
GET/players/meNgười chơi đã đăng nhậpToken người chơi
Phản hồi 200
{
"ok": true,
"player": {
"id": "c7a1…",
"player_id": "player_3f9c…",
"display_name": "Guest 4821",
"auth_type": "guest",
"email_verified": false
}
}
PATCH/players/meĐổi tên hiển thịToken người chơi
Phần thân
{
"display_name": "Nova"
}
Phản hồi 200
{
"ok": true,
"player": {
"id": "c7a1…",
"player_id": "player_3f9c…",
"display_name": "Guest 4821",
"auth_type": "guest",
"email_verified": false
}
}
GET/players/{player_id}Đọc thông tin bất kỳ người chơi nào (khóa bí mật)Khóa bí mật
Phản hồi 200
{
"ok": true,
"player": {
"id": "c7a1…",
"player_id": "player_3f9c…",
"display_name": "Guest 4821",
"auth_type": "guest",
"email_verified": false,
"email": "nova@example.com",
"wallets": [
{
"currency": "coins",
"balance": 150
}
]
}
}
Bảng xếp hạng#
POST/leaderboards/{slug}/scoresGửi điểmToken người chơi
Phần thân
{
"score": 120
}
Phản hồi 200
{
"ok": true,
"accepted": true,
"entry": {
"rank": 1,
"player_id": "player_3f9c…",
"player_name": "Nova",
"score": 9840,
"score_updated_at": "2026-10-09T08:12:00Z",
"is_me": false
},
"period": {
"key": "2026-W41",
"ends_at": "2026-10-12T00:00:00Z"
}
}
Lỗi
validation (bounds)rate_limited (cooldown)plan_limit (entry cap)
GET/leaderboards/{slug}/entriesCác mục đứng đầuKhóa client
Truy vấn
limit— 1-100 (default 10)offset— 0+period— current | previous
Phản hồi 200
{
"ok": true,
"leaderboard": {
"slug": "coins",
"name": "Coins",
"sort_type": "DESC",
"score_mode": "BEST",
"reset_rule": "WEEKLY"
},
"period": {
"key": "2026-W41",
"ends_at": "2026-10-12T00:00:00Z"
},
"entries": [
{
"rank": 1,
"player_id": "player_3f9c…",
"player_name": "Nova",
"score": 9840,
"score_updated_at": "2026-10-09T08:12:00Z",
"is_me": false
}
],
"total": 42,
"limit": 10,
"offset": 0,
"max_entries": 10
}
GET/leaderboards/{slug}/meThứ hạng và điểm của tôiToken người chơi
Truy vấn
period— current | previous
Phản hồi 200
{
"ok": true,
"entry": {
"rank": 1,
"player_id": "player_3f9c…",
"player_name": "Nova",
"score": 9840,
"score_updated_at": "2026-10-09T08:12:00Z",
"is_me": false
},
"total": 42
}
GET/leaderboards/{slug}/around-meCác mục quanh thứ hạng của tôiToken người chơi
Truy vấn
radius— 1-25 (default 3)
Phản hồi 200
{
"ok": true,
"entries": [
{
"rank": 1,
"player_id": "player_3f9c…",
"player_name": "Nova",
"score": 9840,
"score_updated_at": "2026-10-09T08:12:00Z",
"is_me": false
}
],
"me": {
"rank": 1,
"player_id": "player_3f9c…",
"player_name": "Nova",
"score": 9840,
"score_updated_at": "2026-10-09T08:12:00Z",
"is_me": false
},
"total": 42
}
Cấu hình từ xa#
GET/configCấu hình hiện hành, ký RSA; gửi If-None-Match để nhận 304Khóa client
Phản hồi 200
{
"ok": true,
"project_id": "8f3c…",
"version": 12,
"checksum": "sha256 of data",
"data": "base64url(JSON payload)",
"signature": "base64 RSA-SHA256 over data",
"signature_algorithm": "rsa-sha256",
"signing_key_id": "config-v1",
"configs": [
{
"key": "enemy_damage",
"type": "number",
"value": "25"
}
]
}
Lưu trữ đám mây#
GET/cloudLiệt kê các khóa đã lưuToken người chơi
Phản hồi 200
{
"ok": true,
"keys": [
{
"key": "progress",
"revision": 3,
"size_bytes": 180,
"updated_at": "…"
}
],
"total_bytes": 180
}
GET/cloud/{key}Tải một bản lưuToken người chơi
Phản hồi 200
{
"ok": true,
"key": "progress",
"data": {
"level": 3
},
"revision": 3,
"size_bytes": 180,
"updated_at": "…"
}
PUT/cloud/{key}Ghi một bản lưu (tùy chọn kèm bản sửa đổi mong đợi)Token người chơi
Phần thân
{
"data": {
"level": 4
},
"revision": "optional: expected current revision (0 = create only)"
}
Phản hồi 200
{
"ok": true,
"key": "progress",
"revision": 4,
"size_bytes": 190,
"updated_at": "…",
"created": false
}
Lỗi
revision_mismatch (details.current_revision)plan_limit (storage)
DELETE/cloud/{key}Xóa một bản lưuToken người chơi
Phản hồi 200
{
"ok": true,
"key": "progress",
"deleted": true
}
Phần thưởng và ví#
GET/rewardsPhần thưởng đang hoạt động (kèm cờ claimable khi có token người chơi)Khóa client
Phản hồi 200
{
"ok": true,
"rewards": [
{
"reward_key": "daily_coins",
"name": "Daily coins",
"amount": 50,
"currency": "coins",
"cooldown": "daily",
"claimable": true,
"next_claim_at": null
}
]
}
POST/rewards/claimNhận một phần thưởngToken người chơi
Phần thân
{
"reward_key": "daily_coins"
}
Phản hồi 200
{
"ok": true,
"accepted": true,
"reward_key": "daily_coins",
"amount": 50,
"currency": "coins",
"balance": 150,
"next_claim_at": "2026-10-10T00:00:00Z"
}
Lỗi
conflict (already claimed; details.next_claim_at)
GET/walletSố dư víToken người chơi
Phản hồi 200
{
"ok": true,
"wallets": [
{
"currency": "coins",
"balance": 150,
"updated_at": "…"
}
]
}