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

# Credit

> Pay one round's gross payout, or give one stake back, and answer the receipt.

A credit can never be declined. Answer `200` with an applied receipt, or `409` with `credit_unverified` when your own check refuses it. See [Credits](https://docs.kinematic.run/integrate/wallet.md#credits).


## OpenAPI

````yaml api/wallet.openapi.yaml POST /credit
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:
  /credit:
    post:
      tags:
        - Wallet
      summary: Credit a payout or a refund
      description: >
        Adds a round's gross payout, or a refunded stake, to the player's
        balance.


        A payout is gross: it includes the returned stake, because the debit
        took the whole stake. A losing round has no credit. Payouts have IDs
        that start with `payout_`; refunds start with `refund_` and carry
        `refund` instead of `vrf` and `steps`.


        Never decline a credit for funds: answer `status: "applied"`. A wallet
        that checks credits refuses one that fails the check with HTTP 409 and
        the body in `CreditRefusal`; the game server keeps the credit and
        retries it.
      operationId: credit
      parameters:
        - $ref: '#/components/parameters/IdempotencyKey'
        - $ref: '#/components/parameters/Timestamp'
        - $ref: '#/components/parameters/Signature'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreditRequest'
            examples:
              payout:
                summary: A Dice win
                value:
                  id: payout_091aaed882b1fb6a076c877ff78bb307
                  player: player_48213
                  currency: USD
                  amount: '9900'
                  kind: credit
                  rounds:
                    - 1eff8f3759107f88d5d63eaf980a9459
                  settlements:
                    - round: 1eff8f3759107f88d5d63eaf980a9459
                      amount: '9900'
                      bet:
                        type: bet
                        id: 1eff8f3759107f88d5d63eaf980a9459
                        wager:
                          stake: '5000'
                          bet:
                            game: dice
                            target: 5000
                            over: true
                        seedHash: >-
                          e28489e5d5c71d154a9def37a5369339f566e62267ac3222f28c0fc35ac7c0c8
                        authorization:
                          payload:
                            format: og.proof.v3
                            kind: authorization
                            wallet: '["lucky-star","player_48213","USD"]'
                            math: >-
                              dbc64afcb07c0d1c029c9cea07118f495f5a6e350a090ddf4ae6f804079ae132
                            command:
                              type: bet
                              id: 1eff8f3759107f88d5d63eaf980a9459
                              wager:
                                stake: '5000'
                                bet:
                                  game: dice
                                  target: 5000
                                  over: true
                              seedHash: >-
                                e28489e5d5c71d154a9def37a5369339f566e62267ac3222f28c0fc35ac7c0c8
                          publicKey: XfuCuSvxdGBmTC2mYSZ8WLJ0PiuBOD1_k3hs4YK02v0
                          signature: >-
                            2_1mtd2ESweqUBgTojF56idR7mGnU-CA6mSSu--xrt9SV9qskbyyM8bQ1cSKfH-6Xwyp9rrR7iG6YYbG5YhRzA
                      vrf:
                        keyId: 62516d82119a9f4eb688da80f3f41548
                        seed: >-
                          e9ca18e3c557e52e3e6b2feb062e7ab68a8a822114c4de4eabeb0ee1db79214c
                        proof: >-
                          20864c99b79c5037ce8be2768b475757253c431f46d8165b73ed189c4831adec
                        output: >-
                          bafc2f548ebacb0be2767181ac9824cd917b5c3f387c1edaf1ecb4bd8082fa4c
                      steps: []
              refund:
                summary: An abandoned bet's stake
                value:
                  id: refund_4abf140d6ee9b6948e9da913bc3932b7
                  player: player_48213
                  currency: USD
                  amount: '2500'
                  kind: credit
                  rounds:
                    - d5963bfae4ad9081315e9159548f8541
                  settlements:
                    - round: d5963bfae4ad9081315e9159548f8541
                      amount: '2500'
                      bet:
                        type: bet
                        id: d5963bfae4ad9081315e9159548f8541
                        wager:
                          stake: '2500'
                          bet:
                            game: limbo
                            target: 200
                        seedHash: >-
                          cd7b667a7a5cec7400ae8adea855fc51118094b318aeecd5606781309f0dba1d
                        authorization:
                          payload:
                            format: og.proof.v3
                            kind: authorization
                            wallet: '["lucky-star","player_48213","USD"]'
                            math: >-
                              dbc64afcb07c0d1c029c9cea07118f495f5a6e350a090ddf4ae6f804079ae132
                            command:
                              type: bet
                              id: d5963bfae4ad9081315e9159548f8541
                              wager:
                                stake: '2500'
                                bet:
                                  game: limbo
                                  target: 200
                              seedHash: >-
                                cd7b667a7a5cec7400ae8adea855fc51118094b318aeecd5606781309f0dba1d
                          publicKey: XfuCuSvxdGBmTC2mYSZ8WLJ0PiuBOD1_k3hs4YK02v0
                          signature: >-
                            8Tw68L2xjvnKWEkqLIDMO3crynANbyfBdZD3zVfkab0Di30dmp3yKMNQqybZUlmfA0-miUuyOlaXw1adSc0Y3A
                      refund: abandoned
      responses:
        '200':
          description: The credit is applied. Credits are never declined.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Receipt'
              example:
                id: payout_091aaed882b1fb6a076c877ff78bb307
                status: applied
                balance: '102400'
                revision: '42'
                currency: USD
        '409':
          description: >
            Only for wallets that check credits: the credit failed the check,
            and nothing changed. The game server keeps the credit under the same
            ID and body and retries it, and the round stays owed until your
            wallet and the game server agree.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CreditRefusal'
              example:
                error: credit_unverified
                reason: proof
        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:
    CreditRequest:
      type: object
      required:
        - id
        - player
        - currency
        - amount
        - kind
        - rounds
        - settlements
      properties:
        id:
          type: string
          description: The idempotency ID. `payout_` for a payout, `refund_` for a refund.
          pattern: ^(payout|refund)_[0-9a-f]{32}$
        player:
          $ref: '#/components/schemas/PlayerId'
        currency:
          $ref: '#/components/schemas/Currency'
        amount:
          $ref: '#/components/schemas/MinorUnits'
        kind:
          type: string
          const: credit
        rounds:
          type: array
          description: The rounds this credit settles. Each credit pays one round today.
          minItems: 1
          items:
            $ref: '#/components/schemas/BetId'
        settlements:
          type: array
          description: >-
            One settlement per round of `rounds`, in the same order. Their
            amounts add up to `amount`.
          minItems: 1
          items:
            $ref: '#/components/schemas/Settlement'
    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`.
    CreditRefusal:
      type: object
      required:
        - error
        - reason
      properties:
        error:
          type: string
          const: credit_unverified
        reason:
          type: string
          description: The first check that failed.
          enum:
            - malformed
            - amount
            - authorization
            - wallet
            - no_debit
            - duplicate
            - refund
            - key
            - seed
            - proof
            - manifest
            - engine
            - outcome
    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
    Settlement:
      type: object
      required:
        - round
        - amount
        - bet
      properties:
        round:
          $ref: '#/components/schemas/BetId'
        amount:
          $ref: '#/components/schemas/MinorUnits'
          description: What the round pays, gross.
        bet:
          $ref: '#/components/schemas/SignedBet'
        vrf:
          $ref: '#/components/schemas/VrfProof'
        steps:
          type: array
          description: >-
            A payout's round steps (the player's actions and Crash's server
            ticks). Empty for instant games.
          items:
            $ref: '#/components/schemas/Step'
        manifest:
          type: object
          additionalProperties: true
          description: >-
            A payout of a bet at a return to player other than 99%, the payload
            of the signed math manifest the bet was placed under. Its SHA-256 is
            the `math` the player's authorization signs, and
            `catalog.formula_edge_bps` is the round's house edge. Absent at 99%.
        refund:
          type: string
          enum:
            - abandoned
            - engine_failure
            - key_retired
            - stake
          description: >
            A refund instead of a payout. `abandoned`: the bet was accepted and
            its seed never arrived within 24 hours. `engine_failure`: the engine
            could not evaluate the revealed round. `key_retired`: the debit
            applied only after the VRF key the bet's manifest names had retired,
            so the bet was never accepted. `stake`: a staked action the engine
            could not apply.
        action:
          $ref: '#/components/schemas/SignedAction'
    SignedBet:
      type: object
      description: The player's signed bet command, exactly as the game server accepted it.
      required:
        - type
        - id
        - wager
        - seedHash
        - authorization
      properties:
        type:
          type: string
          const: bet
        id:
          $ref: '#/components/schemas/BetId'
        wager:
          $ref: '#/components/schemas/Wager'
        seedHash:
          type: string
          description: >-
            Lowercase hex SHA-256 of the domain `og.seedhash.v1` and the bet's
            32-byte seed.
          pattern: ^[0-9a-f]{64}$
        authorization:
          $ref: '#/components/schemas/Authorization'
    VrfProof:
      type: object
      description: A payout's proof under the VRF key the acceptance named.
      required:
        - keyId
        - seed
        - proof
        - output
      properties:
        keyId:
          type: string
          description: The VRF key's ID, 32 lowercase hex characters.
          pattern: ^[0-9a-f]{32}$
        seed:
          type: string
          description: The seed the player's browser revealed, 64 lowercase hex characters.
          pattern: ^[0-9a-f]{64}$
        proof:
          type: string
          description: >-
            The VRF proof, a compressed BN254 G1 point of 32 bytes as 64
            lowercase hex characters.
          pattern: ^[0-9a-f]{64}$
        output:
          type: string
          description: >-
            SHA-256 of `og.vrf.v1/out` and the proof, 64 lowercase hex
            characters.
          pattern: ^[0-9a-f]{64}$
    Step:
      type: object
      required:
        - action
        - elapsed
      properties:
        action:
          type: object
          description: >-
            The player's action, such as `{"kind":"reveal","index":7}`, or
            Crash's `{"kind":"tick"}`.
          additionalProperties: true
        elapsed:
          type: integer
          description: Milliseconds since the round started, on the game server's clock.
    SignedAction:
      type: object
      description: The player's signed action whose `stake` a `stake` refund returns.
      required:
        - type
        - id
        - roundId
        - action
        - authorization
      properties:
        type:
          type: string
          const: action
        id:
          type: string
        roundId:
          $ref: '#/components/schemas/BetId'
        action:
          type: object
          description: The action, for example `{"kind":"double","hand":0,"stake":"2500"}`.
          additionalProperties: true
        steps:
          type: integer
        authorization:
          $ref: '#/components/schemas/Authorization'
    Wager:
      type: object
      required:
        - stake
        - bet
      properties:
        stake:
          $ref: '#/components/schemas/MinorUnits'
        bet:
          type: object
          description: >-
            The game and its settings, for example
            `{"game":"dice","target":5000,"over":true}`.
          required:
            - game
          additionalProperties: true
          properties:
            game:
              type: string
              enum:
                - mines
                - plinko
                - dice
                - limbo
                - crash
                - roulette
                - keno
                - baccarat
                - wheel
                - pump
                - diamonds
                - hilo
                - blackjack
    Authorization:
      type: object
      description: >-
        The player's Ed25519 signature over the command, under the device key
        the session allowed.
      required:
        - payload
        - publicKey
        - signature
      properties:
        payload:
          type: object
          description: >
            `{format: "og.proof.v3", kind: "authorization", wallet, math,
            command}`. `wallet` is the JSON text of `[casino ID, player,
            currency]`; `math` is the SHA-256 of the signed game math manifest.
          additionalProperties: true
        publicKey:
          type: string
          description: >-
            The player's raw Ed25519 public key, unpadded base64url (43
            characters).
        signature:
          type: string
          description: The Ed25519 signature, unpadded base64url (86 characters).
  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.