# Beexar documentation Full text of https://docs.beexar.com. The OpenAPI contract is at https://docs.beexar.com/api/wallet.yaml, https://docs.beexar.com/api/softswiss/gateway.yaml, https://docs.beexar.com/api/gateway.yaml and https://docs.beexar.com/api/common/schemas.yaml. --- # API Reference Source: https://docs.beexar.com/api-reference/ Description: Interactive OpenAPI documentation for Beexar platform APIs. import { Card, CardGrid, LinkCard } from '@astrojs/starlight/components'; Beexar provides external APIs for operator integration, documented as interactive OpenAPI (Scalar) references where you can explore endpoints, models, and try requests. Game-launch endpoints are **per integration platform** (e.g. SoftSwiss) — an operator uses the launch API for its own `integration_type`. ## Wallet API The Wallet API defines 4 HTTP endpoints that Beexar calls on **the operator's server** during gameplay: | Endpoint | Method | Description | |----------|--------|-------------| | `/balance` | POST | Get player balance before showing the game UI | | `/betwin` | POST | Debit the bet and credit the win in a single atomic request | | `/rollback` | POST | Reverse previously confirmed transactions | | `/finish` | POST | Round completion signal (only when not closed by `/betwin`) | All requests are signed with **HMAC-SHA256** using the operator's API secret (`AUTH_TOKEN`). [Open Wallet API Reference →](/api-reference/wallet/) ## SoftSwiss Launch API Game launch is **per integration platform**. SoftSwiss-integrated operators call these endpoints to launch games: | Endpoint | Method | Description | |----------|--------|-------------| | `/api/v1/softswiss/launcher/real` | POST | Launch a real-money game session, returns `launch_url` | | `/api/v1/softswiss/launcher/demo` | POST | Launch a demo session with virtual balance | All requests are signed with **HMAC-SHA256** using the operator's API secret (`AUTH_TOKEN`); demo sessions from the frontend send 64 zero characters. An operator may only call the endpoints for its own `integration_type` — calling another platform's launcher returns `403 INTEGRATION_TYPE_MISMATCH`. [Open SoftSwiss Launch API Reference →](/api-reference/softswiss/) ## Gateway API (base) The base Gateway API is the platform-agnostic public surface: | Endpoint | Method | Description | |----------|--------|-------------| | `/api/v1/operator/games` | GET | List available games for an operator (public, no auth) | | `/health` | GET | Service health check | [Open Gateway API Reference →](/api-reference/gateway/) --- # AI Design Studio Source: https://docs.beexar.com/backoffice/ai-design/ Description: Restyle the Dice game with an AI chat assistant or a manual design-token editor. import { Aside, Steps } from '@astrojs/starlight/components'; The **Design** step of the Dice game editor lets you restyle the game in two ways: chat with the **AI Design Studio**, or fine-tune every token by hand in **Manual mode**. A live preview of the game sits next to both. Switch between the two modes with the **AI mode / Manual mode** toggle in the top-right of the step. --- ## Before You Start The Design step works on a saved configuration: 1. Select an operator and pick **Dice** as the game type. 2. Fill in Basic Info and **Save Draft**. 3. Open the **Design** step. Until a draft is saved, the AI panel shows a reminder to save first. --- ## AI mode AI mode is a chat assistant. You describe how the game should look — palette, theme, mood, or a reference — and the assistant iterates on the design while you watch the preview update. 1. **Type a prompt** in the message box (e.g. "dark neon theme with purple and cyan, rounded buttons") and send it. 2. **Watch the timeline** — the assistant streams progress and applies changes to the preview. 3. **Keep iterating** — send follow-up prompts to refine. You can either tweak the current look or ask for a brand-new one. 4. **Publish** when you're happy, from the final wizard step. ### Sessions & history - The first message you send automatically starts a **session**. - Use **+ New session** to start a fresh conversation (the previous one is kept). - Use **History** to reopen any previous session for this game and review what was generated. --- ## Manual mode Manual mode is a full design-token editor for operators who want precise control. It exposes every themeable value of the Dice game, grouped into collapsible sections. | Group | Examples | |-------|----------| | **Colors** | Backgrounds, text, accent, slider, button colors | | **Radii / Shadows / Sizes / Spacing / Opacity / Motion** | Corner rounding, elevation, dimensions, gaps, transitions | | **Typography** | Font families for common text and the result display | | **Assets** | Background and logo image slots | | **Sounds** | Game sound slots | Tools in Manual mode: - **Search** — filter tokens by name (e.g. "background", "button"). - **Overrides (N)** — toggle to show only the tokens you've changed; the counter shows how many differ from the default. - **Reset** — each changed token has a reset-to-default button; **Reset all** reverts every override at once. - **Fonts** — pick a built-in font, upload your own, or add a Google font from the font library. --- # Analytics Source: https://docs.beexar.com/backoffice/analytics/ Description: How to use the analytics dashboard and reports in the Beexar Backoffice. import { Aside } from '@astrojs/starlight/components'; ## Currency of reports All analytics and reports are shown in your **organization's settlement currency** (one of USD, EUR, USDT, USDC), chosen when your organization is created. Bets and wins made in other currencies are converted using daily exchange rates, so every total, chart, and report is consistent in a single currency. The current currency is shown as a chip on each analytics screen. --- ## Dashboard The main **Dashboard** provides a real-time overview of your platform performance. An **Auto-refresh** control (toggle + interval + last-updated time) keeps it live. ### Key Metrics | Widget | Description | |--------|-------------| | **Active Players** | Number of players with active sessions right now | | **New Players** | Players who started their first session in the selected period | | **Total GGR** | Gross Gaming Revenue = Total Bets − Total Wins, in your org currency | | **Total Bets** | Sum of all bet amounts in the period, in your org currency | | **Unique Players** | Number of distinct players who placed at least one bet | | **Active Operators** | Number of operators with at least one bet in the period | ### Date Filters | Filter | Description | |--------|-------------| | **Today** | Current day only | | **7 days** | Last 7 days | | **30 days** | Last 30 days (default) | | **Custom** | Pick From and To dates | ### Operator Filter Select a specific operator to see their metrics only, or choose **All** to see platform-wide stats. ### Charts | Chart | Description | |-------|-------------| | **GGR Trend** | Daily GGR breakdown over the selected period | | **Top Players** | Players ranked by total bet amount | | **Top Operators** | Operators ranked by GGR | | **Hourly Activity** | Bet distribution by hour of day | | **Game Distribution** | Pie chart of bets by game type | --- ## Analytics Reports Navigate to **Analytics → Reports** for a detailed pivot-style drill-down report. Filters at the top: **From / To** dates, **Game Type** (multi-select), and **Operator** (multi-select); apply with **Apply**, and export the current view with **CSV**. ### Report Dimensions Reports support hierarchical grouping by: | Dimension | Description | |-----------|-------------| | **Operator** | Group by operator | | **Game** | Group by individual game | | **Game Type** | Group by game category (dice, plinko, slots, crash) | | **Currency** | Group by currency | You can **drag and drop** dimensions to change the grouping order. For example: - `Operator → Game → Currency` — see per-game revenue for each operator, broken down by currency - `Game Type → Operator` — compare operators across game categories ### Drill-Down Click on any row to expand it and see the next level of detail. For example: 1. Click on an operator → see their games 2. Click on a game → see the currency breakdown 3. Each level shows total bets, total wins, GGR, and round count ### Currency Conversion All monetary values are shown in your **organization's currency**. Amounts in other currencies are converted using **daily exchange rates** (per day, then re-aggregated), so the figures reflect real day-to-day FX movement rather than a single snapshot rate. --- ## Player Activity Navigate to **Analytics → Players** for per-player analytics (with the same Auto-refresh control): | Column | Description | |--------|-------------| | **Player ID** | External player identifier from the operator | | **Operator** | Which operator the player belongs to | | **Total Bets** | Number of bets placed by the player | | **Total Wagered** | Sum wagered, in your org currency | | **Total Payout** | Sum paid out, in your org currency | | **GGR** | Player-level GGR (wagered − payout) | | **Favorite Game** | The player's most-played game | | **Sessions** | Number of game sessions | | **Last Active** | When the player was last active | --- # API Keys & Callback URLs Source: https://docs.beexar.com/backoffice/api-keys/ Description: How to manage API keys and configure wallet callback URLs. import { Aside, Steps } from '@astrojs/starlight/components'; ## Overview Each operator has **one API key** that is used for: - **Authentication** — the key identifies the operator in API calls - **Request signing** — the secret is used to compute HMAC-SHA256 signatures The API key and callback URLs are configured in the operator detail page. --- ## Managing the API Key Navigate to **Operators** → select an operator → **API Keys** tab. ### Creating a Key 1. Click **Create API Key** 2. The system generates an **API Secret** — the HMAC signing secret (`AUTH_TOKEN`), **shown only once!**. It is prefixed with `bxr_` (production) or `dev_` (sandbox/local), followed by a random URL-safe token. There is no separate public key; your operator is identified by its `casino_id` (slug). 3. **Copy the secret immediately** — it will not be displayed again ### Regenerating a Key If you need a new secret (e.g. it was compromised): 1. Click **Regenerate** 2. A new secret is generated — the old one is immediately invalidated 3. Copy the new secret and update your system ### Deleting a Key Click **Delete** to remove the API key entirely. The operator will not be able to launch games until a new key is created. --- ## Configuring Callback URLs Navigate to **Operators** → select an operator → **Callback URLs** tab. Enter the 4 wallet callback URLs that Beexar will call during gameplay: | Field | Endpoint | Description | |-------|----------|-------------| | **Balance URL** | `POST /balance` | Fetch player balance | | **BetWin URL** | `POST /betwin` | Debit/credit player account (atomic) | | **Rollback URL** | `POST /rollback` | Reverse previous transactions | | **Finish URL** | `POST /finish` | Signal round completion | 1. Enter each URL in the corresponding field 2. Click **Save** 3. The URLs take effect immediately for new game sessions ### Example Configuration ``` Balance URL: https://api.casino.com/beexar/balance BetWin URL: https://api.casino.com/beexar/betwin Rollback URL: https://api.casino.com/beexar/rollback Finish URL: https://api.casino.com/beexar/finish ``` ### Requirements | Requirement | Details | |-------------|---------| | **Protocol** | HTTPS required | | **Availability** | Must be publicly accessible from Beexar servers | | **Response time** | Should respond within 10 seconds | --- ## Using the API Secret ### In Launch Requests The API secret signs the request body; the resulting HMAC goes in the `X-REQUEST-SIGN` header: ```bash BODY='{"casino_id":"your-slug","game":"dice","account":{"id":"player_1","currency":"USD"}}' SECRET="your_api_secret" SIGNATURE=$(echo -n "$BODY" | openssl dgst -sha256 -hmac "$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" ``` ### In Wallet Callbacks Beexar signs every wallet request with the same secret. Your server must validate the `X-REQUEST-SIGN` header: ```javascript const crypto = require('crypto'); function validateSignature(body, signature, secret) { const expected = crypto.createHmac('sha256', secret) .update(body) .digest('hex'); return crypto.timingSafeEqual( Buffer.from(signature), Buffer.from(expected) ); } ``` See [Authentication](/getting-started/authentication/) for code samples in Go, Python, PHP, and more. --- # Audit Logs Source: https://docs.beexar.com/backoffice/audit-logs/ Description: Review changes made in the backoffice. import { Aside } from '@astrojs/starlight/components'; The **Audit Logs** section records changes made in your organization's backoffice, so you can see who changed what and when. --- ## What's Logged | Area | Example actions | |------|-----------------| | **Operators** | create, update, delete | | **API keys** | create, regenerate, delete | | **Game configs** | create, update, delete | | **Organization** | create, update, delete | | **Team** | invite, remove, role update | Each entry is color-coded by action (create, update/regenerate, delete) and can be expanded to see details. Entries are paginated. --- ## Filtering Narrow the log by: - **Action** — the type of change (create, update, delete, regenerate, invite, …) - **Resource type** — what was changed (operator, API key, game config, organization, team member) --- # Billing Source: https://docs.beexar.com/backoffice/billing/ Description: View and download your monthly invoices. import { Aside } from '@astrojs/starlight/components'; Operator organizations have a **Billing** section (**Billing → Invoices**) where you can review and download your monthly invoices. All amounts are shown in your organization's settlement currency. --- ## Invoices List | Column | Description | |--------|-------------| | **Invoice** | Invoice number | | **Period** | Billing period (start → end) | | **Status** | Invoice status (see below) | | **Total** | Amount due, in your org currency | | **Due** | Due date | | **Actions** | Download the invoice PDF | Filter by **Period from / Period to** to narrow the list. ### Downloading a PDF Use the **Download** action to get the invoice PDF. Invoices with a zero total (or no generated document) have the download disabled, with a tooltip explaining why. --- ## What's on an Invoice A monthly invoice can include: - **Platform fees** — your GGR-based commission for the period. - **Subscriptions** — active paid features (e.g. [custom currencies](/backoffice/subscriptions/)), billed per calendar day they were active in the month. - **Custom charges** — one-off line items Beexar may add for the period. --- ## Questions about an invoice If a figure looks wrong or you need a copy re-issued, contact your Beexar account manager — invoice generation, cancellation, and custom charges are managed by Beexar. --- # Custom Currencies Source: https://docs.beexar.com/backoffice/currencies/ Description: How to add and manage custom currencies and tokens for your operator. import { Aside, Steps } from '@astrojs/starlight/components'; ## Overview By default, operators can use standard global currencies (e.g. USD, EUR, USDT, USDC) that are available in Beexar. If your platform uses custom tokens or non-standard currencies, you can add them as **custom currencies** in the backoffice. Custom currencies use the `CUSTOM_*` prefix internally (e.g. `CUSTOM_GOLD`, `CUSTOM_SHITCOIN`), but are displayed to players **without** the prefix. --- ## Adding a Custom Currency Navigate to **Operators** → select an operator → **Currencies** tab. (The tab requires an active `custom_currencies` subscription.) 1. Click **Add Currency** 2. Fill in the form: | Field | Required | Description | Example | |-------|----------|-------------|---------| | **Code** | Yes | Currency identifier. Will be prefixed with `CUSTOM_` automatically | `GOLD` → stored as `CUSTOM_GOLD` | | **Name** | Yes | Display name for the currency | `Gold Coins` | | **Decimals** | Yes | Number of decimal places (0–16) | `2` for cents, `0` for whole tokens, `8` for crypto | 3. Click **Save** ### Currency Code Rules | Rule | Details | |------|---------| | **Format** | Uppercase letters, digits, and underscores | | **Raw code length** | 1–25 characters (what you enter, e.g. `GOLD`) | | **Full code length** | 8–32 characters (with `CUSTOM_` prefix, e.g. `CUSTOM_GOLD`) | | **Full code pattern** | `^[A-Z][A-Z0-9_]{2,31}$` — same regex for all currencies in the system | | **Prefix** | `CUSTOM_` is added automatically — don't include it in the code field | | **Uniqueness** | Must be unique per operator | ### Examples | You Enter | Stored As | Displayed to Player | |-----------|-----------|-------------------| | `GOLD` | `CUSTOM_GOLD` | `GOLD` | | `SHITCOIN` | `CUSTOM_SHITCOIN` | `SHITCOIN` | | `VIP_TOKEN` | `CUSTOM_VIP_TOKEN` | `VIP_TOKEN` | --- ## Decimals The **decimals** field controls how monetary amounts are formatted and displayed: | Decimals | Example Amount | Use Case | |----------|---------------|----------| | `0` | `100` | Whole tokens (coins, gems) | | `2` | `100.50` | Fiat-like currencies (USD, EUR) | | `8` | `0.00001234` | Cryptocurrency-like tokens | | `16` | `0.0000000000000001` | Maximum supported precision | The decimals value you configure is automatically used across the entire platform — from session creation through game logic to the player-facing UI. All monetary amounts are formatted according to the currency's decimal precision. --- ## Deactivating a Currency To remove a custom currency: 1. Find the currency in the **Currencies** tab 2. Click the **Deactivate** button 3. Confirm the action --- ## Using Custom Currencies in the API ### Launch Request When launching a game with a custom currency, use the full `CUSTOM_*` name: ```bash BODY='{"casino_id":"your-slug","game":"dice","account":{"id":"player_1","currency":"CUSTOM_GOLD"}}' SIGNATURE=$(echo -n "$BODY" | openssl dgst -sha256 -hmac "$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" ``` ### Wallet Callbacks Beexar sends the full `CUSTOM_*` currency code in wallet callbacks: ```json { "account_id": "player_1", "currency": "CUSTOM_GOLD", "game_id": "dice", "round_id": "550e8400-e29b-41d4-a716-446655440000", "finished": true, "transactions": [ { "id_provider": "tx_1", "type": "bet", "amount": "100" }, { "id_provider": "tx_2", "type": "win", "amount": "195" } ] } ``` --- ## Currency Validation at Launch When a game session is launched, Beexar validates that the requested currency is available for the operator: 1. **Global currencies** (USD, EUR, USDT, USDC, etc.) are always available to every operator 2. **Custom currencies** (`CUSTOM_*`) must be added to the operator **and** require an active `custom_currencies` subscription 3. If the currency is not configured, the launch returns an error; if it is a custom currency but the subscription is inactive, the launch returns `403 FEATURE_SUBSCRIPTION_REQUIRED` This ensures players cannot launch games with currencies that the operator hasn't configured or paid for. --- ## Games List and Currencies The [Games List API](/game-integration/launch/) (`GET /api/v1/operator/games`) returns available currencies for each game. The currencies are determined by the game's **owner operator**: - **Global games** (available to all operators) — show global currencies - **Operator-specific games** — show global currencies plus the owner operator's custom currencies This allows game aggregators to display which currencies each game supports. --- # Game Preview Source: https://docs.beexar.com/backoffice/game-preview/ Description: How to preview and test games using the built-in demo launcher. import { Aside, Steps } from '@astrojs/starlight/components'; ## Overview The **Game Preview** feature lets you launch a demo version of any game directly from the backoffice. This is useful for: - Testing a game configuration before publishing it to players - Verifying visual assets (backgrounds, symbols, sounds) - Checking game behavior across different device sizes - Demonstrating games to stakeholders --- ## Launching a Preview 1. Navigate to **Games** in the sidebar 2. Find the game you want to preview 3. Click the **Preview** button (play icon) in the actions column 4. The game opens in a **preview modal** with an embedded iframe --- ## Device Simulation The preview modal includes device simulation controls: | Mode | Resolution | Description | |------|-----------|-------------| | **Desktop** | 1280×720 | Standard desktop browser | | **Tablet** | 768×1024 | iPad-like tablet | | **Mobile** | 375×667 | iPhone-like mobile | You can also: - **Rotate** — toggle between portrait and landscape orientation - **Fullscreen** — expand the preview to fill the browser window - **Proportional scaling** — the game scales to fit the preview area while maintaining aspect ratio --- ## Demo vs Real Sessions The preview uses a **demo session** with virtual balance: | Property | Preview Demo | Real Session | |----------|-------------|--------------| | Balance | Virtual (10,000 default) | Real operator wallet | | Wallet callbacks | None | POST /betwin, /balance, etc. | | Analytics | Not recorded | Fully recorded | | TTL | 30 minutes | 30 minutes (sliding) | --- ## Testing Workflow The recommended workflow for game configuration changes: 1. **Edit** the game configuration in the game editor wizard 2. **Save as Draft** (don't publish yet) 3. **Preview** the draft configuration to verify it looks and plays correctly 4. **Publish** the configuration to make it live for players 5. **Preview** again to confirm the published version --- # Game Management Source: https://docs.beexar.com/backoffice/games/ Description: How to create, configure, and publish games in the Beexar Backoffice. import { Aside, Steps } from '@astrojs/starlight/components'; ## Overview The **Games** section lets you create and manage game configurations. A configuration is a per-operator instance of a game (Dice, Plinko, Slots, or Crash) with its own: - **Basic info** — name, slug, description - **Game parameters** — bet limits, RTP / house edge, and game-specific mechanics - **Layout** — the on-screen arrangement of game elements - **Visual design** — backgrounds, symbols, logo, fonts, colors, sounds (Dice has its own [AI / manual design step](/backoffice/ai-design/)) --- ## Games List Open **Games** in the sidebar. At the top, pick an operator from the **Select Operator** dropdown to see that operator's configurations. | Column | Description | |--------|-------------| | **Game Name** | Display name of the configuration | | **Operator** | Which operator owns this configuration | | **Slug** | Game slug used in the launch API | | **Type** | Game type: Slots, Dice, Plinko, Crash | | **Status** | `Draft`, `Active`, or `Archived` | | **Version** | Configuration version (`vN`) | | **Created** | Creation date | Use the status tabs (**All / Draft / Active / Archived**) to filter. ### Row Actions | Action | Description | |--------|-------------| | **Edit** | Open the game editor wizard | | **Preview** | Launch a demo preview in an iframe (see [Game Preview](/backoffice/game-preview/)) | | **Version history** | View previous versions and roll back | | **Global / Private** toggle | (Platform admin only) make a game available to all operators or just the owner | The header **Create Game** button starts a new configuration. --- ## Creating a Game **Create Game** opens a multi-step wizard. The steps adapt to the game type. The footer always has **Back**, **Save Draft**, and **Next** (or **Publish Game** / **Update Game** on the last step). 1. **Operator** — choose which operator owns this configuration. (Skipped when editing.) 2. **Basic Info** — **Game Name**, **URL Slug** (auto-generated from the name), and an optional **Description**. 3. **Configuration** — first pick the **Game Type** (Slots / Dice / Plinko / Crash). After creation the type is **locked** (shown as a read-only badge) because changing it would invalidate the saved design and history. Then set the game-specific parameters — see [Game Parameters](#game-parameters). 4. **Layout** — choose how game elements are arranged on screen. Crash auto-selects its fixed Aviator-style layout (bets left, game center, chat right). 5. **Visual Editor** *(Slots, Plinko, Crash)* — upload assets and tune colors with a live preview. Dice replaces this with a dedicated **Design** step ([AI Design Studio](/backoffice/ai-design/) + manual token editor). 6. **Preview & Publish** — review everything, then **Publish Game** (or **Update Game** when editing). --- ## Game Parameters ### Dice Dice is configured around a single **RTP** value (the roll range and bet-window limits are derived from it — see the [Dice game page](/games/dice/)). | Setting | Description | Default | |---------|-------------|---------| | **Game Mode** | **Classic** (single target, over/under) or **Range** (two handles, inside/outside) | Range | | **RTP** | Return-to-player, slider 80%–99% | 96% | | **Bet Limits** | Min / Max bet | Configurable | The configurator shows the **Theoretical RTP**, the derived **House Edge**, and a **Derived limits** panel (max/min multiplier, widest player bet, chance range) computed from `maxWindow = floor(RTP × 10000) − 100`. The backend re-validates this exact formula on every bet. ### Plinko Plinko currently uses the platform **default configuration** — there are no editable parameters in the configurator. (Rows and risk levels are chosen by the player in-game; see the [Plinko game page](/games/plinko/).) ### Slots You can start from a **preset** (Preset Selector) and then adjust manually: | Setting | Description | |---------|-------------| | **Grid Size** | Reels (3–7) and Rows (1–5) | | **Paylines** | Active paylines (1–50) | | **Bet Limits** | Min / Max bet | | **Free Spins** | Enable + Trigger Count (2–5), Spins Awarded, Multiplier, optional retrigger + Max Retriggers | | **Cascade Wins** | Enable + Start / Increment / Max multiplier, Reset on no win | | **Bonus Game** | Enable + type (**Pick Game** / **Wheel**), Trigger Count, prize values + weights | | **Symbols** | Per-symbol editor (high1–3, low1–3, wild, scatter): payouts and weights | An **RTP Calculator** continuously shows the theoretical RTP from your symbol weights, paylines, and features. ### Crash | Setting | Description | Default | |---------|-------------|---------| | **House Edge** | Slider 1%–10% (RTP = 100% − house edge) | 3% | | **Bet Limits** | Min / Max bet | Configurable | --- ## Visual Editor & Assets The **Visual Editor** step has a tabbed asset panel on the left and a live preview on the right. Drag an image onto the preview to set it. ### Slots tabs | Tab | What you set | |-----|--------------| | **Background** | Game background (1920×1080 recommended) | | **Symbols** | high1–3, low1–3, wild, scatter | | **Buttons** | spin, bet up, bet down, autoplay, menu | | **Logo** | Game logo (PNG with transparency) | | **Fonts** | Built-in, uploaded, or Google fonts | ### Crash tabs | Tab | What you set | |-----|--------------| | **Background** | Game background | | **Game Object** | Rocket / plane sprite (PNG with transparency) | | **Colors** | Color scheme (Primary / Secondary / Accent / Background / Text), Multiplier Display (font size + glow color), Chat Panel (background / text / border) | | **Sounds** | Takeoff, crash, cashout, background music | | **Logo** | Game logo | | **Fonts** | Built-in, uploaded, or Google fonts | Uploaded assets are stored per operator and served to players from the Beexar CDN (`cdn.beexar.com`). --- ## Versioning Each publish creates a new **version**. From the games list you can open **Version history** to review previous versions and **roll back** to one. The editor shows a "Version N → N+1" indicator when you edit a published configuration. --- ## Game Visibility | Type | Visibility | Set by | |------|-----------|--------| | **Global** | Available to all operators | Platform admin | | **Operator-specific** | Only the owning operator | Organization admin | Global games appear for every operator; operator-specific games only for their owner. --- ## Games List API Operators can retrieve their available games via the public Gateway endpoint (no auth): ``` GET {GATEWAY_URL}/api/v1/operator/games?operator={slug} ``` The response lists each game with `title`, `identifier` (slug), `category` (dice/plinko/slots/crash), `payout` (RTP %), `volatility_rating`, `currencies`, `thumbnail`, and `demo_available`. --- # Managing Operators Source: https://docs.beexar.com/backoffice/operators/ Description: How to create and manage operators in the Beexar Backoffice. import { Aside, Steps } from '@astrojs/starlight/components'; ## What Is an Operator? An operator represents a casino or gaming platform that integrates with Beexar. Each operator has: - A unique **slug** (used in game URLs and API calls as `casino_id`) - An **API key** for authentication - **Callback URLs** for wallet integration - **Custom currencies** (optional) - **Game configurations** assigned to them --- ## Operators List Navigate to **Operators** in the sidebar to see all operators in your organization. The table shows: | Column | Description | |--------|-------------| | **Name** | Operator display name | | **Slug** | Unique identifier (used as `casino_id` in the API) | | **Project URL** | Operator's website URL | | **Status** | `Active`, `Pending Review`, or `Suspended` | | **Created** | Creation date | --- ## Creating an Operator 1. Click **Create New Operator** 2. Fill in the form: | Field | Required | Description | |-------|----------|-------------| | **Operator Name** | Yes | Display name (e.g. "Lucky Casino") | | **Project URL** | Yes | Operator's website URL (`http(s)://…`) | 3. Click **Create** The **slug** is generated automatically from the name (you don't enter it). It is permanent once created. --- ## Operator Detail Page Click on an operator name or the view icon to open the detail page. It has the following tabs: | Tab | Description | See | |-----|-------------|-----| | **Analytics** | Operator-specific analytics *(coming soon)* | [Analytics](/backoffice/analytics/) | | **API Keys** | Manage the API key and secret | [API Keys](/backoffice/api-keys/) | | **Callback URLs** | Configure wallet callback endpoints | [API Keys](/backoffice/api-keys/) | | **Branding** | Operator logo and branding assets *(coming soon)* | — | | **Currencies** | Manage custom currencies (paid add-on) | [Currencies](/backoffice/currencies/) | | **Paid Features** | View activated paid features (read-only) | [Paid Features](/backoffice/subscriptions/) | The header also shows the operator's status, copyable slug, Project URL, and (if set) commission rate. The **Edit** button changes the name and Project URL (the slug stays fixed). --- ## Operator Statuses | Status | Meaning | Can Launch Games? | |--------|---------|-------------------| | **Pending Review** | Newly created, awaiting activation | No | | **Active** | Fully operational | Yes | | **Suspended** | Temporarily disabled by platform admin | No | --- ## Operator Slug in the API The operator slug is used as `casino_id` in all API calls: ```bash # Launch a game for this operator curl -X POST https://gateway.beexar.com/api/v1/softswiss/launcher/real \ -H "Content-Type: application/json" \ -H "X-REQUEST-SIGN: ..." \ -d '{"casino_id": "lucky-casino", "game": "dice", "account": {"id": "player_1", "currency": "USD"}}' ``` It also appears in game URLs: ``` https://games.beexar.com/dice/lucky-casino/dice-game?token=... ``` --- # Organization Source: https://docs.beexar.com/backoffice/organization/ Description: Your organization, its settlement currency, and organization types. import { Aside } from '@astrojs/starlight/components'; Everything in the backoffice belongs to an **organization** — your account. An organization owns its operators, games, team members, reports, and invoices. --- ## Settlement Currency Each organization has a single **settlement currency** — one of **USD, EUR, USDT, USDC** — chosen when the organization is created. It is the currency used for **all** money in the backoffice: - Dashboard and report totals - Per-player figures - Invoices and paid-feature charges Bets and wins placed in other currencies are converted to your settlement currency using exchange rates, so all reporting stays in one consistent currency. --- ## Organization Types | Type | What they do | Cabinet | |------|--------------|---------| | **Operator** (casino brand) | Run games for players, integrate the wallet API | Operators, Games, Analytics, Billing, Team | | **Partner** (affiliate) | Earn commission on linked operators | [Partner cabinet](/backoffice/partner/) (Dashboard, Attached Operators, Earnings) | --- ## Provisioning In **production**, organizations and operators are provisioned by Beexar. Your account manager creates your organization (with its settlement currency) and your first operator, then gives you login access. Within your organization, owners can [invite team members](/backoffice/team/) themselves. --- # Backoffice Overview Source: https://docs.beexar.com/backoffice/overview/ Description: Introduction to the Beexar Backoffice — the management panel for operators. import { Aside, Steps } from '@astrojs/starlight/components'; ## What Is the Beexar Backoffice? The Beexar Backoffice is a web-based management panel where operators configure their integration, manage games, set up custom currencies, and monitor analytics. It is available at your organization's backoffice URL (e.g. `https://app.beexar.com`). --- ## Main Sections | Section | Description | Who Uses It | |---------|-------------|-------------| | **Dashboard** | Real-time overview: GGR, total bets, active players, operator stats | All users | | **Analytics** | Reports with drill-down by operator, game, game type, currency, plus per-player activity | All users | | **Operators** | Manage operators, API keys, callback URLs, custom currencies, paid features | Organization admins | | **Games** | Create, configure, and publish game configurations | Organization admins | | **Team** | Invite members and manage roles | Organization owners | | **Billing** | View and download your invoices | Operator organizations | | **Audit Logs** | Track changes: operator updates, API key operations, game config changes, team changes | All users | Affiliate (partner) organizations get a dedicated **Partner** cabinet (Dashboard, Attached Operators, Earnings) instead of Operators/Games — see [Partners](/backoffice/partner/). --- ## Getting Access Your Beexar account manager provides: 1. **Backoffice URL** — the web address for your organization's backoffice 2. **Login credentials** — email and password for your account 3. **Role assignment** — your role determines what you can access ### Roles | Role | Permissions | |------|------------| | **Owner** | Full access: manage operators, games, team, billing | | **Game Manager** | Manage games and game configurations | | **Billing** | View analytics and financial reports | | **Viewer** | Read-only access to all sections | --- ## Quick Navigation - **[Managing Operators](/backoffice/operators/)** — create operators, configure settings - **[API Keys & Callbacks](/backoffice/api-keys/)** — set up authentication and wallet callback URLs - **[Custom Currencies](/backoffice/currencies/)** — add custom tokens (paid add-on) - **[Game Management](/backoffice/games/)** — create, configure, and publish games - **[AI Design Studio](/backoffice/ai-design/)** — restyle the Dice game with AI or manual tokens - **[Game Preview](/backoffice/game-preview/)** — test games with the demo preview feature - **[Analytics](/backoffice/analytics/)** — monitor performance, GGR, player activity - **[Billing](/backoffice/billing/)** — view and download invoices - **[Paid Features](/backoffice/subscriptions/)** — see which add-ons are active - **[Team & Access](/backoffice/team/)** — invite members and manage roles - **[Audit Logs](/backoffice/audit-logs/)** — review changes made in the backoffice - **[Organization](/backoffice/organization/)** — your org, settlement currency, partners --- # Partners Source: https://docs.beexar.com/backoffice/partner/ Description: The partner (affiliate) cabinet — dashboard, attached operators, and earnings. import { Aside } from '@astrojs/starlight/components'; A **partner** earns commission on the operators it is linked to. Partner organizations get a dedicated cabinet with three screens. All amounts are shown in your organization's settlement currency. --- ## Dashboard A date-filtered overview of your performance, with KPI cards: | Card | Description | |------|-------------| | **Total GGR** | Gross gaming revenue across your active operators | | **Turnover (bets)** | Total amount wagered | | **Wins paid out** | Total amount paid to players | | **Partner Earnings** | Your commission across active operators | A **per-currency breakdown** table shows Bets, Wins, and GGR by currency. --- ## Attached Operators The operators linked to you, with the link's status and active window: | Column | Description | |--------|-------------| | **Operator Organization** | The linked operator | | **Slug** | Operator slug | | **Active** | Whether the link is currently active | | **Since / Until** | The link's active period | --- ## Earnings A per-operator breakdown of what you earned: | Column | Description | |--------|-------------| | **Operator** | The operator | | **Commission Rate** | Your agreed rate | | **GGR** | Operator GGR in the period, in your org currency | | **Earnings** | Your commission, in your org currency | --- # Paid Features Source: https://docs.beexar.com/backoffice/subscriptions/ Description: Optional paid add-ons activated per operator. import { Aside } from '@astrojs/starlight/components'; Some Beexar capabilities are **paid features** (add-ons) enabled per operator. You can see which features are active for an operator on the **Paid Features** tab of the operator detail page. | Feature | What it unlocks | |---------|-----------------| | **Custom currencies** | Add operator-specific `CUSTOM_*` currencies — see [Custom Currencies](/backoffice/currencies/) | --- ## Viewing active features Open **Operators → select an operator → Paid Features**. The table is **read-only** and shows each supported feature, its status, and the agreed amount. --- ## How a paid feature affects gameplay A feature must be **active** for the capability to work at runtime. For example, with **custom currencies**: - While active, players can launch games in your custom currencies. - If it is not active, launching a game with a custom currency returns `403 FEATURE_SUBSCRIPTION_REQUIRED`. Global currencies (USD, EUR, USDT, USDC) are always available regardless of subscriptions. --- ## Billing Active features are billed on your monthly [invoice](/backoffice/billing/), prorated by the number of calendar days the feature was active during the month. The charge is in your organization's settlement currency. --- # Team & Access Source: https://docs.beexar.com/backoffice/team/ Description: Invite team members and manage their roles. import { Aside, Steps } from '@astrojs/starlight/components'; The **Team** section (**Team Management**) lets you manage who has access to your organization's backoffice and what they can do. --- ## Members List | Column | Description | |--------|-------------| | **Email** | Member's login email | | **Full Name** | Member's name | | **Role** | Their role (see below) | | **Created** | When they were added | | **Last Login** | Last sign-in time | | **Actions** | Edit role or remove the member | Your own row is marked with a **You** chip. --- ## Inviting a Member 1. Click **Invite** (or the add-member action). 2. Enter the member's **Email**, **Full name**, and **Role**. 3. Submit — the member is added to your organization. You can change a member's **Role** later, or **remove** them entirely. --- ## Roles | Role | Permissions | |------|------------| | **Owner** | Full access: operators, games, team, billing | | **Game Manager** | Manage games and game configurations | | **Billing** | View analytics and financial reports | | **Viewer** | Read-only access | --- # Frontend Integration Source: https://docs.beexar.com/game-integration/frontend/ Description: CSP, responsive design, and iframe configuration. import { Aside } from '@astrojs/starlight/components'; ## Iframe Configuration Beexar games are embedded in your platform using standard HTML iframes. The `launch_url` from the [launch response](/game-integration/launch/) is used as the iframe `src`. ### Recommended Attributes ```html ``` | Attribute | Value | Purpose | |-----------|-------|---------| | `src` | `launch_url` from launch | Game URL with session token | | `allow` | `autoplay` | Enable game audio/animations | | `sandbox` | `allow-scripts allow-same-origin allow-popups` | Security sandboxing | | `title` | Game name | Accessibility | --- ## Content Security Policy (CSP) If your site uses a Content Security Policy, you must allow Beexar game domains in your CSP headers: ```http Content-Security-Policy: frame-src https://games.beexar.com; connect-src https://games.beexar.com https://gateway.beexar.com; ``` | Directive | Domain | Purpose | |-----------|--------|---------| | `frame-src` | `https://games.beexar.com` | Allow game iframes | | `connect-src` | `https://games.beexar.com` | Allow game API requests | | `connect-src` | `https://gateway.beexar.com` | Allow gateway requests | --- ## Responsive Design Beexar games are responsive and adapt to the container size. For the best experience: ### Desktop Layout ```css .game-container { width: 100%; max-width: 1280px; height: 720px; margin: 0 auto; } .game-container iframe { width: 100%; height: 100%; border: none; } ``` ### Full-Screen Layout ```css .game-container { position: fixed; top: 0; left: 0; width: 100vw; height: 100vh; } .game-container iframe { width: 100%; height: 100%; border: none; } ``` ### Mobile Layout On mobile, games are best displayed in landscape orientation at full viewport width: ```css @media (max-width: 768px) { .game-container { width: 100vw; height: 100vh; position: fixed; top: 0; left: 0; } } ``` --- ## Game Dimensions | Game | Aspect Ratio | Min Width | Recommended | |------|-------------|-----------|-------------| | Dice | 16:9 | 320px | 1280x720 | | Plinko | 16:9 | 320px | 1280x720 | | Slots | 16:9 | 320px | 1280x720 | | Crash | 16:9 | 320px | 1280x720 | All games scale down gracefully to mobile viewport sizes. --- ## Return URL When the player finishes playing, the game redirects to the `return_url` configured during launch: 1. Player clicks "Back to Lobby" in the game 2. Game redirects to `return_url` 3. Your platform's lobby page loads If no `return_url` is provided, the game shows a "Session ended" message. --- ## Troubleshooting | Issue | Cause | Solution | |-------|-------|---------| | Game shows blank | CSP blocking iframe | Add `games.beexar.com` to `frame-src` | | No audio | Missing `allow="autoplay"` | Add `autoplay` to iframe `allow` attribute | | Game too small on mobile | Container not full-width | Use `100vw` / `100vh` on mobile | | CORS errors in console | Missing CSP `connect-src` | Add gateway domain to `connect-src` | | "Session expired" message | Token expired | Create a new session via launch API | --- # Game Launch Source: https://docs.beexar.com/game-integration/launch/ Description: How to create a game session and embed the game. import { Aside, Badge, Steps } from '@astrojs/starlight/components'; Beexar provides two launch endpoints: one for real-money sessions and one for demo sessions with virtual balance. --- ## Real-Money Launch `POST {GATEWAY_URL}/api/v1/softswiss/launcher/real` ### Headers | Header | Value | |--------|-------| | `Content-Type` | `application/json` | | `X-REQUEST-SIGN` | HMAC-SHA256 signature of the request body (64 hex chars) | ### Body | Field | Type | Required | Description | |-------|------|----------|-------------| | `casino_id` | string | Yes | Operator slug (e.g. `"casinoxyz"`) | | `game` | string | Yes | Game slug (e.g. `"dice"`, `"slots"`, `"crash"`) | | `account` | object | Yes | Player account details | | `account.id` | string | Yes | Player ID on your side (max 255 chars) | | `account.currency` | string | Yes | Currency code (e.g. `"USD"`, `"EUR"`, or custom `"CUSTOM_TOKEN"`) | | `account.nickname` | string | No | Player nickname (may be displayed in multiplayer games) | | `account.country` | string | No | ISO 3166-1 alpha-2 country code | | `locale` | string | No | UI language (default: `"en"`) | | `ip` | string | No | Player IP address (IPv4 or IPv6) | | `client_type` | string | No | `"desktop"` or `"mobile"` | | `urls.return_url` | string | No | URL to redirect player after game | | `urls.deposit_url` | string | No | URL for player to make a deposit | | `jurisdiction` | string | No | Country code for regulatory restrictions (e.g. `"DE"`, `"CA-ON"`) | | `session_id` | string | No | Your session identifier (UUID) for round tracking | | `session_payload` | string | No | Opaque string (max 4096 chars) echoed back in every wallet callback | ### Example ```json { "casino_id": "casinoxyz", "game": "dice", "account": { "id": "player_123", "currency": "USD", "nickname": "LuckyPlayer" }, "locale": "en", "client_type": "desktop", "urls": { "return_url": "https://casino.example.com/lobby", "deposit_url": "https://casino.example.com/deposit" } } ``` ### Response (200 OK) ```json { "launch_url": "https://games.beexar.com/dice/casinoxyz/dice-game?token=a1b2c3d4e5f6..." } ``` | Field | Type | Description | |-------|------|-------------| | `launch_url` | string | Full URL to launch the game (embed in iframe or redirect) | --- ## Demo Launch `POST {GATEWAY_URL}/api/v1/softswiss/launcher/demo` Demo sessions use a virtual balance stored in Beexar — no wallet callbacks are triggered during demo play. ### Two Modes | Mode | Authentication | Use Case | |------|---------------|----------| | **Operator mode** | `X-REQUEST-SIGN` with real HMAC signature | Casino backend launches demo for a known player | | **Frontend mode** | `X-REQUEST-SIGN: 0000...0000` (64 zeros) | Game lobby or website launches anonymous demo | ### Body | Field | Type | Required | Description | |-------|------|----------|-------------| | `casino_id` | string | Yes | Operator slug | | `game` | string | Yes | Game slug | | `currency` | string | No | Currency for virtual balance (default: `"USD"`) | | `balance` | string | No | Initial virtual balance (default: `"10000"`) | | `player_id` | string | No | Anonymous player ID (for frontend mode, stored in localStorage) | | `locale` | string | No | UI language | ### Example (Operator Mode) ```json { "casino_id": "casinoxyz", "game": "slots", "currency": "USD", "balance": "5000" } ``` ### Example (Frontend Mode) ```bash curl -X POST https://gateway.beexar.com/api/v1/softswiss/launcher/demo \ -H "Content-Type: application/json" \ -H "X-REQUEST-SIGN: 0000000000000000000000000000000000000000000000000000000000000000" \ -d '{ "casino_id": "casinoxyz", "game": "dice", "player_id": "anon_abc123" }' ``` ### Response (200 OK) ```json { "launch_url": "https://games.beexar.com/dice/casinoxyz/dice-game/demo?token=demo_a1b2c3...&balance=10000¤cy=USD" } ``` --- ## Error Responses Both endpoints answer with the SoftSwiss Twirp envelope. Only **two** values ever appear in `code` — `invalid_argument` and `internal` — and the specific meaning is carried by `meta.api_code`. Branch on `meta.api_code`, never on `code`. | HTTP | `code` | `meta.api_code` | Meaning | |------|--------|-----------------|---------| | 403 | `invalid_argument` | `403` | Invalid request signature | | 400 | `invalid_argument` | `400` | Malformed body or schema validation failure — `meta.api_message` names the offending field | | 400 | `invalid_argument` | `404` | `casino_id` not found, or it does not match the operator | | 400 | `invalid_argument` | `405` | Game is not available to your casino | | 400 | `invalid_argument` | `410` | Casino is disabled | | 400 | `invalid_argument` | `420` | This endpoint is not available for the operator's integration type | | 400 | `invalid_argument` | `154` | Currency not allowed — also returned when the currency needs an active feature subscription, or when bet limits are not configured for it. See [Custom Currencies](/backoffice/currencies/) | | 500 | `internal` | `500` | Internal error, or a temporarily unavailable game-availability check. Retryable | ```json { "code": "invalid_argument", "msg": "invalid request signature", "meta": { "api_code": "403", "api_message": "invalid request signature" } } ``` --- ## Embedding the Game ### Desktop: iframe ```html ``` ### Mobile: Redirect For mobile browsers, redirect the player directly to the `launch_url`: ```javascript if (isMobile()) { window.location.href = launchUrl; } else { document.getElementById('game-frame').src = launchUrl; } ``` | Device | Strategy | Implementation | |--------|----------|---------------| | Desktop | iframe | Embed `launch_url` in ` ``` See [Game Launch](/game-integration/launch/) for responsive design and CSP configuration. --- ## What Happens During Gameplay Once the player starts playing, Beexar automatically sends wallet requests to your callback URLs: 1. **Balance check** — Beexar fetches the current balance when the game loads 2. **BetWin** — Player places a bet (and wins), Beexar sends `POST /betwin` with bet and win transactions atomically 3. **Rollback** — If an error occurs, Beexar sends `POST /rollback` to reverse the transactions 4. **Finish** — If the round was not closed by `finished: true` in BetWin, Beexar sends `POST /finish` --- ## Next Steps - [Authentication](/getting-started/authentication/) — HMAC-SHA256 signing details and code samples - [Wallet API Reference](/wallet-api/overview/) — detailed endpoint documentation - [Error Handling](/guides/error-handling/) — error codes and retry strategies - [Integration Test Game](/guides/testing/#integration-test-game) — automated 29-test validation suite --- # Callback Configuration Source: https://docs.beexar.com/guides/callbacks/ Description: Setting up and managing your 4 wallet callback URLs. import { Aside } from '@astrojs/starlight/components'; ## Overview Beexar needs to know where to send wallet requests during gameplay. You configure 4 callback URLs in the Beexar backoffice for each operator. --- ## Required Callbacks | Callback | Purpose | Endpoint | See | |----------|---------|----------|-----| | **Balance URL** | Fetch player balance | `POST /balance` | [/balance](/wallet-api/balance/) | | **BetWin URL** | Debit/credit player account (atomic) | `POST /betwin` | [/betwin](/wallet-api/betwin/) | | **Rollback URL** | Reverse transactions | `POST /rollback` | [/rollback](/wallet-api/rollback/) | | **Finish URL** | Round completion signal | `POST /finish` | [/finish](/wallet-api/finish/) | ### Example Configuration | Setting | URL | |---------|-----| | Balance URL | `https://api.casino.com/beexar/balance` | | BetWin URL | `https://api.casino.com/beexar/betwin` | | Rollback URL | `https://api.casino.com/beexar/rollback` | | Finish URL | `https://api.casino.com/beexar/finish` | --- ## URL Requirements | Requirement | Details | |-------------|---------| | **Protocol** | HTTPS required | | **Method** | All callbacks use `POST` | | **Content-Type** | `application/json` | | **Availability** | URLs must be publicly accessible from Beexar servers | | **Response time** | Should respond within 10 seconds | | **Authentication** | `X-REQUEST-SIGN` header with HMAC-SHA256 signature | --- ## URL Patterns You can use different URL patterns depending on your architecture: ### Separate Endpoints ``` balance_url: https://api.casino.com/wallet/balance betwin_url: https://api.casino.com/wallet/betwin rollback_url: https://api.casino.com/wallet/rollback finish_url: https://api.casino.com/wallet/finish ``` ### Single Base Path ``` balance_url: https://api.casino.com/beexar/v1/balance betwin_url: https://api.casino.com/beexar/v1/betwin rollback_url: https://api.casino.com/beexar/v1/rollback finish_url: https://api.casino.com/beexar/v1/finish ``` --- ## Configuring in the Backoffice Callback URLs are configured per-operator in the Beexar backoffice: 1. Log in to the Beexar backoffice 2. Navigate to **Operators** and select your operator 3. Go to the **Callback URLs** tab 4. Enter all 4 callback URLs 5. Save the configuration See the [Backoffice: API Keys & Callbacks](/backoffice/api-keys/) guide for step-by-step instructions with screenshots. Changes take effect immediately for new game sessions. Existing sessions continue using the URLs that were configured at session creation time. --- ## Beexar Retry Behavior When Beexar calls your callback URLs and encounters an error: | Scenario | Beexar Action | |----------|--------------| | Connection refused | Retry up to 3 times, then return error to player | | Timeout | Retry up to 3 times, then return error to player | | HTTP 500 | Retry up to 3 times, then return error to player | | HTTP 400 (api_code `100`) | No retry, show "insufficient funds" to player | | HTTP 400 (other) | No retry, log error | | Invalid JSON response | No retry, return error to player | --- ## Health Monitoring We recommend implementing monitoring for your callback endpoints: - **Uptime**: 99.9% availability target - **Latency**: P99 < 1 second, P50 < 200ms - **Error rate**: < 0.1% non-business errors (exclude code 100) - **Alerting**: Set up alerts for response time spikes and error rate increases --- # Error Handling Source: https://docs.beexar.com/guides/error-handling/ Description: Error codes, retry strategy, and timeout handling. import { Aside } from '@astrojs/starlight/components'; ## Error Response Format All error responses use the Twirp format with an `api_code` in the `meta` field: ```json { "code": "invalid_argument", "msg": "Player has not enough funds to process an action.", "meta": { "api_code": "100", "api_message": "Player has not enough funds to process an action.", "balance": "50.00" } } ``` | Field | Type | Required | Description | |-------|------|----------|-------------| | `code` | string | Yes | Twirp error code (see below) | | `msg` | string | Yes | Human-readable error description | | `meta.api_code` | string | Yes | Numeric API error code | | `meta.api_message` | string | Yes | API error message | | `meta.balance` | string | Conditional | Current balance — required when api_code is `100`, `105`, or `106` | ### Twirp Error Codes Only two Twirp codes are used: | Twirp Code | HTTP Status | Meaning | |------------|-------------|---------| | `invalid_argument` | 400 | Client error (bad request, auth failure, business rule violation) | | `internal` | 500 | Server error | --- ## API Error Codes ### Funds-Related Codes (balance required in response) | api_code | Description | Operator Action | |----------|-------------|----------------| | `100` | Insufficient funds | Return current `balance` in meta. Beexar shows "not enough funds" to player. | | `105` | Bet limit exceeded | Return current `balance` in meta. | | `106` | Win limit exceeded | Return current `balance` in meta. | ### Player Errors | api_code | Description | Operator Action | |----------|-------------|----------------| | `101` | Player not found or disabled | Beexar terminates the session. | ### Request Errors | api_code | Description | Operator Action | |----------|-------------|----------------| | `400` | Bad request | Malformed JSON, missing required fields. | | `403` | Invalid signature | HMAC-SHA256 signature mismatch. Verify `AUTH_TOKEN`. | | `155` | Transaction tombstoned | The `id_provider` was already rolled back. Reject the action. | ### Server Errors | api_code | Description | Operator Action | |----------|-------------|----------------| | `500` | Internal server error | Generic server failure. Beexar will retry. | --- ## Retry Strategy (Beexar Side) When Beexar receives an error or timeout from the operator's wallet: | Response | Beexar Behavior | |----------|----------------| | **HTTP 200** | Success, no retry | | **HTTP 400, api_code `100`** | Insufficient funds — no retry, show error to player | | **HTTP 400, api_code `403`** | Signature error — no retry (configuration issue) | | **HTTP 400, api_code `155`** | Tombstoned — no retry, action already cancelled | | **HTTP 400, other** | Bad request — no retry (logged) | | **HTTP 500** | Server error — retry with exponential backoff | | **Timeout** | No response — retry with exponential backoff | ### Retry Parameters | Parameter | BetWin | Rollback | Finish | |-----------|--------|----------|--------| | Max attempts | 4 (1 + 3 retries) | Unlimited | Unlimited | | Initial backoff | 100 ms | 10 s | 10 s | | Max backoff | 400 ms | 1 hour | 1 hour | | Backoff multiplier | 2x | 2x | 2x | | Total time budget | 5 s | Up to 7 days | Up to 7 days | ### What Happens When Retries Are Exhausted | Action | Behavior on failure | |--------|-------------------| | **BetWin** | Error returned to player. The round is considered "not started" — **no rollback is sent.** | | **Rollback** | Retried via the outbox worker (async, up to 7 days). Rollbacks are critical for financial consistency. | | **Finish** | Retried via the outbox worker (async, up to 7 days). Finish is informational — financial actions already completed. | --- ## Timeout Handling (Operator Side) ### Recommendations 1. **Process quickly** — aim for response times under 500ms 2. **Return early** — validate and respond before heavy background processing 3. **Handle retries gracefully** — same `id_provider` = return original response (idempotency) 4. **Never block on external calls** — if your wallet depends on downstream services, implement circuit breakers ### What Happens on Timeout ```mermaid sequenceDiagram participant Beexar participant Wallet as Operator Wallet Beexar->>Wallet: POST /betwin (id_provider: "tx_1") Note right of Wallet: Server slow / timeout Beexar->>Wallet: POST /betwin (retry 1, same id_provider) Note right of Wallet: Still no response Beexar->>Wallet: POST /betwin (retry 2, same id_provider) Note right of Wallet: Still no response Beexar->>Wallet: POST /betwin (retry 3, same id_provider) Note right of Wallet: Still no response Note over Beexar: All retries exhausted — error shown to player ``` --- ## Best Practices 1. **Always return valid JSON** — even on errors, return the Twirp error format 2. **Include `balance` on funds-related codes** — api_codes `100`, `105`, `106` 3. **Log all requests** — include `id_provider`, `round_id`, and `account_id` for debugging 4. **Monitor response times** — alert if P99 exceeds 1 second 5. **Implement health checks** — Beexar may check endpoint availability --- # FAQ Source: https://docs.beexar.com/guides/faq/ Description: Frequently asked questions about the Beexar integration. import { Aside } from '@astrojs/starlight/components'; ## General ### What is the Seamless Wallet pattern? The Seamless Wallet means Beexar never holds player funds. Instead, we call **your** server to debit (bet), credit (win), or reverse (rollback) funds. Your platform is the single source of truth for player balances. --- ## Amounts & Currency ### Why does Beexar use decimal strings? Decimal strings (e.g. `"10.50"`) are human-readable and avoid precision issues with integer conversion, especially for cryptocurrencies with many decimal places (e.g. BTC has 8 decimals, ETH has 18). ### How should I handle currency precision? Use the ISO 4217 standard for the number of decimal places per currency. Store amounts using a decimal type (not floating-point) in your database. The maximum precision is 18 decimal places. --- ## Rounds & Actions ### Can a win be matched to a specific bet? Not directly. A win and a bet within the same round share the same `round_id`, but they have independent `id_provider` values. In simple games (dice, plinko, crash), there is typically one bet and one win per round. In slots, there can be multiple bets and wins per round. ### Can multiple bet/win transactions happen in one round? Yes. In multi-step games like slots with bonus rounds or free spins, a single `round_id` can contain multiple bet and win transactions, delivered across one or more `/betwin` calls. Each transaction has its own `id_provider`. ### What if a rollback arrives before the original action? Create a **tombstone** — a record that prevents the original action from being processed if it arrives later. Return a successful response (HTTP 200), not an error. This is a critical edge case due to network timing. ### Is the `/finish` endpoint mandatory? You must implement it, but it is **not** sent on every round. Beexar sends `/finish` only when the last `/betwin` did **not** set `finished: true` (for example, a multi-step slots round, or session expiry with an open round). It does not change the balance — respond with the current balance: `{ "balance": "..." }`. Use it for reconciliation and reporting. ### What is `round_id` vs `id_provider`? - **`round_id`**: Identifies a game round. All transactions (bets, wins, rollbacks) in one round share the same `round_id`. In multiplayer games (crash), each player bet is settled as its own round, so each bet has its own `round_id` even though the underlying game round is shared. - **`id_provider`**: Identifies a single transaction within a round, generated by Beexar. Used for idempotency. Each transaction has a unique `id_provider`. --- ## Rollback ### When does Beexar send a rollback? Beexar sends a rollback when: - A game error occurs **after the bet was confirmed** (operator returned HTTP 200) but before the result was determined - A bonus or free-spins session times out in multi-step games (e.g., slots) - In crash games, if a win wallet call fails during cashout, or if a bet is stuck in a transitional state for too long Beexar does **not** send a rollback after a failed or timed-out bet. If all retries are exhausted without a successful response, the round is considered "not started" and an error is returned to the player. ### Should I process a rollback if the player has insufficient funds? Yes. Even if rolling back a win would make the player's balance negative, process the rollback. The financial integrity of the round takes priority. ### What if I receive the same rollback twice? Return the original response. Like bets and wins, rollbacks are identified by `id_provider` and must be idempotent. --- ## Sessions & Game Launch ### How long does a session last? Sessions use a 30-minute sliding TTL — each player action extends it. When a session expires, open rounds are finalized (pending bets rolled back, `/finish` sent). The player is redirected to `return_url` if configured. ### Can a player have multiple active sessions? A player can have one active session per game. Starting a new session for the same player and game invalidates the previous session. ### Do I need to implement gRPC? No. All operator-facing communication is HTTP/REST. You only need to implement HTTP endpoints. --- ## Security ### Do I need to whitelist Beexar IPs? Beexar does not require IP whitelisting. All requests are authenticated using HMAC-SHA256 signatures. However, you may optionally whitelist Beexar's IP ranges for additional security — contact your account manager for the current IP list. ### How do I rotate API keys? Contact your Beexar account manager to rotate credentials. You can configure a new API key before deactivating the old one to avoid downtime. --- ## Crash Game ### How does crash multiplayer work from the operator's perspective? Each player's bet is treated as an independent round. Even though multiple players share the same crash round, each bet gets its own `round_id` and its own `/betwin` (and `/finish` when needed) calls. The operator does not need to know about the shared underlying round — just process each `round_id` independently. ### Can a player place multiple bets in one crash round? Yes. Each player can place up to 2 bets (slot 1 and slot 2) in a single crash round. Each bet gets a **separate `round_id`** and is settled independently. You will receive separate wallet callbacks for each bet. ### What happens if a player disconnects during a crash round? If the player already placed a bet, the round continues normally on the server side. The bet will either be resolved by the crash event (player loses) or by auto-cashout if configured. The operator will still receive all the wallet callbacks (`/betwin`, and `/finish` when the round was not already closed). ### Does crash use WebSocket? The crash game frontend uses WebSocket for real-time updates (multiplier, round state, other players' bets). However, operators do not need to implement or interact with WebSocket — all operator communication is standard HTTP callbacks. --- ## Testing ### How do I test the integration? Use [demo mode and the Integration Test Game](/guides/testing/). Demo mode exercises the game UI with a virtual balance (no wallet calls); the Integration Test Game drives real callbacks to your wallet against a test operator — no real money involved. ### Is there a reference wallet implementation? Yes. Beexar provides a reference wallet implementation that covers all 4 wallet endpoints. Contact your account manager for access. --- # Testing Source: https://docs.beexar.com/guides/testing/ Description: How to test the integration using demo mode and the Integration Test Game. import { Aside, Steps } from '@astrojs/starlight/components'; ## Two Ways to Test 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](/game-integration/launch/)). The Integration Test Game is launched via the standard real launcher with `game: "testgame"` (see below). --- ## Integration Test Game Beexar includes a built-in **Integration Test Game** that validates your wallet implementation against 29 test scenarios. It covers the full SoftSwiss wallet API contract. ### How It Works 1. Launch the test game via the standard launcher API 2. Select which tests to run (or run all) 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 ### Test Categories | 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 | ### Running the Test Game ```bash 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. ### Test Results 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 all tests pass --- ## Reference Wallet Implementation 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](/tools/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](https://github.com/beexar-games/public-api/tree/main/conformance): 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. --- ## Integration Checklist 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` --- ## Testing Scenarios ### Happy Path: Dice Round ```bash 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) ``` ### Happy Path: Crash Round ```bash 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 ``` ### Error Scenarios to Test | 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 | --- # Beexar Integration Guide Source: https://docs.beexar.com/index/ Description: Complete guide for integrating Beexar games into your platform. import { Card, CardGrid } from '@astrojs/starlight/components'; SDKs for Node, PHP, Go and Python, an AI agent skill that does the integration for you, and the public OpenAPI contract. [Overview](/tools/) | [AI agent](/tools/ai-agent/) | [Prompts](/tools/prompts/) | [Reference wallet](/tools/reference-wallet/) Learn about Beexar's Seamless Wallet pattern, set up your integration, and launch your first game session in minutes. [Introduction](/getting-started/introduction/) | [Quick Start](/getting-started/quickstart/) | [Authentication](/getting-started/authentication/) Implement 4 HTTP endpoints that Beexar calls during gameplay: balance, betwin, rollback, and finish. [Overview](/wallet-api/overview/) | [Balance](/wallet-api/balance/) | [BetWin](/wallet-api/betwin/) | [Rollback](/wallet-api/rollback/) | [Finish](/wallet-api/finish/) Launch game sessions, embed games in iframes, and handle the session lifecycle. [Game Launch](/game-integration/launch/) | [Session Flow](/game-integration/session-flow/) | [Frontend](/game-integration/frontend/) Explore available games: Dice (over/under), Plinko (ball-drop), Slots (multi-reel with bonus features), and Crash (multiplayer rising multiplier). [Dice](/games/dice/) | [Plinko](/games/plinko/) | [Slots](/games/slots/) | [Crash](/games/crash/) Manage operators, API keys, custom currencies, game configurations, and view analytics. [Overview](/backoffice/overview/) | [Operators](/backoffice/operators/) | [Currencies](/backoffice/currencies/) | [Games](/backoffice/games/) Interactive API documentation powered by Scalar. Explore request/response schemas for the Wallet and Gateway APIs. [Open API Reference](/api-reference/) Testing, error handling, callback configuration, and frequently asked questions. [Testing](/guides/testing/) | [Error Handling](/guides/error-handling/) | [Callbacks](/guides/callbacks/) | [FAQ](/guides/faq/) --- # Integration Tools Source: https://docs.beexar.com/tools/ Description: SDKs, an AI agent skill, copy-paste prompts and the OpenAPI contract. import { Card, CardGrid, Aside } from '@astrojs/starlight/components'; Everything you need to build the integration, in the order most people want it. --- ## Let an AI agent do it ```bash npx skills add beexar-games/public-api ``` Installs the `beexar-integration` skill into Claude Code, Cursor, Codex, OpenCode and ~80 other agents. It analyses your codebase, picks the right SDK, wires up the launcher and the four wallet callbacks, and knows the parts that are easy to get wrong — raw-body signing, idempotency, tombstones, decimal money. Unlike a hand-written guide, it is **generated from the platform's own source**, so its error-code table and timing budgets cannot drift from what the platform actually does. → [How it works](/tools/ai-agent/) Not using an agent with skill support? [Copy a prompt](/tools/prompts/) instead. --- ## Or use an SDK `npm install @beexar/sdk` Zero dependencies, ESM + CJS, Node 18+. [Guide](/tools/sdk-node/) · [GitHub](https://github.com/beexar-games/beexar-node) `composer require beexar/sdk` Zero dependencies — no bcmath, no gmp. PHP 8.1+. [Guide](/tools/sdk-php/) · [GitHub](https://github.com/beexar-games/beexar-php) `go get github.com/beexar-games/beexar-go` Standard library only. Go 1.22+. [Guide](/tools/sdk-go/) · [GitHub](https://github.com/beexar-games/beexar-go) `pip install beexar` Standard library only. Python 3.9+. [Guide](/tools/sdk-python/) · [GitHub](https://github.com/beexar-games/beexar-python) Each SDK gives you the same two halves: a signed client for launching games, and a wallet server where you implement four methods against your own ledger while the SDK handles signature verification, parsing, validation, decimal money and the error envelope. --- ## Or neither The contract is public and small — four callbacks you implement, three calls you make. Point any OpenAPI generator at it: ```bash openapi-generator-cli generate \ -i https://docs.beexar.com/api/wallet.yaml \ -g -o ./beexar ``` | Spec | What it describes | |---|---| | [`/api/wallet.yaml`](/api/wallet.yaml) | the four callbacks **you** implement | | [`/api/softswiss/gateway.yaml`](/api/softswiss/gateway.yaml) | launching a real or demo session | | [`/api/gateway.yaml`](/api/gateway.yaml) | the operator game catalogue | | [`/api/common/schemas.yaml`](/api/common/schemas.yaml) | shared schemas | Then read the [manual integration reference](https://github.com/beexar-games/public-api/blob/main/skill/beexar-integration/references/manual.md) for what a generator will not give you: raw-body signing, idempotency, tombstones and the money rules. --- ## Then prove it works A complete, correct wallet in ~250 lines, in all four languages. Read it, run it, or copy the parts you need. → [Reference wallet](/tools/reference-wallet/) 29 scenarios against your live callbacks — signature, idempotency, tombstones, insufficient funds, batch atomicity. → [Testing](/guides/testing/) --- # AI agent skill Source: https://docs.beexar.com/tools/ai-agent/ Description: Install the Beexar integration skill into your coding agent. import { Aside, Steps, Tabs, TabItem } from '@astrojs/starlight/components'; ```bash npx skills add beexar-games/public-api ``` That installs the `beexar-integration` skill into every agent on your machine that supports skills — Claude Code, Cursor, Codex, OpenCode, Gemini CLI, GitHub Copilot and around eighty others. Then just ask: > Integrate Beexar into this project. --- ## What it does 1. **Reads your codebase first.** Language and runtime pick the SDK; the project type decides whether you need the wallet callbacks, the launcher, or both; and it looks for the ledger the callbacks will have to run inside. 2. **Reads only what it needs.** The skill ships a reference per language plus focused notes on the wallet callbacks, error codes, timings and the launcher. 3. **Implements against your code.** Credentials from environment variables, the four callbacks wired into your existing router, one database transaction per request. 4. **Tells you what to verify.** Which files changed, which environment variables to set, and to run the [Integration Test Game](/guides/testing/) — the only real proof the integration is correct. ## Why it stays correct Most integration skills are a snapshot of a document someone wrote once. This one is **generated from the platform's own source** on every release: | Part of the skill | Generated from | |---|---| | the api_code registry | the platform's own code table | | the timing and retry budgets | the gateway's retry configuration | | the contract versions it quotes | `info.version` in the four OpenAPI documents | Our CI fails if any of them drifts. And the skill itself carries the contract versions it was built against, with instructions to check them against the live specs and to tell you — rather than invent a method name — when they disagree. ## What it will not do - It will not implement idempotency inside the SDK. That has to live in your database transaction, and the skill says so instead of pretending otherwise. - It will not turn off signature verification to make something work. - It will not use floating-point arithmetic for money. ## Without the skill Every agent can still read the docs directly: [`https://docs.beexar.com/llms.txt`](/llms.txt) — a map of this site for language models, and [`/llms-full.txt`](/llms-full.txt) with the full text of every page in one file. [Copy-paste prompts](/tools/prompts/) for Node, PHP, Go, Python and any other language. The four specs, linked from the [API reference](/api-reference/). --- # AI prompts Source: https://docs.beexar.com/tools/prompts/ Description: Copy-paste prompts for integrating Beexar with any coding assistant. import { Tabs, TabItem, Aside } from '@astrojs/starlight/components'; For agents without skill support, or when you would rather steer it yourself. Paste one of these into your assistant inside the project you are integrating. ```text Integrate the Beexar casino platform into this project using the official SDK. Install: npm install @beexar/sdk (zero dependencies, ESM + CJS, Node 18+) Docs: https://docs.beexar.com/tools/sdk-node/ 1. ANALYSE Find the HTTP router, the configuration layer, and the ledger/wallet code that owns player balances. Report what you found before writing anything. 2. IMPLEMENT a. Launcher — `new Client({ casinoId, apiSecret })` from BEEXAR_CASINO_ID and BEEXAR_API_SECRET. `launchReal()` returns { launch_url } for an iframe. b. Wallet callbacks — implement WalletHandler's four methods (balance, betWin, rollback, finish) against the existing ledger, and mount with `beexarWallet(new WalletServer(handler, { apiSecret }))` from '@beexar/sdk/express'. Mount it BEFORE any JSON body parser; if the app already uses express.json(), switch it to express.json({ verify: captureRawBody }). c. Inside betWin, in ONE database transaction: look up id_provider (return the stored id and stored balance if found); check the rollback tombstone (throw WalletError.alreadyRolledBack() if set); then apply, all-or-nothing. d. Money is the SDK's Money type — never a number, never parseFloat. e. Errors: throw WalletError.insufficientFunds(balance) and friends. Codes 100/105/106 require the balance as an argument. 3. VERIFY List changed files and the env vars I must set. Confirm it builds and any tests you added pass. Tell me to run the Integration Test Game (https://docs.beexar.com/guides/testing/) against the live callbacks. Do not invent method names. If something in the SDK does not match this prompt, stop and tell me. ``` ```text Integrate the Beexar casino platform into this project using the official SDK. Install: composer require beexar/sdk (zero dependencies, PHP 8.1+) Docs: https://docs.beexar.com/tools/sdk-php/ 1. ANALYSE Find the HTTP routing (framework or none), the configuration layer, and the ledger code that owns player balances. Report what you found first. 2. IMPLEMENT a. Launcher — `new Beexar\Client($casinoId, $apiSecret)` from BEEXAR_CASINO_ID and BEEXAR_API_SECRET. launchReal() returns the URL for an iframe. b. Wallet callbacks — implement Beexar\WalletHandler's four methods against the existing ledger. With a framework, register Beexar\Http\WalletMiddleware BEFORE any body-parsing middleware. Without one, call $server->handleGlobals(). c. Inside betWin(), in ONE database transaction: look up id_provider (return the stored id and stored balance if found); check the rollback tombstone (throw WalletError::alreadyRolledBack() if set); then apply, all-or-nothing. d. Money is Beexar\Money — never a float. e. Errors: throw WalletError::insufficientFunds($balance) and friends. Codes 100/105/106 require the balance as an argument. 3. VERIFY List changed files and the env vars I must set. Confirm it runs and any tests you added pass. Tell me to run the Integration Test Game (https://docs.beexar.com/guides/testing/) against the live callbacks. Do not invent method names. If something in the SDK does not match this prompt, stop and tell me. ``` ```text Integrate the Beexar casino platform into this project using the official SDK. Install: go get github.com/beexar-games/beexar-go (stdlib only, Go 1.22+) Docs: https://docs.beexar.com/tools/sdk-go/ 1. ANALYSE Find the HTTP mux, the configuration layer, and the ledger code that owns player balances. Report what you found before writing anything. 2. IMPLEMENT a. Launcher — beexar.NewClient(casinoID, apiSecret) from BEEXAR_CASINO_ID and BEEXAR_API_SECRET. LaunchReal returns LaunchURL for an iframe. b. Wallet callbacks — implement beexar.WalletHandler against the existing ledger and mount server.NewHandler() on the router. c. Inside BetWin, in ONE database transaction: look up IDProvider (return the stored id and stored balance if found); check the rollback tombstone (return beexar.ErrAlreadyRolledBack() if set); then apply, all-or-nothing. d. Money is beexar.Money — never a float64. e. Errors: return beexar.ErrInsufficientFunds(balance) and friends. Codes 100/105/106 take the balance as a parameter. 3. VERIFY List changed files and the env vars I must set. Confirm `go build ./...` and `go test ./...` pass. Tell me to run the Integration Test Game (https://docs.beexar.com/guides/testing/) against the live callbacks. Do not invent identifiers. If something in the SDK does not match this prompt, stop and tell me. ``` ```text Integrate the Beexar casino platform into this project using the official SDK. Install: pip install beexar (stdlib only, Python 3.9+) Docs: https://docs.beexar.com/tools/sdk-python/ 1. ANALYSE Find the web framework, the configuration layer, and the ledger code that owns player balances. Report what you found before writing anything. 2. IMPLEMENT a. Launcher — Client(casino_id, api_secret) from BEEXAR_CASINO_ID and BEEXAR_API_SECRET. launch_real() returns the URL for an iframe. b. Wallet callbacks — a class with balance, bet_win, rollback and finish against the existing ledger, mounted with beexar.asgi.fastapi_router / flask_blueprint / asgi_app. Do NOT declare a Pydantic model on those routes: it consumes the raw body the signature covers. c. Inside bet_win, in ONE database transaction: look up id_provider (return the stored id and stored balance if found); check the rollback tombstone (raise WalletError.already_rolled_back() if set); then apply, all-or-nothing. d. Money is beexar.Money — never a float. e. Errors: raise WalletError.insufficient_funds(balance) and friends. Codes 100/105/106 require the balance as an argument. 3. VERIFY List changed files and the env vars I must set. Confirm the app starts and any tests you added pass. Tell me to run the Integration Test Game (https://docs.beexar.com/guides/testing/) against the live callbacks. Do not invent method names. If something in the SDK does not match this prompt, stop and tell me. ``` ```text Integrate the Beexar casino platform into this project. There is no SDK for this language, so implement directly against the public OpenAPI contract. Specs (fetch them, do not guess): https://docs.beexar.com/api/wallet.yaml the four callbacks I implement https://docs.beexar.com/api/softswiss/gateway.yaml launching a session https://docs.beexar.com/api/gateway.yaml the game catalogue https://docs.beexar.com/api/common/schemas.yaml shared schemas 1. ANALYSE the router, the config layer and the ledger. Report first. 2. IMPLEMENT a. Signing: X-REQUEST-SIGN = lowercase hex HMAC-SHA256 of the RAW request body keyed with the API secret. Serialise the body ONCE, sign those exact bytes, send those exact bytes. Verify against the bytes as received — capture them before any JSON middleware. Compare in constant time. b. The four callbacks: POST /balance, /betwin, /rollback, /finish. c. Validate before handling: currency ^[A-Z][A-Z0-9_]{2,31}$ (reject lowercase, do not upcase); amount ^\d+(\.\d{1,16})?$, at most 40 chars, greater than zero — REJECT the exponent form; body at most 64 KiB. Do NOT reject unknown JSON fields. d. In ONE database transaction: dedupe on id_provider (a repeat returns the STORED id and STORED balance), then check the rollback tombstone (answer api_code 409), then apply all-or-nothing. e. On rollback, record a tombstone for original_id_provider whether or not the original exists; answer 200 with an empty id when there was nothing to reverse. f. Money is a decimal string in the currency's main unit. No floats anywhere. g. Errors: {"code":"invalid_argument"|"internal","msg":..., "meta":{"api_code":...,"api_message":...}}. Only HTTP 400 and 500 exist — a bad signature is 400 with api_code 403, never HTTP 403. api_code 100, 105 and 106 must also carry meta.balance. 3. VERIFY against the public conformance fixtures at https://github.com/beexar-games/public-api/tree/main/conformance — request bytes, signature, ledger before and after, expected response. Then tell me to run the Integration Test Game (https://docs.beexar.com/guides/testing/). ``` --- # Reference wallet Source: https://docs.beexar.com/tools/reference-wallet/ Description: A complete, correct wallet implementation in all four languages. import { Aside, Tabs, TabItem } from '@astrojs/starlight/components'; Every Beexar SDK ships a working wallet in about 250 readable lines. It is not durable and it is not your ledger — it exists to show the three rules that decide whether an integration is correct, in the order they have to happen. [`examples/inmemory-wallet.ts`](https://github.com/beexar-games/beexar-node/blob/main/examples/inmemory-wallet.ts) [`examples/InMemoryWallet.php`](https://github.com/beexar-games/beexar-php/blob/main/examples/InMemoryWallet.php) [`examples/inmemory`](https://github.com/beexar-games/beexar-go/blob/main/examples/inmemory/wallet.go) [`examples/inmemory_wallet.py`](https://github.com/beexar-games/beexar-python/blob/main/examples/inmemory_wallet.py) --- ## The three rules, in order ### 1. Dedupe on `id_provider` first The platform retries, so the same `id_provider` will arrive twice. The second time must be invisible: return the transaction id and the balance you **stored the first time**. Not today's balance. Not a fresh id. ### 2. Then check the tombstone A rollback can arrive **before** the transaction it reverses. That is normal delivery, not an error. When the bet finally shows up, its `id_provider` is already tombstoned and it must be refused with api_code `409` — never applied. ### 3. Then apply, atomically A `/betwin` request can carry several transactions. Apply them in the order given, all or none. If the third cannot be paid, the first two must not have happened — and the `insufficient funds` answer reports the balance as it was *before* the batch, because nothing moved. ``` lookup(id_provider) ──found──▶ return stored id + stored balance, change nothing │ not found ▼ tombstone(id_provider)? ──yes──▶ api_code 409, change nothing │ no ▼ apply, record {id_provider → your id, balance after} ``` ## Running one Each SDK also ships a runnable server that wires the reference wallet to an HTTP port. Point your operator's callback URLs at it and run the [Integration Test Game](/guides/testing/) — it should score 29 of 29. ```bash BEEXAR_API_SECRET=... node examples/server.js # Node BEEXAR_API_SECRET=... php -S 0.0.0.0:8080 examples/server.php # PHP BEEXAR_API_SECRET=... go run ./examples/server # Go BEEXAR_API_SECRET=... python examples/server.py # Python ``` ## Conformance fixtures The same reference wallets are driven by a shared fixture set that all four SDKs run: [`conformance/`](https://github.com/beexar-games/public-api/tree/main/conformance). Each case carries the **exact request bytes**, the signature over them, the ledger before and after, and the expected response. Request bodies are compared byte for byte — several use a key order no serialiser would produce, so an implementation that re-serialises before verifying fails immediately. They are language-neutral. If you are integrating without an SDK, point your own test suite at them and you get the same coverage the official SDKs have. --- # Go SDK Source: https://docs.beexar.com/tools/sdk-go/ Description: Launch games and serve the wallet callbacks from Go. import { Aside } from '@astrojs/starlight/components'; ```bash go get github.com/beexar-games/beexar-go ``` Zero dependencies — standard library only, in the SDK and in its tests. Go 1.22+. **Source:** [github.com/beexar-games/beexar-go](https://github.com/beexar-games/beexar-go) · **Reference:** [README](https://github.com/beexar-games/beexar-go#readme) --- ## What it gives you Two halves, and the second one is the work. - **`Client`** — launch a real-money or demo session, read the catalogue. Signs every request over the exact bytes it sends. - **`WalletServer`** — the four callbacks. You implement four methods against your own ledger; the SDK does signature verification over the raw body, parsing, validation, decimal money and the Twirp error envelope. It also ships a **complete reference wallet** (~250 lines) with correct idempotency and tombstones, and the [conformance fixtures](/tools/reference-wallet/#conformance-fixtures) every Beexar SDK is tested against. ## The three things that decide whether it works 1. **The raw body.** The signature is an HMAC over the exact bytes received. Any middleware that parses the JSON and serialises it again destroys them. The SDK's framework bindings exist to prevent that, and when a signature fails for that reason the SDK says so in plain words instead of leaving you with a 400. 2. **Idempotency.** `id_provider` is the platform's idempotency key. A repeat must return the transaction id and balance you stored the first time. That check has to be in the same database transaction as the balance update — so the SDK deliberately does **not** do it for you. 3. **Money.** Decimal strings in the currency's main unit. The SDK's money type cannot be built from a float. ## Next - The full README on GitHub has the complete API and worked examples. - [Reference wallet](/tools/reference-wallet/) — what a correct implementation looks like. - [Integration Test Game](/guides/testing/) — 29 scenarios against your live callbacks. This is the proof. --- # Node / TypeScript SDK Source: https://docs.beexar.com/tools/sdk-node/ Description: Launch games and serve the wallet callbacks from Node. import { Aside } from '@astrojs/starlight/components'; ```bash npm install @beexar/sdk ``` Zero runtime dependencies. ESM and CommonJS. Node 18+. **Source:** [github.com/beexar-games/beexar-node](https://github.com/beexar-games/beexar-node) · **Reference:** [README](https://github.com/beexar-games/beexar-node#readme) --- ## What it gives you Two halves, and the second one is the work. - **`Client`** — launch a real-money or demo session, read the catalogue. Signs every request over the exact bytes it sends. - **`WalletServer`** — the four callbacks. You implement four methods against your own ledger; the SDK does signature verification over the raw body, parsing, validation, decimal money and the Twirp error envelope. It also ships a **complete reference wallet** (~250 lines) with correct idempotency and tombstones, and the [conformance fixtures](/tools/reference-wallet/#conformance-fixtures) every Beexar SDK is tested against. ## The three things that decide whether it works 1. **The raw body.** The signature is an HMAC over the exact bytes received. Any middleware that parses the JSON and serialises it again destroys them. The SDK's framework bindings exist to prevent that, and when a signature fails for that reason the SDK says so in plain words instead of leaving you with a 400. 2. **Idempotency.** `id_provider` is the platform's idempotency key. A repeat must return the transaction id and balance you stored the first time. That check has to be in the same database transaction as the balance update — so the SDK deliberately does **not** do it for you. 3. **Money.** Decimal strings in the currency's main unit. The SDK's money type cannot be built from a float. ## Next - The full README on GitHub has the complete API and worked examples. - [Reference wallet](/tools/reference-wallet/) — what a correct implementation looks like. - [Integration Test Game](/guides/testing/) — 29 scenarios against your live callbacks. This is the proof. --- # PHP SDK Source: https://docs.beexar.com/tools/sdk-php/ Description: Launch games and serve the wallet callbacks from PHP. import { Aside } from '@astrojs/starlight/components'; ```bash composer require beexar/sdk ``` Zero runtime dependencies — no bcmath, no gmp, no HTTP client. PHP 8.1+. **Source:** [github.com/beexar-games/beexar-php](https://github.com/beexar-games/beexar-php) · **Reference:** [README](https://github.com/beexar-games/beexar-php#readme) --- ## What it gives you Two halves, and the second one is the work. - **`Client`** — launch a real-money or demo session, read the catalogue. Signs every request over the exact bytes it sends. - **`WalletServer`** — the four callbacks. You implement four methods against your own ledger; the SDK does signature verification over the raw body, parsing, validation, decimal money and the Twirp error envelope. It also ships a **complete reference wallet** (~250 lines) with correct idempotency and tombstones, and the [conformance fixtures](/tools/reference-wallet/#conformance-fixtures) every Beexar SDK is tested against. ## The three things that decide whether it works 1. **The raw body.** The signature is an HMAC over the exact bytes received. Any middleware that parses the JSON and serialises it again destroys them. The SDK's framework bindings exist to prevent that, and when a signature fails for that reason the SDK says so in plain words instead of leaving you with a 400. 2. **Idempotency.** `id_provider` is the platform's idempotency key. A repeat must return the transaction id and balance you stored the first time. That check has to be in the same database transaction as the balance update — so the SDK deliberately does **not** do it for you. 3. **Money.** Decimal strings in the currency's main unit. The SDK's money type cannot be built from a float. ## Next - The full README on GitHub has the complete API and worked examples. - [Reference wallet](/tools/reference-wallet/) — what a correct implementation looks like. - [Integration Test Game](/guides/testing/) — 29 scenarios against your live callbacks. This is the proof. --- # Python SDK Source: https://docs.beexar.com/tools/sdk-python/ Description: Launch games and serve the wallet callbacks from Python. import { Aside } from '@astrojs/starlight/components'; ```bash pip install beexar ``` Zero runtime dependencies — standard library only. Python 3.9+. **Source:** [github.com/beexar-games/beexar-python](https://github.com/beexar-games/beexar-python) · **Reference:** [README](https://github.com/beexar-games/beexar-python#readme) --- ## What it gives you Two halves, and the second one is the work. - **`Client`** — launch a real-money or demo session, read the catalogue. Signs every request over the exact bytes it sends. - **`WalletServer`** — the four callbacks. You implement four methods against your own ledger; the SDK does signature verification over the raw body, parsing, validation, decimal money and the Twirp error envelope. It also ships a **complete reference wallet** (~250 lines) with correct idempotency and tombstones, and the [conformance fixtures](/tools/reference-wallet/#conformance-fixtures) every Beexar SDK is tested against. ## The three things that decide whether it works 1. **The raw body.** The signature is an HMAC over the exact bytes received. Any middleware that parses the JSON and serialises it again destroys them. The SDK's framework bindings exist to prevent that, and when a signature fails for that reason the SDK says so in plain words instead of leaving you with a 400. 2. **Idempotency.** `id_provider` is the platform's idempotency key. A repeat must return the transaction id and balance you stored the first time. That check has to be in the same database transaction as the balance update — so the SDK deliberately does **not** do it for you. 3. **Money.** Decimal strings in the currency's main unit. The SDK's money type cannot be built from a float. ## Next - The full README on GitHub has the complete API and worked examples. - [Reference wallet](/tools/reference-wallet/) — what a correct implementation looks like. - [Integration Test Game](/guides/testing/) — 29 scenarios against your live callbacks. This is the proof. --- # POST /balance Source: https://docs.beexar.com/wallet-api/balance/ Description: Return the current player balance. import { Aside, Badge } from '@astrojs/starlight/components'; Beexar sends this request to fetch the current player balance. It is called when the game loads and may be called periodically during gameplay. --- ## Request `POST {balance_url}` ### Headers | Header | Value | |--------|-------| | `Content-Type` | `application/json` | | `X-REQUEST-SIGN` | HMAC-SHA256 signature of request body | ### Body | Field | Type | Required | Description | |-------|------|----------|-------------| | `account_id` | string | Yes | Player account identifier | | `currency` | string | Yes | Currency code — standard (`"USD"`, `"EUR"`) or custom (`"CUSTOM_GOLD"`) | | `game_id` | string | Yes | Game identifier (slug) | | `session_id` | string | No | Session identifier (UUID) | ### Example ```json { "account_id": "player_123", "currency": "USD", "game_id": "slots", "session_id": "7b115688-3849-490a-95bd-7c281d81c64c" } ``` --- ## Response ### Success (200 OK) | Field | Type | Required | Description | |-------|------|----------|-------------| | `balance` | string | Yes | Current player balance as decimal string | ```json { "balance": "500.00" } ``` ### Error Responses | HTTP Status | Twirp Code | api_code | Description | |-------------|------------|----------|-------------| | 400 | `invalid_argument` | `101` | Player not found or disabled | | 400 | `invalid_argument` | `403` | Invalid or missing signature | | 500 | `internal` | `500` | Internal server error | ```json { "code": "invalid_argument", "msg": "Player not found", "meta": { "api_code": "101", "api_message": "Player not found" } } ``` --- ## curl Example ```bash curl -X POST https://casino.example.com/wallet/balance \ -H "Content-Type: application/json" \ -H "X-REQUEST-SIGN: abc123def456..." \ -d '{ "account_id": "player_123", "currency": "USD", "game_id": "slots" }' ``` --- ## Behavioral Rules - Return the **real-time balance** — do not cache - The `game_id` field provides game context for operators who maintain per-game balances - This request does **not** modify the player's balance - If the player does not exist, return api_code `101` --- # POST /betwin Source: https://docs.beexar.com/wallet-api/betwin/ Description: Process bet and win transactions atomically in a single request. import { Aside, Badge } from '@astrojs/starlight/components'; Beexar sends this request to debit and/or credit the player balance during gameplay. All transactions in the request must be processed **atomically** and in order. This single endpoint replaces separate bet and win calls — both transaction types are included in the `transactions` array. --- ## Request `POST {betwin_url}` ### Headers | Header | Value | |--------|-------| | `Content-Type` | `application/json` | | `X-REQUEST-SIGN` | HMAC-SHA256 signature of request body | ### Body | Field | Type | Required | Description | |-------|------|----------|-------------| | `account_id` | string | Yes | Player account identifier | | `currency` | string | Yes | Currency code — standard (`"USD"`, `"EUR"`, `"BTC"`) or custom (`"CUSTOM_GOLD"`) | | `game_id` | string | Yes | Game identifier (slug) | | `round_id` | string | Yes | Game round identifier (generated by Beexar) | | `finished` | boolean | No | If `true`, the round is complete — no `/finish` call will follow | | `transactions` | array | Yes | List of bet/win transactions (min 1) | | `session_id` | string | No | Session identifier (UUID). Always sent, but operators are not required to use it | ### Transaction Object Each item in the `transactions` array: | Field | Type | Required | Description | |-------|------|----------|-------------| | `id_provider` | string | Yes | Unique transaction identifier (generated by Beexar, used for idempotency) | | `type` | string | Yes | `"bet"` or `"win"` | | `amount` | string | Yes | Transaction amount as decimal string (must be > 0) | --- ## Examples ### Simple Round (Dice — bet + win, finished) A player bets 10 USD and wins 19.80 USD. The round is complete in one request: ```json { "account_id": "player_123", "currency": "USD", "game_id": "dice", "round_id": "550e8400-e29b-41d4-a716-446655440000", "finished": true, "transactions": [ { "id_provider": "tx_bet_001", "type": "bet", "amount": "10.00" }, { "id_provider": "tx_win_001", "type": "win", "amount": "19.80" } ], "session_id": "7b115688-3849-490a-95bd-7c281d81c64c" } ``` ### Bet Only (Slots — first spin) A player places a bet. The round continues (free spins or bonus may follow): ```json { "account_id": "player_123", "currency": "USD", "game_id": "slots", "round_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "finished": false, "transactions": [ { "id_provider": "tx_bet_002", "type": "bet", "amount": "5.00" } ] } ``` ### Win Only (Slots — free spin result) A win from a free spin within an ongoing round: ```json { "account_id": "player_123", "currency": "USD", "game_id": "slots", "round_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "finished": false, "transactions": [ { "id_provider": "tx_win_002", "type": "win", "amount": "15.00" } ] } ``` ### Losing Round (Plinko — bet only, finished) A player bets and loses. No win transaction: ```json { "account_id": "player_123", "currency": "EUR", "game_id": "plinko", "round_id": "deadbeef-cafe-1234-5678-abcdef012345", "finished": true, "transactions": [ { "id_provider": "tx_bet_003", "type": "bet", "amount": "2.50" } ] } ``` --- ## Response ### Success (200 OK) | Field | Type | Required | Description | |-------|------|----------|-------------| | `round_id` | string | Yes | Round identifier on operator side | | `balance` | string | Yes | Player balance after all transactions | | `transactions` | array | Yes | Results for each transaction (same order as request) | Each transaction result: | Field | Type | Required | Description | |-------|------|----------|-------------| | `id_provider` | string | Yes | Transaction identifier from request (echo back) | | `id` | string | Yes | Transaction identifier assigned by operator | ```json { "round_id": "697962ac-fd0d-4dc2-b52c-e850e40825dc", "balance": "509.80", "transactions": [ { "id_provider": "tx_bet_001", "id": "op_tx_101" }, { "id_provider": "tx_win_001", "id": "op_tx_102" } ] } ``` ### Error Responses Errors use the Twirp format with an `api_code` in the `meta` field: | HTTP Status | Twirp Code | api_code | Description | |-------------|------------|----------|-------------| | 400 | `invalid_argument` | `100` | Insufficient funds | | 400 | `invalid_argument` | `105` | Bet limit exceeded | | 400 | `invalid_argument` | `106` | Win limit exceeded | | 400 | `invalid_argument` | `155` | Action was already rolled back (tombstoned) | | 400 | `invalid_argument` | `403` | Invalid or missing signature | | 500 | `internal` | `500` | Internal server error | **Insufficient funds error:** ```json { "code": "invalid_argument", "msg": "Player has not enough funds to process an action.", "meta": { "api_code": "100", "api_message": "Player has not enough funds to process an action.", "balance": "5.00" } } ``` --- ## curl Example ```bash curl -X POST https://casino.example.com/wallet/betwin \ -H "Content-Type: application/json" \ -H "X-REQUEST-SIGN: abc123def456..." \ -d '{ "account_id": "player_123", "currency": "USD", "game_id": "dice", "round_id": "550e8400-e29b-41d4-a716-446655440000", "finished": true, "transactions": [ { "id_provider": "tx_bet_001", "type": "bet", "amount": "10.00" }, { "id_provider": "tx_win_001", "type": "win", "amount": "19.80" } ] }' ``` --- ## Behavioral Rules - **Atomicity**: All transactions in the request must be processed atomically — either all succeed or none are applied - **Order**: Transactions are processed in the order they appear in the array - **Idempotency**: If an `id_provider` has already been processed, return the **original response** — do NOT process the transaction again - **Tombstone check**: If an `id_provider` was already rolled back (tombstone exists), respond with HTTP 400 and api_code `155` - **Amounts**: Always positive, never zero - **`finished` flag**: When `true`, the round is complete. No `/finish` call will be sent. When `false` or absent, more BetWin requests may follow, and a `/finish` call will close the round - **Multiple requests per round**: In multi-step games (slots with free spins/bonus), a single `round_id` may span multiple BetWin requests with different `id_provider` values - **Win before bet**: In rare timing scenarios, a win request may arrive before the corresponding bet. The win **must** still be processed ## The `finished` Flag The `finished` flag optimizes the round lifecycle by eliminating the separate `/finish` call: ```mermaid flowchart LR Start(("●")) -- "BetWin finished=false" --> Active Active -- "BetWin finished=false" --> Active Active -- "BetWin finished=true" --> Done(("●")) Active -- "/finish" --> Done ``` - **Simple games** (dice, plinko): `finished: true` in the first (and only) BetWin request - **Crash**: `finished: true` in the final BetWin (cashout or loss) - **Slots**: `finished: false` during free spins, `finished: true` in the last action, or `/finish` sent separately ## Sequence Diagram ```mermaid sequenceDiagram participant Beexar participant Wallet as Operator Wallet Note over Beexar,Wallet: Player places bet (dice) Beexar->>Beexar: Calculate result Beexar->>Wallet: POST /betwin (bet + win, finished=true) alt Sufficient funds Wallet->>Wallet: Debit bet, credit win (atomic) Wallet-->>Beexar: 200 { balance, transactions } Note over Beexar: Show result to player else Insufficient funds Wallet-->>Beexar: 400 { api_code: "100", balance } Note over Beexar: Show error to player end ``` --- # POST /finish Source: https://docs.beexar.com/wallet-api/finish/ Description: Round completion signal. import { Aside, Badge } from '@astrojs/starlight/components'; Beexar sends this request to signal that a game round is complete. This is only sent when the last `/betwin` request did **not** set `finished: true`. --- ## Request `POST {finish_url}` ### Headers | Header | Value | |--------|-------| | `Content-Type` | `application/json` | | `X-REQUEST-SIGN` | HMAC-SHA256 signature of request body | ### Body | Field | Type | Required | Description | |-------|------|----------|-------------| | `account_id` | string | Yes | Player account identifier | | `currency` | string | Yes | Currency code — standard (`"USD"`, `"EUR"`) or custom (`"CUSTOM_GOLD"`) | | `round_id` | string | Yes | Game round identifier (Beexar's round_id) | | `session_id` | string | No | Session identifier (UUID) | ### Example ```json { "account_id": "player_123", "currency": "USD", "round_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "session_id": "7b115688-3849-490a-95bd-7c281d81c64c" } ``` --- ## Response ### Success (200 OK) | Field | Type | Required | Description | |-------|------|----------|-------------| | `balance` | string | Yes | Current player balance | ```json { "balance": "509.80" } ``` ### Error Responses | HTTP Status | Twirp Code | api_code | Description | |-------------|------------|----------|-------------| | 400 | `invalid_argument` | `400` | Invalid request | | 400 | `invalid_argument` | `403` | Invalid or missing signature | | 500 | `internal` | `500` | Internal server error | --- ## curl Example ```bash curl -X POST https://casino.example.com/wallet/finish \ -H "Content-Type: application/json" \ -H "X-REQUEST-SIGN: abc123def456..." \ -d '{ "account_id": "player_123", "currency": "USD", "round_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890" }' ``` --- ## Behavioral Rules - **Informational only**: The `/finish` request does NOT modify the player's balance. All financial operations have already been processed via `/betwin` and `/rollback` - **Only sent when needed**: If the last `/betwin` request included `finished: true`, Beexar does **not** send `/finish`. This means simple games (dice, plinko) typically do not trigger `/finish` at all - **Idempotency**: Handle duplicate `/finish` requests for the same `round_id` gracefully — return success both times - **Guaranteed delivery**: If your server returns an error or is unreachable, Beexar retries `/finish` asynchronously with exponential backoff - **Use for reconciliation**: Operators should use `/finish` as a signal to close the round in their bookkeeping system ## When Is `/finish` Sent? | Scenario | `/finish` sent? | |----------|----------------| | Dice/Plinko: single BetWin with `finished: true` | No | | Crash: final BetWin with `finished: true` | No | | Slots: multi-step round, last BetWin has `finished: true` | No | | Slots: multi-step round, no `finished` flag on last BetWin | **Yes** | | Session expired with open round | **Yes** | | Error recovery after rollback | **Yes** | --- # Wallet API Overview Source: https://docs.beexar.com/wallet-api/overview/ Description: Architecture, amount format, idempotency, and round lifecycle. import { Aside } from '@astrojs/starlight/components'; ## Architecture Beexar uses the **Seamless Wallet** pattern. Your operator server acts as the player's wallet — Beexar never holds funds. During gameplay, Beexar sends HTTP POST requests to your configured callback URLs. ```mermaid flowchart LR Player -->|plays| Beexar Beexar -->|"POST /balance"| Operator Beexar -->|"POST /betwin"| Operator Beexar -->|"POST /rollback"| Operator Beexar -->|"POST /finish"| Operator ``` All requests flow **from Beexar to the Operator**. The operator never calls these endpoints — they implement them. ### Callback URLs You configure 4 callback URLs in the Beexar backoffice for each operator: | Callback | Endpoint | Purpose | |----------|----------|---------| | `balance_url` | `POST /balance` | Return player's current balance | | `betwin_url` | `POST /betwin` | Debit (bet) and/or credit (win) — atomic | | `rollback_url` | `POST /rollback` | Reverse previous transactions | | `finish_url` | `POST /finish` | Round completion signal | --- ## Amount Format All `amount`, `balance`, `total_bet`, and `total_win` fields are transmitted as **string representations of decimal numbers**. | Example | Currency | Decimal value | |---------|----------|---------------| | `"10.50"` | USD | 10.50 USD | | `"0.01"` | USD | 0.01 USD | | `"100.00"` | EUR | 100.00 EUR | | `"1.12345678"` | BTC | 1.12345678 BTC | **Rules:** - Amounts are always positive (or zero for rollback) - Maximum 18 decimal places (supports crypto precision) - Pattern: `^\d+(\.\d{1,18})?$` - Currency codes: ISO 4217 (`USD`, `EUR`) or custom tokens (`CUSTOM_*` format, up to 32 chars) --- ## Request Signing Every request includes an `X-REQUEST-SIGN` header with an HMAC-SHA256 signature of the request body. See [Authentication](/getting-started/authentication/) for details and code samples. If the signature is invalid, respond with **HTTP 400** and api_code `403`: ```json { "code": "invalid_argument", "msg": "Invalid signature", "meta": { "api_code": "403", "api_message": "Invalid signature" } } ``` --- ## Error Response Format All error responses follow the Twirp format: ```json { "code": "invalid_argument", "msg": "Player has not enough funds to process an action.", "meta": { "api_code": "100", "api_message": "Player has not enough funds to process an action.", "balance": "50.00" } } ``` | Field | Type | Required | Description | |-------|------|----------|-------------| | `code` | string | Yes | Twirp error code: `"invalid_argument"` (HTTP 400) or `"internal"` (HTTP 500) | | `msg` | string | Yes | Human-readable error description | | `meta.api_code` | string | Yes | Numeric API error code (see [Error Handling](/guides/error-handling/)) | | `meta.api_message` | string | Yes | API error message | | `meta.balance` | string | Conditional | Current balance — required when api_code is `100`, `105`, or `106` | --- ## Idempotency Every bet, win, and rollback transaction includes a unique `id_provider`. Your wallet **must** handle idempotency: - If an `id_provider` has already been processed, return the **original response** (same balance, same transaction IDs) - Do **NOT** process the transaction again (no double-debit, no double-credit) - This applies to all transaction types: bet, win, and rollback --- ## Round Lifecycle A **round** is a complete game cycle identified by `round_id`. Every round follows this lifecycle: ```mermaid flowchart LR Start(("●")) -- "First /betwin" --> Active Active -- "/betwin" --> Active Active -- "/rollback" --> Active Active -- "/betwin finished=true" --> Finished(("●")) Active -- "/finish" --> Finished ``` ### Single-Step Rounds (Dice, Plinko, Crash) ``` /betwin (bet + win, finished=true) ``` One request with bet and win transactions. The `finished: true` flag closes the round — no separate `/finish` call needed. ### Multi-Step Rounds (Slots with Bonus/Free Spins) ``` /betwin (bet) → /betwin (win) → /betwin (win) → ... → /betwin (win, finished=true) ``` Multiple BetWin requests within a single `round_id`. The last request sets `finished: true`, or a separate `/finish` closes the round. ### Rules 1. **All rounds must be finished** — every round that starts with a bet will eventually be closed (via `finished: true` or `/finish`) 2. **Transactions share the same `round_id`** — use this to group them 3. **Each transaction has a unique `id_provider`** — use this for idempotency 4. **Rollbacks can happen mid-round** — e.g., in slots, a bonus timeout triggers a rollback of pending actions 5. **The `finished` flag eliminates the `/finish` call** — for simple games, the round is complete in a single BetWin request --- ## Full Integration Flow ```mermaid sequenceDiagram participant Operator participant Beexar participant Game as Game Frontend participant Wallet as Operator Wallet Note over Operator,Wallet: 1. Session Creation Operator->>Beexar: POST /api/v1/softswiss/launcher/real Beexar-->>Operator: { launch_url } Note over Operator,Wallet: 2. Game Load Operator->>Game: Embed launch_url in iframe Game->>Beexar: Load game with token Beexar->>Wallet: POST /balance Wallet-->>Beexar: { balance: "500.00" } Beexar-->>Game: Show game UI Note over Operator,Wallet: 3. Gameplay (dice example) Game->>Beexar: Player bets 10 USD Beexar->>Wallet: POST /betwin (bet=10, win=19.80, finished=true) Wallet-->>Beexar: { balance: "509.80", transactions } Beexar-->>Game: Show result Note over Operator,Wallet: 4. Error Recovery Game->>Beexar: Player bets 5 USD Beexar->>Wallet: POST /betwin (bet=5) Wallet-->>Beexar: 200 OK Note right of Beexar: Game engine error Beexar->>Wallet: POST /rollback (original bet) Wallet-->>Beexar: { balance: "509.80" } ``` --- # POST /rollback Source: https://docs.beexar.com/wallet-api/rollback/ Description: Reverse previously processed transactions. import { Aside, Badge } from '@astrojs/starlight/components'; Beexar sends this request to reverse previously processed transactions (bets or wins). The operator must undo the financial effect of each original transaction. --- ## Request `POST {rollback_url}` ### Headers | Header | Value | |--------|-------| | `Content-Type` | `application/json` | | `X-REQUEST-SIGN` | HMAC-SHA256 signature of request body | ### Body | Field | Type | Required | Description | |-------|------|----------|-------------| | `account_id` | string | Yes | Player account identifier | | `currency` | string | Yes | Currency code — standard (`"USD"`, `"EUR"`) or custom (`"CUSTOM_GOLD"`) | | `game_id` | string | Yes | Game identifier (slug) | | `round_id_provider` | string | Yes | Game round identifier (Beexar's round_id) | | `finished` | boolean | Yes | Whether the game round is finished after this rollback | | `transactions` | array | Yes | List of rollback transactions (min 1) | | `session_id` | string | No | Session identifier (UUID) | ### Transaction Object Each item in the `transactions` array: | Field | Type | Required | Description | |-------|------|----------|-------------| | `id_provider` | string | Yes | Unique rollback transaction identifier (generated by Beexar) | | `type` | string | Yes | Always `"rollback"` | | `original_id_provider` | string | Yes | `id_provider` of the original transaction to reverse | ### Example ```json { "account_id": "player_123", "currency": "USD", "game_id": "slots", "round_id_provider": "550e8400-e29b-41d4-a716-446655440000", "finished": true, "transactions": [ { "id_provider": "tx_rb_001", "type": "rollback", "original_id_provider": "tx_bet_001" } ], "session_id": "7b115688-3849-490a-95bd-7c281d81c64c" } ``` --- ## Response ### Success (200 OK) | Field | Type | Required | Description | |-------|------|----------|-------------| | `balance` | string | Yes | Player balance after rollback | | `round_id` | string | Yes | Round identifier on operator side | | `transactions` | array | Yes | Results for each rollback transaction | Each transaction result: | Field | Type | Required | Description | |-------|------|----------|-------------| | `id_provider` | string | Yes | Rollback transaction identifier from request (echo back) | | `id` | string | Yes | Transaction identifier assigned by operator (may be empty if original was not found) | ```json { "balance": "500.00", "round_id": "697962ac-fd0d-4dc2-b52c-e850e40825dc", "transactions": [ { "id_provider": "tx_rb_001", "id": "op_tx_201" } ] } ``` ### Error Responses | HTTP Status | Twirp Code | api_code | Description | |-------------|------------|----------|-------------| | 400 | `invalid_argument` | `403` | Invalid or missing signature | | 500 | `internal` | `500` | Internal server error | --- ## curl Example ```bash curl -X POST https://casino.example.com/wallet/rollback \ -H "Content-Type: application/json" \ -H "X-REQUEST-SIGN: abc123def456..." \ -d '{ "account_id": "player_123", "currency": "USD", "game_id": "slots", "round_id_provider": "550e8400-e29b-41d4-a716-446655440000", "finished": true, "transactions": [ { "id_provider": "tx_rb_001", "type": "rollback", "original_id_provider": "tx_bet_001" } ] }' ``` --- ## Behavioral Rules These rules are critical for correct rollback implementation: 1. **If the original transaction exists** — reverse it and return the updated balance - Rollback of a **bet** → credit the bet amount back to the player - Rollback of a **win** → debit the win amount from the player 2. **If the original transaction does NOT exist** — create a **tombstone** and return a valid response (NOT an error) - The tombstone prevents the original transaction from being processed if it arrives later - This handles the case where rollback arrives before the original transaction due to network timing 3. **Tombstone prevents late processing** — if a BetWin arrives and a tombstone exists for that `id_provider`, the transaction must be rejected (api_code `155`) 4. **Process rollback even if player has insufficient funds** — if rolling back a win would make the balance negative, still process it 5. **Duplicate rollback** — if the same `id_provider` is received again, return the original response, do NOT reverse the transaction again 6. **Idempotency applies to `id_provider`** (the rollback's own ID), not `original_id_provider` --- ## When Does Beexar Send Rollback? | Trigger | Description | |---------|-------------| | **Game error** | An error occurred in the game engine after the bet was confirmed but before the result was determined | | **Bonus/Free-Spins timeout** | In multi-step games (slots), if the player does not complete a bonus or free-spins session within the timeout period | | **Crash game win failure** | If the win wallet call fails during cashout, the win is rolled back asynchronously | | **Stale bets** | If a bet is stuck in a transitional state for too long, the system rolls it back automatically | --- ## Sequence Diagram ```mermaid sequenceDiagram participant Beexar participant Wallet as Operator Wallet Note over Beexar,Wallet: Scenario 1: Normal rollback Beexar->>Wallet: POST /betwin (bet tx_bet_1) Wallet-->>Beexar: 200 OK Beexar->>Wallet: POST /rollback (original: tx_bet_1) Wallet->>Wallet: Reverse bet, credit player Wallet-->>Beexar: 200 { balance } Note over Beexar,Wallet: Scenario 2: Tombstone (rollback before bet) Beexar->>Wallet: POST /rollback (original: tx_bet_2) Wallet->>Wallet: tx_bet_2 not found, create tombstone Wallet-->>Beexar: 200 { balance } Note right of Wallet: Later, if tx_bet_2 arrives... Beexar->>Wallet: POST /betwin (bet tx_bet_2) Wallet->>Wallet: Tombstone exists, reject Wallet-->>Beexar: 400 { api_code: "155" } ```