{
  "openapi": "3.1.0",
  "info": {
    "title": "Crypto Flight Ace — Operator API",
    "version": "1.0.0",
    "description": "Server-to-server API for crypto casinos to launch Crypto Flight Ace inside their lobby. All calls to /session are authenticated with an HMAC-SHA256 signature computed from the operator's secret API key over `${timestamp}.${rawBody}`. Round lifecycle endpoints are driven by single-use launch tokens. Wallet (debit/credit) and webhook callbacks are POSTed to operator-hosted URLs and signed with the same scheme.",
    "contact": {
      "name": "Crypto Flight Ace Integrations",
      "url": "https://crypto-flight-x.lovable.app/casino"
    }
  },
  "servers": [
    {
      "url": "https://crypto-flight-x.lovable.app",
      "description": "Production"
    }
  ],
  "tags": [
    {
      "name": "Launch",
      "description": "Mint and resolve signed launch sessions"
    },
    {
      "name": "Rounds",
      "description": "Real-money round lifecycle (commit → settle → reveal)"
    },
    {
      "name": "Tracking",
      "description": "Revenue-share round tracking"
    },
    {
      "name": "Operator Callbacks",
      "description": "Endpoints YOU host; we call them"
    }
  ],
  "components": {
    "securitySchemes": {
      "OperatorSignature": {
        "type": "apiKey",
        "in": "header",
        "name": "x-cfx-signature",
        "description": "hex(HMAC_SHA256(api_key, `${x-cfx-timestamp}.${rawBody}`)). Send alongside x-cfx-operator (your operator_id) and x-cfx-timestamp (unix ms)."
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "string"
          },
          "detail": {
            "type": "string"
          }
        }
      },
      "Fairness": {
        "type": "object",
        "properties": {
          "serverSeedHash": {
            "type": "string",
            "description": "SHA-256 of the server seed, published before play"
          },
          "clientSeed": {
            "type": "string"
          },
          "nonce": {
            "type": "integer"
          }
        }
      },
      "SessionRequest": {
        "type": "object",
        "required": [
          "playerId"
        ],
        "properties": {
          "playerId": {
            "type": "string",
            "minLength": 1,
            "maxLength": 128,
            "example": "PLAYER-123"
          },
          "bet": {
            "type": "number",
            "minimum": 0,
            "example": 5
          },
          "currency": {
            "type": "string",
            "example": "USDT"
          }
        }
      },
      "SessionResponse": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "token": {
            "type": "string",
            "example": "cfx_ls_8f2c..."
          },
          "launchUrl": {
            "type": "string",
            "example": "https://crypto-flight-x.lovable.app/embed?token=cfx_ls_8f2c..."
          },
          "expiresAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "ResolveResponse": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "operator": {
            "type": "string"
          },
          "player": {
            "type": "string",
            "nullable": true
          },
          "bet": {
            "type": "number"
          },
          "currency": {
            "type": "string"
          },
          "name": {
            "type": "string",
            "nullable": true
          },
          "theme": {
            "type": "string",
            "nullable": true
          }
        }
      },
      "CommitRequest": {
        "type": "object",
        "required": [
          "token"
        ],
        "properties": {
          "token": {
            "type": "string"
          },
          "bet": {
            "type": "number",
            "minimum": 0
          },
          "clientSeed": {
            "type": "string"
          }
        }
      },
      "CommitResponse": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "roundId": {
            "type": "string",
            "format": "uuid"
          },
          "bet": {
            "type": "number"
          },
          "currency": {
            "type": "string"
          },
          "balance": {
            "type": "number",
            "nullable": true
          },
          "fairness": {
            "$ref": "#/components/schemas/Fairness"
          }
        }
      },
      "SettleRequest": {
        "type": "object",
        "required": [
          "roundId"
        ],
        "properties": {
          "roundId": {
            "type": "string",
            "format": "uuid"
          },
          "cashoutTarget": {
            "type": "number",
            "description": "Multiplier the player cashed out at. Win if <= server crash point.",
            "example": 2
          }
        }
      },
      "SettleResponse": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "roundId": {
            "type": "string",
            "format": "uuid"
          },
          "crashPoint": {
            "type": "number"
          },
          "cashoutTarget": {
            "type": "number",
            "nullable": true
          },
          "win": {
            "type": "boolean"
          },
          "winAmount": {
            "type": "number"
          },
          "balance": {
            "type": "number",
            "nullable": true
          },
          "fairness": {
            "$ref": "#/components/schemas/Fairness"
          }
        }
      },
      "RevealRequest": {
        "type": "object",
        "required": [
          "token"
        ],
        "properties": {
          "token": {
            "type": "string"
          }
        }
      },
      "WalletCall": {
        "type": "object",
        "description": "Body we POST to your wallet_url. Verify the signature, then move funds.",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "debit",
              "credit"
            ]
          },
          "operatorId": {
            "type": "string"
          },
          "playerId": {
            "type": "string",
            "nullable": true
          },
          "amount": {
            "type": "number"
          },
          "currency": {
            "type": "string"
          },
          "roundId": {
            "type": "string",
            "format": "uuid"
          },
          "idempotencyKey": {
            "type": "string",
            "example": "debit:<roundId>"
          }
        }
      },
      "WalletReply": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "balance": {
            "type": "number",
            "description": "New player balance after the move"
          },
          "providerRef": {
            "type": "string"
          }
        }
      },
      "WebhookEvent": {
        "type": "object",
        "description": "Body we POST to your webhook_url after a round settles.",
        "properties": {
          "event": {
            "type": "string",
            "example": "round.settled"
          },
          "roundId": {
            "type": "string",
            "format": "uuid"
          },
          "operatorId": {
            "type": "string"
          },
          "playerId": {
            "type": "string",
            "nullable": true
          },
          "bet": {
            "type": "number"
          },
          "currency": {
            "type": "string"
          },
          "cashoutTarget": {
            "type": "number",
            "nullable": true
          },
          "crashPoint": {
            "type": "number"
          },
          "win": {
            "type": "boolean"
          },
          "winAmount": {
            "type": "number"
          },
          "fairness": {
            "$ref": "#/components/schemas/Fairness"
          }
        }
      }
    }
  },
  "paths": {
    "/api/public/casino/session": {
      "post": {
        "tags": [
          "Launch"
        ],
        "summary": "Mint a signed, single-use launch token (server-to-server)",
        "security": [
          {
            "OperatorSignature": []
          }
        ],
        "parameters": [
          {
            "name": "x-cfx-operator",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "x-cfx-timestamp",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Unix epoch ms"
          },
          {
            "name": "x-cfx-signature",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SessionRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Token minted",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SessionResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid payload",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Bad signature / unknown operator",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/public/casino/session/resolve": {
      "post": {
        "tags": [
          "Launch"
        ],
        "summary": "Resolve a launch token into trusted session details (called by the embed)",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "token"
                ],
                "properties": {
                  "token": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Resolved",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResolveResponse"
                }
              }
            }
          },
          "404": {
            "description": "Invalid token"
          },
          "410": {
            "description": "Token expired"
          }
        }
      }
    },
    "/api/public/casino/round/commit": {
      "post": {
        "tags": [
          "Rounds"
        ],
        "summary": "Start a real-money round: publish fairness hash + debit the bet",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CommitRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Round committed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CommitResponse"
                }
              }
            }
          },
          "402": {
            "description": "Insufficient balance / wallet error"
          },
          "404": {
            "description": "Invalid token"
          },
          "410": {
            "description": "Session expired"
          },
          "422": {
            "description": "Bet outside min/max"
          }
        }
      }
    },
    "/api/public/casino/round/settle": {
      "post": {
        "tags": [
          "Rounds"
        ],
        "summary": "Decide a committed round server-side and credit any win",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SettleRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Round settled",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SettleResponse"
                }
              }
            }
          },
          "404": {
            "description": "Round not found"
          },
          "409": {
            "description": "Round already settled / voided"
          }
        }
      }
    },
    "/api/public/casino/round/reveal": {
      "post": {
        "tags": [
          "Rounds"
        ],
        "summary": "Reveal the server seed after a session expires for provably-fair verification",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RevealRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Fairness data (serverSeed revealed only after expiry)"
          },
          "404": {
            "description": "No fairness data for this token"
          }
        }
      }
    },
    "/api/public/casino/track": {
      "post": {
        "tags": [
          "Tracking"
        ],
        "summary": "Record a played round for revenue-share accounting",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "operator"
                ],
                "properties": {
                  "operator": {
                    "type": "string"
                  },
                  "sessionId": {
                    "type": "string"
                  },
                  "player": {
                    "type": "string",
                    "nullable": true
                  },
                  "bet": {
                    "type": "number"
                  },
                  "multiplier": {
                    "type": "number"
                  },
                  "cashedOut": {
                    "type": "boolean"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Recorded"
          }
        }
      }
    }
  },
  "x-operatorCallbacks": {
    "walletUrl": {
      "description": "POST we send to your configured wallet_url. Reply with WalletReply.",
      "request": {
        "$ref": "#/components/schemas/WalletCall"
      },
      "response": {
        "$ref": "#/components/schemas/WalletReply"
      }
    },
    "webhookUrl": {
      "description": "POST we send to your configured webhook_url after settle.",
      "request": {
        "$ref": "#/components/schemas/WebhookEvent"
      }
    }
  }
}