High-performance speedrun.com mirror and native v1 API — faster responses, better availability, richer data.
/src and /v1 data are licensed under CC-BY-NC 4.0 — see the Data License for full terms. By using this API you agree to the Terms of Service.
A faithful, high-performance mirror of the speedrun.com public API. Responses are carbon copies of the upstream JSON. No fields added, removed, or transformed. Use as a high-performance, low latency alternative.
The API is live. Full endpoint documentation is undergoing final updates over the next week.
A restructured, normalized schema with fat trimmed and speedrun.io-specific fields added: run statistics, aggregate run analytics, leaderboard snapshots, and daily differential feeds. Public access with the same IP-based rate limits as /src.
🔒 Currently in developer preview. Full public docs will be posted here at release.
Want early access to the native /v1 namespace and other features before they're public? Leave your email and we'll reach out as new previews open up.
| /src | Public — no authentication required |
| /v1 | Public with IP-based rate limits. Bearer token authentication will be available at a future date. |
| Limit | 100 requests / minute |
| Window | 60-second fixed window |
| Scope | Per IP address |
| Exceeded | Returns 429 with Retry-After header |
| Abuse detection | 5 rate-limit hits within 1 hour → blacklisted for 1 hour |
| Gametypes, platforms, regions | 30 days |
| Games, series | 7 days |
| Categories, levels, variables, users, runs (single) | 1 day |
| Runs (list), leaderboards | 5 minutes |
Cache duration is deliberately kept well under how often each resource type is actually re-scraped from speedrun.com, so the cache is never the limiting factor on data freshness.
All responses use application/json. Successful responses wrap the payload in a top-level data field alongside a status code.
{
"status": 200,
"data": { ... }
}
Error responses use a nested error object with a code and human-readable msg. Request metadata (request ID, timing, URI) is returned in response headers, not the body. This keeps successful response bodies pure, cacheable data.
{
"status": 400,
"error": { "code": "BAD_REQUEST", "msg": "invalid id: must be 8 characters" }
}
| 400 | Invalid input (malformed ID, bad or unsupported parameter) |
| 403 | Path doesn't exist, unsupported endpoint |
| 404 | Valid request, record not found |
| 404 | Content too large, specific to embedding |
| 429 | Rate limit exceeded |
| 500 | Internal server error |
| 501 | Endpoint is planned but not yet implemented — see Current Status |
Additional status codes apply to the /v1 namespace and will be documented alongside its public release.
| Header | Required | Description |
|---|---|---|
| User-Agent | Optional, recommended | Identify your application (e.g. my-app/1.2.0). Not enforced, but including it helps us reach out and help debug your integration, specifically if something looks off on our end. An unidentified client is much harder to trace through logs. |
| Header | Scope | Description |
|---|---|---|
| X-SRIO-Request-ID | Always | UUID for this request |
| X-SRIO-Perf | Always | Handler execution time in milliseconds |
| X-SRIO-Timestamp | Always | Unix timestamp of request start |
| X-SRIO-URI | Always | Request URI including query string |
| X-SRIO-SRCRef | 200 responses only | mirrored — response is a carbon copy of speedrun.com. generated — assembled by speedrun.io |
| X-RateLimit-Limit | Always (non-exempt) | Configured request limit (default 100/min) |
| X-RateLimit-Remaining | Always (non-exempt) | Remaining requests in window |
| X-RateLimit-Reset | Always (non-exempt) | Unix timestamp when window resets |
| X-RateLimit-Method | Always | Always ip — rate limiting is IP-scoped |
| X-RateLimit-Namespace | Always | src on this namespace |
| X-RateLimit-Exempt | Exempt IPs only | "true" for whitelisted IPs |
| Retry-After | 429 responses only | Seconds until retry is allowed |
GET /src/health returns 200 with {"status":"ok"} when all dependencies are reachable, or 503 with {"status":"degraded","unhealthy":[...]} naming which one isn't. No authentication or rate limiting applies.
speedrun.com uses base36-encoded IDs for all records, always exactly 8 characters (e.g. 02q8o4p2). The /src namespace enforces this width strictly. An ID with fewer than 8 characters or extra padding is not a valid ID and returns 400. This matches speedrun.com's own behavior for canonical lookups, not a stricter-than-upstream restriction. The games endpoint allows an exception for the "abbreviation" field (e.g. sm64, celeste) and returns a 302 redirect when appropriate, as per the original API specification.
The /v1 namespace uses independently generated speedrun.io IDs — source IDs are not used in /v1 endpoint URIs. A dedicated mapping endpoint for resolving a /src ID to its corresponding /v1 ID is planned; details will be published here once finalized.
Until we have a formal ticket system in place, feel free to email any questions, issues, feature requests or general feedback to [email protected].