< Intégration REST />
UTD Games
Ajoutez un catalogue de jeux complet à votre app — UTD l'exploite en tant que votre agence.
# From your backend, read the launch flag with the API token.
# Show or hide games in your app based on the response.
curl https://utdsoftware.com/api/games/launch-flag \
-H "Authorization: Bearer 12|xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
# => { "games_enabled": true }
# games_enabled reflects the games wallet balance (gated at zero).
# Cache briefly server-side; never ship this token to a client app.REST
Protocole
launch-flag
Indicateur d'exécution
Server-to-server
Intégration
Agency
Modèle
< utd-games />
Fonctionnalités clés
Une intégration REST serveur à serveur qui permet à votre app de proposer un catalogue de jeux complet sans rien construire ni héberger. UTD agit comme votre agence de jeux : vous provisionnez chaque projet depuis le tableau de bord, notre équipe le vérifie et l'active, et votre backend lit un unique launch flag pour afficher ou masquer les jeux. Le jeu se déroule directement entre votre app et le fournisseur ; UTD gère le provisionnement, le launch flag et la facturation mensuelle des commissions — les secrets du fournisseur n'atteignent jamais votre app.
REST serveur à serveur — intégrez depuis n'importe quel langage, aucun SDK requis
Un seul endpoint launch flag décide d'afficher ou de masquer les jeux
Jetons API à portée limitée (launch-flag uniquement) — sûrs à exécuter sur vos serveurs
Gating automatique : les jeux se désactivent lorsque le solde du portefeuille atteint zéro
Modèle d'agence — UTD provisionne et vérifie chaque projet avant sa mise en ligne
Facturation mensuelle des commissions sur les coins nets, calculée et réglée pour vous
Les secrets du fournisseur restent côté serveur et ne sont jamais exposés à votre app
Jusqu'à 10 jetons API actifs par compte, révocables à tout moment
< utd-games />
Commencer
Installer
# Mint a server-to-server API token (scoped to launch-flag only).
# Run once from your dashboard session; the secret is shown a single time.
curl -X POST https://utdsoftware.com/api/games/api-tokens \
-H "Authorization: Bearer <your-session-token>" \
-H "Content-Type: application/json" \
-d '{"name":"production-server"}'
# => { "token": { "id": 12, "name": "production-server", ... },
# "secret": "12|xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" } # store securelyDemander l'accès
Ajoutez un catalogue de jeux complet à votre app — UTD l'exploite en tant que votre agence.
< utd-games />
Référence de l'API
Game callbacks (hosted on YOUR backend)
Our games platform calls these three endpoints on your backend to read and move each player's coin balance. All three are POST, live under one base URL at the /api/leader-cc-game/ prefix (base = the Callback base URL you enter when creating the project — e.g. base https://api.yourapp.com means we call https://api.yourapp.com/api/leader-cc-game/get-user-info), and ALWAYS answer HTTP 200 — success or failure travels in the body as errorCode (0 = success). The response envelope is {errorCode, errorMsg, data} — NOT {code/status/msg}. Any other envelope is rejected as "structure incorrect". Your APP_KEY (the shared signing secret) is shown in the "Callback test" step of the create-project wizard before you submit, and stays the same after activation. Signature rule for every endpoint: concatenate the values in the exact order listed (a missing/absent field enters the string as "", an empty string), append APP_KEY, md5 — then compare case-insensitively.
How a game session works (read this first)fieldlaunchUrl + '&uid=' + playerId + '&token=' + playerToken1) Your app opens the game's Launch URL in a WebView and appends the player's identity: &uid=<player id>&token=<a session token YOUR backend issued for that player>. 2) The game engine calls your get-user-info callback with that same uid + token — you MUST verify the token really belongs to that uid (mismatch → errorCode 10003); the signature only proves the call came from the games platform, the token is what proves the player. 3) Every bet/win during play calls your change-balance callback. coin values are in YOUR app's coin currency (the coin price you set at submission, e.g. 1 USD = 13,000 coins). In get-user-info, nickname/avatar personalize the game UI; vipLevel and water can be 0 if you don't use them.
POST {base}/api/leader-cc-game/get-user-infomethodPOST {base}/api/leader-cc-game/get-user-info
Content-Type: application/json
{ "gameId", "uid", "token", "roomId", "sign" }Called once when a player opens a game. Verify sign = md5(gameId + uid + token + roomId + APP_KEY) — concatenated values, no separators, compared case-insensitively — then return the player's profile and current balance. uid and coin are REQUIRED inside data. Bad signature → errorCode 10004. Unknown player or uid/token mismatch → 10003. Player blocked or games intentionally disabled on your side → 30001.
Retourne: { errorCode: 0, errorMsg: "success", data: { uid, nickname, avatar, coin, vipLevel, water } } — HTTP 200 always. data.coin is the player's current balance (integer).
POST {base}/api/leader-cc-game/change-balancemethodPOST {base}/api/leader-cc-game/change-balance
Content-Type: application/json
{ "orderId", "gameId", "roundId", "uid", "coin", "type", "rewardType", "token", "winId", "roomId", "sign" }Called on every bet and win. type=1 → deduct coin (bet), type=2 → add coin (win). Verify sign = md5(orderId + gameId + roundId + uid + coin + type + rewardType + token + winId + roomId + APP_KEY). Apply the change, then read the wallet AGAIN and return the NEW balance — returning the old unchanged balance is the #1 activation rejection. Insufficient balance on a bet → errorCode 4004 and move no money. Must be idempotent by orderId: the same orderId arriving twice moves money once and returns the current balance with errorCode 0. coin=0 is a valid no-op (used by the dashboard self-test).
Retourne: { errorCode: 0, errorMsg: "success", data: { coins: <NEW balance>, coin: <NEW balance> } } — HTTP 200 always. data.coins MUST reflect the balance AFTER the debit/credit.
POST {base}/api/leader-cc-game/make-up-ordersmethodPOST {base}/api/leader-cc-game/make-up-orders
Content-Type: application/json
{ "orderId", "gameId", "roundId", "uid", "coin", "rewardType", "winId", "roomId", "sign" }Re-settles a reward the platform believes was lost (rare). Signature has NO type and NO token: sign = md5(orderId + gameId + roundId + uid + coin + rewardType + winId + roomId + APP_KEY). CRITICAL: share ONE idempotency key with change-balance, scoped to the orderId. If that orderId was already settled, return the current balance with errorCode 0 and move NO money — a separate per-endpoint key double-credits (mints coins).
Retourne: { errorCode: 0, errorMsg: "success", data: { coin: <NEW balance> } } — HTTP 200 always. Returns the balance after the credit (or the current balance on an idempotent replay).
Error codesfield{ "errorCode": 30001, "errorMsg": "games disabled", "data": [] }0 success · 4004 insufficient coins on a bet · 4005 missing/invalid parameter or a REAL backend failure ONLY (platform monitoring alerts on 4005 — never use it for intentional stops) · 10003 user not found / uid-token mismatch · 10004 signature verification failed · 30001 intentional block (player banned, or games disabled on your side). Every response is HTTP 200 with the {errorCode, errorMsg, data} envelope; error responses use data: [].
Launch flag
The one endpoint your app calls at runtime. Read it server-to-server with a scoped API token to decide whether to show or hide games. Reflects the games wallet balance — automatically gated at zero.
GET /api/games/launch-flagmethodGET /api/games/launch-flag
Authorization: Bearer <api-token>Returns whether games are enabled for the account. Requires an API token carrying the games:launch-flag ability (a session token also works for owner testing). Cache the result briefly server-side; never expose the token to a client app.
Retourne: { games_enabled: boolean } — games_enabled is true when the games wallet has a positive balance, false when gated.
API tokens
Server-to-server tokens scoped to launch-flag only — they cannot read analytics, mint other tokens, or touch any other route. Managed from your dashboard session (the session bearer). Up to 10 active tokens per account.
POST /api/games/api-tokensmethodPOST /api/games/api-tokens
Authorization: Bearer <session-token>
Content-Type: application/jsonMints a new API token scoped to the games:launch-flag ability. The plaintext secret is returned once and never again — store it securely. Fails with 422 token_limit_reached at 10 active tokens.
Paramètres
namestringrequisA label to identify the token (max 60 chars), e.g. "production-server".
Retourne: { token: { id, name, last_used_at, created_at }, secret: string } — secret is the plaintext bearer, shown only in this response (HTTP 201).
GET /api/games/api-tokensmethodGET /api/games/api-tokens
Authorization: Bearer <session-token>Lists your active games API tokens (masked — no secrets). Only games tokens are listed; your browser session token is never included.
Retourne: { tokens: Array<{ id, name, last_used_at, created_at }> } — Metadata only; the secret is never re-exposed after creation.
DELETE /api/games/api-tokens/{id}methodDELETE /api/games/api-tokens/{id}
Authorization: Bearer <session-token>Revokes (permanently deletes) one of your games API tokens by id. Returns 404 if the id is not one of your games tokens.
Retourne: { ok: true } — Revocation is immediate and irreversible.
Provisioning (agency model)
UTD is your games agency: each project is created from the dashboard and reviewed by our team before it goes live. You do not integrate the game engine yourself — gameplay runs directly between your app and the provider; UTD handles provisioning, the launch flag, and monthly billing. Submission order: (1) get your signing key from GET /api/games/draft-credentials, (2) build the three callbacks, (3) pass POST /api/games/draft-callback-test with your callback URL + test account, (4) submit the project with the SAME values — submissions without a passing test are rejected with callback_test_required. The dashboard wizard walks these steps for you.
GET /api/games/draft-credentialsmethodGET /api/games/draft-credentials
Authorization: Bearer <session-token>Returns your signing key (app_key) BEFORE any project exists, so you can implement signature verification and test it. The key is stable per account — calling twice returns the same key, and the project you later submit keeps this same key after activation, so nothing you built breaks.
Retourne: { app_key: string } — Your APP_KEY — the shared secret used in every callback signature.
POST /api/games/draft-callback-testmethodPOST /api/games/draft-callback-test
Authorization: Bearer <session-token>
Content-Type: application/jsonRuns the full integration self-test against your backend before a project exists: UTD sends genuinely signed payloads (with your draft app_key) to your three callbacks and validates every response against the exact contract above — envelope, errorCode 0, balance fields, forged-signature and foreign-token rejection. It then proves the balance actually MOVES: a small credit → replay of the same orderId (must be a no-op, no coin minting) → an equal debit that restores the balance — all net-zero on your test account. This catches a backend that returns 'success' with an unchanged balance (the #1 activation rejection). A passing test unlocks project submission for the exact (callback_base_url, test_uid, test_token) you tested; changing any of them invalidates the pass and you must re-test. Rate-limited to 6 calls per minute.
Paramètres
callback_base_urlstringrequisYour backend base URL hosting the three callbacks (https, publicly reachable).
test_uidstringrequisA real test account id on YOUR platform.
test_tokenstringrequisA valid session token for that test account (your backend must accept it in get-user-info).
Retourne: { ok: boolean, checks: Array<{ name, url, ok, http_status, error, response }>, error_codes_contract: string } — One check per callback with the exact failure reason when a response doesn't match the contract. ok: true = you can submit.
POST /api/games/projectsmethodPOST /api/games/projects
Authorization: Bearer <session-token>
Content-Type: multipart/form-data
payload = JSON string of the fields below
screenshots[] = 1–8 image files (jpg/png/webp, max 4MB each)Submits a new games project for review from your dashboard session. Requires a verified phone on the account, and a passing draft callback test matching the submitted callback_base_url + test_uid + test_token exactly — otherwise 422 {"message":"callback_test_required"}. The request is multipart: all fields go JSON-encoded inside a single "payload" part, plus screenshots[] file parts. The project starts pending; the UTD team provisions it with the provider and approves it (status becomes active). Provider secrets are never exposed to your app.
Paramètres
namestringrequisProject display name (max 255).
callback_base_urlstringrequisYour backend base URL that hosts the three game callbacks. Must match the URL that passed the draft callback test.
coin_priceintegerrequisHow many of your in-app coins equal 1 unit of currency (e.g. 13000 for 1 USD = 13,000 coins). coin values in the callbacks use this currency.
coin_currencystringCurrency of coin_price (default USD, max 10 chars).
app_linksArray<{platform, url}>requisAt least one live link to your app (store page or APK/site).
test_uid / test_tokenstringrequisThe test account that passed the draft callback test — the games team also uses it to verify your callbacks before activation.
languagesstring[]requisGame languages to enable (min 1): Arabic, English, Urdu, Indian, Turkish.
regionstringrequisWhere most of your users are, e.g. "Dubai" or "Doha" (max 120) — used to place game servers near them.
screen_sizesstring[]requisGame screen sizes to provision (min 1): full, HD, Half.
timezonestringrequisYour app's timezone, e.g. "GMT+03" (max 32).
game_idsinteger[]requisCatalog ids of the games you want (1–8). Launches start with a maximum of 8 games — more are added later as your audience grows.
daily_active_usersintegerApproximate daily active users (optional).
requested_games_notestringFree-text list of games you want that are not in the catalog (max 2000 chars).
Retourne: { project: { id, name, status, provider_app_id } } — The created project in pending status, awaiting UTD review. 422 callback_test_required = run the draft callback test first with these exact values.
POST /api/games/projects/{id}/callback-testmethodPOST /api/games/projects/{id}/callback-test
Authorization: Bearer <session-token>Self-test for your three game callbacks (get-user-info / change-balance / make-up-orders). UTD sends genuinely signed payloads to your callback base URL using the project's test account. Beyond the contract checks (envelope, errorCode 0, forged-signature and foreign-token rejection), it proves the balance actually moves: a small credit → replay of the same orderId (must be a no-op — no coin minting) → an equal debit that restores the balance, all net-zero on your test account. This catches a backend that returns 'success' with an unchanged balance (the #1 activation rejection). Rate-limited to 6 calls per minute (429 → wait a minute). Requires callback_base_url, test_uid and test_token on the project.
Retourne: { ok: boolean, checks: Array<{ name, url, ok, http_status, error, response }>, error_codes_contract: string } — One entry per check: the three callbacks, the two negative checks (forged-signature-rejected, wrong-token-rejected), and the three balance-movement checks (balance-credit-applied, balance-idempotent, balance-debit-restored). error_codes_contract restates the rule: intentional blocking must return errorCode 30001; 4005 is reserved for real failures (provider monitoring alerts on it).
Prêt à construire avec UTD ?
Créez votre compte, alimentez votre portefeuille principal et activez les services dont vous avez besoin.