openapi: '3.0.3'
info:
  title: ProofBets API
  description: >-
    REST API for ProofBets — crypto casino reviews, bonus verification,
    prediction market data, World Cup 2026 odds, and gambling glossary.
    Powers the ProofBets MCP server for AI assistants.
  version: '1.0.0'
  contact:
    name: ProofBets
    url: https://proofbets.com
  license:
    name: MIT
    url: https://opensource.org/licenses/MIT

servers:
  - url: https://proofbets.com/api/v1
    description: Production

tags:
  - name: Casinos
    description: Crypto casino search, details, and comparisons
  - name: Bonuses
    description: Casino bonuses and bonus code verification
  - name: Odds
    description: Sports betting odds (World Cup 2026)
  - name: Content
    description: Guides, reviews, and glossary
  - name: Prediction Markets
    description: P2P prediction market platforms
  - name: Health
    description: API health check

components:
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: X-API-Key
      description: Optional API key for higher rate limits

  schemas:
    ProblemDetail:
      type: object
      required: [type, title, status, detail]
      properties:
        type:
          type: string
          example: about:blank
        title:
          type: string
          example: Not Found
        status:
          type: integer
          example: 404
        detail:
          type: string
          example: No casino found with slug "unknown"

    CasinoSummary:
      type: object
      properties:
        name:
          type: string
          example: Stake.com
        slug:
          type: string
          example: stake
        rating:
          type: number
          example: 9.2
        welcome_bonus:
          type: string
          example: '200% up to $1,000'
        provably_fair:
          type: boolean
          example: true
        kyc_required:
          type: string
          example: optional
        cryptos_accepted:
          type: array
          items:
            type: string
          example: [BTC, ETH, LTC, DOGE]
        games_count:
          type: integer
          example: 3000
        source_url:
          type: string
          format: uri

    CasinoDetail:
      type: object
      properties:
        name:
          type: string
        slug:
          type: string
        logo:
          type: string
        founded:
          type: integer
        licence:
          type: string
        cryptos_accepted:
          type: array
          items:
            type: string
        games_count:
          type: integer
        min_deposit:
          type: string
        withdrawal_speed_hours:
          type: number
        provably_fair:
          type: boolean
        kyc_required:
          type: string
        welcome_bonus:
          type: string
        wagering_requirement:
          type: integer
        rating:
          type: number
        pros:
          type: array
          items:
            type: string
        cons:
          type: array
          items:
            type: string
        geo_restrictions:
          type: array
          items:
            type: string
        last_verified:
          type: string
          format: date
        data_verified:
          type: boolean
        source_url:
          type: string
          format: uri

    BonusSummary:
      type: object
      properties:
        casino:
          type: string
        code:
          type: string
        type:
          type: string
          enum: [welcome, reload, cashback, free-spins, no-deposit]
        value_usd:
          type: number
        description:
          type: string
        wagering_requirement:
          type: integer
        active:
          type: boolean
        expires:
          type: string
          format: date
        source_url:
          type: string
          format: uri

    BonusCheckResult:
      type: object
      properties:
        code:
          type: string
        found:
          type: boolean
        active:
          type: boolean
        casino:
          type: string
        type:
          type: string
        description:
          type: string
        value_usd:
          type: number
        wagering_requirement:
          type: integer
        expires:
          type: string
        source_url:
          type: string
          format: uri

    GlossaryTerm:
      type: object
      properties:
        term:
          type: string
          example: Provably Fair
        slug:
          type: string
          example: provably-fair
        definition:
          type: string
        category:
          type: string
          example: technology
        source_url:
          type: string
          format: uri

    GuideDetail:
      type: object
      properties:
        slug:
          type: string
        title:
          type: string
        author:
          type: string
        date:
          type: string
          format: date
        updated:
          type: string
          format: date
          nullable: true
        category:
          type: string
          nullable: true
        seo_title:
          type: string
          nullable: true
        seo_description:
          type: string
          nullable: true
        source_url:
          type: string
          format: uri

    ReviewSummary:
      type: object
      properties:
        casino:
          type: string
        title:
          type: string
        rating:
          type: number
        summary:
          type: string
        date:
          type: string
          format: date
        updated:
          type: string
          format: date
          nullable: true
        source_url:
          type: string
          format: uri

    P2PPlatformSummary:
      type: object
      properties:
        name:
          type: string
          example: Polymarket
        slug:
          type: string
          example: polymarket
        type:
          type: string
          enum: [crypto, regulated, decentralized]
        description:
          type: string
        trading_fee:
          type: string
        kyc_required:
          type: boolean
        supported_markets:
          type: array
          items:
            type: string
        source_url:
          type: string
          format: uri

    P2PPlatformFees:
      type: object
      properties:
        name:
          type: string
        slug:
          type: string
        type:
          type: string
        description:
          type: string
        trade_size:
          type: number
        fees:
          type: object
          properties:
            trading_fee_pct:
              type: string
            trading_fee_usd:
              type: number
            settlement_fee_pct:
              type: string
            settlement_fee_usd:
              type: number
            gas_estimate:
              type: string
            total_platform_fees_usd:
              type: number
        limits:
          type: object
          properties:
            min_trade:
              type: string
            max_trade:
              type: string
        kyc_required:
          type: boolean
        supported_markets:
          type: array
          items:
            type: string
        website:
          type: string
          format: uri
        source_url:
          type: string
          format: uri

    WorldCupOdds:
      type: object
      properties:
        tournament:
          type: string
        host:
          type: string
        start_date:
          type: string
          format: date
        last_updated:
          type: string
          format: date
        market:
          type: string
          enum: [outright, top-scorer]
        results:
          type: array
          items:
            type: object
        source_url:
          type: string
          format: uri

  parameters:
    LimitParam:
      name: limit
      in: query
      schema:
        type: integer
        minimum: 1
        maximum: 50
        default: 10
      description: Maximum number of results

  responses:
    BadRequest:
      description: Bad request
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/ProblemDetail'
    NotFound:
      description: Resource not found
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/ProblemDetail'
    TooManyRequests:
      description: Rate limit exceeded
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/ProblemDetail'
          example:
            type: about:blank
            title: Too Many Requests
            status: 429
            detail: Rate limit of 20 requests per minute exceeded

security:
  - {}
  - ApiKeyAuth: []

paths:
  /health:
    get:
      tags: [Health]
      summary: Health check
      operationId: getHealth
      responses:
        '200':
          description: API is healthy
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                    example: ok
                  timestamp:
                    type: string
                    format: date-time

  /casinos:
    get:
      tags: [Casinos]
      summary: Search and list crypto casinos
      operationId: searchCasinos
      parameters:
        - name: q
          in: query
          schema:
            type: string
          description: Search term (casino name or feature)
        - name: minRating
          in: query
          schema:
            type: number
            minimum: 0
            maximum: 10
          description: Minimum rating (0-10)
        - name: features
          in: query
          schema:
            type: string
          description: 'Comma-separated required features (e.g. provably-fair,no-kyc)'
        - $ref: '#/components/parameters/LimitParam'
      responses:
        '200':
          description: List of matching casinos
          content:
            application/json:
              schema:
                type: object
                properties:
                  count:
                    type: integer
                  results:
                    type: array
                    items:
                      $ref: '#/components/schemas/CasinoSummary'
                  source_url:
                    type: string
                    format: uri
        '429':
          $ref: '#/components/responses/TooManyRequests'

  /casinos/{slug}:
    get:
      tags: [Casinos]
      summary: Get casino details by slug
      operationId: getCasino
      parameters:
        - name: slug
          in: path
          required: true
          schema:
            type: string
          description: Casino slug (e.g. stake, bc-game, roobet)
      responses:
        '200':
          description: Casino details
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CasinoDetail'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/TooManyRequests'

  /bonuses:
    get:
      tags: [Bonuses]
      summary: List casino bonuses
      operationId: searchBonuses
      parameters:
        - name: casino
          in: query
          schema:
            type: string
          description: Filter by casino slug
        - name: type
          in: query
          schema:
            type: string
            enum: [welcome, reload, cashback, free-spins, no-deposit]
          description: Bonus type
        - name: minValue
          in: query
          schema:
            type: number
          description: Minimum bonus value in USD
      responses:
        '200':
          description: List of bonuses
          content:
            application/json:
              schema:
                type: object
                properties:
                  count:
                    type: integer
                  results:
                    type: array
                    items:
                      $ref: '#/components/schemas/BonusSummary'
                  source_url:
                    type: string
                    format: uri
        '429':
          $ref: '#/components/responses/TooManyRequests'

  /bonuses/check/{code}:
    get:
      tags: [Bonuses]
      summary: Verify a bonus code
      operationId: checkBonusCode
      parameters:
        - name: code
          in: path
          required: true
          schema:
            type: string
          description: The bonus code to check
        - name: casino
          in: query
          schema:
            type: string
          description: Casino slug to narrow the search
      responses:
        '200':
          description: Bonus code verification result
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BonusCheckResult'
        '400':
          $ref: '#/components/responses/BadRequest'
        '429':
          $ref: '#/components/responses/TooManyRequests'

  /comparisons:
    get:
      tags: [Casinos]
      summary: Compare 2-3 casinos side by side
      operationId: compareCasinos
      parameters:
        - name: slugs
          in: query
          required: true
          schema:
            type: string
          description: 'Comma-separated casino slugs (e.g. stake,bc-game)'
      responses:
        '200':
          description: Casino comparison data
          content:
            application/json:
              schema:
                type: object
                properties:
                  casinos:
                    type: array
                    items:
                      $ref: '#/components/schemas/CasinoDetail'
                  existing_comparison:
                    type: object
                    nullable: true
                    properties:
                      title:
                        type: string
                      winner:
                        type: string
                      comparison_points:
                        type: array
                        items:
                          type: string
                      source_url:
                        type: string
                        format: uri
                  source_url:
                    type: string
                    format: uri
        '400':
          $ref: '#/components/responses/BadRequest'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/TooManyRequests'

  /odds/world-cup:
    get:
      tags: [Odds]
      summary: Get World Cup 2026 betting odds
      operationId: getWorldCupOdds
      parameters:
        - name: market
          in: query
          schema:
            type: string
            enum: [outright, group, match, top-scorer]
            default: outright
          description: Market type
        - name: team
          in: query
          schema:
            type: string
          description: Filter by team name
      responses:
        '200':
          description: World Cup odds data
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WorldCupOdds'
        '429':
          $ref: '#/components/responses/TooManyRequests'

  /glossary:
    get:
      tags: [Content]
      summary: Search crypto gambling glossary terms
      operationId: searchGlossary
      parameters:
        - name: q
          in: query
          schema:
            type: string
          description: Search term (e.g. wagering, provably fair, RTP)
      responses:
        '200':
          description: Glossary terms
          content:
            application/json:
              schema:
                type: object
                properties:
                  count:
                    type: integer
                  results:
                    type: array
                    items:
                      $ref: '#/components/schemas/GlossaryTerm'
                  source_url:
                    type: string
                    format: uri
        '429':
          $ref: '#/components/responses/TooManyRequests'

  /guides/{slug}:
    get:
      tags: [Content]
      summary: Get guide by slug
      operationId: getGuide
      parameters:
        - name: slug
          in: path
          required: true
          schema:
            type: string
          description: Guide slug (e.g. what-is-provably-fair, no-kyc-crypto-casinos)
      responses:
        '200':
          description: Guide details
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/GuideDetail'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/TooManyRequests'

  /reviews:
    get:
      tags: [Content]
      summary: Search casino review summaries
      operationId: searchReviews
      parameters:
        - name: q
          in: query
          schema:
            type: string
          description: Search term
        - name: minRating
          in: query
          schema:
            type: number
            minimum: 0
            maximum: 10
          description: Minimum rating
      responses:
        '200':
          description: Review summaries
          content:
            application/json:
              schema:
                type: object
                properties:
                  count:
                    type: integer
                  results:
                    type: array
                    items:
                      $ref: '#/components/schemas/ReviewSummary'
                  source_url:
                    type: string
                    format: uri
        '429':
          $ref: '#/components/responses/TooManyRequests'

  /p2p:
    get:
      tags: [Prediction Markets]
      summary: List prediction market platforms
      operationId: searchP2PPlatforms
      parameters:
        - name: q
          in: query
          schema:
            type: string
          description: Search term
        - name: type
          in: query
          schema:
            type: string
            enum: [all, crypto, regulated, decentralized]
          description: Platform type filter
      responses:
        '200':
          description: Prediction market platforms
          content:
            application/json:
              schema:
                type: object
                properties:
                  count:
                    type: integer
                  results:
                    type: array
                    items:
                      $ref: '#/components/schemas/P2PPlatformSummary'
                  source_url:
                    type: string
                    format: uri
        '429':
          $ref: '#/components/responses/TooManyRequests'

  /p2p/compare:
    get:
      tags: [Prediction Markets]
      summary: Compare prediction market platforms
      operationId: comparePlatforms
      parameters:
        - name: slugs
          in: query
          required: true
          schema:
            type: string
          description: 'Comma-separated platform slugs (e.g. polymarket,kalshi)'
      responses:
        '200':
          description: Platform comparison
          content:
            application/json:
              schema:
                type: object
                properties:
                  platforms:
                    type: array
                    items:
                      $ref: '#/components/schemas/P2PPlatformFees'
                  source_url:
                    type: string
                    format: uri
        '400':
          $ref: '#/components/responses/BadRequest'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/TooManyRequests'

  /p2p/{slug}:
    get:
      tags: [Prediction Markets]
      summary: Get platform fee breakdown
      operationId: getPlatformFees
      parameters:
        - name: slug
          in: path
          required: true
          schema:
            type: string
          description: Platform slug (e.g. polymarket, kalshi, azuro)
        - name: tradeSize
          in: query
          schema:
            type: number
            default: 100
          description: Trade size in USD for fee calculation
      responses:
        '200':
          description: Platform fee breakdown
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/P2PPlatformFees'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/TooManyRequests'
