{"openapi":"3.1.0","info":{"title":"dino.markets API","summary":"Related Kalshi and Polymarket data: matched markets, live arbitrage, and a real-time stream.","description":"**dino.markets** — related Kalshi and Polymarket prediction-market data for developers and AI agents.\n\nWe match related markets across **Kalshi** and **Polymarket** in sports, crypto, weather, and economics. The API\npublishes the matched feed, confirmed **live arbitrage** when settlement terms align, confidence bands, and a\n**real-time WebSocket stream**.\n\n### Authentication\nEvery endpoint takes your key as a Bearer token: `Authorization: Bearer sk_live_...`.\nProvision a key at https://dino.markets. Every tier gets the REST surface AND a WebSocket stream — Free's is a\ncurated `sample` taste; **Basic/Premium/Pro** get the full market stream.\n\n### Tiers (REST limit is a 60s rps window; the quota is per calendar month)\n| Tier | REST | WebSocket |\n|---|---|---|\n| Free ($0) | 600 req/60s, 10,000/mo | `sample` stream (curated taste), 1 conn |\n| Basic ($30) | 600 req/60s, 1,000,000/mo | full market stream, 3 conns |\n| Premium ($100) | 1500 req/60s, 5,000,000/mo | full market stream, 10 conns |\n| Pro ($200) | 1500 req/60s, 5,000,000/mo | + raw quotes & candidates, 10 conns |\n\n### Real-time\n`POST /v1/stream/token` mints a ~120s connect ticket; connect tokenless to\n`wss://stream.dino.markets/connection/websocket` carrying the ticket in the connect `data.t` field. The server\nderives your channel subscriptions from your tier — the ticket never carries entitlements.\n\n### Markets, arbitrage, and detail\n`GET /v2/markets` returns the matched cross-venue catalog as canonical **Market** objects.\n`GET /v2/arbitrage` returns confirmed **Opportunity** objects with exact selected legs, conservative modeled net\nedge and ROI, explicit fee-model disclosure, executable contract count, USD capital estimate, and snapshot freshness. These are separate resources;\n`signal=arb` is rejected on `/v2/markets`. `GET /v2/pairs/{id}` returns one Market with full settlement disclosure\n(`settlement.parity`, `settlement.risks[]`) and venue ids.\n\nThe default catalog serves `moneyline,outright`. Use `market_type=` for `total`, `spread`, `team_total`, `advance`,\n`weather_high`, `weather_low`, `crypto_above`, `fed_decision`, `econ_print`, or `cb_decision`; pass `all` to remove the default\nfamily filter. Ladder-family rows carry per-leg relation and settlement disclosures rather than fabricated prices.\n\n`Market.signal` is `\"arb\"` (confirmed + backtested cross-venue settlement parity — the earned, risk-locked subset, with\n`potential_arb_pct` populated) or `\"spread\"` (cross-venue gap shown by `spread_pts`, settlement risk disclosed — an\nobservation, not a return).\n\n### AI agents / MCP\nA Model Context Protocol server is mounted at **`/v2/mcp/`** (Streamable HTTP; note the trailing slash, and send your\nkey as the raw `X-API-Key` header). Tools mirror the REST resource split:\n`find_markets`, `find_arbitrage`, `list_markets`, `list_categories`, `get_market`, `get_spreads`, `report_bad_arb`,\n`watch_markets`.\nSee https://dino.markets/llms.txt.\n\n### Categories, context & market families\nEvery Market has `category` and `market_type`. Sports add `sport` and `competition`; weather adds `location`;\ncrypto and commodities add `asset`; economic prints add `indicator` and `basis`; central-bank decisions add\n`institution`. Narrow `/v2/markets` with those explicit fields and call `GET /v2/categories` to discover valid\ncategory, market-type, and contextual-facet combinations.\n\nThe REST snapshot is best-effort and about two minutes delayed on every tier — **not execution-grade**. The gapless,\nexecution-grade feed is the WebSocket push.\n","contact":{"name":"dino.markets","url":"https://dino.markets/"},"license":{"name":"Proprietary"},"version":"2.0.0"},"servers":[{"url":"https://api.dino.markets","description":"Production"}],"paths":{"/health":{"get":{"tags":["ops"],"summary":"Liveness probe (no auth)","operationId":"health_health_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[]}},"/v1/stream/token":{"post":{"tags":["stream"],"summary":"Mint a WebSocket connect ticket (every tier)","operationId":"stream_token_v1_stream_token_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"401":{"description":"Missing, malformed, or revoked API key"},"402":{"description":"Subscription inactive"},"429":{"description":"Per-tier REST rps window (60s) OR monthly quota exceeded — body carries error plus tier/quota/count/window"},"503":{"description":"Auth admission gate full (transient) — retry shortly, see retry_after"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v2/markets":{"get":{"tags":["data"],"summary":"Matched cross-venue catalog (v2)","description":"Canonical market list.\n\nUnfiltered / ?signal=spread: the Market catalog. ?signal=candidates: review-band Market rows.\nArbitrage is a different resource with different identity and execution fields; use GET /v2/arbitrage.\nmarket_type default (moneyline,outright) preserves the pre-family-build row set and existing field\nsemantics — MARKET_FAMILIES.md §2 DoD #2. Additive type discriminators may appear; `all` removes\nthe filter.","operationId":"v2_markets_v2_markets_get","parameters":[{"name":"category","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Category"}},{"name":"sport","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sport"}},{"name":"competition","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Competition"}},{"name":"location","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Location"}},{"name":"asset","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Asset"}},{"name":"indicator","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Indicator"}},{"name":"basis","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Basis"}},{"name":"institution","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Institution"}},{"name":"league","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Deprecated sports-only alias for competition","title":"League"},"description":"Deprecated sports-only alias for competition"},{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Comma-separated: open,live,resolving,closed,settled. Default: open,live","title":"Status"},"description":"Comma-separated: open,live,resolving,closed,settled. Default: open,live"},{"name":"signal","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"spread | candidates. Arbitrage is GET /v2/arbitrage","title":"Signal"},"description":"spread | candidates. Arbitrage is GET /v2/arbitrage"},{"name":"sort","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"start_time | -start_time | -spread_pts","default":"start_time","title":"Sort"},"description":"start_time | -start_time | -spread_pts"},{"name":"include","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"ids,depth,settlement","title":"Include"},"description":"ids,depth,settlement"},{"name":"market_type","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Comma-separated: moneyline,outright,total,spread,team_total,advance,weather_high,weather_low,crypto_above,fed_decision,econ_print,cb_decision,all. Default: moneyline,outright","title":"Market Type"},"description":"Comma-separated: moneyline,outright,total,spread,team_total,advance,weather_high,weather_low,crypto_above,fed_decision,econ_print,cb_decision,all. Default: moneyline,outright"},{"name":"game_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Exact match on the family grouping key","title":"Game Id"},"description":"Exact match on the family grouping key"},{"name":"has_history","in":"query","required":false,"schema":{"type":"boolean","description":"Resolved markets only: require real price history","default":false,"title":"Has History"},"description":"Resolved markets only: require real price history"},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"description":"Page through history-backed resolved markets","default":1,"title":"Page"},"description":"Page through history-backed resolved markets"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":1000,"minimum":1,"default":500,"title":"Limit"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"401":{"description":"Missing or invalid API key"},"402":{"description":"Subscription inactive"},"429":{"description":"Rate limit exceeded"},"503":{"description":"Auth admission gate full (transient) — retry shortly, see retry_after"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v2/arbitrage":{"get":{"tags":["data"],"summary":"Confirmed cross-venue arbitrage opportunities (v2)","description":"Confirmed, engine-fired Opportunities with one exact selected execution leg per outcome. Money\nfields name USD/contract units, include venue fees under the disclosed conservative_per_contract model,\nand distinguish payout edge from modeled ROI. Every row is rechecked against the current matched market\nbefore serving; stale or malformed rows fail closed. This is not a Market object or /v2/markets filter.","operationId":"v2_arbitrage_v2_arbitrage_get","parameters":[{"name":"sport","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sport"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":500,"minimum":1,"default":100,"title":"Limit"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ArbitrageResponse"}}}},"401":{"description":"Missing or invalid API key"},"402":{"description":"Subscription inactive"},"429":{"description":"Rate limit exceeded"},"503":{"description":"Auth admission gate full (transient) — retry shortly, see retry_after"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v2/pairs/{market_id}":{"get":{"tags":["data"],"summary":"Canonical market detail (v2)","description":"One canonical market object with include=ids,depth,settlement applied by default.\n\nAccepts `dino_<uuid>` OR bare UUID.","operationId":"v2_pair_detail_v2_pairs__market_id__get","parameters":[{"name":"market_id","in":"path","required":true,"schema":{"type":"string","title":"Market Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"401":{"description":"Missing or invalid API key"},"402":{"description":"Subscription inactive"},"404":{"description":"Pair not found"},"429":{"description":"Rate limit exceeded"},"503":{"description":"Auth admission gate full (transient) — retry shortly, see retry_after"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v2/pairs/{market_id}/history":{"get":{"tags":["data"],"summary":"Per-outcome price history (v2)","description":"Per-outcome Kalshi/Polymarket ask history for one pair, oldest->newest, for the /live/[id] chart.\n\nAccepts `dino_<uuid>` OR bare UUID. Empty `series` when the sampler hasn't captured this pair yet\n(a brand-new pair, or one seen only within the current sample bucket) — never a 404 for that.\n\n§131b: trims trailing points newer than now - REST_DELAY_S (same uniform delay as every other REST\nprice surface — a chart must not show the price ~2min ahead of what /v2/markets/pairs serve for the\nsame pair). The sampler buckets at _PH_BUCKET_S (60s), so this drops at most ceil(delay/60)+1 points\n(~2 points at the 120s default).","operationId":"v2_pair_history_v2_pairs__market_id__history_get","parameters":[{"name":"market_id","in":"path","required":true,"schema":{"type":"string","title":"Market Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"401":{"description":"Missing or invalid API key"},"402":{"description":"Subscription inactive"},"404":{"description":"Pair not found"},"429":{"description":"Rate limit exceeded"},"503":{"description":"Auth admission gate full (transient) — retry shortly, see retry_after"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v2/categories":{"get":{"tags":["data"],"summary":"Market categories and valid contextual discovery facets (v2)","description":"Normalized categories plus market types and category-valid contextual facets.","operationId":"v2_categories_v2_categories_get","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"401":{"description":"Missing or invalid API key"},"402":{"description":"Subscription inactive"},"429":{"description":"Rate limit exceeded"},"503":{"description":"Auth admission gate full (transient) — retry shortly, see retry_after"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v2/search":{"get":{"tags":["data"],"summary":"Free-text market/event lookup by title, normalized context, or native id (v2)","description":"Market/event lookup by free text — the MCP find_markets front door (UNIFIED_PLAN §7: \"an agent that\ncan't FIND a market can't use anything else\"). Available to every tier — it reads the same uniformly-\ndelayed catalog REST already serves (§131), never a live/paid-only surface.\n\nSources from db.search() -- the SAME matched_markets predicate markets() uses (active/review,\ncomplete_coverage, entity_confidence>=0.95), matched case-insensitively against team/league/sport/\nmarket_type/slugs/native ids. Identity-only (no live price join): a lookup tool doesn't need prices,\njust enough to hand a market_id to /v2/markets or /v2/pairs/{id} for pricing detail — this keeps the\nendpoint fast and avoids duplicating the Centrifugo-history join machinery for a discovery surface.","operationId":"v2_search_v2_search_get","parameters":[{"name":"q","in":"query","required":true,"schema":{"type":"string","minLength":1,"maxLength":100,"description":"Free text: title, team, competition, location, asset, or institution","title":"Q"},"description":"Free text: title, team, competition, location, asset, or institution"},{"name":"category","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Category"}},{"name":"sport","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sport"}},{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Comma-separated: open,live,resolving,closed,settled. Default: open,live","title":"Status"},"description":"Comma-separated: open,live,resolving,closed,settled. Default: open,live"},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1,"title":"Page"}},{"name":"page_size","in":"query","required":false,"schema":{"type":"integer","maximum":50,"minimum":1,"default":20,"title":"Page Size"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"400":{"description":"Missing/blank q"},"401":{"description":"Missing or invalid API key"},"402":{"description":"Subscription inactive"},"429":{"description":"Rate limit exceeded"},"503":{"description":"Auth admission gate full (transient) — retry shortly, see retry_after"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v2/spreads":{"get":{"tags":["data"],"summary":"Cross-venue price-gap view over matched pairs (v2)","description":"The Market-shaped spread-observation counterpart to /v2/arbitrage: matched pairs whose resolution rule\nmarks them spread-only (never arb-fireable) but that still carry a live, disclosed cross-venue price\ngap. Same tier availability as the arb surface — every active-subscription tier, gated only by the\ngeneric account/rate-limit check (no tier-specific feature gate on this REST surface, §7.1).","operationId":"v2_spreads_v2_spreads_get","parameters":[{"name":"category","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Category"}},{"name":"sport","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sport"}},{"name":"competition","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Competition"}},{"name":"location","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Location"}},{"name":"asset","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Asset"}},{"name":"indicator","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Indicator"}},{"name":"basis","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Basis"}},{"name":"institution","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Institution"}},{"name":"min_gap","in":"query","required":false,"schema":{"anyOf":[{"type":"number","minimum":0},{"type":"null"}],"description":"Minimum spread_pts (cross-venue gap, in points)","title":"Min Gap"},"description":"Minimum spread_pts (cross-venue gap, in points)"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":500,"minimum":1,"default":100,"title":"Limit"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"401":{"description":"Missing or invalid API key"},"402":{"description":"Subscription inactive"},"429":{"description":"Rate limit exceeded"},"503":{"description":"Auth admission gate full (transient) — retry shortly, see retry_after"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v2/coverage":{"get":{"tags":["data"],"summary":"Venue-coverage census — every head-to-head competition on the venues and its aggregation status (v2)","description":"The full Kalshi head-to-head universe (every match-winner series, wired or not) with per-competition status:\naggregated (paired live), pending (wired, awaiting a counterpart or confirmation), quiet (wired, offseason),\nkalshi_only (listed there, no pairing wired), dormant (series exists, nothing open). poly_unpaired carries\nthe sport-level Polymarket surplus. Written hourly by the matcher pass (discovery inversion, 2026-07-04).","operationId":"v2_coverage_v2_coverage_get","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"401":{"description":"Missing or invalid API key"},"402":{"description":"Subscription inactive"},"429":{"description":"Rate limit exceeded"},"503":{"description":"Auth admission gate full (transient) — retry shortly, see retry_after"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v2/report-bad-arb":{"post":{"tags":["feedback"],"summary":"Flag a bad/incorrect arbitrage opportunity (v2)","description":"Port of /v1/report-bad-arb. Verbatim auth + logic.","operationId":"v2_report_bad_arb_v2_report_bad_arb_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"default":{},"title":"Payload"}}}},"responses":{"202":{"description":"Report received","content":{"application/json":{"schema":{}}}},"400":{"description":"No reportable field supplied"},"401":{"description":"Missing or invalid API key"},"402":{"description":"Subscription inactive"},"429":{"description":"Rate limit exceeded"},"503":{"description":"Auth admission gate full (transient) — retry shortly, see retry_after"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}},"components":{"schemas":{"ArbitrageLegResponse":{"properties":{"outcome":{"type":"string","title":"Outcome","description":"Outcome this leg pays $1 on if it resolves true."},"venue":{"type":"string","enum":["kalshi","polymarket"],"title":"Venue"},"side":{"anyOf":[{"type":"string","enum":["yes","no"]},{"type":"null"}],"title":"Side","description":"Kalshi side when the contract requires one; null for a Polymarket outcome token."},"ask_usd":{"type":"number","maximum":1.0,"exclusiveMinimum":0.0,"title":"Ask Usd","description":"USD paid per contract at the selected best ask."},"stake_fraction":{"type":"number","maximum":1.0,"exclusiveMinimum":0.0,"title":"Stake Fraction","description":"Fraction of total wager allocated to this leg, fees included."},"available_contracts":{"type":"number","exclusiveMinimum":0.0,"title":"Available Contracts","description":"Contracts available at ask_usd in the observed book."},"contract_id":{"type":"string","title":"Contract Id","description":"Exact venue ticker or outcome-token id for execution."},"url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Url","description":"Venue event URL when a verified public slug is available."}},"type":"object","required":["outcome","venue","side","ask_usd","stake_fraction","available_contracts","contract_id","url"],"title":"ArbitrageLegResponse"},"ArbitrageResponse":{"properties":{"as_of":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"As Of","description":"Newest priced_at among returned opportunities; null when empty."},"delay_seconds":{"type":"number","minimum":0.0,"title":"Delay Seconds","description":"Configured REST snapshot delay. Use as_of for actual freshness."},"count":{"type":"integer","minimum":0.0,"title":"Count"},"opportunities":{"items":{"$ref":"#/components/schemas/OpportunityResponse"},"type":"array","title":"Opportunities"}},"type":"object","required":["as_of","delay_seconds","count","opportunities"],"title":"ArbitrageResponse"},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"OpportunityResponse":{"properties":{"id":{"type":"string","title":"Id","description":"Stable opportunity id for this open arbitrage window."},"market_id":{"type":"string","title":"Market Id","description":"Stable dino_ market id shared with GET /v2/pairs/{id}."},"title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Title"},"category":{"type":"string","title":"Category"},"market_type":{"type":"string","title":"Market Type"},"sport":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sport"},"competition":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Competition"},"location":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Location"},"asset":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Asset"},"indicator":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Indicator"},"basis":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Basis"},"institution":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Institution"},"tags":{"items":{"type":"string"},"type":"array","title":"Tags"},"start_time":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Start Time"},"edge_pct":{"type":"number","exclusiveMinimum":0.0,"title":"Edge Pct","description":"Conservative modeled net profit as percentage points of the $1 payout, after venue fees."},"roi_pct":{"type":"number","exclusiveMinimum":0.0,"title":"Roi Pct","description":"Conservative modeled net profit divided by max_wager_usd, as a percentage."},"fees_included":{"type":"boolean","const":true,"title":"Fees Included"},"fee_model":{"type":"string","const":"conservative_per_contract","title":"Fee Model","description":"Fees are modeled for one contract per selected leg, then scaled to max_contracts; quantity-level venue rounding can make an executed block differ."},"cost_per_payout_usd":{"type":"number","exclusiveMaximum":1.0,"exclusiveMinimum":0.0,"title":"Cost Per Payout Usd","description":"Conservative fee-inclusive modeled wager for $1 payout."},"max_contracts":{"type":"number","exclusiveMinimum":0.0,"title":"Max Contracts","description":"Snapshot executable equal contract count per outcome."},"max_wager_usd":{"type":"number","exclusiveMinimum":0.0,"title":"Max Wager Usd","description":"Conservative fee-inclusive capital estimate at max_contracts."},"confidence":{"type":"number","maximum":1.0,"minimum":0.95,"title":"Confidence"},"detected_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Detected At","description":"When this arbitrage window first opened."},"priced_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Priced At","description":"When its selected asks and size last changed."},"legs":{"items":{"$ref":"#/components/schemas/ArbitrageLegResponse"},"type":"array","title":"Legs"}},"type":"object","required":["id","market_id","title","category","market_type","tags","start_time","edge_pct","roi_pct","fees_included","fee_model","cost_per_payout_usd","max_contracts","max_wager_usd","confidence","detected_at","priced_at","legs"],"title":"OpportunityResponse"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"},"input":{"title":"Input"},"ctx":{"type":"object","title":"Context"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"}},"securitySchemes":{"bearerApiKey":{"type":"http","scheme":"bearer","description":"Your sk_live_ API key as a Bearer token: `Authorization: Bearer sk_live_...`"}}},"tags":[{"name":"data","description":"The matched cross-venue feed, live arbitrage, and matcher confidence. Free to any active key."},{"name":"stream","description":"Real-time WebSocket access, every tier: mint a connect ticket, then connect to stream.dino.markets. Free gets a curated `sample` taste; Basic/Premium/Pro get the full market stream."},{"name":"feedback","description":"Report a bad or incorrect arbitrage opportunity for review."},{"name":"ops","description":"Health and liveness."}],"security":[{"bearerApiKey":[]}]}