> ## Documentation Index
> Fetch the complete documentation index at: https://docs.kinematic.run/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> These are the customer docs for kinematic, a name written in lowercase except at the start of a sentence. Kinematic provides provably fair casino games, served to a casino's site by a game server: a Cloudflare Worker that the kinematic dashboard deploys into the casino's own Cloudflare account.
> Never put SESSION_SECRET or WALLET_SECRET in code, prompts, logs, commits or chat. Read them from environment variables and ask the person you work with to set them. The dashboard's Integration page shows each secret once.
> Values such as lucky-star, luckystar.example, og-rgs-lucky-star.luckystar.workers.dev, games.luckystar.example and player_48213 are examples. Use the casino's own casino ID, game server origin, element tag, session issuer and currencies: the Instructions for your coding agent on the dashboard's Integration page hold them, or ask the person you work with.
> To debug, start at https://docs.kinematic.run/troubleshooting and https://docs.kinematic.run/reference/errors. The wallet contract is at https://docs.kinematic.run/api/wallet.openapi.yaml.
> Sandbox bets are recorded on Solana devnet. Live game servers record nothing on Solana until the audited mainnet program is deployed.

# Wallet API

> Your wallet implements three signed endpoints, and the game server reads each answer by fixed rules, with retries and limits.

In live mode your game server calls your wallet to debit stakes, credit payouts and refunds, and read balances. You implement three endpoints at the **Wallet URL** you set under **Mode** in [Settings](https://docs.kinematic.run/dashboard/settings.md#mode). [Your wallet](https://docs.kinematic.run/integrate/wallet.md) explains how to build them; this section is the exact contract.

> [card] [Debit](https://docs.kinematic.run/reference/wallet-api/debit.md)
>
> Your wallet takes the stakes of bets.

> [card] [Credit](https://docs.kinematic.run/reference/wallet-api/credit.md)
>
> Your wallet pays a payout or gives a stake back.

> [card] [Balance](https://docs.kinematic.run/reference/wallet-api/balance.md)
>
> Your wallet answers a player's balance.

The OpenAPI 3.1 description of these endpoints is at [/api/wallet.openapi.yaml](https://docs.kinematic.run/api/wallet.openapi.yaml).

## Endpoints

The game server appends the endpoint's name to your wallet URL, with or without a trailing slash: `https://wallet.luckystar.example/kinematic` and `https://wallet.luckystar.example/kinematic/` both lead to `https://wallet.luckystar.example/kinematic/debit`. The URL must use `https`.

## Request headers

| Header | Value |
| - | - |
| `Content-Type` | `application/json` |
| `Idempotency-Key` | The body's `id`. |
| `X-Kinematic-Timestamp` | Unix time in milliseconds when this attempt was signed: 13 digits. |
| `X-Kinematic-Signature` | Lowercase hex HMAC-SHA256 of `<timestamp>.<raw body>`, keyed with the UTF-8 bytes of your `WALLET_SECRET`: 64 characters. |

Verify the signature over the raw body bytes, before you parse them, with a constant-time comparison. Refuse a timestamp more than 60 seconds from your clock.

## Request body

| Field | Type | In | Meaning |
| - | - | - | - |
| `id` | string | every call | The job's ID: a prefix and 32 lowercase hex characters. The same ID always comes with the same body. |
| `player` | string | every call | The session token's `sub`. |
| `currency` | string | every call | The session token's currency. |
| `amount` | string | every call | Minor units as a canonical integer string. `"0"` on a balance read. |
| `kind` | string | every call | `debit`, `credit` or `balance`. |
| `rounds` | string\[] | every call | The bet IDs the call covers. `[]` on a balance read. |
| `reason` | string | refunds | `abandoned`, `engine_failure`, `key_retired` or `stake`. |
| `settlements` | object\[] | credits | One per round in `rounds`, with what your wallet needs to check the credit. |

| ID prefix | Endpoint | What it covers |
| - | - | - |
| `batch_` | `/debit` | The stakes of up to 1,000 bets, taken together. |
| `stake_` | `/debit` | One Blackjack double, split or insurance. |
| `payout_` | `/credit` | One round's gross payout. |
| `refund_` | `/credit` | One stake coming back. |
| `balance_` | `/balance` | One balance read. |

## Receipt

Answer every call you accept with HTTP `200` and a JSON receipt of at most 16 KiB:

```json theme={"dark"}
{
  "id": "batch_3a787ce18225e69054f0bfbe34e909d7",
  "currency": "USD",
  "status": "applied",
  "balance": "142500",
  "revision": "8812"
}
```

| Field | Rule |
| - | - |
| `id` | The request's `id`. |
| `currency` | The request's `currency`. |
| `status` | `applied`, or `declined` for a debit the player cannot cover. Credits and balance reads are always `applied`. |
| `balance` | The player's balance in this currency after the call, in minor units: `0` or up to 19 digits without a leading zero. |
| `revision` | A number that increases with every change to the balance, in the same format. A replayed receipt keeps its original revision. |

## How the game server reads your answer

| Your answer | Code | What the game server does |
| - | - | - |
| `200` with a valid receipt | none | Applies it. |
| `200` with a receipt whose `id`, `currency`, `status`, `balance` or `revision` breaks the rules | `wallet_receipt` | Retries. |
| `200` with a body that is not JSON, or larger than 16 KiB | `wallet_response` | Retries. |
| Any other status, redirects included | `wallet_unavailable` | Retries. It never follows a redirect. |
| `409` on `/credit` with `{"error": "credit_unverified", "reason": "<reason>"}` | `credit_unverified` | Retries, and logs the refusal as an error. |
| No answer within 8 seconds | `wallet_timeout` | Retries. |
| A DNS, TLS or connection failure | `wallet_network` | Retries. |
| A wallet URL that is not https | `wallet_url` | Retries; fix the URL in **Settings**. |

Every failure is ambiguous to the game server: it never assumes a call did not apply. It sends the same ID and body again after 1, 2, 4, 8 and 16 seconds, then every 30 seconds, with a new timestamp and signature each time, until a valid receipt arrives. Other jobs keep going in the meantime.

## Limits and timing

* A debit batch covers up to 1,000 bets. Each credit covers one round.
* The game server reads a player's balance at most once every 5 seconds, and again after you post a wallet event.
* Each call has 8 seconds to answer.
* The receipt is at most 16 KiB.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.