# Lumify — Full Machine Reference for AI Agents # https://lumify.ai/llms-full.txt # # Auto-generated from the OpenAPI schema by scripts/gen_llms_full.py — do not edit # by hand. This is the complete endpoint reference; see /llms.txt for the summary. > Lumify is an agent-ready sports intelligence API: schedules, live scores, odds, > public betting splits, and AI-powered bet intelligence (confidence scores, > signal breakdowns, and LLM-generated narratives) across MLB, tennis, soccer > (FIFA World Cup + MLS, EPL, La Liga, Serie A, Bundesliga, Ligue 1, and UEFA > Champions League), NFL, NCAAF, NCAAB, NBA, and NHL. ## Base URL https://lumify.ai ## Authentication Every /v1/* request requires a Bearer API key: Authorization: Bearer lmfy-xxxxxx.yyyyyyyy... Create keys at https://lumify.ai/api-keys or programmatically via POST /api/agent/keys. ## Conventions - Timestamps: ISO-8601 UTC with trailing Z (2026-06-23T23:40:00Z). - Errors: {"error": {"code","message","status","doc_url"}, "detail": "..."} — switch on error.code. - Headers: X-RateLimit-{Limit,Remaining,Reset}, X-Credits-Used, X-Credits-Remaining. - Pagination: cursor-based ?after_id=&limit= (max 100); responses carry next_after_id. - Credits: most calls cost 1 credit; compound/multi-book calls cost 2-3 (see per-endpoint notes). ## Model Context Protocol (MCP) Connect an MCP client to https://lumify.ai/mcp (streamable HTTP), authenticating with your Lumify API key. Tools mirror the endpoints below. ## Endpoints ### GET /api/agent/credit-packs List purchasable credit packs Returns: CreditPackListResponse Fields: data: array, total: integer ### GET /api/agent/credits Get credit balance and usage Returns: AgentCreditsResponse Fields: tier: string | null, credits_used: integer | null, credit_limit: integer | null, bonus_credits: integer | null, total_remaining: integer | null, period_start: string | null, period_end: string | null, is_trial: boolean | null, is_trial_expired: boolean | null ### POST /api/agent/credits/topup Purchase a credit pack Request body: application/json object (see /openapi.json for schema). Returns: CreditTopupResponse Fields: success: boolean | null, credits_added: integer | null, bonus_credits: integer | null, pack_id: integer | null ### GET /api/agent/keys List API keys Returns: AgentApiKeyListResponse Fields: data: array, total: integer ### POST /api/agent/keys Create an API key Request body: application/json object (see /openapi.json for schema). Returns: AgentApiKey Fields: id: integer | null, name: string | null, key_prefix: string | null, scopes: array | null, created_at: string | null, last_used_at: string | null, expires_at: string | null, is_active: boolean | null, key: string | null ### DELETE /api/agent/keys/{key_id} Revoke an API key Parameters: - key_id (integer, required, in=path): Returns: AgentApiKeyRevokeResponse Fields: revoked: boolean, id: integer | null ### POST /mcp MCP JSON-RPC endpoint (streamable HTTP) ### GET /v1/events List events Parameters: - sport (string | null, optional, in=query): Sport slug: nfl, nba, mlb, nhl, tennis, soccer… - league (string | null, optional, in=query): League slug: nfl, nba, atp, fifa_world_cup… - status (string | null, optional, in=query): Event status: scheduled|inprogress|final|… - date (string | null, optional, in=query): UTC date YYYY-MM-DD (single day) - from (string | null, optional, in=query): UTC start date YYYY-MM-DD - to (string | null, optional, in=query): UTC end date YYYY-MM-DD (inclusive) - season_id (integer | null, optional, in=query): Filter by season ID - team_id (integer | null, optional, in=query): Filter to events where this team participates. Resolve ids via GET /v1/teams?q=… - after_id (integer | null, optional, in=query): Cursor: return events with id > after_id - limit (integer, optional, in=query): - include_scores (boolean, optional, in=query): Inline participants + scores in each event. Intended for small result sets (≤ 200 events). - has_recommend (boolean | null, optional, in=query): When true, return only events with at least one recommended bet (has_recommend=1 in intelligence). Requires intelligence pipeline to have run. - sort (string, optional, in=query): Sort order: 'time' (chronological, default) or 'status' (Live → Delayed/Upcoming → Final → Cancelled/Postponed). Cursor pagination (after_id) is not supported with sort=status. Returns: EventListResponse Fields: events: array, total: integer, next_after_id: integer | null ### POST /v1/events/batch Get multiple events in one call Fetch multiple events by id in a single round-trip — for agents that already have a list of ids (e.g. from GET /v1/events) and want full detail for each without issuing one GET per event. Body: {"event_ids": [1, 2, 3], "include_odds": bool, "include_intelligence": bool, "bookmaker": str} Max 25 ids per call. Duplicate ids are billed once. Credits are the sum of each event's normal GET /v1/events/{id} cost — billing fairness applies per event (unavailable odds/intelligence are free; ids that don't exist cost nothing and are returned under "not_found"). Request body: application/json object (see /openapi.json for schema). Returns: BatchEventsResponse Fields: events: array, not_found: array, total: integer ### GET /v1/events/{event_id} Get an event Parameters: - event_id (integer, required, in=path): Lumify event ID - include_odds (boolean, optional, in=query): Inline current odds (all bookmakers) into the response under the 'odds' key. Costs +1 credit (total 2 for this call). - include_intelligence (boolean, optional, in=query): Inline bet intelligence (signals, bets, narratives) into the response under the 'intelligence' key. Costs +1 credit (total 2 for this call). - bookmaker (string | null, optional, in=query): Bookmaker to use for market prices in intelligence.bets[].market when include_intelligence=true. Valid values: pinnacle, fanduel, draftkings. Returns: EventDetail Fields: id: integer, name: string | null, sport: string | null, league: string | null, season_id: integer | null, starts_at: string | null, status: string | null, period: string | null, clock: string | null, venue: object | null, participants: array, updated_at: string | null ### GET /v1/events/{event_id}/intelligence Get bet intelligence for an event Parameters: - event_id (integer, required, in=path): Lumify event ID - bookmaker (string | null, optional, in=query): Bookmaker to use for market.price and market.line in the response. Overrides the system default (pinnacle). Valid values: pinnacle, fanduel, draftkings. Returns: IntelligenceResponse Fields: event_id: integer | null, available: boolean, has_recommend: boolean | null, analyst_take: string | null, match_overview: string | null, intelligence_updated_at: string | null, bets: array ### GET /v1/events/{event_id}/odds Get current betting odds for an event Parameters: - event_id (integer, required, in=path): Lumify event ID - bookmaker (string | null, optional, in=query): Bookmaker filter. Default: pinnacle. Use 'all' or a comma-separated list (e.g. 'fanduel,draftkings') for multiple books. Single book = 1 credit; multiple or 'all' = 2 credits. Returns: OddsResponse Fields: event_id: integer | null, available: boolean, bookmakers: array, last_updated: string | null ### GET /v1/events/{event_id}/odds/history Get line movement history for an event Parameters: - event_id (integer, required, in=path): Lumify event ID - bookmaker (string | null, optional, in=query): Bookmaker filter. Default: pinnacle. Use 'all' or a comma-separated list for multiple books. Single book = 1 credit; multiple or 'all' = 2 credits. - limit (integer, optional, in=query): Max movements to return Returns: OddsHistoryResponse Fields: event_id: integer, movements: array, total: integer ### GET /v1/events/{event_id}/score Get an event's score Parameters: - event_id (integer, required, in=path): Lumify event ID Returns: ScoreResponse Fields: event_id: integer, status: string | null, finished: boolean | null, period: string | null, clock: string | null, scores: array, updated_at: string | null ### GET /v1/events/{event_id}/splits Get public betting splits for an event Parameters: - event_id (integer, required, in=path): Lumify event ID Returns: SplitsResponse Fields: event_id: integer, available: boolean, captured_at: string | null, consensus: object, books: array ### GET /v1/events/{event_id}/stream Stream live score updates (SSE) Parameters: - event_id (integer, required, in=path): Lumify event ID ### GET /v1/health Health ### GET /v1/players List players Parameters: - sport (string | null, optional, in=query): Sport slug, e.g. 'tennis' or 'mlb' - q (string | null, optional, in=query): Name search (partial match) - country (string | null, optional, in=query): ISO 3166-1 alpha-3 country code, e.g. 'USA' - active (boolean | null, optional, in=query): Filter by active status - ranked (boolean | null, optional, in=query): If true, only players with a tennis ranking - after_id (integer, optional, in=query): Cursor: last player id from previous page - limit (integer, optional, in=query): Returns: PlayersListResponse Fields: data: array, has_more: boolean, next_after_id: integer | null ### GET /v1/players/{player_id} Get a player Parameters: - player_id (integer, required, in=path): Returns: Player Fields: id: integer | null, slug: string | null, full_name: string | null, first_name: string | null, last_name: string | null, sport: string | null, country_code: string | null, birthdate: string | null, position: string | null, handedness: string | null, height_cm: integer | null, weight_kg: number | null, tennis_ranking: integer | null, tennis_ranking_points: integer | null, current_team_id: integer | null, current_team_name: string | null, is_active: boolean | null, retired_at: string | null, image_url: string | null ### GET /v1/players/{player_id}/events List a player's events Parameters: - player_id (integer, required, in=path): - status (string | null, optional, in=query): Event status filter - from (string | null, optional, in=query): Start date YYYY-MM-DD - to (string | null, optional, in=query): End date YYYY-MM-DD - after_id (integer, optional, in=query): Cursor: last event id from previous page - limit (integer, optional, in=query): Returns: PlayerEventsResponse Fields: player_id: integer, data: array, has_more: boolean, next_after_id: integer | null ### POST /v1/query Natural-language event search Map a natural-language query to the same filters GET /v1/events accepts, then run that exact list query — results are identical to, and as fresh as, calling /v1/events directly. This is a small rule-based mapper, not an LLM call — see the module-level `_parse_nl_query` docstring for exactly what it recognizes. Body: {"query": "live nfl games today", "limit": 25} An explicit top-level "limit" overrides one parsed from the text. Costs 1 credit, same as GET /v1/events — interpreting the query text is free. Request body: application/json object (see /openapi.json for schema). Returns: NLQueryResponse Fields: query: string, interpreted: NLQueryFilters, unrecognized_terms: array, equivalent_request: string, events: array, total: integer, next_after_id: integer | null ### GET /v1/seasons List seasons Parameters: - sport (string | null, optional, in=query): Filter by sport slug (e.g. nhl, nba, soccer) - current_only (boolean, optional, in=query): Return only currently active seasons Returns: SeasonsListResponse Fields: seasons: array, total: integer ### GET /v1/sports List sports Parameters: - active_only (boolean, optional, in=query): Return only active sports (default true) Returns: SportsListResponse Fields: sports: array, total: integer ### GET /v1/teams List teams Parameters: - sport (string | null, optional, in=query): Sport slug, e.g. 'nba' or 'nhl' - league (string | null, optional, in=query): League slug, e.g. 'nba' - conference (string | null, optional, in=query): Conference filter - division (string | null, optional, in=query): Division filter - country (string | null, optional, in=query): ISO country code, e.g. 'USA' - q (string | null, optional, in=query): Team name search (partial match) - active (boolean | null, optional, in=query): Filter by active status - after_id (integer, optional, in=query): Cursor: last team id from previous page - limit (integer, optional, in=query): Returns: TeamsListResponse Fields: data: array, has_more: boolean, next_after_id: integer | null ### GET /v1/teams/{team_id} Get a team Parameters: - team_id (integer, required, in=path): Lumify team ID Returns: Team Fields: id: integer | null, slug: string | null, name: string | null, short_name: string | null, abbreviation: string | null, sport: string | null, league: string | null, city: string | null, state: string | null, country_code: string | null, conference: string | null, division: string | null, venue: object | null, is_active: boolean | null ### POST /v1/trial-key Issue an instant, unauthenticated trial API key Issues a throwaway API key with no signup or email verification — 100 lifetime credits, 14-day expiry, one per network per 7 days. Requires a valid Cloudflare Turnstile token. Intended for the 'Get instant trial key' button on /docs/ai, not for building a persistent integration — use /register for that. Request body: application/json object (see /openapi.json for schema). ### GET /v1/webhooks List webhook subscriptions Returns: WebhookListResponse Fields: data: array, total: integer ### POST /v1/webhooks Create a webhook subscription Request body: application/json object (see /openapi.json for schema). Returns: WebhookCreateResponse Fields: id: integer | null, url: string | null, event_types: array, sport: string | null, event_id: integer | null, is_active: boolean | null, created_at: string | null, signing_secret: string | null ### DELETE /v1/webhooks/{subscription_id} Delete a webhook subscription Parameters: - subscription_id (integer, required, in=path): Returns: WebhookDeleteResponse Fields: deleted: boolean, id: integer | null ## Error codes - bad_request (400): malformed request or conflicting parameters - unauthorized (401): missing or invalid API key - payment_required (402): credit top-up or payment method required — specific codes: insufficient_credits, daily_credit_cap_exceeded (see error.code; includes upgrade_url / topup_url; daily_credit_cap_exceeded includes resets_at for the rolling 24h free-tier window) - forbidden (403): API key lacks scope for the requested sport (see error.upgrade_url) - not_found (404): resource does not exist - validation_error (422): parameter failed validation (see error.errors[]) - rate_limit_exceeded (429): slow down; see Retry-After and error.retry_after - internal_error (500) / service_unavailable (503): transient server error — retry with backoff ## SDKs - Python: pip install lumify-sdk (import lumify) - TypeScript: npm install @lumifyai/sdk ## Support - Docs: https://lumify.ai/docs - Contact: https://lumify.ai/contact-us