Public API
Free, no key required, CORS enabled. Rate limited per client. Please cache responses using the ETag we return.
Quick start
Fetch the two newest published Codex events:
curl 'https://tokenresets.com/api/v1/events?provider=openai-codex&limit=2'Open the live JSON response. Read endpoints require no API key and allow cross-origin GET,HEAD, and OPTIONS requests.
Representative response
This abbreviated example is generated from the newest event in the same dataset as the website. Cursor text is descriptive; clients must reuse the opaque value returned by the live endpoint.
{
"data": [
{
"id": "715142ee-d20a-47cf-8d58-dc20c2db9d7d",
"slug": "openai-codex-hard-reset-2026-10-02-eac569d8a1",
"provider": {
"slug": "openai-codex",
"name": "OpenAI Codex"
},
"event_type": "hard_reset",
"status": "published",
"title": "OpenAI Codex: Usage limits reset",
"announced_at": "2026-10-02T21:18:48Z",
"scope": {
"products": [],
"plans": [],
"windows": [],
"scope_evidence": "unknown"
},
"confidence": {
"label": "reported",
"score": 0.5,
"reasons": [
"allowlisted public catalog classifies this item as regular",
"catalog report does not state affected plans",
"published as reported catalog evidence; excluded from interval stats",
"auto-published at confidence reported (0.5)"
]
},
"links": {
"html": "/events/openai-codex-hard-reset-2026-10-02-eac569d8a1",
"self": "/api/v1/events/715142ee-d20a-47cf-8d58-dc20c2db9d7d"
}
}
],
"pagination": {
"next_cursor": "opaque value returned when more rows exist",
"has_more": true,
"limit": 1,
"total": 81
},
"meta": {
"generated_at": "2026-10-03T03:11:38Z",
"schema_version": "1.0",
"non_additive": false,
"non_additive_reason": null
}
}Endpoints
| Method | Path | Description |
|---|---|---|
| GET | /api/v1/health | Service status and operating mode. |
| GET | /api/v1/providers | Published providers with their latest event and coverage. |
| GET | /api/v1/providers/{slug} | Provider detail with statistics, 26-week heatmap, latest event, and latest reset. |
| GET | /api/v1/providers/{slug}/events | Events for one provider. |
| GET | /api/v1/events | All published events, newest first. |
| GET | /api/v1/events/{id-or-slug} | Event detail with evidence and revision history. |
| POST | /api/v1/reactions | Anonymous reaction. One per browser per event. |
| GET | /api/v1/reset-wishes | Current anonymous reset-wish counts by provider. |
| POST | /api/v1/reset-wishes | Add one repeatable reset wish to a provider total. |
| GET | /api/v1/feed.rss | RSS 2.0 feed. |
| GET | /api/v1/feed.atom | Atom 1.0 feed. |
Rate limits and caching
| Surface | Path | Fixed window | Notes |
|---|---|---|---|
| All public API routes | /api/v1/* | 600 requests / 60 seconds | Base fixed-window limit per pseudonymous client key. |
| Event reactions | /api/v1/reactions | 20 requests / 3600 seconds | Additional write limit; the base limit also applies. |
| Reset wishes | /api/v1/reset-wishes | 120 requests / 3600 seconds | Additional POST limit; GET uses only the base limit. |
Responses expose X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset. A rejected request returns 429, anapplication/problem+json body, and Retry-After.
Provider and event JSON is publicly cacheable for60 seconds. RSS and Atom feeds are cacheable for 30 seconds. Reset-wish reads and writes useCache-Control: no-store.
Query parameters
- provider
- Filter by provider slug.
- event_type
- Comma-separated event types.
- from / to
- RFC3339 bounds on announcement time. from is inclusive, to is exclusive.
- limit
- 1 to 100. Defaults to 50.
- cursor
- Opaque pagination cursor from the previous response.
- minimum_confidence
- Feeds only. Defaults to verified.
Response notes
- Every response carries a
metaobject with the generation time and schema version. - Statistics include
includedEventTypes,excludedCount, andexclusionReasonsso you can see exactly what was counted. - Provider detail returns
latest_event,latest_verified_reset, andlatest_published_reset. The last field may be a lower-confidence report.latest_resetremains a verified-only compatibility alias. - Fields the source did not state are
nullor empty withscope_evidence: "unknown". They are never inferred. - Pagination is keyset-based. Pass
next_cursorback ascursor; do not construct cursors yourself. - Errors use
application/problem+jsonand include arequest_id.
Conditional requests
curl -H 'If-None-Match: W/"abc123"' \
https://tokenresets.com/api/v1/eventsA matching ETag returns 304 Not Modified with no body. The ETag is computed from the content only, so it does not change just because you asked again.