Disclosure: we build Codex Reset, an independent community tracker. This walkthrough uses its public data and explains the limits of the resulting analysis.
If you want to study Codex reset timing, the first decision is what to count. A prediction that a reset may happen, an announcement that one happened, and a banked reset granted for later use describe different things. Putting them into one column produces a neat chart with an unclear meaning.
Our earlier terminal guide shows how to query the API and connect an agent. This article takes the next step: save a dataset, reproduce a small calculation, then choose where a live API or MCP query belongs. The previous post explains the forecast itself.
Choose the record that answers your question
There are three useful entry points:
| Your question | Start here | Keep with the result |
|---|---|---|
| What does the historical archive contain? |
/data/codex-resets.json or .csv
|
The downloaded file, retrieval time and source |
| What is the forecast now? | /api/forecast |
Its updated_at, confidence and the forecast label |
| What should an agent retrieve? | /mcp |
The selected tool, returned timestamp and evidence links |
The developer page documents the interfaces. They need no API key. The historical export is a particularly small starting point: it contains event rows rather than all the context in the timeline API.

The English-only developer page, captured November 6, 2026. Setup and the current interface contract live here.
Download once, then analyze that file
Run this in an empty working directory. It needs curl; the analysis below uses Python's standard library.
curl -fsS https://codex-reset.com/data/codex-resets.json \
-A 'reset-history-example/1.0 (+https://codex-reset.com/)' \
-o codex-resets.json
Replace the example User-Agent with your project's name and contact URL when building your own reader. Saving the response makes the analysis inspectable. If the live archive is corrected tomorrow, today's calculation still has an identifiable input.
On November 6, our saved JSON contained 71 events: 59 resets and 12 banked grants. Its updated_at was 2026-11-06T07:21:49.669Z. Those are snapshot counts, not permanent totals. The first recorded event was September 17, 2025; the latest event in that file was a November 1, 2026 banked grant.
The Data Package schema describes eight fields. Three distinctions matter before calculating anything:
-
event_idis a string identifier. Keep it as a string, including when importing CSV into a spreadsheet. Do not use a rounded numeric value as your join key. -
typeisresetorbanked. A post announcing both can contribute two rows with distinct event IDs. Deduplicating by source URL would merge two different facts. -
sourceispostorobserved. An observed-only grant has no publicpost_url; an empty URL does not turn it into a public announcement.
banked_state preserves the grant's recorded state, such as announced, arriving or available. None of those labels means that the recipient redeemed it.
Reproduce a small calculation
Save this as analyze.py, beside the JSON, and run python3 analyze.py:
import hashlib
import json
from collections import Counter
from datetime import datetime
from pathlib import Path
from statistics import median
raw = Path("codex-resets.json").read_bytes()
data = json.loads(raw)
events = data["events"]
ids = [event["event_id"] for event in events]
assert all(isinstance(value, str) for value in ids)
assert len(ids) == len(set(ids)), "Duplicate event IDs"
resets = [event for event in events if event["type"] == "reset"]
times = sorted(
datetime.fromisoformat(event["announced_at"].replace("Z", "+00:00"))
for event in resets
)
gaps = [(b - a).total_seconds() / 86400 for a, b in zip(times, times[1:])]
print("sha256:", hashlib.sha256(raw).hexdigest())
print("updated_at:", data["updated_at"])
print("events:", len(events))
print("types:", dict(Counter(event["type"] for event in events)))
print("sources:", dict(Counter(event["source"] for event in events)))
print("completed intervals:", len(gaps))
if gaps:
print("median historical gap (days):", round(median(gaps), 2))
The November 6 file produced:
events: 71
types: {'reset': 59, 'banked': 12}
sources: {'post': 68, 'observed': 3}
completed intervals: 58
median historical gap (days): 3.56
The program also prints the file hash and update time. Keep those with any published calculation. Sorting parsed UTC timestamps makes the calculation independent of file order. Filtering before calculating gaps prevents a banked grant from shortening the measured interval between reset records.
There are 58 completed intervals between 59 reset rows. The ongoing wait after the last row is absent from that list. The 3.56-day median describes these recorded historical gaps; it is neither a countdown nor the site's current forecast. Our script does not reproduce the forecast model.
The timestamps need care too. The timeline methodology explains their announcement and confirmation context. A recorded time is not a measurement of when every account received a refill. A statistic calculated from those times inherits that limitation.

Dataset provenance on the canonical timeline, captured November 6, 2026. Read it alongside the rows before interpreting a timing statistic.
Use the live API for a live question
A saved export cannot answer what the forecast is now. Query that separately:
curl -fsS https://codex-reset.com/api/forecast \
-A 'reset-history-example/1.0 (+https://codex-reset.com/)' \
-D forecast-headers.txt \
| jq '{updated_at, confidence, last_reset_at,
p24: .probabilities.rounded_24h,
p48: .probabilities.rounded_48h}'
This needs jq as well as curl. Keep updated_at beside the numbers in a dashboard. A successful HTTP response tells you that the request worked; it does not, by itself, tell you that the underlying observation is recent enough for your purpose.
The saved response headers expose x-published-checked-at and x-published-expires-at. The developer contract asks readers to poll at most once a minute and honor Retry-After on a 429 response. During this check, forecast responses had a 60-second cache lifetime; service-status history had 300 seconds. Repeated requests inside the cache window do not create new evidence.
The live timeline also uses a different schema from the export. Its documented reset filter is group == "reset" together with announcement_state == "announced"; exported rows use type. Do not copy a filter between them without reading the schema. /api/feed carries announcement-feed freshness, while /api/status-history answers service-health questions. Neither is a personal quota reading.
Give an agent an evidence question
The MCP server exposes three read-only tools: get_reset_forecast, get_reset_timeline and get_codex_status. Instead of asking an agent to guess whether your allowance changed, ask it for dated evidence and a source link.
Here is a direct call to the timeline tool, tested against this server:
curl -fsS https://codex-reset.com/mcp \
-A 'reset-history-example/1.0 (+https://codex-reset.com/)' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json, text/event-stream' \
-d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"get_reset_timeline","arguments":{"group":"reset","limit":2}}}' \
| jq '.result.content[] | select(.type == "text") | .text | fromjson
| {returned, events: [.events[] | {announced_at, url}]}'
The tool result places JSON inside a text content block, so this example parses that text before selecting the dates and URLs. At our check, the two returned reset dates were October 28 and October 26, 2026. This is a read operation against the public archive; it neither redeems a banked reset nor changes any account's usage.
Preserve the source and the limits
The Hugging Face dataset card labels its copy as an October 12, 2026 snapshot, with 62 events. It is not an automatically refreshed mirror. Choose the canonical live export for current history, or retain a dated download when reproducibility matters. A Data Package can still point at a live CSV, so save the actual data file used in your calculation.
The dataset is released under CC BY 4.0. Preserve provenance, credit the source where your derived result appears, and explain your transformations. For example: “Reset rows only; median of completed recorded intervals; snapshot retrieved November 6, 2026. Data: codex-reset.com.”
This archive cannot establish anyone's personal quota, complete rollout coverage, or the next reset time. It can support a narrower result that somebody else can check: which rows you counted, which timestamps you used, and how you calculated the number.
Codex Reset is an independent community project and is not affiliated with OpenAI. “Codex” is a trademark of OpenAI.
Top comments (0)