openapi: "3.1.0"
info:
  title: Evens United Predictions API
  version: "1.0.0"
  description: |
    Unified prediction market data across Kalshi, Polymarket, Smarkets, and BetRivers.
    Access real-time prices, cross-provider market matching, and historical price data.
  contact:
    name: Evens
    url: https://evens.app
servers:
  - url: https://evens.app/api/v1
    description: Production

security:
  - ApiKeyAuth: []

components:
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: X-API-Key
      description: API key from your Evens account page

  schemas:
    Market:
      type: object
      properties:
        id:
          type: integer
        title:
          type: string
        market_type:
          type: string
          enum: [moneyline, moneyline_3way, spread, total, team_prop, player_prop, milestone, first_score, game_prop, series, half_full, win_margin, highest_scoring, race_to, double_chance, futures, novelty, other]
          nullable: true
        stat_type:
          type: string
          nullable: true
        line:
          type: number
          nullable: true
        outcome_type:
          type: string
          enum: [over, under, home, away, yes, no, draw, two_way, three_way]
          nullable: true
        time_qualifier:
          type: string
          nullable: true
        category:
          type: string
          nullable: true
        status:
          type: string
          enum: [unopened, open, closed, finalized]
          nullable: true
        best_yes_price:
          type: string
          nullable: true
        best_no_price:
          type: string
          nullable: true
        total_volume:
          type: string
        provider_coverage:
          type: array
          items:
            type: string
        event_id:
          type: integer
          nullable: true
        home_team:
          $ref: "#/components/schemas/TeamRef"
        away_team:
          $ref: "#/components/schemas/TeamRef"
        person:
          $ref: "#/components/schemas/PersonRef"
        references:
          type: array
          items:
            $ref: "#/components/schemas/MarketReference"
          description: Only included on single-market endpoints

    MarketReference:
      type: object
      properties:
        id:
          type: integer
        provider:
          type: string
          enum: [kalshi, polymarket, smarkets, betrivers]
        external_id:
          type: string
        title:
          type: string
        market_type:
          type: string
          nullable: true
        outcome_type:
          type: string
          nullable: true
        stat_type:
          type: string
          nullable: true
        line:
          type: number
          nullable: true
        time_qualifier:
          type: string
          nullable: true
        status:
          type: string
        outcomes:
          $ref: "#/components/schemas/Outcomes"
        volume:
          type: string
          nullable: true
        open_interest:
          type: string
          nullable: true
        liquidity:
          type: string
          nullable: true
        url:
          type: string
          format: uri
          nullable: true
        last_synced_at:
          type: string
          format: date-time
          nullable: true
        market_id:
          type: integer
          nullable: true
        event_id:
          type: integer
          nullable: true

    Event:
      type: object
      properties:
        id:
          type: integer
        title:
          type: string
        event_identifier:
          type: string
          nullable: true
        event_type:
          type: string
          nullable: true
        sport:
          type: string
          nullable: true
        competition:
          type: string
          nullable: true
        status:
          type: string
          nullable: true
        starts_at:
          type: string
          format: date-time
          nullable: true
        home_team:
          $ref: "#/components/schemas/TeamRef"
        away_team:
          $ref: "#/components/schemas/TeamRef"
        market_count:
          type: integer
        provider_coverage:
          type: array
          items:
            type: string
        markets:
          type: array
          items:
            $ref: "#/components/schemas/Market"
          description: Only included on single-event endpoints

    EventReference:
      type: object
      properties:
        id:
          type: integer
        provider:
          type: string
        external_id:
          type: string
        title:
          type: string
          nullable: true
        sport:
          type: string
          nullable: true
        competition:
          type: string
          nullable: true
        status:
          type: string
          nullable: true
        starts_at:
          type: string
          format: date-time
          nullable: true
        event_id:
          type: integer
          nullable: true

    Price:
      type: object
      properties:
        timestamp:
          type: string
          format: date-time
        aggregation_type:
          type: string
          enum: [raw, hourly, 4hour, daily]
        yes_bid:
          type: string
          nullable: true
        yes_ask:
          type: string
          nullable: true
        no_bid:
          type: string
          nullable: true
        no_ask:
          type: string
          nullable: true
        last_price:
          type: string
          nullable: true
        volume:
          type: string
          nullable: true
        open_interest:
          type: string
          nullable: true

    Sport:
      type: object
      properties:
        id:
          type: integer
        name:
          type: string
        slug:
          type: string

    Competition:
      type: object
      properties:
        id:
          type: integer
        name:
          type: string
        slug:
          type: string
        competition_type:
          type: string
          nullable: true
        sport_id:
          type: integer
          nullable: true
        sport_name:
          type: string
          nullable: true
        year:
          type: integer
          nullable: true
        season_type:
          type: string
          nullable: true

    Provider:
      type: object
      properties:
        name:
          type: string
        market_count:
          type: integer
        event_count:
          type: integer

    Outcomes:
      type: object
      properties:
        "yes":
          type: object
          properties:
            bid:
              type: string
              nullable: true
            ask:
              type: string
              nullable: true
            last_price:
              type: string
              nullable: true
        "no":
          type: object
          properties:
            bid:
              type: string
              nullable: true
            ask:
              type: string
              nullable: true

    TeamRef:
      type: object
      nullable: true
      properties:
        id:
          type: integer
        name:
          type: string

    PersonRef:
      type: object
      nullable: true
      properties:
        id:
          type: integer
        name:
          type: string

    Pagination:
      type: object
      properties:
        next_cursor:
          type: string
          nullable: true
        has_next:
          type: boolean

    ErrorResponse:
      type: object
      properties:
        error:
          type: object
          properties:
            message:
              type: string
            status:
              type: integer

  parameters:
    cursor:
      name: cursor
      in: query
      schema:
        type: string
      description: Opaque pagination cursor from previous response
    limit:
      name: limit
      in: query
      schema:
        type: integer
        default: 50
        maximum: 200
      description: Results per page
    provider:
      name: provider
      in: path
      required: true
      schema:
        type: string
        enum: [kalshi, polymarket, smarkets, betrivers]
      description: Prediction market provider

  responses:
    Unauthorized:
      description: Invalid or missing API key
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/ErrorResponse"
    NotFound:
      description: Resource not found
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/ErrorResponse"
    RateLimited:
      description: Rate limit exceeded
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/ErrorResponse"

paths:
  # ============ Unified Endpoints ============

  /markets:
    get:
      summary: List canonical markets
      description: List markets with aggregated cross-provider pricing.
      operationId: listMarkets
      tags: [Unified]
      parameters:
        - name: status
          in: query
          schema:
            type: string
            enum: [unopened, open, closed, finalized]
        - name: market_type
          in: query
          schema:
            type: string
        - name: event_id
          in: query
          schema:
            type: integer
        - name: sport
          in: query
          schema:
            type: string
        - name: competition
          in: query
          schema:
            type: string
        - name: provider
          in: query
          schema:
            type: string
          description: Filter to markets with coverage on this provider
        - name: search
          in: query
          schema:
            type: string
        - $ref: "#/components/parameters/cursor"
        - $ref: "#/components/parameters/limit"
      responses:
        "200":
          description: Paginated list of markets
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: "#/components/schemas/Market"
                  pagination:
                    $ref: "#/components/schemas/Pagination"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "429":
          $ref: "#/components/responses/RateLimited"

  /markets/{id}:
    get:
      summary: Get a canonical market
      description: Returns a market with all approved provider references.
      operationId: getMarket
      tags: [Unified]
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: integer
      responses:
        "200":
          description: Market with references
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: "#/components/schemas/Market"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"

  /markets/{id}/prices:
    get:
      summary: Market price history
      description: Historical price snapshots across all providers.
      operationId: getMarketPrices
      tags: [Unified]
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: integer
        - name: start_time
          in: query
          schema:
            type: string
            format: date-time
        - name: end_time
          in: query
          schema:
            type: string
            format: date-time
        - name: interval
          in: query
          schema:
            type: string
            enum: [raw, hourly, 4hour, daily]
            default: raw
        - name: provider
          in: query
          schema:
            type: string
          description: Filter to a specific provider's prices
        - $ref: "#/components/parameters/cursor"
        - name: limit
          in: query
          schema:
            type: integer
            default: 100
            maximum: 200
      responses:
        "200":
          description: Paginated price snapshots
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: "#/components/schemas/Price"
                  pagination:
                    $ref: "#/components/schemas/Pagination"

  /events:
    get:
      summary: List canonical events
      description: List events with participant and market summary data.
      operationId: listEvents
      tags: [Unified]
      parameters:
        - name: sport
          in: query
          schema:
            type: string
        - name: competition
          in: query
          schema:
            type: string
        - name: status
          in: query
          schema:
            type: string
        - name: start_after
          in: query
          schema:
            type: string
            format: date-time
        - name: start_before
          in: query
          schema:
            type: string
            format: date-time
        - name: search
          in: query
          schema:
            type: string
        - $ref: "#/components/parameters/cursor"
        - $ref: "#/components/parameters/limit"
      responses:
        "200":
          description: Paginated list of events
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: "#/components/schemas/Event"
                  pagination:
                    $ref: "#/components/schemas/Pagination"

  /events/{id}:
    get:
      summary: Get a canonical event
      description: Returns an event with all its markets.
      operationId: getEvent
      tags: [Unified]
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: integer
      responses:
        "200":
          description: Event with markets
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: "#/components/schemas/Event"

  /events/{event_id}/markets:
    get:
      summary: List markets for an event
      description: Returns all markets for a specific event.
      operationId: listEventMarkets
      tags: [Unified]
      parameters:
        - name: event_id
          in: path
          required: true
          schema:
            type: integer
        - name: market_type
          in: query
          schema:
            type: string
        - name: status
          in: query
          schema:
            type: string
        - $ref: "#/components/parameters/cursor"
        - $ref: "#/components/parameters/limit"
      responses:
        "200":
          description: Paginated list of markets
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: "#/components/schemas/Market"
                  pagination:
                    $ref: "#/components/schemas/Pagination"

  # ============ Provider Endpoints ============

  /{provider}/markets:
    get:
      summary: List provider markets
      description: List market references for a specific provider.
      operationId: listProviderMarkets
      tags: [Provider]
      parameters:
        - $ref: "#/components/parameters/provider"
        - name: status
          in: query
          schema:
            type: string
        - name: market_type
          in: query
          schema:
            type: string
        - name: event_id
          in: query
          schema:
            type: integer
        - name: search
          in: query
          schema:
            type: string
        - $ref: "#/components/parameters/cursor"
        - $ref: "#/components/parameters/limit"
      responses:
        "200":
          description: Paginated list of market references
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: "#/components/schemas/MarketReference"
                  pagination:
                    $ref: "#/components/schemas/Pagination"
                  meta:
                    type: object
                    properties:
                      provider:
                        type: string

  /{provider}/markets/{id}:
    get:
      summary: Get a provider market
      description: Get a single market reference by ID.
      operationId: getProviderMarket
      tags: [Provider]
      parameters:
        - $ref: "#/components/parameters/provider"
        - name: id
          in: path
          required: true
          schema:
            type: integer
      responses:
        "200":
          description: Market reference
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: "#/components/schemas/MarketReference"
                  meta:
                    type: object
                    properties:
                      provider:
                        type: string

  /{provider}/markets/{id}/prices:
    get:
      summary: Provider market prices
      description: Price history for a specific provider market.
      operationId: getProviderMarketPrices
      tags: [Provider]
      parameters:
        - $ref: "#/components/parameters/provider"
        - name: id
          in: path
          required: true
          schema:
            type: integer
        - name: start_time
          in: query
          schema:
            type: string
            format: date-time
        - name: end_time
          in: query
          schema:
            type: string
            format: date-time
        - name: interval
          in: query
          schema:
            type: string
            enum: [raw, hourly, 4hour, daily]
        - $ref: "#/components/parameters/cursor"
        - name: limit
          in: query
          schema:
            type: integer
            default: 100
            maximum: 200
      responses:
        "200":
          description: Paginated price snapshots
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: "#/components/schemas/Price"
                  pagination:
                    $ref: "#/components/schemas/Pagination"
                  meta:
                    type: object
                    properties:
                      provider:
                        type: string

  /{provider}/events:
    get:
      summary: List provider events
      description: List event references for a specific provider.
      operationId: listProviderEvents
      tags: [Provider]
      parameters:
        - $ref: "#/components/parameters/provider"
        - name: status
          in: query
          schema:
            type: string
        - name: sport
          in: query
          schema:
            type: string
        - name: competition
          in: query
          schema:
            type: string
        - name: start_after
          in: query
          schema:
            type: string
            format: date-time
        - name: start_before
          in: query
          schema:
            type: string
            format: date-time
        - name: search
          in: query
          schema:
            type: string
        - $ref: "#/components/parameters/cursor"
        - $ref: "#/components/parameters/limit"
      responses:
        "200":
          description: Paginated list of event references
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: "#/components/schemas/EventReference"
                  pagination:
                    $ref: "#/components/schemas/Pagination"
                  meta:
                    type: object
                    properties:
                      provider:
                        type: string

  /{provider}/events/{id}:
    get:
      summary: Get a provider event
      description: Get a single event reference by ID.
      operationId: getProviderEvent
      tags: [Provider]
      parameters:
        - $ref: "#/components/parameters/provider"
        - name: id
          in: path
          required: true
          schema:
            type: integer
      responses:
        "200":
          description: Event reference
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: "#/components/schemas/EventReference"
                  meta:
                    type: object
                    properties:
                      provider:
                        type: string

  # ============ Metadata Endpoints ============

  /sports:
    get:
      summary: List sports
      description: List all available sports.
      operationId: listSports
      tags: [Metadata]
      responses:
        "200":
          description: List of sports
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: "#/components/schemas/Sport"

  /competitions:
    get:
      summary: List competitions
      description: List available competitions, optionally filtered by sport.
      operationId: listCompetitions
      tags: [Metadata]
      parameters:
        - name: sport
          in: query
          schema:
            type: string
          description: Filter by sport slug
        - name: type
          in: query
          schema:
            type: string
          description: Filter by competition type
      responses:
        "200":
          description: List of competitions
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: "#/components/schemas/Competition"

  /providers:
    get:
      summary: List providers
      description: List all supported prediction market providers with counts.
      operationId: listProviders
      tags: [Metadata]
      responses:
        "200":
          description: List of providers
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: "#/components/schemas/Provider"

  /matching-markets:
    get:
      summary: Find matching markets
      description: Find the same market across different providers. Supply either a canonical market_id or a provider + provider_market_id pair.
      operationId: findMatchingMarkets
      tags: [Cross-Platform]
      parameters:
        - name: market_id
          in: query
          schema:
            type: integer
          description: Canonical market ID
        - name: provider
          in: query
          schema:
            type: string
          description: Provider name (use with provider_market_id)
        - name: provider_market_id
          in: query
          schema:
            type: string
          description: Provider's external market ID
      responses:
        "200":
          description: Market with all provider references
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: "#/components/schemas/Market"
        "404":
          $ref: "#/components/responses/NotFound"

tags:
  - name: Unified
    description: Canonical market and event data aggregated across all providers
  - name: Provider
    description: Raw market data from a specific provider
  - name: Metadata
    description: Discovery endpoints for sports, competitions, and providers
  - name: Cross-Platform
    description: Cross-provider market matching
