Start here
- Cheat sheet Auth, envelope, and the hero query on one page.
- Understanding odds Read a real moneyline and a player-prop ticket.
- Glossary Juice, moneyline, handle — mapped to Lumify fields.
- Sports Coverage What is live on each sport, surface by surface.
- 5-minute walkthrough Longer first-call path, credits, and troubleshooting.
Quickstart
Get your first Lumify API response in under 60 seconds.
1 — Get your API key
Click Get instant trial key in the banner above — no signup required. Keys look like lmfy-xxxxxx.yyyy… and are passed as a Bearer token on every request. For a persistent account, create a key in your API Keys dashboard.
2 — Make your first request
Fetch today's MLB schedule:
curl "https://lumify.ai/v1/events?sport=mlb&status=scheduled" \
-H "Authorization: Bearer YOUR_API_KEY"
import requests resp = requests.get( "https://lumify.ai/v1/events", params={"sport": "mlb", "status": "scheduled"}, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) games = resp.json()["events"] print(f"{len(games)} games today")
const { events } = await fetch( "https://lumify.ai/v1/events?sport=mlb&status=scheduled", { headers: { "Authorization": "Bearer YOUR_API_KEY" } } ).then(r => r.json()); console.log(`${events.length} games today`);
Response
{
"events": [
{
"id": 9199,
"name": "Atlanta Braves @ San Diego Padres",
"sport": "mlb",
"league": "mlb",
"status": "scheduled",
"starts_at": "2026-06-23T23:40:00Z",
"venue": { "id": 42, "name": "Petco Park", "city": "San Diego" }
}
],
"total": 1,
"next_after_id": null
}
That's a successful call — grab any id from events for the next request.
That's it. From here, explore the full API Reference. Common next steps: look up a player, fetch live odds, or poll a live score.
Next (2 minutes) — Get bet intelligence for a game
Take any id from the events response and fetch its intelligence payload. On MLB, tennis, soccer, NFL, and NCAAF that includes predictive bets[] (probability / fair_price). On NBA, NCAAB, and NHL, available is often false and bets[] is empty — still read forecasts[], or scan the daily board with GET /v1/intelligence/forecasts (MCP list_forecasts). How to read that payload: Understanding Odds. How forecasts work: /docs/forecasts.
curl "https://lumify.ai/v1/events/{id}/intelligence" \ -H "Authorization: Bearer YOUR_API_KEY"
event_id = games[0]["id"] intel = requests.get( f"https://lumify.ai/v1/events/{event_id}/intelligence", headers={"Authorization": "Bearer YOUR_API_KEY"}, ).json() # Print vig-stripped fair prices for bet in intel["bets"]: print(bet["bet_type"], bet.get("probability"), bet.get("fair_price"))
const intel = await fetch( `https://lumify.ai/v1/events/${events[0].id}/intelligence`, { headers: { "Authorization": "Bearer YOUR_API_KEY" } } ).then(r => r.json()); // Print vig-stripped fair prices intel.bets.forEach(b => console.log(b.bet_type, b.probability, b.fair_price));
Prefer a longer walkthrough? See the Quick Start Guide. Agents: /docs/getting-started/quick-start.md.
Introduction
The Lumify v1 API gives you structured, real-time sports intelligence — schedules, live scores, team and player data — all in one consistent interface. Every endpoint is authenticated with a bearer token and returns JSON.
Base URL https://lumify.ai
All timestamps are ISO-8601 UTC strings with a T and a Z (2026-08-12T14:42:19Z). Date-only fields use YYYY-MM-DD. All request bodies and responses use UTF-8 JSON.
Prefer an interactive explorer or a machine-readable contract? The full OpenAPI schema is at /openapi.json — browse it live in ReDoc or Swagger UI.
Authentication
Every /v1/* request must include a valid Lumify API key as a Bearer token. Keys are created in your dashboard and follow the format lmfy-xxxxxx.yyyyyyyy…
Request header
| Header | Value |
|---|---|
Authorization | Bearer YOUR_API_KEY |
Example
curl https://lumify.ai/v1/events \
-H "Authorization: Bearer YOUR_API_KEY"
import requests resp = requests.get( "https://lumify.ai/v1/events", headers={"Authorization": "Bearer YOUR_API_KEY"}, ) data = resp.json()
const resp = await fetch("https://lumify.ai/v1/events", { headers: { "Authorization": "Bearer YOUR_API_KEY" }, }); const data = await resp.json();
Auth errors
| Status | Reason | When it occurs |
|---|---|---|
| 401 | Unauthorized | Missing, malformed, invalid, inactive, or expired API key. Expired keys return the same 401 as invalid keys (no expiry leak). Check Authorization: Bearer lmfy-…. |
| 403 | Forbidden | Valid key but denied for this resource — e.g. sport scope not granted (error.code = sport_scope_denied). See upgrade_url in the error body. |
Rate Limits
Limits are enforced per API key on a sliding 60-second window. Every response — success or error — includes the following headers so you can throttle proactively:
| Response header | Description |
|---|---|
X-RateLimit-Limit | Maximum requests allowed in the window |
X-RateLimit-Remaining | Requests remaining in the current window |
X-RateLimit-Reset | Unix timestamp when the window resets |
X-Credits-Used | Credits charged for this successful authenticated call (variable-cost endpoints may be > 1) |
X-Credits-Remaining | Best-effort remaining balance after this call. Omitted when the plan is unlimited (pure metered PAYG) or the balance cannot be resolved. |
Limits by plan
| Plan | Requests / minute |
|---|---|
| Free Tier | 20 |
| Pay As You Go | 60 |
| Growth | 120 |
| Enterprise | Custom |
Limits are enforced per API key on a sliding 60-second window. Exceeding your limit returns 429 Too Many Requests. No credits are consumed on a 429 response.
429 response
{
"error": {
"code": "rate_limit_exceeded",
"message": "Rate limit exceeded",
"status": 429,
"doc_url": "https://lumify.ai/docs/reference#error-codes",
"retry_after": 23
},
"detail": "Rate limit exceeded"
}
Best practice: Read X-RateLimit-Remaining on every response and back off before you hit zero. When you receive a 429, wait error.retry_after seconds (also mirrored in the Retry-After header) before retrying. Switch on error.code.
Versioning
The API version is part of the path (/v1/…). We guarantee backwards compatibility within a major version. Breaking changes ship under a new prefix (/v2/…) with at least 90 days notice.