> ## 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.

# Debit

> Take the stakes of one or more bets, or one Blackjack extra stake, from the player's balance in one atomic change.

Apply the whole `amount` or nothing. A `declined` debit stays declined under its ID, even if funds arrive later. See [Debits](https://docs.kinematic.run/integrate/wallet.md#debits) for the rules your implementation keeps.


## OpenAPI

````yaml api/wallet.openapi.yaml POST /debit
openapi: 3.1.0
info:
  title: Wallet API
  version: '1.0'
  summary: The three endpoints your wallet implements for your kinematic game server.
  description: >
    In live mode your game server calls your wallet to debit stakes, credit
    payouts and read balances. You implement these endpoints under the wallet
    URL you set in the dashboard's Settings; the game server appends `debit`,
    `credit` or `balance` to it.


    Every call is a `POST` with a JSON body, signed with your `WALLET_SECRET`.
    Every ID is idempotent: the game server retries a call with the same ID and
    the same body until it gets a valid receipt. Amounts, balances and revisions
    are integer strings in the currency's minor units.
  contact:
    name: kinematic
    email: hello@kinematic.run
servers:
  - url: https://wallet.luckystar.example/kinematic
    description: Your wallet URL from Settings. It must use https.
security: []
tags:
  - name: Wallet
    description: Endpoints your wallet answers. Your game server is the caller.
paths:
  /debit:
    post:
      tags:
        - Wallet
      summary: Debit stakes
      description: >
        Takes the stakes of one or more bets from the player's balance in one
        atomic change.


        Apply the whole `amount` and answer `status: "applied"`, or apply
        nothing and answer `status: "declined"` when the player cannot cover it.
        Record the decision durably under the ID: a declined ID stays declined
        if funds arrive later, and an applied ID is never applied twice. Never
        debit part of a batch.


        Record which rounds each applied debit named. If your wallet checks
        credits, it pays only rounds it debited.


        A Blackjack double, split or insurance is a separate debit with an ID
        that starts with `stake_`: its `rounds` holds the round's bet ID and
        `amount` is the extra stake.
      operationId: debit
      parameters:
        - $ref: '#/components/parameters/IdempotencyKey'
        - $ref: '#/components/parameters/Timestamp'
        - $ref: '#/components/parameters/Signature'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/DebitRequest'
            examples:
              batch:
                summary: Two bets debited together
                value:
                  id: batch_3a787ce18225e69054f0bfbe34e909d7
                  player: player_48213
                  currency: USD
                  amount: '7500'
                  kind: debit
                  rounds:
                    - 1eff8f3759107f88d5d63eaf980a9459
                    - d5963bfae4ad9081315e9159548f8541
              stake:
                summary: A Blackjack double
                value:
                  id: stake_e5adbf27e5ff4e5283b9dc871388a32d
                  player: player_48213
                  currency: USD
                  amount: '2500'
                  kind: debit
                  rounds:
                    - 8d10611c88a4f04ae84cc76caa182257
      responses:
        '200':
          description: The debit is applied, or durably declined.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Receipt'
              examples:
                applied:
                  summary: Applied
                  value:
                    id: batch_3a787ce18225e69054f0bfbe34e909d7
                    status: applied
                    balance: '92500'
                    revision: '41'
                    currency: USD
                declined:
                  summary: Declined for funds
                  value:
                    id: batch_3a787ce18225e69054f0bfbe34e909d7
                    status: declined
                    balance: '4200'
                    revision: '40'
                    currency: USD
        default:
          $ref: '#/components/responses/Ambiguous'
components:
  parameters:
    IdempotencyKey:
      name: Idempotency-Key
      in: header
      required: true
      description: Equals the body's `id`.
      schema:
        type: string
        examples:
          - batch_3a787ce18225e69054f0bfbe34e909d7
    Timestamp:
      name: X-Kinematic-Timestamp
      in: header
      required: true
      description: >
        When the game server signed this attempt, in Unix milliseconds. Refuse a
        call whose timestamp is more than 60 seconds from your clock. A retry
        carries a fresh timestamp.
      schema:
        type: string
        pattern: ^[0-9]{13}$
        examples:
          - '1793629805120'
    Signature:
      name: X-Kinematic-Signature
      in: header
      required: true
      description: >
        Lowercase hex HMAC-SHA256, keyed with your `WALLET_SECRET`, over the
        exact UTF-8 bytes of `timestamp + "." + body`. Compare it in constant
        time before you parse the body, and refuse the call with a status other
        than 200 when it does not match.
      schema:
        type: string
        pattern: ^[0-9a-f]{64}$
        examples:
          - 0315897c76ddcf819b7603a809501ff9ef1dd518187448e6d41597b6d4b7a021
  schemas:
    DebitRequest:
      type: object
      required:
        - id
        - player
        - currency
        - amount
        - kind
        - rounds
      properties:
        id:
          type: string
          description: >-
            The idempotency ID. `batch_` for bets, `stake_` for a Blackjack
            double, split or insurance.
          pattern: ^(batch|stake)_[0-9a-f]{32}$
        player:
          $ref: '#/components/schemas/PlayerId'
        currency:
          $ref: '#/components/schemas/Currency'
        amount:
          $ref: '#/components/schemas/MinorUnits'
        kind:
          type: string
          const: debit
        rounds:
          type: array
          description: >-
            The bets this debit pays for. Their stakes add up to `amount`. A
            batch holds up to 1,000 bets.
          minItems: 1
          items:
            $ref: '#/components/schemas/BetId'
    Receipt:
      type: object
      required:
        - id
        - status
        - balance
        - revision
        - currency
      properties:
        id:
          type: string
          description: The request's `id`.
        status:
          type: string
          enum:
            - applied
            - declined
          description: >-
            `declined` only for a debit the player cannot cover. Credits and
            balance reads are always `applied`.
        balance:
          $ref: '#/components/schemas/MinorUnits'
          description: The player's balance after this operation, in minor units.
        revision:
          $ref: '#/components/schemas/MinorUnits'
          description: >
            Your wallet-wide revision after this operation. It increases with
            every change to the account, including changes outside kinematic.
            Two different balances never share a revision.
        currency:
          $ref: '#/components/schemas/Currency'
          description: The request's `currency`.
    PlayerId:
      type: string
      description: Your stable player ID, the `sub` of the session token.
      pattern: ^[A-Za-z0-9_-]{1,128}$
      examples:
        - player_48213
    Currency:
      type: string
      description: The currency code. Each currency is a separate account of the player.
      pattern: ^[A-Z0-9]{2,12}$
      examples:
        - USD
    MinorUnits:
      type: string
      description: >-
        A canonical non-negative integer string in the currency's minor units.
        No decimals, signs or leading zeros.
      pattern: ^(0|[1-9][0-9]{0,18})$
      examples:
        - '9900'
    BetId:
      type: string
      description: >-
        A bet ID, chosen by the player's browser. The element uses 32 lowercase
        hex characters.
      pattern: ^[A-Za-z0-9_-]{16,80}$
      examples:
        - 1eff8f3759107f88d5d63eaf980a9459
  responses:
    Ambiguous:
      description: >
        Any status other than 200, a timeout after 8 seconds, a redirect, a body
        that is not a JSON object of at most 16 KiB, or a receipt whose `id`,
        `currency` or amounts do not match: the game server cannot tell whether
        the call applied. It keeps the job and sends the same ID and body again
        after 1, 2, 4 and up to 30 seconds. It never treats such an answer as a
        declined debit.

````

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