openapi: 3.0.3
info:
  title: Nakamoto's Dice public API
  version: "1.0"
  description: |
    Provably-fair Lightning coin-flip and dice. No signup, no auth.
    Agents and humans use the same endpoints. Identity is a self-generated
    UUID (`session_id`) which the server hashes (SHA-256 + salt) before
    storing — your raw UUID never leaves your client.

    See https://nakamotosdice.com/for-bots for examples and an MCP server.
  contact:
    name: Nakamoto's Dice
    url: https://nakamotosdice.com
servers:
  - url: https://nakamotosdice.com/api
paths:
  /games:
    get:
      summary: List games
      parameters:
        - name: type
          in: query
          required: true
          schema: { type: string, enum: [coin_flip, dice] }
        - name: status
          in: query
          schema: { type: string, enum: [waiting, complete, cancelled], default: waiting }
        - name: stake_tier
          in: query
          schema: { type: integer, enum: [500, 1000, 5000, 10000, 50000] }
      responses:
        '200':
          description: List of games
    post:
      summary: Create a new game
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [game_type, stake_tier, position]
              properties:
                game_type: { type: string, enum: [coin_flip, dice] }
                stake_tier: { type: integer, enum: [500, 1000, 5000, 10000, 50000] }
                position:
                  type: string
                  description: "coin_flip: 'heads' or 'tails'. dice: '1'..'6'."
                session_id:
                  type: string
                  description: Stable UUID. Required to receive winnings.
                client_seed:
                  type: string
                  description: 32+ hex chars random. Required for provably-fair.
      responses:
        '200': { description: Game created — returns bolt11 stake invoice. }
  /games/{id}:
    get:
      summary: Get a game's state
      parameters:
        - name: id
          in: path
          required: true
          schema: { type: string }
      responses:
        '200': { description: Full game state including players. }
  /games/{id}/join:
    post:
      summary: Take an open position on an existing game
      parameters:
        - name: id
          in: path
          required: true
          schema: { type: string }
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [position]
              properties:
                position: { type: string }
                session_id: { type: string }
                client_seed: { type: string }
      responses:
        '200': { description: Joined — returns bolt11 stake invoice. }
        '409': { description: Position already taken. }
  /games/{id}/verify:
    get:
      summary: Provably-fair verification material
      parameters:
        - name: id
          in: path
          required: true
          schema: { type: string }
      responses:
        '200':
          description: |
            Returns server_seed_hash (committed at creation), server_seed (revealed),
            client_seeds, and result. Verify HMAC_SHA256(server_seed,
            "client_seed_1:client_seed_2:...") yourself.
  /winnings:
    get:
      summary: Read winnings balance for a session
      parameters:
        - name: session_id
          in: query
          required: true
          schema: { type: string }
      responses:
        '200':
          description: |
            Returns earned_sats, available_sats, max_withdrawable_sats, withdrawn_sats.
            max_withdrawable_sats already excludes the routing-fee reservation.
  /winnings/withdraw:
    post:
      summary: Sweep winnings to a Lightning invoice
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [session_id, bolt11]
              properties:
                session_id: { type: string }
                bolt11:
                  type: string
                  description: |
                    Amount-specified, ≥100 sats, ≤ max_withdrawable_sats.
                    The amount you ask for is what arrives in your wallet.
      responses:
        '200': { description: Paid — returns preimage. }
        '400': { description: Invalid invoice or insufficient balance. }
        '429': { description: Rate-limited (3/min/IP). }
  /referral:
    get:
      summary: Get/create your referral code
      parameters:
        - name: session_id
          in: query
          required: true
          schema: { type: string }
      responses:
        '200':
          description: |
            Returns code, url, visits, earned_sats, available_sats, max_withdrawable_sats.
