API
Everything the site runs on is a static JSON file served with
Access-Control-Allow-Origin: *. No key, no rate limit, no signup. Cache it —
it changes when the dataset is rebuilt, roughly weekly.
Endpoints
| URL | What | Size |
|---|---|---|
https://badgood.day/api/v1/manifest.json | Version, coverage, links to everything below | ~1 KB |
https://badgood.day/api/v1/countries.json | All 248 markets: code, name, slug, flag, region, tier, timezone | ~40 KB |
https://badgood.day/api/v1/events.json | The curated dataset: 176 dates with signal, guidance, greetings, exact times and occurrences 2026–2030 | ~300 KB |
https://badgood.day/api/v1/holidays/<CC>.json | Public holidays for one market, classified into signals | ~25 KB |
https://badgood.day/api/v1/profiles.json | Population, religion mix and the topic-acceptability matrix per market | ~420 KB |
https://badgood.day/api/v1/cases.json | The case studies behind /fail and /win | ~30 KB |
Answering “can I post on this date?”
There is no query endpoint on purpose — a static file plus five lines of code is faster than a round trip. Pull the two files for a market once and evaluate locally:
const [events, holidays] = await Promise.all([
fetch("https://badgood.day/api/v1/events.json").then(r => r.json()),
fetch("https://badgood.day/api/v1/holidays/US.json").then(r => r.json()),
]);
const on = (market, date) =>
[...events.events, ...holidays]
.filter(e => e.countries.includes(market))
.filter(e => e.occurrences.some(o => o.start <= date && date <= (o.end || o.start)));
const signal = e => e.risk !== "green" ? e.risk : e.opportunity ? "good" : "green";
const worst = ["green", "good", "amber", "red"];
const hits = on("US", "2026-09-11");
const verdict = hits.reduce((a, e) =>
worst.indexOf(signal(e)) > worst.indexOf(a) ? signal(e) : a, "green");
// => "red" · hits[0].name === "September 11 attacks anniversary (Patriot Day)"
Fields worth knowing
risk—red·amber·green. Combine withopportunity: trueto get the fourth signal.occurrences—[{start, end}], ISO dates, inclusive. Multi-day periods are one entry.at— exact moments a country stops, as{t, tz, what}. Convert with the IANA zone.approx— lunar or moon-sighting date, may shift ±1 day.regional/counties— not nationwide.greeting— the phrase used in-market on opportunity dates.
Licence
Dataset CC BY-SA 4.0 (it embeds Wikipedia extracts). Attribution: “On This Day — badgood.day”. Public-holiday rows originate from Nager.Date, Hebcal and the Aladhan Hijri calendar; population and religion figures from the CIA World Factbook (public domain).