API reference
Base URL https://chronosapi.dev. Every endpoint returns JSON over HTTPS. Examples in curl, Python, JavaScript, and C#. The language tabs stay in sync as you read.
Authentication
Pass your key in the X-Api-Key header. A key takes one signup with
an email address (free tier included) and is shown
once, at creation. Lost keys are replaced, not recovered: POST /v1/rotate
with your email revokes the old key and mails a new one.
curl "https://chronosapi.dev/v1/check?region=US&date=2027-11-25" -H "X-Api-Key: $KEY"import requests
r = requests.get("https://chronosapi.dev/v1/check",
headers={"X-Api-Key": KEY},
params={'region': 'US', 'date': '2027-11-25'})
r.raise_for_status()
print(r.json())const r = await fetch("https://chronosapi.dev/v1/check?region=US&date=2027-11-25", {
headers: { "X-Api-Key": KEY },
});
if (!r.ok) throw new Error(`chronos: ${r.status}`);
console.log(await r.json());using var http = new HttpClient();
http.DefaultRequestHeaders.Add("X-Api-Key", key);
var json = await http.GetStringAsync(
"https://chronosapi.dev/v1/check?region=US&date=2027-11-25");
Console.WriteLine(json);Where headers are awkward, as with calendar feeds and spreadsheet imports,
?api_key= works as a query parameter. Treat URLs containing it as
secrets: they end up in logs.
Keys come in two kinds. Your secret key (ck_...)
belongs on servers and never in a browser. For client-side code and widgets,
mint a publishable key: origin-locked, read-only, and
safe to ship. CORS is open on the whole API; the key is the gate.
Limits
| Plan | Requests / day | Price |
|---|---|---|
| Free | 100 | $0 |
| Developer | 2,500 | $7 / month |
| Starter | 10,000 | $15 / month |
| Pro | 100,000 | $49 / month |
| Business | 500,000 | $149 / month |
| Enterprise | negotiated | from $500 / month |
Every response carries X-RateLimit-Limit and
X-RateLimit-Used. Limits reset at midnight UTC. Requests over the
limit return 429 and are not counted against you. Batch operations
meter per inner operation.
Errors
Errors are { "error": { "code", "message" } } with a matching
HTTP status. The codes worth handling:
| Status | Code | Meaning |
|---|---|---|
| 400 | bad_date · bad_terms · bad_rule | Malformed input. Dates are yyyy-MM-dd. |
| 401 | missing_key · invalid_key | No key, or a revoked one. |
| 404 | unknown_region | Not in /v1/regions. |
| 422 | out_of_range | The result would leave 2020–2035. We refuse rather than guess. |
| 429 | quota_exceeded | Daily limit reached. |
GET /v1/check
Classify one date: business day, weekend, or holiday, with the next business day included.
| Parameter | Notes |
|---|---|
region | ISO 3166 code, subdivision, or market · see /v1/regions |
date | yyyy-MM-dd |
curl "https://chronosapi.dev/v1/check?region=US&date=2027-11-25" -H "X-Api-Key: $KEY"import requests
r = requests.get("https://chronosapi.dev/v1/check",
headers={"X-Api-Key": KEY},
params={'region': 'US', 'date': '2027-11-25'})
r.raise_for_status()
print(r.json())const r = await fetch("https://chronosapi.dev/v1/check?region=US&date=2027-11-25", {
headers: { "X-Api-Key": KEY },
});
if (!r.ok) throw new Error(`chronos: ${r.status}`);
console.log(await r.json());using var http = new HttpClient();
http.DefaultRequestHeaders.Add("X-Api-Key", key);
var json = await http.GetStringAsync(
"https://chronosapi.dev/v1/check?region=US&date=2027-11-25");
Console.WriteLine(json);Response
{ "region": "US", "date": "2027-11-25", "business_day": false,
"weekend": false, "holiday": true, "next_business_day": "2027-11-26" }
GET /v1/add
Add or subtract business days. days may be negative; zero returns the start date unchanged. The primitive under settlement dates and simple deadlines.
| Parameter | Notes |
|---|---|
region | calendar to use · XNYS here, so Good Friday counts as closed |
start | yyyy-MM-dd |
days | -5000 to 5000 |
curl "https://chronosapi.dev/v1/add?region=XNYS&start=2027-03-25&days=2" -H "X-Api-Key: $KEY"import requests
r = requests.get("https://chronosapi.dev/v1/add",
headers={"X-Api-Key": KEY},
params={'region': 'XNYS', 'start': '2027-03-25', 'days': '2'})
r.raise_for_status()
print(r.json())const r = await fetch("https://chronosapi.dev/v1/add?region=XNYS&start=2027-03-25&days=2", {
headers: { "X-Api-Key": KEY },
});
if (!r.ok) throw new Error(`chronos: ${r.status}`);
console.log(await r.json());using var http = new HttpClient();
http.DefaultRequestHeaders.Add("X-Api-Key", key);
var json = await http.GetStringAsync(
"https://chronosapi.dev/v1/add?region=XNYS&start=2027-03-25&days=2");
Console.WriteLine(json);Response
{ "region": "XNYS", "start": "2027-03-25", "days": 2, "result": "2027-03-30" }
GET /v1/count
Business days between two dates, inclusive of both ends. Negative when to precedes from, so count(a,b) = -count(b,a) always holds.
| Parameter | Notes |
|---|---|
region | subdivisions carry their own holidays · Bavaria observes Epiphany; Berlin does not |
from, to | yyyy-MM-dd |
curl "https://chronosapi.dev/v1/count?region=DE-BY&from=2027-01-01&to=2027-01-31" -H "X-Api-Key: $KEY"import requests
r = requests.get("https://chronosapi.dev/v1/count",
headers={"X-Api-Key": KEY},
params={'region': 'DE-BY', 'from': '2027-01-01', 'to': '2027-01-31'})
r.raise_for_status()
print(r.json())const r = await fetch("https://chronosapi.dev/v1/count?region=DE-BY&from=2027-01-01&to=2027-01-31", {
headers: { "X-Api-Key": KEY },
});
if (!r.ok) throw new Error(`chronos: ${r.status}`);
console.log(await r.json());using var http = new HttpClient();
http.DefaultRequestHeaders.Add("X-Api-Key", key);
var json = await http.GetStringAsync(
"https://chronosapi.dev/v1/count?region=DE-BY&from=2027-01-01&to=2027-01-31");
Console.WriteLine(json);Response
{ "region": "DE-BY", "from": "2027-01-01", "to": "2027-01-31", "business_days": 19 }
GET /v1/due-date
Invoice date plus payment terms, rolled forward to a real working day when the nominal date lands on a weekend or holiday. Terms grammar: net30 (calendar days), net10b (business days), eom, eom+15.
| Parameter | Notes |
|---|---|
invoice_date | yyyy-MM-dd |
terms | net<n>, net<n>b, eom, eom+<n> |
curl "https://chronosapi.dev/v1/due-date?region=US&invoice_date=2027-01-15&terms=net30" -H "X-Api-Key: $KEY"import requests
r = requests.get("https://chronosapi.dev/v1/due-date",
headers={"X-Api-Key": KEY},
params={'region': 'US', 'invoice_date': '2027-01-15', 'terms': 'net30'})
r.raise_for_status()
print(r.json())const r = await fetch("https://chronosapi.dev/v1/due-date?region=US&invoice_date=2027-01-15&terms=net30", {
headers: { "X-Api-Key": KEY },
});
if (!r.ok) throw new Error(`chronos: ${r.status}`);
console.log(await r.json());using var http = new HttpClient();
http.DefaultRequestHeaders.Add("X-Api-Key", key);
var json = await http.GetStringAsync(
"https://chronosapi.dev/v1/due-date?region=US&invoice_date=2027-01-15&terms=net30");
Console.WriteLine(json);Response
{ "invoice_date": "2027-01-15", "terms": "net30",
"nominal_due": "2027-02-14", "due_date": "2027-02-16", "rolled": true }
GET /v1/paydays
A year of pay dates from a rule. Dates landing on weekends or holidays roll backward: payroll pays early, never late. December 2027 in the US is the canonical trap: the 31st is New Year's Day observed.
| Parameter | Notes |
|---|---|
year | 2020–2035 |
rule | last-business-day · nth:<1-28> · semi:<day>,<day|last> |
curl "https://chronosapi.dev/v1/paydays?region=US&year=2027&rule=semi:15,last" -H "X-Api-Key: $KEY"import requests
r = requests.get("https://chronosapi.dev/v1/paydays",
headers={"X-Api-Key": KEY},
params={'region': 'US', 'year': '2027', 'rule': 'semi:15,last'})
r.raise_for_status()
print(r.json())const r = await fetch("https://chronosapi.dev/v1/paydays?region=US&year=2027&rule=semi:15,last", {
headers: { "X-Api-Key": KEY },
});
if (!r.ok) throw new Error(`chronos: ${r.status}`);
console.log(await r.json());using var http = new HttpClient();
http.DefaultRequestHeaders.Add("X-Api-Key", key);
var json = await http.GetStringAsync(
"https://chronosapi.dev/v1/paydays?region=US&year=2027&rule=semi:15,last");
Console.WriteLine(json);Response
{ "region": "US", "year": 2027, "rule": "semi:15,last",
"paydays": ["2027-01-15", "2027-01-29", "...", "2027-12-15", "2027-12-30"] }
GET /v1/common-days
Days that are business days in every region listed. The question behind cross-border settlement, international support coverage, and shipping cutoffs. A memorable case: a US–Saudi pair shares only Monday to Thursday even in a quiet week.
| Parameter | Notes |
|---|---|
regions | 2–5 comma-separated codes |
from, to | at most 92 days apart |
curl "https://chronosapi.dev/v1/common-days?regions=US,DE&from=2027-05-28&to=2027-06-01" -H "X-Api-Key: $KEY"import requests
r = requests.get("https://chronosapi.dev/v1/common-days",
headers={"X-Api-Key": KEY},
params={'regions': 'US,DE', 'from': '2027-05-28', 'to': '2027-06-01'})
r.raise_for_status()
print(r.json())const r = await fetch("https://chronosapi.dev/v1/common-days?regions=US,DE&from=2027-05-28&to=2027-06-01", {
headers: { "X-Api-Key": KEY },
});
if (!r.ok) throw new Error(`chronos: ${r.status}`);
console.log(await r.json());using var http = new HttpClient();
http.DefaultRequestHeaders.Add("X-Api-Key", key);
var json = await http.GetStringAsync(
"https://chronosapi.dev/v1/common-days?regions=US,DE&from=2027-05-28&to=2027-06-01");
Console.WriteLine(json);Response
{ "regions": ["US", "DE"], "from": "2027-05-28", "to": "2027-06-01",
"common_business_days": ["2027-05-28", "2027-06-01"] }
GET /v1/year
A year at a glance: total business days, per-month counts, and the full holiday list. Capacity planning and forecasting input.
| Parameter | Notes |
|---|---|
year | 2020–2035 |
curl "https://chronosapi.dev/v1/year?region=GB&year=2027" -H "X-Api-Key: $KEY"import requests
r = requests.get("https://chronosapi.dev/v1/year",
headers={"X-Api-Key": KEY},
params={'region': 'GB', 'year': '2027'})
r.raise_for_status()
print(r.json())const r = await fetch("https://chronosapi.dev/v1/year?region=GB&year=2027", {
headers: { "X-Api-Key": KEY },
});
if (!r.ok) throw new Error(`chronos: ${r.status}`);
console.log(await r.json());using var http = new HttpClient();
http.DefaultRequestHeaders.Add("X-Api-Key", key);
var json = await http.GetStringAsync(
"https://chronosapi.dev/v1/year?region=GB&year=2027");
Console.WriteLine(json);Response
{ "region": "GB", "year": 2027, "business_days_total": 253,
"business_days_per_month": [20, 20, 23, ...], "holidays_count": 10,
"holidays": [{ "date": "2027-01-01", "name": "New Year's Day" }, ...] }
GET /v1/bridge-days
Windows where a little leave buys a long break, ranked by days off per day spent. Germany's best 2027 window: one day of leave around Easter yields five consecutive days off.
| Parameter | Notes |
|---|---|
year | 2020–2035 |
pto | leave budget, 1–5 days |
curl "https://chronosapi.dev/v1/bridge-days?region=DE&year=2027&pto=1" -H "X-Api-Key: $KEY"import requests
r = requests.get("https://chronosapi.dev/v1/bridge-days",
headers={"X-Api-Key": KEY},
params={'region': 'DE', 'year': '2027', 'pto': '1'})
r.raise_for_status()
print(r.json())const r = await fetch("https://chronosapi.dev/v1/bridge-days?region=DE&year=2027&pto=1", {
headers: { "X-Api-Key": KEY },
});
if (!r.ok) throw new Error(`chronos: ${r.status}`);
console.log(await r.json());using var http = new HttpClient();
http.DefaultRequestHeaders.Add("X-Api-Key", key);
var json = await http.GetStringAsync(
"https://chronosapi.dev/v1/bridge-days?region=DE&year=2027&pto=1");
Console.WriteLine(json);Response
{ "region": "DE", "year": 2027, "pto_budget": 1, "windows": [
{ "from": "2027-03-25", "to": "2027-03-29", "pto_days": 1,
"total_days_off": 5, "pto_dates": ["2027-03-25"], "efficiency": 5.0 }, ...] }
GET /v1/next-holiday
Upcoming holidays with a countdown. Ops dashboards, deploy-freeze checks, or a desk widget.
| Parameter | Notes |
|---|---|
count | 1–10, default 1 |
curl "https://chronosapi.dev/v1/next-holiday?region=US&count=2" -H "X-Api-Key: $KEY"import requests
r = requests.get("https://chronosapi.dev/v1/next-holiday",
headers={"X-Api-Key": KEY},
params={'region': 'US', 'count': '2'})
r.raise_for_status()
print(r.json())const r = await fetch("https://chronosapi.dev/v1/next-holiday?region=US&count=2", {
headers: { "X-Api-Key": KEY },
});
if (!r.ok) throw new Error(`chronos: ${r.status}`);
console.log(await r.json());using var http = new HttpClient();
http.DefaultRequestHeaders.Add("X-Api-Key", key);
var json = await http.GetStringAsync(
"https://chronosapi.dev/v1/next-holiday?region=US&count=2");
Console.WriteLine(json);Response
{ "region": "US", "as_of": "2026-08-31", "holidays": [
{ "date": "2026-09-07", "name": "Labor Day", "days_until": 7 }, ...] }
GET /v1/holidays
The raw holiday calendar for a region and range (up to three years), when you want the list itself.
| Parameter | Notes |
|---|---|
from, to | range up to 3 years |
curl "https://chronosapi.dev/v1/holidays?region=GB&from=2027-12-01&to=2027-12-31" -H "X-Api-Key: $KEY"import requests
r = requests.get("https://chronosapi.dev/v1/holidays",
headers={"X-Api-Key": KEY},
params={'region': 'GB', 'from': '2027-12-01', 'to': '2027-12-31'})
r.raise_for_status()
print(r.json())const r = await fetch("https://chronosapi.dev/v1/holidays?region=GB&from=2027-12-01&to=2027-12-31", {
headers: { "X-Api-Key": KEY },
});
if (!r.ok) throw new Error(`chronos: ${r.status}`);
console.log(await r.json());using var http = new HttpClient();
http.DefaultRequestHeaders.Add("X-Api-Key", key);
var json = await http.GetStringAsync(
"https://chronosapi.dev/v1/holidays?region=GB&from=2027-12-01&to=2027-12-31");
Console.WriteLine(json);Response
{ "region": "GB", "holidays": [
{ "date": "2027-12-25", "name": "Christmas Day" },
{ "date": "2027-12-27", "name": "Christmas Day (observed)" }, ...] }
GET /v1/holidays.ics
The same calendar as an iCal feed. Subscribe from Google Calendar, Apple Calendar, or Outlook and holidays appear alongside your events. No key required: calendar apps can't send headers, and the data is open-licensed. Rate-limited per IP.
| Parameter | Notes |
|---|---|
year | defaults to the current year |
curl "https://chronosapi.dev/v1/holidays.ics?region=US&year=2027" -H "X-Api-Key: $KEY"import requests
r = requests.get("https://chronosapi.dev/v1/holidays.ics",
headers={"X-Api-Key": KEY},
params={'region': 'US', 'year': '2027'})
r.raise_for_status()
print(r.json())const r = await fetch("https://chronosapi.dev/v1/holidays.ics?region=US&year=2027", {
headers: { "X-Api-Key": KEY },
});
if (!r.ok) throw new Error(`chronos: ${r.status}`);
console.log(await r.json());using var http = new HttpClient();
http.DefaultRequestHeaders.Add("X-Api-Key", key);
var json = await http.GetStringAsync(
"https://chronosapi.dev/v1/holidays.ics?region=US&year=2027");
Console.WriteLine(json);Response
BEGIN:VCALENDAR
VERSION:2.0
X-WR-CALNAME:Holidays US 2027
BEGIN:VEVENT
DTSTART;VALUE=DATE:20270101
SUMMARY:New Year's Day
...
POST /v1/batch
Up to 100 operations in one request: add, count, check, or due-date. Each operation is metered as one request; results come back in order, with per-item errors instead of all-or-nothing failure.
| Parameter | Notes |
|---|---|
operations[].op | add · count · check · due-date |
operations[].region | any region code |
operations[]. … | parameters matching the single-call endpoint |
curl -X POST "https://chronosapi.dev/v1/batch" \
-H "X-Api-Key: $KEY" -H "Content-Type: application/json" \
-d '{"operations": [{"op": "add", "region": "XNYS", "start": "2027-03-25", "days": 2}, {"op": "due-date", "region": "US", "start": "2027-01-15", "terms": "net30"}]}'import requests
r = requests.post("https://chronosapi.dev/v1/batch",
headers={"X-Api-Key": KEY},
json={"operations": [{"op": "add", "region": "XNYS", "start": "2027-03-25", "days": 2}, {"op": "due-date", "region": "US", "start": "2027-01-15", "terms": "net30"}]})
r.raise_for_status()
print(r.json())const r = await fetch("https://chronosapi.dev/v1/batch", {
method: "POST",
headers: { "X-Api-Key": KEY, "Content-Type": "application/json" },
body: JSON.stringify({"operations": [{"op": "add", "region": "XNYS", "start": "2027-03-25", "days": 2}, {"op": "due-date", "region": "US", "start": "2027-01-15", "terms": "net30"}]}),
});
if (!r.ok) throw new Error(`chronos: ${r.status}`);
console.log(await r.json());using var http = new HttpClient();
http.DefaultRequestHeaders.Add("X-Api-Key", key);
var body = JsonContent.Create({"operations": [{"op": "add", "region": "XNYS", "start": "2027-03-25", "days": 2}, {"op": "due-date", "region": "US", "start": "2027-01-15", "terms": "net30"}]});
var res = await http.PostAsync("https://chronosapi.dev/v1/batch", body);
res.EnsureSuccessStatusCode();
Console.WriteLine(await res.Content.ReadAsStringAsync());Response
{ "count": 2, "results": [
{ "result": "2027-03-30" },
{ "due_date": "2027-02-16", "rolled": true } ] }
GET /v1/regions
Every supported region: countries, subdivisions, and financial markets. Each carries its own weekend definition, applied to calculations automatically.
curl "https://chronosapi.dev/v1/regions" -H "X-Api-Key: $KEY"import requests
r = requests.get("https://chronosapi.dev/v1/regions",
headers={"X-Api-Key": KEY})
r.raise_for_status()
print(r.json())const r = await fetch("https://chronosapi.dev/v1/regions", {
headers: { "X-Api-Key": KEY },
});
if (!r.ok) throw new Error(`chronos: ${r.status}`);
console.log(await r.json());using var http = new HttpClient();
http.DefaultRequestHeaders.Add("X-Api-Key", key);
var json = await http.GetStringAsync(
"https://chronosapi.dev/v1/regions");
Console.WriteLine(json);Response
{ "count": 1801, "regions": [
{ "code": "US", "country": "US", "subdiv": null, "kind": "country" },
{ "code": "US-CA", "country": "US", "subdiv": "CA", "kind": "subdivision" },
{ "code": "XNYS", "country": "XNYS", "subdiv": null, "kind": "financial" }, ...] }
GET /v1/diff
Day-type census for a range: how many business days, weekend days, and holidays between two dates. Capacity planning and prorating.
| Parameter | Notes |
|---|---|
from, to | up to 3 years apart |
curl "https://chronosapi.dev/v1/diff?region=DE-BY&from=2027-01-01&to=2027-03-31" -H "X-Api-Key: $KEY"import requests
r = requests.get("https://chronosapi.dev/v1/diff",
headers={"X-Api-Key": KEY},
params={'region': 'DE-BY', 'from': '2027-01-01', 'to': '2027-03-31'})
r.raise_for_status()
print(r.json())const r = await fetch("https://chronosapi.dev/v1/diff?region=DE-BY&from=2027-01-01&to=2027-03-31", {
headers: { "X-Api-Key": KEY },
});
if (!r.ok) throw new Error(`chronos: ${r.status}`);
console.log(await r.json());using var http = new HttpClient();
http.DefaultRequestHeaders.Add("X-Api-Key", key);
var json = await http.GetStringAsync(
"https://chronosapi.dev/v1/diff?region=DE-BY&from=2027-01-01&to=2027-03-31");
Console.WriteLine(json);Response
{ "region": "DE-BY", "from": "2027-01-01", "to": "2027-03-31",
"total_days": 90, "business_days": 62, "weekend_days": 25, "holiday_days": 3 }
GET /v1/window
The next N business days from a date, as a list. The feed behind date pickers, slot schedulers, and delivery choosers.
| Parameter | Notes |
|---|---|
count | 1-100, default 10 |
start | included when it is a business day |
curl "https://chronosapi.dev/v1/window?region=US&start=2027-11-24&count=5" -H "X-Api-Key: $KEY"import requests
r = requests.get("https://chronosapi.dev/v1/window",
headers={"X-Api-Key": KEY},
params={'region': 'US', 'start': '2027-11-24', 'count': '5'})
r.raise_for_status()
print(r.json())const r = await fetch("https://chronosapi.dev/v1/window?region=US&start=2027-11-24&count=5", {
headers: { "X-Api-Key": KEY },
});
if (!r.ok) throw new Error(`chronos: ${r.status}`);
console.log(await r.json());using var http = new HttpClient();
http.DefaultRequestHeaders.Add("X-Api-Key", key);
var json = await http.GetStringAsync(
"https://chronosapi.dev/v1/window?region=US&start=2027-11-24&count=5");
Console.WriteLine(json);Response
{ "region": "US", "start": "2027-11-24", "count": 5,
"business_days": ["2027-11-24", "2027-11-26", "2027-11-29", "2027-11-30", "2027-12-01"] }
GET /v1/holidays.csv
The holiday calendar as CSV for spreadsheets and data pipelines. Pairs well with the query-parameter key form.
| Parameter | Notes |
|---|---|
year | defaults to the current year |
curl "https://chronosapi.dev/v1/holidays.csv?region=GB&year=2027" -H "X-Api-Key: $KEY"import requests
r = requests.get("https://chronosapi.dev/v1/holidays.csv",
headers={"X-Api-Key": KEY},
params={'region': 'GB', 'year': '2027'})
r.raise_for_status()
print(r.json())const r = await fetch("https://chronosapi.dev/v1/holidays.csv?region=GB&year=2027", {
headers: { "X-Api-Key": KEY },
});
if (!r.ok) throw new Error(`chronos: ${r.status}`);
console.log(await r.json());using var http = new HttpClient();
http.DefaultRequestHeaders.Add("X-Api-Key", key);
var json = await http.GetStringAsync(
"https://chronosapi.dev/v1/holidays.csv?region=GB&year=2027");
Console.WriteLine(json);Response
date,name
2027-01-01,"New Year's Day"
2027-03-26,"Good Friday"
...
POST /v1/public-keys
Mints a publishable key (pk_...) for browser code and widgets: locked to the origins you list, accepted only on read-only endpoints, metered against your account, and revoked when you rotate your secret key. Requires your secret key; keep that one server-side.
| Parameter | Notes |
|---|---|
origins | 1-10; https only, except http on localhost |
curl -X POST "https://chronosapi.dev/v1/public-keys" \
-H "X-Api-Key: $KEY" -H "Content-Type: application/json" \
-d '{"origins": ["https://your-site.com", "http://localhost:4200"]}'import requests
r = requests.post("https://chronosapi.dev/v1/public-keys",
headers={"X-Api-Key": KEY},
json={"origins": ["https://your-site.com", "http://localhost:4200"]})
r.raise_for_status()
print(r.json())const r = await fetch("https://chronosapi.dev/v1/public-keys", {
method: "POST",
headers: { "X-Api-Key": KEY, "Content-Type": "application/json" },
body: JSON.stringify({"origins": ["https://your-site.com", "http://localhost:4200"]}),
});
if (!r.ok) throw new Error(`chronos: ${r.status}`);
console.log(await r.json());using var http = new HttpClient();
http.DefaultRequestHeaders.Add("X-Api-Key", key);
var body = JsonContent.Create({"origins": ["https://your-site.com", "http://localhost:4200"]});
var res = await http.PostAsync("https://chronosapi.dev/v1/public-keys", body);
res.EnsureSuccessStatusCode();
Console.WriteLine(await res.Content.ReadAsStringAsync());Response
{ "public_key": "pk_4c9...",
"origins": ["https://your-site.com", "http://localhost:4200"] }
Invoice due dates that survive the calendar
Accounts receivable at volume: one batch call turns an invoice run into correct, holiday-aware due dates.
curl -X POST "https://chronosapi.dev/v1/batch" \
-H "X-Api-Key: $KEY" -H "Content-Type: application/json" \
-d '{"operations": [{"op": "due-date", "region": "US", "start": "2027-01-15", "terms": "net30"}, {"op": "due-date", "region": "DE", "start": "2027-01-15", "terms": "net45"}, {"op": "due-date", "region": "GB", "start": "2027-01-15", "terms": "eom+15"}]}'import requests
r = requests.post("https://chronosapi.dev/v1/batch",
headers={"X-Api-Key": KEY},
json={"operations": [{"op": "due-date", "region": "US", "start": "2027-01-15", "terms": "net30"}, {"op": "due-date", "region": "DE", "start": "2027-01-15", "terms": "net45"}, {"op": "due-date", "region": "GB", "start": "2027-01-15", "terms": "eom+15"}]})
r.raise_for_status()
print(r.json())const r = await fetch("https://chronosapi.dev/v1/batch", {
method: "POST",
headers: { "X-Api-Key": KEY, "Content-Type": "application/json" },
body: JSON.stringify({"operations": [{"op": "due-date", "region": "US", "start": "2027-01-15", "terms": "net30"}, {"op": "due-date", "region": "DE", "start": "2027-01-15", "terms": "net45"}, {"op": "due-date", "region": "GB", "start": "2027-01-15", "terms": "eom+15"}]}),
});
if (!r.ok) throw new Error(`chronos: ${r.status}`);
console.log(await r.json());using var http = new HttpClient();
http.DefaultRequestHeaders.Add("X-Api-Key", key);
var body = JsonContent.Create({"operations": [{"op": "due-date", "region": "US", "start": "2027-01-15", "terms": "net30"}, {"op": "due-date", "region": "DE", "start": "2027-01-15", "terms": "net45"}, {"op": "due-date", "region": "GB", "start": "2027-01-15", "terms": "eom+15"}]});
var res = await http.PostAsync("https://chronosapi.dev/v1/batch", body);
res.EnsureSuccessStatusCode();
Console.WriteLine(await res.Content.ReadAsStringAsync());Response
{ "count": 3, "results": [
{ "due_date": "2027-02-16", "rolled": true },
{ "due_date": "2027-03-01", "rolled": false },
{ "due_date": "2027-02-16", "rolled": true } ] }
An SLA deadline that holds up in a dispute
Ticket opened in Munich on the Wednesday before Easter, five business days to respond. Good Friday and Easter Monday are statutory holidays in Germany; the deadline is a week later than a weekend-only calculation claims.
curl "https://chronosapi.dev/v1/add?region=DE&start=2027-03-24&days=5" -H "X-Api-Key: $KEY"import requests
r = requests.get("https://chronosapi.dev/v1/add",
headers={"X-Api-Key": KEY},
params={'region': 'DE', 'start': '2027-03-24', 'days': '5'})
r.raise_for_status()
print(r.json())const r = await fetch("https://chronosapi.dev/v1/add?region=DE&start=2027-03-24&days=5", {
headers: { "X-Api-Key": KEY },
});
if (!r.ok) throw new Error(`chronos: ${r.status}`);
console.log(await r.json());using var http = new HttpClient();
http.DefaultRequestHeaders.Add("X-Api-Key", key);
var json = await http.GetStringAsync(
"https://chronosapi.dev/v1/add?region=DE&start=2027-03-24&days=5");
Console.WriteLine(json);Response
{ "region": "DE", "start": "2027-03-24", "days": 5, "result": "2027-04-01" }
Publishing next year's payroll calendar
One call per pay group. Semi-monthly staff paid on the 15th and month-end, rolled back from weekends and holidays:
curl "https://chronosapi.dev/v1/paydays?region=US&year=2027&rule=semi:15,last" -H "X-Api-Key: $KEY"import requests
r = requests.get("https://chronosapi.dev/v1/paydays",
headers={"X-Api-Key": KEY},
params={'region': 'US', 'year': '2027', 'rule': 'semi:15,last'})
r.raise_for_status()
print(r.json())const r = await fetch("https://chronosapi.dev/v1/paydays?region=US&year=2027&rule=semi:15,last", {
headers: { "X-Api-Key": KEY },
});
if (!r.ok) throw new Error(`chronos: ${r.status}`);
console.log(await r.json());using var http = new HttpClient();
http.DefaultRequestHeaders.Add("X-Api-Key", key);
var json = await http.GetStringAsync(
"https://chronosapi.dev/v1/paydays?region=US&year=2027&rule=semi:15,last");
Console.WriteLine(json);Response
{ "paydays": ["2027-01-15", "2027-01-29", "2027-02-12", "2027-02-26",
"...", "2027-12-15", "2027-12-30"] }
Checking a cross-border settlement window
A EUR/USD trade needs both TARGET2 and US markets open. Ask for the days both calendars agree on:
curl "https://chronosapi.dev/v1/common-days?regions=ECB,XNYS&from=2027-05-01&to=2027-05-31" -H "X-Api-Key: $KEY"import requests
r = requests.get("https://chronosapi.dev/v1/common-days",
headers={"X-Api-Key": KEY},
params={'regions': 'ECB,XNYS', 'from': '2027-05-01', 'to': '2027-05-31'})
r.raise_for_status()
print(r.json())const r = await fetch("https://chronosapi.dev/v1/common-days?regions=ECB,XNYS&from=2027-05-01&to=2027-05-31", {
headers: { "X-Api-Key": KEY },
});
if (!r.ok) throw new Error(`chronos: ${r.status}`);
console.log(await r.json());using var http = new HttpClient();
http.DefaultRequestHeaders.Add("X-Api-Key", key);
var json = await http.GetStringAsync(
"https://chronosapi.dev/v1/common-days?regions=ECB,XNYS&from=2027-05-01&to=2027-05-31");
Console.WriteLine(json);Response
{ "regions": ["ECB", "XNYS"],
"common_business_days": ["2027-05-03", "2027-05-04", "..."] }
Data provenance
Holiday data derives from the MIT-licensed python-holidays project, one of the most actively maintained calendar datasets anywhere. It is regenerated and cross-verified against independent sources on every refresh. Weekend rules are curated separately: Friday–Saturday across much of the Middle East, Saturday alone in Nepal, Friday and Sunday in Brunei. The dataset version and generation timestamp are public at /health.
Found an error in a calendar? Tell us. Corrections ship in the next daily refresh, and we credit reporters who want it.