{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://artifacts.apis.io/owlsinsight-com/json-schema/owlsinsight-com-evresponse-schema.json",
  "title": "EVResponse",
  "description": "Response for `GET /api/v1/{sport}/ev` (MVP+). Pre-game value bets only.\n\nNo opportunity is listed while the odds snapshot behind the answer is over 90\nseconds old, or for a game that has started. Within that, a sportsbook price must be\nunder 3 minutes old and an exchange quote (Novig by default, Kalshi and Polymarket\nwith `venues: true`) under 2 minutes, each by its own timestamp.\n\nThe optional fields (`kind`, `fairUnadjusted`, `roi`, `fee`, `tradeable`, `reason`,\n`route`, `size`, `link` and `quoteAgeMs` on an opportunity, `canonicalEventId` and\n`fair` on an event, `board` in `meta`) come with `fair_method: \"fair_v1\"`.",
  "x-generated": "2026-10-31",
  "x-method": "derived",
  "x-generator": "derive-json-schema.py",
  "x-source": "openapi/owlsinsight-com-openapi.json#/components/schemas/EVResponse",
  "properties": {
    "data": {
      "items": {
        "$ref": "#/$defs/EVEvent"
      },
      "type": "array"
    },
    "meta": {
      "properties": {
        "board": {
          "$ref": "#/$defs/EVBoard",
          "description": "The board the response was read from. Sent with `fair_method: \"fair_v1\"`."
        },
        "book": {
          "type": "string"
        },
        "events": {
          "format": "double",
          "type": "number"
        },
        "fair_method": {
          "description": "How the fair is computed: `fair_v1` (Pinnacle's de-vigged line, the other books only veto, a 1-point margin). `consensus_devig_median` is the method it replaced.",
          "type": "string"
        },
        "freshness": {
          "description": "Age of the odds snapshot behind the answer. `ageSeconds` is always a number; `stale` is true when the snapshot is over 90 seconds old or there is no data.",
          "properties": {
            "ageSeconds": {
              "format": "double",
              "type": "number"
            },
            "stale": {
              "type": "boolean"
            }
          },
          "type": "object",
          "x-owls-required": [
            "ageSeconds",
            "stale"
          ]
        },
        "market": {
          "type": "string",
          "x-extensible-enum": [
            "h2h"
          ]
        },
        "max_ev": {
          "format": "double",
          "type": "number"
        },
        "min_ev": {
          "format": "double",
          "type": "number"
        },
        "odds_format": {
          "type": "string",
          "x-extensible-enum": [
            "american"
          ]
        },
        "opportunities": {
          "format": "double",
          "type": "number"
        },
        "pregame_only": {
          "type": "boolean"
        },
        "sport": {
          "type": "string"
        },
        "timestamp": {
          "description": "When the odds snapshot behind the answer was written (ISO 8601); `1970-01-01T00:00:00.000Z` when there is no data at all.",
          "type": "string"
        }
      },
      "type": "object",
      "x-owls-required": [
        "sport",
        "market",
        "odds_format",
        "min_ev",
        "max_ev",
        "fair_method",
        "pregame_only",
        "events",
        "opportunities",
        "timestamp",
        "freshness"
      ]
    },
    "success": {
      "type": "boolean"
    }
  },
  "type": "object",
  "x-owls-required": [
    "success",
    "data",
    "meta"
  ],
  "$defs": {
    "EVBoard": {
      "description": "The board an EV response was read from, and how old it is.",
      "properties": {
        "ageMs": {
          "description": "Age of the board when this response was sent, in milliseconds; null when there is no board.",
          "format": "double",
          "type": [
            "number",
            "null"
          ]
        },
        "builtAt": {
          "description": "When the board was built (ISO 8601); null when there is no board.",
          "type": [
            "string",
            "null"
          ]
        },
        "stale": {
          "description": "True when there is no board or it is too old: no EV is served from it.",
          "type": "boolean"
        },
        "venueQuotes": {
          "description": "Whether the board holds Kalshi or Polymarket quotes.",
          "type": "boolean"
        },
        "venues": {
          "description": "Whether this request asked for Kalshi and Polymarket (`venues=true`).",
          "type": "boolean"
        }
      },
      "type": "object",
      "x-owls-required": [
        "builtAt",
        "ageMs",
        "stale",
        "venues",
        "venueQuotes"
      ]
    },
    "EVEvent": {
      "description": "A game with its fair and the +EV opportunities found across books.",
      "properties": {
        "awayTeam": {
          "type": "string"
        },
        "booksInConsensus": {
          "description": "Independent price sources behind the event's fair.",
          "format": "double",
          "type": "number"
        },
        "canonicalEventId": {
          "description": "Our stable id of the game, `{sport}:{away}@{home}-{date}`: the `eventId` the odds board and the history endpoints use. Null when unknown.",
          "type": [
            "string",
            "null"
          ]
        },
        "commenceTime": {
          "type": "string"
        },
        "eventId": {
          "description": "The game's `id` on the odds board. The history endpoints take `canonicalEventId` instead.",
          "type": "string"
        },
        "fair": {
          "$ref": "#/$defs/EVFair",
          "description": "How the fair was formed, and the fair per side before the margin."
        },
        "fairProbability": {
          "description": "The conservative fair per side (the fair minus 1 percentage point); null for a side with no fair. The fair before the margin is in `fair`.",
          "properties": {
            "away": {
              "format": "double",
              "type": [
                "number",
                "null"
              ]
            },
            "draw": {
              "format": "double",
              "type": [
                "number",
                "null"
              ]
            },
            "home": {
              "format": "double",
              "type": [
                "number",
                "null"
              ]
            }
          },
          "type": "object",
          "x-owls-required": [
            "home",
            "away",
            "draw"
          ]
        },
        "homeTeam": {
          "type": "string"
        },
        "market": {
          "type": "string",
          "x-extensible-enum": [
            "h2h"
          ]
        },
        "opportunities": {
          "description": "Best EV first.",
          "items": {
            "$ref": "#/$defs/EVOpportunity"
          },
          "type": "array"
        },
        "sport": {
          "type": "string"
        }
      },
      "type": "object",
      "x-owls-required": [
        "eventId",
        "sport",
        "homeTeam",
        "awayTeam",
        "commenceTime",
        "market",
        "fairProbability",
        "booksInConsensus",
        "opportunities"
      ]
    },
    "EVFair": {
      "description": "How an event's fair was formed, and the fair per side before the 1-point margin.\nEach side is de-vigged on its own, conservatively, so the sides can sum to slightly\nless than 1.",
      "properties": {
        "anchor": {
          "description": "Which Pinnacle line anchored the fair: the realtime feed or the /odds entry; null when Pinnacle did not.",
          "type": [
            "string",
            "null"
          ],
          "x-extensible-enum": [
            "odds",
            "realtime"
          ]
        },
        "away": {
          "description": "Fair probability of an away win before the margin; null when there is none.",
          "format": "double",
          "type": [
            "number",
            "null"
          ]
        },
        "draw": {
          "description": "Fair probability of a draw before the margin (three-way markets); null otherwise.",
          "format": "double",
          "type": [
            "number",
            "null"
          ]
        },
        "home": {
          "description": "Fair probability of a home win before the margin; null when there is none.",
          "format": "double",
          "type": [
            "number",
            "null"
          ]
        },
        "method": {
          "description": "`pinnacle`: Pinnacle's de-vigged line. `consensus`: no Pinnacle line, so the median\nof at least three independent books; only venues are scored against it, never a\nsportsbook. Null when there is no fair (`reason` says why).",
          "type": [
            "string",
            "null"
          ],
          "x-extensible-enum": [
            "consensus",
            "pinnacle"
          ]
        },
        "reason": {
          "description": "Why there is no fair, in plain text; null when there is one.",
          "type": [
            "string",
            "null"
          ]
        },
        "sources": {
          "description": "Independent price sources behind the event's fair.",
          "format": "double",
          "type": "number"
        }
      },
      "type": "object",
      "x-owls-required": [
        "method",
        "anchor",
        "sources",
        "reason",
        "home",
        "away",
        "draw"
      ]
    },
    "EVOpportunity": {
      "description": "One +EV opportunity: a sportsbook price, or a venue's ask (an exchange such as Novig,\nand with `venues: true` the prediction markets Kalshi and Polymarket), that beats the\nfair.\n\nThe fair is Pinnacle's de-vigged line: the other books do not move it, they only\nveto a side they disagree with (when Pinnacle has no line, a venue can be scored\nagainst a consensus of books instead; see `EVFair.method`). `fairProbability` is the\nCONSERVATIVE fair, the fair minus 1 percentage point, and `fairPrice`, `evPct`,\n`edgePp` and `kellyFraction` are all computed at it. The fair before that margin is\n`fairUnadjusted`.",
      "properties": {
        "book": {
          "description": "Sportsbook or venue key. `kalshi` and `polymarket` are listed only with `venues: true`.",
          "type": "string"
        },
        "bookImplied": {
          "description": "Implied probability of `bookPrice` (a sportsbook's includes its vig; a venue's is its ask).",
          "format": "double",
          "type": "number"
        },
        "bookPrice": {
          "description": "American odds of the price: a sportsbook's price, or a venue's ask.",
          "format": "double",
          "type": "number"
        },
        "booksInConsensus": {
          "description": "Independent price sources behind the fair this price was scored against. A\nsportsbook's own feed never counts toward its own fair, so 1 means Pinnacle alone.",
          "format": "double",
          "type": "number"
        },
        "edgePp": {
          "description": "(fairProbability - bookImplied) * 100, in percentage points.",
          "format": "double",
          "type": "number"
        },
        "evPct": {
          "description": "Expected value %, at `fairProbability`. Sportsbook: `(fairProbability * decimalOdds - 1) * 100`.\nVenue, its fee included: `(fairProbability - ask - fee) / (ask + fee) * 100`.",
          "format": "double",
          "type": "number"
        },
        "fairPrice": {
          "description": "American odds of `fairProbability` (the break-even price).",
          "format": "double",
          "type": "number"
        },
        "fairProbability": {
          "description": "The conservative fair probability of this outcome: the fair minus 1 percentage point. `fairPrice`, `evPct`, `edgePp` and `kellyFraction` are computed at it.",
          "format": "double",
          "type": "number"
        },
        "fairUnadjusted": {
          "description": "The fair probability before the 1-point margin: `fairProbability` is this minus 0.01.",
          "format": "double",
          "type": "number"
        },
        "fee": {
          "description": "The venue's trading fee per contract, in dollars; 0 for a sportsbook.",
          "format": "double",
          "type": "number"
        },
        "kellyFraction": {
          "description": "Full-Kelly bankroll fraction at `fairProbability`.",
          "format": "double",
          "type": "number"
        },
        "kind": {
          "description": "`book` for a sportsbook, `venue` for an exchange or prediction market (Novig, Kalshi, Polymarket).",
          "type": "string",
          "x-extensible-enum": [
            "book",
            "venue"
          ]
        },
        "link": {
          "description": "The market's page at the venue; null for a sportsbook.",
          "type": [
            "string",
            "null"
          ]
        },
        "market": {
          "type": "string",
          "x-extensible-enum": [
            "h2h"
          ]
        },
        "quoteAgeMs": {
          "description": "Age of the price when this answer was served, in milliseconds, by its own timestamp; null when unknown.",
          "format": "double",
          "type": [
            "number",
            "null"
          ]
        },
        "reason": {
          "description": "Why it is not tradeable, in plain text (such as `EV under 2%`); null when it is.",
          "type": [
            "string",
            "null"
          ]
        },
        "roi": {
          "description": "`evPct / 100`, not rounded: EV per dollar staked (sportsbook) or per dollar paid, fee included (venue).",
          "format": "double",
          "type": "number"
        },
        "route": {
          "description": "Kalshi and Polymarket: the contract to buy, `yes`, or `no:<CODE>` (NO on the opponent's market). Null otherwise.",
          "type": [
            "string",
            "null"
          ]
        },
        "side": {
          "type": "string",
          "x-extensible-enum": [
            "away",
            "draw",
            "home"
          ]
        },
        "size": {
          "description": "Dollars available at the ask; null when unknown (Polymarket, sportsbooks).",
          "format": "double",
          "type": [
            "number",
            "null"
          ]
        },
        "team": {
          "type": "string"
        },
        "tradeable": {
          "description": "Whether the opportunity clears the markets page trade bar. Sportsbook: EV of at\nleast 2%. Venue: EV of at least 4%, a bid, a spread of 4 cents or less and at least\n$50 at the ask.",
          "type": "boolean"
        }
      },
      "type": "object",
      "x-owls-required": [
        "book",
        "market",
        "side",
        "team",
        "bookPrice",
        "bookImplied",
        "fairProbability",
        "fairPrice",
        "evPct",
        "edgePp",
        "kellyFraction",
        "booksInConsensus"
      ]
    }
  }
}