Rate limits & pagination

One page an agent can fetch for the complete picture — per-tier limits, sliding-window rules, cursor semantics, and stream caps.

API key Sign in, or get an instant trial key below — no signup required.

Per-tier limits

Limits are enforced per API key on a sliding 60-second window. There is no separate hourly quota.

PlanRequests / minuteNotes
Free Tier20Plus a rolling 24h anti-abuse credit spend cap
Pay As You Go60Metered credits; no monthly credit cap
Growth12010,000 credits included / month
EnterpriseCustomNegotiated

Instant trial keys (no signup) use a tighter anonymous limit. Persistent free-tier keys use the Free row above.

Headers on every response

HeaderMeaning
X-RateLimit-LimitMax requests in the current 60s window
X-RateLimit-RemainingRequests left in the window
X-RateLimit-ResetUnix timestamp when the window resets
X-Credits-UsedCredits charged for this call (0 on errors / available:false)
X-Credits-RemainingBest-effort balance after the call (omitted when unlimited / unknown)
Retry-AfterSeconds to wait (on 429 responses)

429 behavior

json
{
  "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"
}

No credits are consumed on a 429. Switch on error.code and sleep retry_after (or the Retry-After header) before retrying.

Cursor pagination

  • Query params: ?after_id=<last_id>&limit=<n>
  • limit range: 1–100 (defaults vary by endpoint; events default 25)
  • Response field: next_after_id — pass it back as after_id; null means last page
  • Cursor is stable even if new rows are ingested between pages
  • Caveat: sort=status on events does not support after_id — combining them returns 400. Use sort=time (default) for cursor pagination, or fetch a single page with sort=status.
python
import requests

after_id = None
while True:
    params = {"sport": "nba", "limit": 100}
    if after_id:
        params["after_id"] = after_id
    r = requests.get(
        "https://lumify.ai/v1/events",
        headers={"Authorization": "Bearer lmfy-YOUR_KEY"},
        params=params,
        timeout=30,
    )
    r.raise_for_status()
    body = r.json()
    for event in body["events"]:
        process(event)
    after_id = body.get("next_after_id")
    if not after_id:
        break

Both SDKs expose helpers (.paginate() / .iterate() in Python; typed iterators in TypeScript).

SSE concurrency

  • Max 5 concurrent streams per API key
  • Each connection costs 1 credit to open (same as a score poll)
  • Connections close after 5 minutes; the server sends event: reconnect first
  • Both SDKs' stream helpers reopen automatically so a long game looks like one continuous stream

Related: Best practices · Docs overview · Cheat sheet