TR
Demolar

API · v1

API belgeleri

Operatör API’si ve cüzdan protokolü, sürüm 1.

Teknik belgeler İngilizce yayımlanır.

Overview

Callisto Minis are short multiplayer games: two to four players at a table, each stakes, the game decides, and the pot less the configured rake goes to the winners. You launch your players into a game; the provider calls your wallet for every stake and every payout. The integration is two pieces:

  • The operators’ API, which you call: launch a player, list your games, read rounds.
  • Your wallet, which we call: balance, bet, win, refund.

Environments

Operators’ APIOpenAPI
Sandboxhttps://sandbox-api.callistominis.com/v1/v1/openapi.json
Productionhttps://api.callistominis.com/v1/v1/openapi.json

A sandbox key works in the sandbox only. You move to production with a new key.

Signing

Every call, both ways, carries three headers:

X-Minis-Key:       key_id
X-Minis-Timestamp: unix seconds, within 5 minutes of the receiver’s clock
X-Minis-Signature: hex_lowercase(HMAC_SHA256(secret, timestamp + "." + payload))

payload is the raw body exactly as sent. A request without a body signs its request line, for example GET /v1/games or GET /v1/players/p-1/rounds?limit=10. Our calls to your wallet are signed with your key, so you check them with the same secret. Keep the secret on your server only; you can hold two active keys, so you rotate by asking for a second one and dropping the first.

import { createHmac } from 'node:crypto'

const timestamp = Math.floor(Date.now() / 1000).toString()
const body = JSON.stringify(payload)            // exactly the bytes you send
const signature = createHmac('sha256', secret)
  .update(timestamp + '.' + body)
  .digest('hex')

headers['X-Minis-Key'] = keyId
headers['X-Minis-Timestamp'] = timestamp
headers['X-Minis-Signature'] = signature

Operators’ API

Answers are { "data": ... }.

RouteWhat it does
GET /v1/pingWho the signature says you are: operator_code, environment.
GET /v1/gamesThe games your players can open now: game_id, name, type, min_seats, max_seats, real_money.
POST /v1/sessionsOpen a game for a player; answers the game_url.
POST /v1/games/{game_id}/demoA demo with coins and bots, no wallet. Body { "language": "en" } or empty.
GET /v1/rounds/{round_id}One round with the seats of your players: session_id, player_alias, stake, rake, payout. Other operators’ players at a shared table are not shown.
GET /v1/players/{player_id}/roundsA player’s rounds, newest first, by your own id for the player; offset, limit (50). Answers { items, total }.

Game ids: snake, sharks, bombs, seabattle.

Launching a player

POST /v1/sessions
{
  "game_id": "snake",
  "player_id": "p-1",
  "player_name": "Ann",
  "currency": "EUR",
  "token": "<your token for this player>",
  "language": "en",
  "exit_url": "https://casino.example/lobby",
  "cashier_url": "https://casino.example/cashier"
}
{
  "data": {
    "session_id": "6f1c…",
    "game_url": "https://snake.callistominis.com/?session=…",
    "expires_at": "2026-10-08T22:00:00Z"
  }
}

Open game_url in the player’s frame. The token you pass comes back to your wallet with every call of this session, so you know which player and session a bet belongs to.

Your wallet

The provider calls POST {wallet_url}/{call} with JSON in snake_case, signed with your key. Check the signature and the timestamp before anything else, and refuse a bad one with 401 and an error. Every call carries session_id, token, player_id and currency.

CallDoes
balanceNothing; answers the balance.
betTakes amount.
winPays amount, which may be 0.
refundGives back the bet bet_transaction_id.

Money calls add:

transaction_idThe provider’s id of this movement, a UUID. The same id twice is the same movement.
round_idThe round it belongs to.
game_idThe game.
amountDecimal, two places, never negative.
bet_transaction_idOn win and refund: the bet it closes.
POST {wallet_url}/bet
{
  "session_id": "6f1c…",
  "token": "<your token>",
  "player_id": "p-1",
  "currency": "EUR",
  "transaction_id": "0b7e…",
  "round_id": "snake-…",
  "game_id": "snake",
  "amount": 5.00
}

Wallet answers

  • Done: 2xx with the balance and your id for the movement.
  • Refused: 4xx with error and message. The provider understands insufficient_funds and invalid_token; any other code is a refusal too.
  • Anything else (5xx, no JSON, no answer within 5 seconds) is unknown: you may or may not have done it.
200 { "balance": 995.00, "transaction_id": "<your id for it>" }
402 { "error": "insufficient_funds", "message": "Not enough money" }

Wallet rules

  1. Idempotent by transaction_id. A call you have already done is answered as done, with the same answer, and moves nothing. The provider repeats calls whose answer it did not get.
  2. A refund of a bet you never received succeeds and moves nothing. It happens when your answer to a bet was lost.
  3. Never refuse a win or a refund short of a broken request. A refused credit goes to manual handling; an unknown one is retried, 5 seconds at first, doubling, at most an hour apart, until it gets through.
  4. A bet with no answer is given up. After 5 seconds the round does not start; after two minutes the provider sends a refund for that bet, in case you did take it.
  5. Stakes of a round are all or none. When another player’s bet is refused, yours is refunded.

Money in a round

Every player’s stake is taken before the round starts. When the game ends, each player gets a win, of 0 when they lost; a cancelled round gives each stake back as a refund. The rake is a percentage of the pot configured for your operator, and a payout never exceeds the pot less the rake. In the shared pool your players may win money staked by another operator’s players; who owes whom is settled monthly on your invoice.

Errors

Every refusal of the operators’ API is { error, message, retryable, fields? }. Retry only when retryable is true.

StatuserrorWhen
401unauthorizedSignature missing or wrong, a revoked key, a suspended operator; retryable only for the clock.
404not_foundAn unknown game, player or round, or not yours.
409currency_not_enabled, game_not_available, … or conflictA business refusal.
422validation_failed, with fieldsThe request is malformed.
503unavailableA service behind did not answer; retryable.

Self-test and going live

The integration kit has a self-test that signs like we do and checks your wallet: signature and clock refusals, balance, bet, win, refund, repeats, a refund of a bet you never received, insufficient funds, a foreign token, and that each answer comes within 5 seconds. It moves a few units of the test player’s money and leaves the balance where it found it.

node selftest/wallet-selftest.mjs --wallet-url https://wallet.example/minis \
  --key-id <key_id> --secret <secret> \
  --player <a test player> --token <a valid token of that player> --currency EUR
  1. Every self-test line is PASS.
  2. On the sandbox, launch two players of yours and play a round in two browsers; your wallet sees two bets and two wins, and GET /v1/rounds/{round_id} agrees.
  3. Stop your wallet during a bet: the round does not start, and the bet is refunded within two minutes.
  4. We move you to production with a new key.

Minis oyunlarını oyuncularınıza getirin

Bize casinonuzdan ve nasıl bağlanmak istediğinizden bahsedin. Sandbox anahtarlarını ve entegrasyon paketini gönderelim.

Bize ulaşın sales@callistoplatform.com