Skip to content

Testing

Beexar provides two ways to validate your integration without involving real money:

Tool What it tests Wallet callbacks
Demo mode Game UI, launch flow, embedding None — virtual balance, no wallet calls
Integration Test Game Your wallet implementation against the full SoftSwiss contract Real calls to your callback URLs

Demo mode is launched via POST /api/v1/softswiss/launcher/demo (see Game Launch). The Integration Test Game is launched via the standard real launcher with game: "testgame" (see below).


Beexar includes a built-in Integration Test Game that validates your wallet implementation against 30 test scenarios. 29 of them cover the full SoftSwiss wallet API contract and run together with Run all; the 30th certifies your Freespins/Finish callback and runs on its own, once you have issued freespins to the test player (see The Freespins Test).

  1. Launch the test game via the standard launcher API
  2. Select which tests to run (or Run all — the 29 wallet tests; the freespins test is started on its own)
  3. The test game sends real wallet requests to your callback URLs
  4. Each test validates request/response behavior and displays pass/fail results
  5. You can inspect the actual HTTP request/response exchanged with your wallet
Category Tests What It Validates
Signature & Balance 2 HMAC signature validation, balance endpoint
Bets & Wins 8 Single bet, multiple bets, BetWin combined, win after finish, new params
No Funds 3 Insufficient funds (single bet, large win, two bets)
Idempotency 3 Duplicate bet, one duplicate in batch, duplicate win
Rollback 6 Normal rollback, win rollback, tombstone scenarios
SoftSwiss v2 Edge Cases 7 Win before bet, zero amount, BetWin response transactions, bonus amount, duplicate finish, rollback count
Freespins 1 Freespins/Finish: no wallet call per free spin, the win credited once, a repeated Finish answered with the original balance, a wrong signature refused, an unknown field ignored. Outside Run all — see The Freespins Test
Terminal window
BODY='{"casino_id":"your-operator-slug","game":"testgame","account":{"id":"test_player","currency":"USD"}}'
SIGNATURE=$(echo -n "$BODY" | openssl dgst -sha256 -hmac "your_api_secret" | awk '{print $2}')
curl -X POST https://gateway.beexar.com/api/v1/softswiss/launcher/real \
-H "Content-Type: application/json" \
-H "X-REQUEST-SIGN: $SIGNATURE" \
-d "$BODY"

Open the returned launch_url in a browser. You will see the test game interface with checkboxes for each test.

Each test run records:

  • Pass/Fail status for each test
  • Step-by-step execution log
  • Actual HTTP request/response between Beexar and your wallet (the Operator Exchange)
  • Summary badge: “Integration Ready” when every wallet test passes — the freespins test counts only once it has been run

The freespins_finish test, in the Freespins group, certifies the operator side of freespins: a free round reaches no wallet endpoint, and the one Freespins/Finish credits what the rounds won — once, whatever repeats it. It is not part of Run all: the test game cannot give the player freespins, so you issue them first.

  1. Issue freespins to the test player in the test game. Send Freespins/Issue with games: ["testgame"], bet_level: 1 and at most 50 spins — the test plays every one of them. The test game has a single bet level: 100 minor units of the account currency (1.00 USD, 100 JPY). Use the player and currency you launch the test game with; the issue may be sent before or after opening the game.

    Terminal window
    BODY='{"casino_id":"your-operator-slug","issue_id":"fs-test-0001","games":["testgame"],"freespins_quantity":5,"bet_level":1,"valid_until":"2026-11-20T00:00:00Z","account":{"id":"test_player","currency":"USD"}}'
    SIGNATURE=$(echo -n "$BODY" | openssl dgst -sha256 -hmac "your_api_secret" | awk '{print $2}')
    curl -X POST https://gateway.beexar.com/api/v1/softswiss/freespins/issue \
    -H "Content-Type: application/json" \
    -H "X-REQUEST-SIGN: $SIGNATURE" \
    -d "$BODY"
  2. Run the test. In the test game, start freespins_finish from the Freespins group. Its steps, and what must happen on your side:

    Step Your side
    Find the active freespins issue of this player in this game The issue from step 1 is found (with none, the test fails and says to issue one)
    Play a freespin that wins 2× its bet No /betwin reaches you: the balance is unchanged, the issue has one spin fewer
    Play out the remaining spins The issue is played out
    Wait for Freespins/Finish Your endpoint answers HTTP 200 { "balance": "..." }, and the balance is the initial one plus the win
    Send the same Finish again HTTP 200 with the original balance; nothing is credited twice
    Send it with a wrong signature Refused
    Send it with an unknown field HTTP 200 with the original balance; the field is ignored

Every Finish exchange is shown with its request and response, as the wallet tests show theirs. The “Integration Ready” badge takes this test into account only once it has been run. An issue whose only game is the test game is marked as such: only its Finish can be re-sent, and it stays out of analytics — it does not appear under Analytics → Freespins.


Every Beexar SDK ships a complete, correct wallet in about 250 readable lines — in Node, PHP, Go and Python. Read it, run it, or copy the parts you need. See Reference wallet.

Each one implements all four endpoints, verifies the HMAC signature over the raw body, is idempotent on id_provider, records rollback tombstones, and answers in the SoftSwiss Twirp error format.

The same implementations are driven by a public conformance fixture set: exact request bytes, the signature over them, the ledger before and after, and the expected response. If you are integrating without an SDK, point your own tests at those fixtures and you get the coverage the official SDKs have.


Use this checklist to verify your integration is complete:

  1. Signature validation

    • All requests validated with HMAC-SHA256 (X-REQUEST-SIGN header)
    • Invalid signatures return HTTP 400 with api_code 403
  2. Balance endpoint

    • Returns current balance as decimal string
    • Handles unknown players gracefully (api_code 101)
  3. BetWin endpoint

    • Processes all transactions atomically (in order)
    • Returns balance, round_id, and transactions array
    • Idempotent: duplicate id_provider returns original response
    • Insufficient funds returns HTTP 400 with api_code 100 and balance in meta
    • Tombstoned id_provider returns HTTP 400 with api_code 155
    • Handles finished: true to close the round
  4. Rollback endpoint

    • Reverses original transactions
    • Creates tombstone if original transaction not found
    • Idempotent: duplicate rollback id_provider returns original response
    • Processes rollback even with insufficient funds
  5. Finish endpoint

    • Acknowledges round completion with { "balance": "..." }
    • Handles duplicate finish calls idempotently
  6. Error format

    • All errors use Twirp format: { "code": "...", "msg": "...", "meta": { "api_code": "...", "api_message": "..." } }
    • Only HTTP 400 and 500 status codes (no 403, 409, 412)
    • balance included in meta when api_code is 100, 105, or 106
  7. Freespins finish endpoint (only if you issue freespins)

    • Credits amount to the player of issue_id and answers { "balance": "..." }
    • Idempotent: a repeated Finish for the same issue_id answers the original balance and credits nothing
    • Invalid signatures return HTTP 400 with api_code 403
    • Unknown fields are ignored
    • Certified by the freespins_finish test of the Integration Test Game

Terminal window
BODY='{"casino_id":"your-slug","game":"dice","account":{"id":"test_player","currency":"USD"}}'
SIGNATURE=$(echo -n "$BODY" | openssl dgst -sha256 -hmac "your_api_secret" | awk '{print $2}')
curl -X POST https://gateway.beexar.com/api/v1/softswiss/launcher/real \
-H "Content-Type: application/json" \
-H "X-REQUEST-SIGN: $SIGNATURE" \
-d "$BODY"
# Play the game in the returned launch_url
# Verify wallet callbacks were received:
# - POST /balance (on game load)
# - POST /betwin (bet + win, finished=true)
Terminal window
BODY='{"casino_id":"your-slug","game":"crash","account":{"id":"test_player","currency":"USD"}}'
SIGNATURE=$(echo -n "$BODY" | openssl dgst -sha256 -hmac "your_api_secret" | awk '{print $2}')
curl -X POST https://gateway.beexar.com/api/v1/softswiss/launcher/real \
-H "Content-Type: application/json" \
-H "X-REQUEST-SIGN: $SIGNATURE" \
-d "$BODY"
# Open the launch_url — join the next round, place a bet
# Cash out before the crash or let it ride
# Verify wallet callbacks:
# - POST /betwin (bet only)
# - POST /betwin (win, finished=true) — only if player cashed out
# - POST /finish — only if the last BetWin did not set finished=true
Scenario Expected Behavior
Return HTTP 400 with api_code 100 on BetWin Beexar shows “insufficient funds” to player
Return HTTP 500 on BetWin Beexar retries (up to 3 times), then shows error
Timeout (no response) on BetWin Beexar retries (up to 3 times), then shows error
Return invalid JSON Beexar shows error to player
Duplicate id_provider on BetWin Your wallet returns original response, no double processing
Rollback for non-existent transaction Your wallet creates tombstone, returns 200