# Casino API — Full Integration Guide (A to Z)

**Base URL:** `https://casinoapi.shop`
**For:** Clients connecting their casino website to our game API
**Level:** Beginner friendly — no advanced programming needed

---

## Table of Contents

1. What you get & how it works (the big picture)
2. Step 1 — Get your API credentials
3. Step 2 — Set your Callback URL & IP whitelist
4. Step 3 — Create the files on your computer
5. Step 4 — Upload the files to your website (cPanel / FTP)
6. Step 5 — Show the game list on your site
7. Step 6 — Launch a game (real money)
8. Step 7 — Handle bet / win / rollback callbacks
9. Step 8 — Add a full game lobby to your website
10. Step 9 — Test everything with the API Test tool
11. Going live checklist
12. Troubleshooting (common errors & fixes)
13. FAQ

---

## 1. How it works (the big picture)

```
Your player clicks a game on YOUR website
        │
        ▼
Your server calls  POST /api/public/v1/launch  (with your API token)
        │
        ▼
We return a game URL  →  you redirect the player there
        │
        ▼
Player plays. For every bet / win / rollback,
OUR server calls YOUR callback URL  →  you update the player's balance
        │
        ▼
You reply { "code": 0, "balance": <new balance> }
```

**You need 3 things on your website:**
1. A page that lists games (calls `GET /api/public/v1/games`)
2. A launch script (calls `POST /api/public/v1/launch` and redirects)
3. A callback script (receives bet/win/rollback and updates balances)

---

## 2. Step 1 — Get your API credentials

1. Log in to your client panel: `https://casinoapi.shop/auth`
2. Go to **Settings → API Credentials**.
3. Your **API Key (token)** and **Secret Key** are created automatically. If you don't see them, they generate the first time you open the page.
4. Click the **eye icon** to reveal, and **Copy** to copy.
5. Keep the secret key **private** — never put it in browser/JavaScript code.

> If keys are ever leaked, press **Regenerate Keys** — old keys stop working instantly.

---

## 3. Step 2 — Set your Callback URL & IP whitelist

In **Settings**:

- **Callback URL:** the full URL of the callback file you will upload, e.g.
  `https://your-casino.com/casino/callback.php`
  Without this, real-money games cannot run (we can't credit wins).
- **IP whitelist (optional but recommended):** add your server's IP address, one per line. Then only your server can use your API key.
  Find your server IP in your hosting panel, or run `curl ifconfig.me` on your server.

---

## 4. Step 3 — Create the files on your computer

Open **Notepad** (Windows) or **TextEdit** (Mac) — or any code editor — and create these 3 files. Save them exactly with these names:

```
casino/games.php       ← shows the game list
casino/launch.php      ← starts a game
casino/callback.php    ← receives bet / win / rollback
```

### File 1 — `casino/games.php` (game list)

```php
<?php
// casino/games.php — list all available games
$TOKEN = "PASTE_YOUR_API_KEY_HERE";

$ch = curl_init("https://casinoapi.shop/api/public/v1/games");
curl_setopt_array($ch, [
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_HTTPHEADER => ["Authorization: Bearer " . $TOKEN],
]);
$data = json_decode(curl_exec($ch), true);
curl_close($ch);

$games = $data["games"] ?? [];
?>
<!doctype html>
<html>
<head><title>Games</title></head>
<body>
<h1>Our Games (<?php echo count($games); ?>)</h1>
<div style="display:flex;flex-wrap:wrap;gap:12px">
<?php foreach ($games as $g): ?>
  <a href="launch.php?game_uid=<?php echo urlencode($g["game_uid"]); ?>"
     style="border:1px solid #ccc;padding:10px;border-radius:8px;text-decoration:none">
    <?php echo htmlspecialchars($g["name"]); ?>
  </a>
<?php endforeach; ?>
</div>
</body>
</html>
```

### File 2 — `casino/launch.php` (launch a game)

```php
<?php
// casino/launch.php — launch a real-money game and redirect the player
$TOKEN = "PASTE_YOUR_API_KEY_HERE";

// In a real site these come from YOUR login/session system:
$playerId   = "100245";                    // your player's ID — DIGITS ONLY
$gameUid    = $_GET["game_uid"] ?? "";     // from games.php link
$currency   = "BDT";                       // your play currency
$balance    = 1000;                        // starting balance for this session

$payload = json_encode([
  "token"        => $TOKEN,
  "user_id"      => $playerId,
  "game_uid"     => $gameUid,
  "currency_code"=> $currency,
  "balance"      => $balance,
  "return"       => "https://your-casino.com/lobby",
  "callback"     => "https://your-casino.com/casino/callback.php",
]);

$ch = curl_init("https://casinoapi.shop/api/public/v1/launch");
curl_setopt_array($ch, [
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_POST => true,
  CURLOPT_HTTPHEADER => ["Content-Type: application/json"],
  CURLOPT_POSTFIELDS => $payload,
]);
$res  = curl_exec($ch);
$http = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
$data = json_decode($res, true);

if (!empty($data["data"]["url"])) {
  header("Location: " . $data["data"]["url"]);   // send player into the game
  exit;
}
http_response_code(400);
echo "Launch failed: " . ($data["msg"] ?? $res);
```

### File 3 — `casino/callback.php` (player check + round updates)

```php
<?php
// Use the complete, maintained receiver instead of copying an abbreviated
// example. Download it from Client Panel → API Docs → Callback.php.
// Configure API_SECRET and your database connection at the top of that file,
// then upload it as casino/callback.php.
```

**Rules for the callback (very important):**
- Verify `X-Signature` (HMAC-SHA256 of the exact raw request body) before changing money.
- `event: "verify_player"` must return the player's current website balance.
- `event: "round"` sends `bet_amount` and `win_amount`; apply `wallet = wallet - bet_amount + win_amount` atomically.
- Always answer JSON `{"code": 0, "balance": <new balance>}`. Any other `code` = we treat it as failed.
- Use `callback_id` as the unique transaction key. If it arrives twice, do NOT change the balance again; return the current balance.
- The URL must be **publicly reachable over HTTPS** and answer within a few seconds.

---

## 5. Step 4 — Upload the files to your website

### Option A — cPanel File Manager (easiest, most hostings)

1. Log in to your hosting **cPanel**.
2. Open **File Manager** → go to `public_html`.
3. Click **+ Folder**, name it `casino`.
4. Open the `casino` folder → click **Upload** → select your 3 files (`games.php`, `launch.php`, `callback.php`).
5. Done — your files are live at:
   - `https://your-casino.com/casino/games.php`
   - `https://your-casino.com/casino/launch.php`
   - `https://your-casino.com/casino/callback.php`

### Option B — FTP (FileZilla)

1. Install **FileZilla** (free).
2. In your hosting panel find FTP details: **host**, **username**, **password**, port **21**.
3. Connect, open `public_html`, create folder `casino`, drag your 3 files into it.

### Option C — Node.js / custom stack

Use the same logic — see the Node.js examples in your client panel **Setup Documentation** page. Put the callback behind any route, e.g. `POST /casino/callback`.

### After uploading

1. Open `https://your-casino.com/casino/games.php` in a browser — you should see the game list.
2. Go to client panel **Settings** → set **Callback URL** = `https://your-casino.com/casino/callback.php` → Save.
3. Add your server IP to the **IP whitelist** → Save.

---

## 6. Step 5 — Show the game list

Your `games.php` already does this. Design it however you like — the API gives you for each game: `game_uid`, `name`, `provider`, image. Filter by provider with `GET /api/public/v1/providers`.

Want free-play demo buttons? Call:

```
GET /api/public/v1/demo?token=YOUR_API_KEY&game_uid=GAME_UID
```

It returns a demo URL — no balance needed.

---

## 7. Step 6 — Launch a game (real money)

Already covered by `launch.php`. Remember:

- `user_id` must be **digits only** (e.g. `100245`) — map your player IDs to numbers.
- `currency_code` should match your account's play currency.
- `balance` is the starting balance for that game session.
- `return` is where the player comes back after the game.
- `callback` is where we send bet/win/rollback events.
- The player must exist in **your** database — we never store your players.
- Your **GGR balance** must be above 0, otherwise launch is rejected.

---

## 8. Step 7 — Callbacks

Covered by `callback.php`. The callback URL is called as:

```
POST /api/public/v1/notify/{session_id}  →  your Callback URL
Body: { "type": "bet|win|rollback", "player_id": "...", "round_id": "...", "amount": 12.50, ... }
```

Test it by launching a real game and placing a small bet — your player's balance should move.

---

## 9. Step 8 — Add a full game lobby to your website

Below are complete copy-paste examples. Each one loads providers and games from the API, adds a provider filter and search box, and gives every game a **Demo** and a **Play** button.

### PHP — full game lobby (`casino/games.php`)

```php
<?php
$TOKEN = "PASTE_YOUR_API_TOKEN_HERE";
$BASE  = "https://casinoapi.shop";

$providers = json_decode(file_get_contents("$BASE/api/public/v1/providers?token=" . urlencode($TOKEN)), true)["data"]["providers"] ?? [];
$games     = json_decode(file_get_contents("$BASE/api/public/v1/games?token=" . urlencode($TOKEN)), true)["data"]["games"] ?? [];
$brandId   = $_GET["provider"] ?? "";
$q         = strtolower($_GET["q"] ?? "");
if ($brandId !== "") {
  $games = array_filter($games, fn($g) => $g["provider_id"] == $brandId || $g["brand_id"] == $brandId);
}
if ($q) {
  $games = array_filter($games, fn($g) => str_contains(strtolower($g["name"]), $q));
}
?>
<!doctype html>
<html>
<head>
  <title>Casino Games</title>
  <style>
    body { font-family: system-ui, sans-serif; margin: 20px; background:#0b0f19; color:#fff; }
    .filters { display:flex; gap:12px; flex-wrap:wrap; margin-bottom:16px; }
    select, input { padding:8px 12px; border-radius:6px; border:1px solid #334155; background:#111827; color:#fff; }
    .grid { display:grid; grid-template-columns:repeat(auto-fill,minmax(160px,1fr)); gap:16px; }
    .card { background:#1f2937; border-radius:10px; padding:12px; text-align:center; }
    .card img { width:100%; height:120px; object-fit:cover; border-radius:6px; }
    .card h4 { margin:8px 0; font-size:14px; }
    .btns { display:flex; gap:8px; justify-content:center; }
    .btns a { padding:6px 12px; border-radius:6px; text-decoration:none; font-size:12px; }
    .demo { background:#334155; color:#fff; }
    .real { background:#d97706; color:#fff; }
  </style>
</head>
<body>
  <h1>Our Games</h1>
  <form class="filters" method="get">
    <select name="provider" onchange="this.form.submit()">
      <option value="">All providers</option>
      <?php foreach ($providers as $p): ?>
        <option value="<?php echo $p["brand_id"]; ?>" <?php if ($brandId == $p["brand_id"]) echo "selected"; ?>>
          <?php echo htmlspecialchars($p["name"]); ?>
        </option>
      <?php endforeach; ?>
    </select>
    <input name="q" value="<?php echo htmlspecialchars($_GET["q"] ?? ""); ?>" placeholder="Search games..." />
  </form>
  <div class="grid">
    <?php foreach ($games as $g): ?>
      <div class="card">
        <img src="<?php echo htmlspecialchars($g["logo"] ?? "https://via.placeholder.com/160x120"); ?>" alt="<?php echo htmlspecialchars($g["name"]); ?>">
        <h4><?php echo htmlspecialchars($g["name"]); ?></h4>
        <div class="btns">
          <a class="demo" href="demo.php?game_uid=<?php echo urlencode($g["game_uid"]); ?>">Demo</a>
          <a class="real" href="launch.php?game_uid=<?php echo urlencode($g["game_uid"]); ?>">Play</a>
        </div>
      </div>
    <?php endforeach; ?>
  </div>
</body>
</html>
```

### PHP — demo redirect (`casino/demo.php`)

```php
<?php
$TOKEN = "PASTE_YOUR_API_TOKEN_HERE";
$gameUid = $_GET["game_uid"] ?? "";
$url = trim(file_get_contents("https://casinoapi.shop/api/public/v1/demo?token=" . urlencode($TOKEN) . "&game_uid=" . urlencode($gameUid)));
if (strpos($url, "http") === 0) {
  header("Location: " . $url);
  exit;
}
echo "Demo not available: " . htmlspecialchars($url);
```

### HTML + JavaScript — browser game lobby

```html
<!doctype html>
<html>
<head>
  <title>Casino Games</title>
  <style>
    body { font-family: system-ui, sans-serif; margin: 20px; background:#0b0f19; color:#fff; }
    .filters { display:flex; gap:12px; margin-bottom:16px; }
    select, input { padding:8px 12px; border-radius:6px; border:1px solid #334155; background:#111827; color:#fff; }
    .grid { display:grid; grid-template-columns:repeat(auto-fill,minmax(160px,1fr)); gap:16px; }
    .card { background:#1f2937; border-radius:10px; padding:12px; text-align:center; }
    .card img { width:100%; height:120px; object-fit:cover; border-radius:6px; }
    button { margin-top:8px; padding:6px 12px; border-radius:6px; border:none; cursor:pointer; }
    .demo { background:#334155; color:#fff; }
    .real { background:#d97706; color:#fff; }
  </style>
</head>
<body>
  <h1>Our Games</h1>
  <div class="filters">
    <select id="provider"><option value="">All providers</option></select>
    <input id="search" placeholder="Search games..." />
  </div>
  <div id="grid" class="grid"></div>

  <script>
    const TOKEN = "PASTE_YOUR_API_TOKEN_HERE"; // never expose in production — use your backend
    const BASE  = "https://casinoapi.shop";
    let allGames = [];

    async function load() {
      const [pRes, gRes] = await Promise.all([
        fetch(`${BASE}/api/public/v1/providers?token=${TOKEN}`),
        fetch(`${BASE}/api/public/v1/games?token=${TOKEN}`),
      ]);
      const providers = (await pRes.json()).data.providers;
      allGames = (await gRes.json()).data.games;

      const sel = document.getElementById("provider");
      providers.forEach(p => {
        const o = document.createElement("option");
        o.value = p.brand_id;
        o.textContent = p.name;
        sel.appendChild(o);
      });
      render(allGames);
    }

    function render(games) {
      const brand = document.getElementById("provider").value;
      const q = document.getElementById("search").value.toLowerCase();
      const filtered = games.filter(g => (!brand || g.brand_id == brand) && (!q || g.name.toLowerCase().includes(q)));
      document.getElementById("grid").innerHTML = filtered.map(g => `
        <div class="card">
          <img src="${g.logo || "https://via.placeholder.com/160x120"}" alt="${g.name}">
          <h4>${g.name}</h4>
          <button class="demo" onclick="openDemo('${g.game_uid}')">Demo</button>
          <button class="real" onclick="openReal('${g.game_uid}')">Play</button>
        </div>
      `).join("");
    }

    async function openDemo(uid) {
      const url = await fetch(`${BASE}/api/public/v1/demo?token=${TOKEN}&game_uid=${uid}`).then(r => r.text());
      window.open(url.trim(), "_blank");
    }
    async function openReal(uid) {
      const res = await fetch(`${BASE}/api/public/v1/launch`, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({
          token: TOKEN,
          user_id: "100245",
          balance: 1000,
          game_uid: uid,
          currency_code: "BDT",
          return: "https://your-casino.com/lobby",
          callback: "https://your-casino.com/callback",
        }),
      }).then(r => r.json());
      if (res.data?.url) window.open(res.data.url, "_blank");
      else alert(res.msg || "Launch failed");
    }

    document.getElementById("provider").onchange = () => render(allGames);
    document.getElementById("search").oninput = () => render(allGames);
    load();
  </script>
</body>
</html>
```

### Node.js — Express backend lobby + launch

```js
// routes/games.js — Node/Express game lobby + launch backend
const express = require("express");
const router = express.Router();
const TOKEN = process.env.CASINO_API_TOKEN;
const BASE  = "https://casinoapi.shop";

router.get("/games", async (req, res) => {
  const [p, g] = await Promise.all([
    fetch(`${BASE}/api/public/v1/providers?token=${TOKEN}`).then(r => r.json()),
    fetch(`${BASE}/api/public/v1/games?token=${TOKEN}`).then(r => r.json()),
  ]);
  res.render("games", { providers: p.data.providers, games: g.data.games });
});

router.post("/launch", async (req, res) => {
  const { game_uid, player_id, balance } = req.body;
  const out = await fetch(`${BASE}/api/public/v1/launch`, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
      token: TOKEN,
      user_id: String(player_id),
      balance: Number(balance),
      game_uid,
      currency_code: "BDT",
      return: "https://your-casino.com/lobby",
      callback: "https://your-casino.com/callback",
    }),
  }).then(r => r.json());
  if (out.data?.url) return res.redirect(out.data.url);
  res.status(400).json({ error: out.msg || "Launch failed" });
});

module.exports = router;
```

---

## 10. Step 9 — Test everything

Client panel → **API Test** → **Run all tests**. It checks, one by one:

| Check | What it proves |
|---|---|
| Token authentication | your API key works |
| Secret key | encryption secret configured |
| Providers | providers are reachable |
| Games | games available for your account |
| GGR balance | enough balance to launch |
| Live demo launch | a real demo URL opens |
| Callback URL | set (needed for real money) |

All green = ready to go live.

---

## 11. Going live checklist

- [ ] API key + secret copied and stored safely
- [ ] 3 files uploaded under `/casino/` and `games.php` shows games
- [ ] Callback URL set in Settings and reachable over HTTPS
- [ ] Server IP added to whitelist
- [ ] GGR balance topped up (Deposit)
- [ ] API Test page all green
- [ ] One real-money test round: bet + win updated your player's balance correctly

---

## 12. Troubleshooting

| Error / symptom | Cause | Fix |
|---|---|---|
| `Invalid or revoked API token` | wrong/old key | copy the current key from Settings → API Credentials |
| `Provider not allowed for this account` | game from a provider not enabled for you | ask admin to enable the provider, or pick another game |
| `Insufficient GGR balance` | your GGR wallet is empty | Deposit / top up first |
| `user_id must be digits only` | you sent letters/UUID | send a numeric player ID |
| `game_uid required` | missing or non-numeric game id | use `game_uid` from `/api/public/v1/games` |
| Callback not called / round stuck | callback URL wrong or not HTTPS | check Settings URL, open it in browser, check your server logs |
| Balance changed twice | duplicate callback processed | install the latest Callback.php and keep its unique `callback_id` check |
| IP blocked / 403 on every call | your server IP not whitelisted | add the server's public IP in Settings |
| Demo button returns error | game does not support demo | pick another game |

---

## 13. FAQ

**Do you hold my players' money?**
No. Balances live only on your site. We just tell you bet/win/rollback and you update balances.

**What is GGR balance?**
A prepaid credit with us. A small % of each round's volume is deducted as your fee. When it hits 0, real-money launches pause until you top up. Demo mode always works.

**Can I change currency later?**
Yes — ask the admin; your panel and API then work in the new currency.

**How many games do I get?**
16,000+ games from 150+ providers, depending on which providers are enabled for your account.

**Can I use these examples in WordPress?**
Yes. Rename `games.php` to a WordPress page template, or paste the HTML/JS lobby into a Custom HTML block. For PHP files, upload them to your theme folder or use a plugin like Insert PHP Code Snippet.

**Support?**
Use the support channel in your client panel, or reply to your onboarding contact.

---

*Casino API — casinoapi.shop — Client Integration Guide v1.1*
