External API Partner docs
v1 latest

Partner-facing API

External Game Aggregator API

One integration for player creation, game launch, and seamless wallet settlement. The aggregator layer handles the provider bridge while your wallet remains the balance source of truth.

Auth
x-api-key
Format
JSON or form body
Wallet
HMAC-SHA256
01 Authenticate Headers, prefix, IP whitelist 02 Create and launch User handle, provider, game URL 03 Verify callbacks Balance, bet, settle, history

Base URL

All API requests are made to your assigned base URL. Replace https://api.example.com with the host provided to you.

https://api.example.com
Note - every endpoint is served over HTTPS. Plain HTTP requests are rejected.

Authentication

Authenticate every request with your secret API key in the x-api-key header. Your key is unique to your account and must be kept private - never expose it in client-side code.

HeaderRequiredDescription
x-api-keyrequiredYour secret API key.
x-api-prefixoptionalYour account prefix. Speeds up routing when supplied; otherwise it is resolved from the key.
Content-Typeoptionalapplication/json (recommended) or application/x-www-form-urlencoded.
curl https://api.example.com/game/provider \
  -H "x-api-key: YOUR_API_KEY"
Keep it secret - anyone with your API key can act on behalf of your account. Rotate it immediately if it leaks.

IP whitelist

For an extra layer of security your account can be locked to a list of allowed source IP addresses. When a whitelist is configured, requests from any other address are rejected with 403.

  • Provide the public IPs (or CIDR ranges) of your servers to enable the whitelist.
  • Both single addresses (203.0.113.10) and CIDR ranges (203.0.113.0/24) are supported.
  • Leave it unset to allow any source IP (API key only).

Conventions

  • Request bodies may be sent as JSON or form-encoded. Responses are always JSON.
  • The user_agent is the unique identifier of a player, returned by Register (for example LAG1.0632094194).
  • Monetary amounts are decimal numbers in your account currency.
  • Timestamps are ISO-8601 strings in UTC.
API reference
POST /create-user

Register

Create a player in the system. The returned user_agent is the handle you use for every subsequent call for this player.

Body parameters

FieldTypeDescription
user_agentstringrequiredYour unique player reference. Send either the local value (0632094194) or the full public value (LAG1.0632094194); if the prefix is already present it will be normalised before creation.
firstnamestringoptionalPlayer first name.
lastnamestringoptionalPlayer last name.
passwordstringoptionalPlayer password.
phonestringoptionalPlayer phone number.
ipstringoptionalPlayer IP address.
curl https://api.example.com/create-user \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "user_agent": "0632094194",
    "firstname": "Test",
    "lastname": "01",
    "password": "aa1234",
    "phone": "0632094194",
    "ip": "139.180.143.22"
  }'
{
  "user_agent": "LAG1.0632094194"
}
User agent format - the response always uses PREFIX.local_user. For example, both 0632094194 and LAG1.0632094194 create or return LAG1.0632094194, never LAG1.LAG1.0632094194.
GET /game/provider

Product list

Return the list of available game providers (products).

curl https://api.example.com/game/provider \
  -H "x-api-key: YOUR_API_KEY"
[
  {
    "provider_name": "PGSoft",
    "display_name": "pg soft",
    "image": "https://img.example.com/providers/pg.jpg"
  },
  {
    "provider_name": "Evolution Gaming",
    "display_name": "evolution gaming",
    "image": "https://img.example.com/providers/evo.jpg"
  }
]
POST /game/list

Game list

Return the games offered by a single provider.

Body parameters

FieldTypeDescription
game_providerstringrequiredprovider_name from Product list.
mobilebooleanoptionalReturn the mobile catalogue.
curl https://api.example.com/game/list \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "game_provider": "PGSoft", "mobile": true }'
{
  "is_item": true,
  "items": [
    {
      "game_id": "1513328",
      "game_name": "Super Golf Drive",
      "game_provider": "PGSoft",
      "game_type": "slot",
      "game_image": "https://cdn.example.com/pgsoft/spr-golf-drive.png",
      "is_active": true
    }
  ]
}
POST /game/open-game

Open game

Create a launch URL for a player. Redirect the player to the returned url to start playing.

Body parameters

FieldTypeDescription
user_agentstringrequiredPlayer handle from Register.
game_providerstringrequiredprovider_name of the game.
game_idstringrequiredgame_id from Game list. Use 0 for the provider lobby.
redirect_urlstringoptionalWhere to return the player after the game.
mobilebooleanoptionalLaunch the mobile client.
ipstringoptionalPlayer IP address.
curl https://api.example.com/game/open-game \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "user_agent": "LAG1.0632094194",
    "game_provider": "PGSoft",
    "game_id": "1513328",
    "redirect_url": "https://your-site.com/lobby",
    "mobile": true,
    "ip": "139.180.143.22"
  }'
{
  "is_item": false,
  "url": "https://play.example.com/launch?token=..."
}
POST /bet-history/report/detail-bet

Bet history

Return a detail view for a single bet. The item is a URL that renders the round result.

Body parameters

FieldTypeDescription
bet_idstringrequiredThe public bet reference received in the wallet callback or History callback.
curl https://api.example.com/bet-history/report/detail-bet \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "bet_id": "64aa6ac13b909c3b91986abe" }'
{
  "status": true,
  "item": "https://history.example.com/redirect.html?trace_id=..."
}
Seamless wallet

Overview

In the seamless wallet model you hold the player balance. When a player bets or wins, our platform calls your wallet endpoints in real time and uses your response as the source of truth - no balance transfers are required.

You implement and host the five callback endpoints below under a single base URL (your wallet URL). Every request is signed with HMAC-SHA256 so you can verify it is authentic.

CallbackWhen we call it
POST /balanceTo read the player's current balance.
POST /betTo debit a bet amount.
POST /settle-betTo credit the payout for a previously debited bet.
POST /bet-endTo debit and finalise an immediate-result round in one callback.
POST /historyTo deliver a bet record for your reporting.
Correlation - bet_id identifies the public bet record used by /history and /bet-history/report/detail-bet. txn_id identifies the current wallet callback, and the following /history callback echoes the same txn_id.

Wallet callback response contract

ResultHTTP statusResponse bodyMeaning
Applied successfully2xxJSON with a finite numeric balance.balance is the authoritative post-operation wallet balance. A genuine value of 0 is valid.
Rejected, not applied409 or 422Optional error JSON; omit balance.The wallet guarantees that this callback made no balance change.
Technical/unknown failureOther non-2xxOptional error JSON; omit balance.The operation is failed, but the platform does not infer a post-operation balance.
{
  "code": "INSUFFICIENT_FUNDS",
  "error": "insufficient balance"
}
{
  "balance": 0
}
Do not use a placeholder balance - never return HTTP 200 with balance: 0 for a rejected operation. Use 409 or 422 and omit balance. If a repeated txn_id was already applied, return the original successful result idempotently; do not report it as not applied.

Wallet callback relationship

The money callback always happens first. /history is sent afterwards when the bet record is created or updated. Treat /history as reporting/reconciliation data only; do not change wallet balance from /history.

bet_id

Public bet record id. It is the internal history row _id, not the provider transaction id.

txn_id

Unique id for one wallet movement. The matching /history callback repeats the same value.

/history

Confirms the record details for the preceding /bet, /settle-bet, or /bet-end.

Debit then settle - one history row

Use this model when the provider first debits a stake and later settles the same round. The settle callback uses the same bet_id as the original bet, while txn_id changes for each wallet movement.

Debit then settle - separate history rows

Some providers store the bet and the settle as separate reporting rows. In that case each money callback gets its own bet_id, and each following /history uses the matching pair.

Immediate-result round

Use /bet-end only when one provider callback contains both the stake and final payout. The wallet should debit the stake and apply the payout in one idempotent operation.

CallbackMoney actionHistory relationshipIdempotency key
/betDebit the stake.The next /history repeats the same bet_id and txn_id.txn_id for this debit; bet_id for the bet record.
/settle-betCredit the payout. The payout may be 0 when the round closes without a win.For one-row games it updates the original bet_id. For separate-row games it may use a new settle bet_id.txn_id for this settle; bet_id for the affected record.
/bet-endDebit stake and apply final payout in one operation.The next /history repeats the same bet_id and txn_id.txn_id for the combined movement; bet_id for the final record.
/historyNo balance change.Reporting copy of the record created or updated after the money callback.Store by bet_id + txn_id to avoid duplicate processing.
Important - never use a provider transaction id as the public bet_id. The public bet_id must match the _id used by /history and by /bet-history/report/detail-bet.

HMAC signature

Every callback body includes an hmac field. Verify it with your shared AGENT_SECRET before trusting the payload.

  1. Remove the hmac field. The remaining fields are your payload.
  2. Sort the payload keys alphabetically (A to Z).
  3. Serialise to a compact JSON string (no extra whitespace).
  4. Compute HMAC-SHA256 of that string with AGENT_SECRET and output hex.
  5. Compare against the received hmac. If equal, the request is authentic.
const crypto = require('crypto');

function verifyCallbackSignature(reqBody, agentSecret) {
  const { hmac, ...payload } = reqBody;
  if (!hmac) return false;

  const sorted = Object.keys(payload).sort()
    .reduce((acc, k) => { acc[k] = payload[k]; return acc; }, {});

  const expected = crypto
    .createHmac('sha256', agentSecret)
    .update(JSON.stringify(sorted))
    .digest('hex');

  return hmac === expected;
}

// app.post('/bet', (req, res) => {
//   if (!verifyCallbackSignature(req.body, AGENT_SECRET))
//     return res.status(401).json({ error: 'invalid signature' });
//   ...
// });
Reject unsigned requests - if the signature is missing or does not match, respond with an error and do not change any balance.
POST{wallet}/balance

Check balance

Return the player's current balance.

{
  "user_agent": "LAG1.0632094194",
  "hmac": "8f2be832..."
}
{
  "balance": 296.59,
  "tmp": 0,
  "fish_remaining": 0,
  "turn_over": 1580.38,
  "game_type": "slot"
}
POST{wallet}/bet

Bet

Debit a bet from the player's balance. Use this for debit-only provider events where the final result is not included yet. Return the resulting balance.

When the debit is rejected - if your wallet does not deduct the bet and can guarantee that no balance change was made, return HTTP 409 or 422. Do not include balance in the response. Never return HTTP 200 with balance: 0 or success: false for a rejected debit, because every 2xx response represents an applied wallet operation.
FieldTypeDescription
user_agentstringPlayer handle.
balancenumberThe bet amount to debit.
bet_idstringBet-history reference shared by related callbacks.
txn_idstringUnique money-callback transaction id; use this as the idempotency key. The following /history payload will echo this value.
hmacstringSignature - verify before processing.
{
  "user_agent": "LAG1.0632094194",
  "balance": 5,
  "bet_id": "1677950013029748736",
  "txn_id": "01KZ9Q2AMJH7W8G8BNC6Q7TEJ4",
  "hmac": "8f2be832..."
}
{
  "balance": 291.59,
  "tmp": 0,
  "fish_remaining": 0
}

Rejected debit responses

Use 422 for a known business rejection such as insufficient balance. Use 409 for a known transaction conflict or other deterministic rejection. In both cases, the debit must not have been applied and the response must omit balance. The response body is optional.

HTTP/1.1 422 Unprocessable Content
Content-Length: 0
HTTP/1.1 409 Conflict
Content-Type: application/json

{
  "code": "BET_REJECTED",
  "message": "Debit was not applied"
}
Idempotent retry - store the original result by txn_id. A repeated txn_id must never move money a second time and must return the original HTTP status and body. If the first request was applied, replay the original successful 2xx response with its original balance. If it was rejected, replay the original 409 or 422 response.
POST{wallet}/settle-bet

Settle bet

Credit the payout for a previously debited bet. Use this when the provider settles after /bet; use /bet-end instead when stake and final payout arrive together.

FieldTypeDescription
user_agentstringPlayer handle.
betnumberThe original bet amount.
balancenumberThe payout amount to credit. It may be 0 when the round closes without a win.
bet_idstringUnique bet reference.
txn_idstringUnique money-callback transaction id; use this as the idempotency key. The following /history payload will echo this value.
hmacstringSignature.
{
  "user_agent": "LAG1.0632094194",
  "bet": 5,
  "balance": 20,
  "bet_id": "1677950013029748736",
  "txn_id": "01KZ9Q2BK6XRE9G1WKY4K1TW7B",
  "hmac": "8f2be832..."
}
{
  "balance": 311.59,
  "tmp": 0,
  "fish_remaining": 0
}
POST{wallet}/bet-end

Bet end

Finalise an immediate-result round. Sent with both the bet amount and final win amount when the provider reports the result in the same callback.

When bet-end is rejected - process the stake debit and payout as one atomic operation. If your wallet cannot complete it and can guarantee that neither the debit nor the payout was applied, return HTTP 409 or 422 and omit balance. Never return a rejection after applying only part of the operation.
FieldTypeDescription
user_agentstringPlayer handle.
balancenumberThe bet amount.
win_balancenumberThe win amount.
bet_idstringUnique bet reference.
txn_idstringUnique money-callback transaction id; use this as the idempotency key. The following /history payload will echo this value.
hmacstringSignature.
{
  "user_agent": "LAG1.0632094194",
  "balance": 5,
  "win_balance": 20,
  "bet_id": "1677950013029748736",
  "txn_id": "01KZ9Q2CSYYFA5QHHKHPD12F3Y",
  "hmac": "8f2be832..."
}
{
  "balance": 311.59,
  "tmp": 0,
  "fish_remaining": 0
}

Rejected bet-end responses

Use 422 for a known business rejection such as insufficient balance. Use 409 for a known transaction conflict or other deterministic rejection. Both statuses mean the complete bet-end operation was not applied: no stake was debited, no payout was credited, and the response omits balance. The response body is optional.

HTTP/1.1 422 Unprocessable Content
Content-Length: 0
HTTP/1.1 409 Conflict
Content-Type: application/json

{
  "code": "BET_END_REJECTED",
  "message": "Bet-end was not applied"
}
Idempotent retry - store the original atomic result by txn_id. A repeated txn_id must not debit the stake or credit the payout again. Replay an applied operation with its original successful 2xx response and original balance; replay a rejected operation with its original 409 or 422 response.
POST{wallet}/history

History

Delivered whenever a bet record is created or updated, so you can keep a full copy for reporting and reconciliation. This callback is not a wallet movement. Acknowledge with HTTP 200.

FieldTypeDescription
bet_idstringPublic bet record id. This matches the bet_id sent in the wallet callback.
txn_idstringWallet callback transaction id. This matches the preceding /bet, /settle-bet, or /bet-end callback.
createdAtstringCreated timestamp (ISO-8601).
updatedAtstringUpdated timestamp (ISO-8601).
providerstringProvider name.
gamestringGame name.
before_balancenumberBalance before the round.
after_balancenumberBalance after the round.
used_balancenumberAmount staked.
user_agentstringPlayer handle.
receive_balancenumberAmount returned.
winlosenumberNet win (+) or loss (-).
hmacstringSignature.
{
  "bet_id": "1677950013029748736",
  "txn_id": "01KZ9Q2BK6XRE9G1WKY4K1TW7B",
  "createdAt": "2026-06-04T09:30:00.000Z",
  "updatedAt": "2026-06-04T09:30:04.000Z",
  "provider": "PGSoft",
  "game": "Super Golf Drive",
  "before_balance": 296.59,
  "after_balance": 311.59,
  "used_balance": 5,
  "user_agent": "LAG1.0632094194",
  "receive_balance": 20,
  "winlose": 15,
  "hmac": "8f2be832..."
}
Reference

Errors

The API uses standard HTTP status codes. Authentication and authorisation failures return a JSON body with an error message.

StatusMeaningBody
200Success.Endpoint payload.
401Missing or invalid API key.{ "error": "Invalid API key" }
403IP not allowed, or account not permitted.{ "error": "IP not allowed" }
404Unknown route.{ "error": "Not Found" }
500Unexpected server error.{ "error": "..." }

Integration flow

A typical end-to-end integration looks like this:

  1. Register each of your players once with /create-user and store the returned user_agent.
  2. Browse games with /game/provider and /game/list.
  3. Launch a game with /game/open-game and redirect the player to the returned URL.
  4. Settle play as it happens - implement the seamless wallet callbacks so we can read balance, debit bets, and credit wins against your wallet.
  5. Reconcile using the /history feed and /bet-history/report/detail-bet.
Need a key or a base URL? Contact your account manager to receive your API key, base URL, AGENT_SECRET, and to register your wallet URL and IP whitelist.