{
  "openapi": "3.1.0",
  "info": {
    "title": "Provably Fair Game Provider API",
    "version": "0.1.0"
  },
  "paths": {
    "/health": {
      "get": {
        "summary": "Return runtime health and supported currency contract",
        "responses": {
          "200": { "description": "Health payload returned" }
        }
      }
    },
    "/ready": {
      "get": {
        "summary": "Return deployment readiness for a configured operator",
        "parameters": [
          { "name": "operatorId", "in": "query", "required": false, "schema": { "type": "string" } }
        ],
        "responses": {
          "200": { "description": "Readiness checks passed" },
          "503": { "description": "Readiness checks failed" }
        }
      }
    },
    "/sandbox/launch": {
      "post": {
        "summary": "Create a local sandbox launch token and launch URL",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["operatorId", "playerRef", "gameType"],
                "properties": {
                  "operatorId": { "type": "string" },
                  "playerRef": { "type": "string" },
                  "gameType": { "enum": ["dice", "limbo", "plinko", "keno", "mines", "blackjack"] },
                  "launchMode": { "enum": ["single", "lobby"], "default": "single" }
                }
              }
            }
          }
        },
        "responses": {
          "200": { "description": "Sandbox launch payload returned" }
        }
      }
    },
    "/api/sessions": {
      "post": {
        "summary": "Create a game session from a casino launch token",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["operatorId", "launchToken"],
                "properties": {
                  "operatorId": { "type": "string" },
                  "launchToken": { "type": "string" },
                  "gameType": { "enum": ["dice", "limbo", "plinko", "keno", "mines", "blackjack"], "default": "dice" },
                  "launchMode": { "enum": ["single", "lobby"], "default": "single" }
                }
              }
            }
          }
        },
        "responses": {
          "200": { "description": "Session created" }
        }
      }
    },
    "/api/balance": {
      "get": {
        "summary": "Fetch current casino-provided balance for a game session",
        "parameters": [
          { "name": "sessionId", "in": "query", "required": true, "schema": { "type": "string" } }
        ],
        "responses": {
          "200": { "description": "Balance returned" }
        }
      }
    },
    "/api/bets": {
      "post": {
        "summary": "Place a backend-authoritative provably fair bet",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["sessionId", "gameType", "amount", "idempotencyKey"],
                "properties": {
                  "sessionId": { "type": "string" },
                  "gameType": { "enum": ["dice", "limbo", "plinko", "keno"] },
                  "amount": { "type": "number" },
                  "idempotencyKey": { "type": "string" },
                  "clientSeed": { "type": "string" },
                  "params": { "type": "object" }
                }
              }
            }
          }
        },
        "responses": {
          "200": { "description": "Bet settled or an identical retry replayed" },
          "400": { "description": "Validation or idempotency conflict" }
        }
      }
    },
    "/api/bets/{roundId}": {
      "get": {
        "summary": "Return a stored round with fairness proof and casino callback audit",
        "parameters": [
          { "name": "roundId", "in": "path", "required": true, "schema": { "type": "string" } }
        ],
        "responses": {
          "200": { "description": "Round returned" },
          "400": { "description": "Round not found" }
        }
      }
    },
    "/api/mines/rounds": {
      "post": {
        "summary": "Start a Mines active round and debit the casino wallet once",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["sessionId", "amount", "idempotencyKey"],
                "properties": {
                  "sessionId": { "type": "string" },
                  "amount": { "type": "number" },
                  "mineCount": { "type": "integer", "minimum": 1, "maximum": 24, "default": 3 },
                  "clientSeed": { "type": "string" },
                  "idempotencyKey": { "type": "string" }
                }
              }
            }
          }
        },
        "responses": {
          "200": { "description": "Active Mines round returned or identical retry replayed" },
          "400": { "description": "Validation or idempotency conflict" }
        }
      }
    },
    "/api/mines/rounds/{roundId}": {
      "get": {
        "summary": "Restore or inspect a Mines active round",
        "parameters": [
          { "name": "roundId", "in": "path", "required": true, "schema": { "type": "string" } },
          { "name": "sessionId", "in": "query", "required": true, "schema": { "type": "string" } }
        ],
        "responses": {
          "200": { "description": "Mines round returned" },
          "400": { "description": "Round not found or session mismatch" }
        }
      }
    },
    "/api/mines/rounds/{roundId}/reveal": {
      "post": {
        "summary": "Reveal a Mines tile without additional wallet movement",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["sessionId", "tile", "idempotencyKey"],
                "properties": {
                  "sessionId": { "type": "string" },
                  "tile": { "type": "integer", "minimum": 0, "maximum": 24 },
                  "idempotencyKey": { "type": "string" }
                }
              }
            }
          }
        },
        "responses": {
          "200": { "description": "Updated round returned, or final busted bet returned" },
          "400": { "description": "Validation or idempotency conflict" }
        }
      }
    },
    "/api/mines/rounds/{roundId}/cashout": {
      "post": {
        "summary": "Cash out a Mines round and credit the casino wallet once",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["sessionId", "idempotencyKey"],
                "properties": {
                  "sessionId": { "type": "string" },
                  "idempotencyKey": { "type": "string" }
                }
              }
            }
          }
        },
        "responses": {
          "200": { "description": "Final cashed-out bet returned or identical retry replayed" },
          "400": { "description": "Validation or idempotency conflict" }
        }
      }
    },
    "/api/blackjack/rounds": {
      "post": {
        "summary": "Start a Blackjack active round and debit the casino wallet once",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["sessionId", "amount", "idempotencyKey"],
                "properties": {
                  "sessionId": { "type": "string" },
                  "amount": { "type": "number" },
                  "clientSeed": { "type": "string" },
                  "idempotencyKey": { "type": "string" }
                }
              }
            }
          }
        },
        "responses": {
          "200": { "description": "Active Blackjack round or final settled bet returned" },
          "400": { "description": "Validation or idempotency conflict" }
        }
      }
    },
    "/api/blackjack/rounds/{roundId}": {
      "get": {
        "summary": "Restore or inspect a Blackjack active round",
        "parameters": [
          { "name": "roundId", "in": "path", "required": true, "schema": { "type": "string" } },
          { "name": "sessionId", "in": "query", "required": true, "schema": { "type": "string" } }
        ],
        "responses": {
          "200": { "description": "Blackjack round returned" },
          "400": { "description": "Round not found or session mismatch" }
        }
      }
    },
    "/api/blackjack/rounds/{roundId}/insurance": {
      "post": {
        "summary": "Take or decline Blackjack insurance when offered",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["sessionId", "idempotencyKey"],
                "properties": {
                  "sessionId": { "type": "string" },
                  "takeInsurance": { "type": "boolean", "default": false },
                  "idempotencyKey": { "type": "string" }
                }
              }
            }
          }
        },
        "responses": {
          "200": { "description": "Updated round or final settled bet returned" },
          "400": { "description": "Validation or idempotency conflict" }
        }
      }
    },
    "/api/blackjack/rounds/{roundId}/{action}": {
      "post": {
        "summary": "Apply a Blackjack player action: hit, stand, double, or split",
        "parameters": [
          { "name": "roundId", "in": "path", "required": true, "schema": { "type": "string" } },
          { "name": "action", "in": "path", "required": true, "schema": { "enum": ["hit", "stand", "double", "split"] } }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["sessionId", "idempotencyKey"],
                "properties": {
                  "sessionId": { "type": "string" },
                  "idempotencyKey": { "type": "string" }
                }
              }
            }
          }
        },
        "responses": {
          "200": { "description": "Updated round or final settled bet returned" },
          "400": { "description": "Validation or idempotency conflict" }
        }
      }
    },
    "/api/verify": {
      "post": {
        "summary": "Verify a previous game result after server seed reveal",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["gameType", "serverSeed", "serverSeedHash", "clientSeed", "nonce", "amount"],
                "properties": {
                  "gameType": { "enum": ["dice", "limbo", "plinko", "keno", "mines", "blackjack"] },
                  "serverSeed": { "type": "string" },
                  "serverSeedHash": { "type": "string" },
                  "clientSeed": { "type": "string" },
                  "nonce": { "type": "number" },
                  "amount": { "type": "number" },
                  "currency": { "enum": ["USD", "EUR", "GBP", "USDT", "USDC", "BTC", "uBTC", "ETH", "LTC", "DOGE", "BNB", "SOL", "XRP", "ADA", "TRX", "XLM", "ZEC"], "default": "USD" },
                  "params": { "type": "object" }
                }
              }
            }
          }
        },
        "responses": {
          "200": { "description": "Recalculated result" }
        }
      }
    },
    "/api/reconciliation": {
      "get": {
        "summary": "Return casino wallet transaction reconciliation rows",
        "responses": {
          "200": { "description": "Reconciliation rows" }
        }
      }
    },
    "/api/cron/wallet-retries": {
      "get": {
        "summary": "Retry pending casino wallet credit and rollback callbacks",
        "description": "In production, calls without operatorId default to READINESS_OPERATOR_ID instead of scanning every operator.",
        "parameters": [
          { "name": "Authorization", "in": "header", "required": true, "schema": { "type": "string", "example": "Bearer <CRON_SECRET>" } },
          { "name": "operatorId", "in": "query", "required": false, "schema": { "type": "string" } },
          { "name": "playerRef", "in": "query", "required": false, "schema": { "type": "string" } },
          { "name": "limit", "in": "query", "required": false, "schema": { "type": "integer", "minimum": 1, "maximum": 100 } }
        ],
        "responses": {
          "200": { "description": "Pending wallet retry summary" },
          "400": { "description": "Production retry requires operatorId or READINESS_OPERATOR_ID" },
          "401": { "description": "Missing or invalid cron bearer token" }
        }
      }
    },
    "/api/fairness/rotate": {
      "post": {
        "summary": "Rotate the current server seed and reveal the previous server seed",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["sessionId"],
                "properties": {
                  "sessionId": { "type": "string" }
                }
              }
            }
          }
        },
        "responses": {
          "200": { "description": "New seed hash and revealed previous seed returned" }
        }
      }
    }
  }
}
