API reference

Base URL https://dierum.io. 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://dierum.io/v1/check?region=US&date=2027-11-25" -H "X-Api-Key: $KEY"
import requests

r = requests.get("https://dierum.io/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://dierum.io/v1/check?region=US&date=2027-11-25", {
  headers: { "X-Api-Key": KEY },
});
if (!r.ok) throw new Error(`dierum: ${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://dierum.io/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.

Agents: a machine-readable spec lives at /openapi.json and a compact plain-text surface at /llms.txt. Signup, keys, and every endpoint are fully self-serve; no human steps anywhere in the flow.

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

PlanRequests / dayPrice
Free100$0
Developer1,000$8 / month
Starter10,000$20 / month
Pro100,000$48 / month
Business500,000$150 / month
Enterprisenegotiatedfrom $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:

StatusCodeMeaning
400bad_date · bad_terms · bad_ruleMalformed input. Dates are yyyy-MM-dd.
401missing_key · invalid_keyNo key, or a revoked one.
404unknown_regionNot in /v1/regions.
422out_of_rangeThe result would leave 2020–2035. We refuse rather than guess.
429quota_exceededDaily limit reached.

GET /v1/check

Classify one date: business day, weekend, or holiday, with the next business day included.

ParameterNotes
regionISO 3166 code, subdivision, or market · see /v1/regions
dateyyyy-MM-dd
curl "https://dierum.io/v1/check?region=US&date=2027-11-25" -H "X-Api-Key: $KEY"
import requests

r = requests.get("https://dierum.io/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://dierum.io/v1/check?region=US&date=2027-11-25", {
  headers: { "X-Api-Key": KEY },
});
if (!r.ok) throw new Error(`dierum: ${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://dierum.io/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, "holiday_name": "Thanksgiving",
  "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.

ParameterNotes
regioncalendar to use · XNYS here, so Good Friday counts as closed
startyyyy-MM-dd
days-5000 to 5000
curl "https://dierum.io/v1/add?region=XNYS&start=2027-03-25&days=2" -H "X-Api-Key: $KEY"
import requests

r = requests.get("https://dierum.io/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://dierum.io/v1/add?region=XNYS&start=2027-03-25&days=2", {
  headers: { "X-Api-Key": KEY },
});
if (!r.ok) throw new Error(`dierum: ${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://dierum.io/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.

ParameterNotes
regionsubdivisions carry their own holidays · Bavaria observes Epiphany; Berlin does not
from, toyyyy-MM-dd
curl "https://dierum.io/v1/count?region=DE-BY&from=2027-01-01&to=2027-01-31" -H "X-Api-Key: $KEY"
import requests

r = requests.get("https://dierum.io/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://dierum.io/v1/count?region=DE-BY&from=2027-01-01&to=2027-01-31", {
  headers: { "X-Api-Key": KEY },
});
if (!r.ok) throw new Error(`dierum: ${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://dierum.io/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.

ParameterNotes
invoice_dateyyyy-MM-dd
termsnet<n>, net<n>b, eom, eom+<n>
curl "https://dierum.io/v1/due-date?region=US&invoice_date=2027-01-15&terms=net30" -H "X-Api-Key: $KEY"
import requests

r = requests.get("https://dierum.io/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://dierum.io/v1/due-date?region=US&invoice_date=2027-01-15&terms=net30", {
  headers: { "X-Api-Key": KEY },
});
if (!r.ok) throw new Error(`dierum: ${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://dierum.io/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.

ParameterNotes
year2020–2035
rulelast-business-day · nth:<1-28> · semi:<day>,<day|last>
curl "https://dierum.io/v1/paydays?region=US&year=2027&rule=semi:15,last" -H "X-Api-Key: $KEY"
import requests

r = requests.get("https://dierum.io/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://dierum.io/v1/paydays?region=US&year=2027&rule=semi:15,last", {
  headers: { "X-Api-Key": KEY },
});
if (!r.ok) throw new Error(`dierum: ${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://dierum.io/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.

ParameterNotes
regions2–5 comma-separated codes
from, toat most 92 days apart
curl "https://dierum.io/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://dierum.io/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://dierum.io/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(`dierum: ${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://dierum.io/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.

ParameterNotes
year2020–2035
curl "https://dierum.io/v1/year?region=GB&year=2027" -H "X-Api-Key: $KEY"
import requests

r = requests.get("https://dierum.io/v1/year",
    headers={"X-Api-Key": KEY},
    params={'region': 'GB', 'year': '2027'})
r.raise_for_status()
print(r.json())
const r = await fetch("https://dierum.io/v1/year?region=GB&year=2027", {
  headers: { "X-Api-Key": KEY },
});
if (!r.ok) throw new Error(`dierum: ${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://dierum.io/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.

ParameterNotes
year2020–2035
ptoleave budget, 1–5 days
curl "https://dierum.io/v1/bridge-days?region=DE&year=2027&pto=1" -H "X-Api-Key: $KEY"
import requests

r = requests.get("https://dierum.io/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://dierum.io/v1/bridge-days?region=DE&year=2027&pto=1", {
  headers: { "X-Api-Key": KEY },
});
if (!r.ok) throw new Error(`dierum: ${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://dierum.io/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.

ParameterNotes
count1–10, default 1
curl "https://dierum.io/v1/next-holiday?region=US&count=2" -H "X-Api-Key: $KEY"
import requests

r = requests.get("https://dierum.io/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://dierum.io/v1/next-holiday?region=US&count=2", {
  headers: { "X-Api-Key": KEY },
});
if (!r.ok) throw new Error(`dierum: ${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://dierum.io/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.

ParameterNotes
from, torange up to 3 years
curl "https://dierum.io/v1/holidays?region=GB&from=2027-12-01&to=2027-12-31" -H "X-Api-Key: $KEY"
import requests

r = requests.get("https://dierum.io/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://dierum.io/v1/holidays?region=GB&from=2027-12-01&to=2027-12-31", {
  headers: { "X-Api-Key": KEY },
});
if (!r.ok) throw new Error(`dierum: ${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://dierum.io/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.

ParameterNotes
yeardefaults to the current year
curl "https://dierum.io/v1/holidays.ics?region=US&year=2027" -H "X-Api-Key: $KEY"
import requests

r = requests.get("https://dierum.io/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://dierum.io/v1/holidays.ics?region=US&year=2027", {
  headers: { "X-Api-Key": KEY },
});
if (!r.ok) throw new Error(`dierum: ${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://dierum.io/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 (1,000 on Pro and above): 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.

ParameterNotes
operations[].opadd · count · check · due-date
operations[].regionany region code
operations[]. …parameters matching the single-call endpoint
curl -X POST "https://dierum.io/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://dierum.io/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://dierum.io/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(`dierum: ${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://dierum.io/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. Mind the UK: bare GB is aliased to England & Wales holidays (the common industry default when no UK nation is specified). Scotland and Northern Ireland observe different dates for some bank holidays; use GB-SCT or GB-NIR for those. Mind Australia: bare AU is aliased to New South Wales, which includes the weekend-to-weekday substitute dates every state observes for Christmas, Boxing Day, New Year's, and Australia Day (e.g. Sat 25 Dec 2027 shifts the day off to Mon 27 Dec); use another AU-* code for a different state's own extra holidays.

curl "https://dierum.io/v1/regions" -H "X-Api-Key: $KEY"
import requests

r = requests.get("https://dierum.io/v1/regions",
    headers={"X-Api-Key": KEY})
r.raise_for_status()
print(r.json())
const r = await fetch("https://dierum.io/v1/regions", {
  headers: { "X-Api-Key": KEY },
});
if (!r.ok) throw new Error(`dierum: ${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://dierum.io/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.

ParameterNotes
from, toup to 3 years apart
curl "https://dierum.io/v1/diff?region=DE-BY&from=2027-01-01&to=2027-03-31" -H "X-Api-Key: $KEY"
import requests

r = requests.get("https://dierum.io/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://dierum.io/v1/diff?region=DE-BY&from=2027-01-01&to=2027-03-31", {
  headers: { "X-Api-Key": KEY },
});
if (!r.ok) throw new Error(`dierum: ${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://dierum.io/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": 60, "weekend_days": 26, "holiday_days": 4 }

GET /v1/window

The next N business days from a date, as a list. The feed behind date pickers, slot schedulers, and delivery choosers.

ParameterNotes
count1-100, default 10
startincluded when it is a business day
curl "https://dierum.io/v1/window?region=US&start=2027-11-24&count=5" -H "X-Api-Key: $KEY"
import requests

r = requests.get("https://dierum.io/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://dierum.io/v1/window?region=US&start=2027-11-24&count=5", {
  headers: { "X-Api-Key": KEY },
});
if (!r.ok) throw new Error(`dierum: ${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://dierum.io/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.

ParameterNotes
yeardefaults to the current year
curl "https://dierum.io/v1/holidays.csv?region=GB&year=2027" -H "X-Api-Key: $KEY"
import requests

r = requests.get("https://dierum.io/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://dierum.io/v1/holidays.csv?region=GB&year=2027", {
  headers: { "X-Api-Key": KEY },
});
if (!r.ok) throw new Error(`dierum: ${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://dierum.io/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"
...

GET /v1/nth

The nth business day of each month, from either end. The schedule behind "invoice on the 3rd business day" and "settle 3 days before month end" rules.

ParameterNotes
n1-23
from_endtrue counts backward from month end
curl "https://dierum.io/v1/nth?region=US&year=2027&n=3&from_end=false" -H "X-Api-Key: $KEY"
import requests

r = requests.get("https://dierum.io/v1/nth",
    headers={"X-Api-Key": KEY},
    params={'region': 'US', 'year': '2027', 'n': '3', 'from_end': 'false'})
r.raise_for_status()
print(r.json())
const r = await fetch("https://dierum.io/v1/nth?region=US&year=2027&n=3&from_end=false", {
  headers: { "X-Api-Key": KEY },
});
if (!r.ok) throw new Error(`dierum: ${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://dierum.io/v1/nth?region=US&year=2027&n=3&from_end=false");
Console.WriteLine(json);

Response

{ "region": "US", "year": 2027, "n": 3, "from_end": false,
  "dates": ["2027-01-06", "2027-02-03", "..."] }

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.

ParameterNotes
origins1-10; https only, except http on localhost
curl -X POST "https://dierum.io/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://dierum.io/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://dierum.io/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(`dierum: ${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://dierum.io/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"] }

GET /v1/pay-periods

Pay periods with paydays rolled back off non-working days. The anchored biweekly rule is the one fixed-date systems cannot express and most US payrolls run on: pass any known payday as the anchor and the phase is preserved forever.

ParameterNotes
ruleweekly | biweekly | semi-monthly | monthly
anchora known payday; required for weekly/biweekly
from, countfirst period on/after from; up to 60
curl "https://dierum.io/v1/pay-periods?region=US&rule=biweekly&anchor=2027-01-08&from=2027-02-01&count=3" -H "X-Api-Key: $KEY"
import requests

r = requests.get("https://dierum.io/v1/pay-periods",
    headers={"X-Api-Key": KEY},
    params={'region': 'US', 'rule': 'biweekly', 'anchor': '2027-01-08', 'from': '2027-02-01', 'count': '3'})
r.raise_for_status()
print(r.json())
const r = await fetch("https://dierum.io/v1/pay-periods?region=US&rule=biweekly&anchor=2027-01-08&from=2027-02-01&count=3", {
  headers: { "X-Api-Key": KEY },
});
if (!r.ok) throw new Error(`dierum: ${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://dierum.io/v1/pay-periods?region=US&rule=biweekly&anchor=2027-01-08&from=2027-02-01&count=3");
Console.WriteLine(json);

Response

{ "rule": "biweekly", "periods": [
  { "period_start": "2027-01-23", "period_end": "2027-02-05", "payday": "2027-02-05" },
  { "period_start": "2027-02-06", "period_end": "2027-02-19", "payday": "2027-02-19" }, ...] }

GET /v1/add-hours

Business-hours arithmetic inside a working window: "respond within 8 business hours" resolved to an exact date and time. Hours spill across holidays and weekends; a start outside the window clips to the next opening. Times are local wall-clock; time zones stay the caller's affair.

ParameterNotes
timeHH:mm start
hours0-2000, fractions allowed
windowHH:mm-HH:mm, default 09:00-17:00
curl "https://dierum.io/v1/add-hours?region=DE&start=2027-03-25&time=16:00&hours=2&window=09:00-17:00" -H "X-Api-Key: $KEY"
import requests

r = requests.get("https://dierum.io/v1/add-hours",
    headers={"X-Api-Key": KEY},
    params={'region': 'DE', 'start': '2027-03-25', 'time': '16:00', 'hours': '2', 'window': '09:00-17:00'})
r.raise_for_status()
print(r.json())
const r = await fetch("https://dierum.io/v1/add-hours?region=DE&start=2027-03-25&time=16:00&hours=2&window=09:00-17:00", {
  headers: { "X-Api-Key": KEY },
});
if (!r.ok) throw new Error(`dierum: ${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://dierum.io/v1/add-hours?region=DE&start=2027-03-25&time=16:00&hours=2&window=09:00-17:00");
Console.WriteLine(json);

Response

{ "start": "2027-03-25", "time": "16:00", "hours": 2,
  "result_date": "2027-03-30", "result_time": "10:00" }

GET /v1/recurrence

Recurring schedules that respect the calendar: every N weeks on a weekday, the nth weekday monthly, or the last weekday monthly, with your choice of roll policy when a date lands closed.

ParameterNotes
ruleweekly:<1-12>:<dow> | nth:<1-5>:<dow> | last:<dow>
rollforward | backward | skip | none
curl "https://dierum.io/v1/recurrence?region=US&rule=nth:3:thu&start=2027-01-01&count=3&roll=forward" -H "X-Api-Key: $KEY"
import requests

r = requests.get("https://dierum.io/v1/recurrence",
    headers={"X-Api-Key": KEY},
    params={'region': 'US', 'rule': 'nth:3:thu', 'start': '2027-01-01', 'count': '3', 'roll': 'forward'})
r.raise_for_status()
print(r.json())
const r = await fetch("https://dierum.io/v1/recurrence?region=US&rule=nth:3:thu&start=2027-01-01&count=3&roll=forward", {
  headers: { "X-Api-Key": KEY },
});
if (!r.ok) throw new Error(`dierum: ${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://dierum.io/v1/recurrence?region=US&rule=nth:3:thu&start=2027-01-01&count=3&roll=forward");
Console.WriteLine(json);

Response

{ "rule": "nth:3:thu", "dates": ["2027-01-21", "2027-02-18", "2027-03-18"] }

GET /v1/quarter

The fiscal quarter containing a date, with business-day totals, elapsed, and remaining. Custom fiscal-year starts for the July and February crowd.

ParameterNotes
fiscal_startmonth 1-12, default 1
datedefaults to today
curl "https://dierum.io/v1/quarter?region=US&date=2027-02-15&fiscal_start=7" -H "X-Api-Key: $KEY"
import requests

r = requests.get("https://dierum.io/v1/quarter",
    headers={"X-Api-Key": KEY},
    params={'region': 'US', 'date': '2027-02-15', 'fiscal_start': '7'})
r.raise_for_status()
print(r.json())
const r = await fetch("https://dierum.io/v1/quarter?region=US&date=2027-02-15&fiscal_start=7", {
  headers: { "X-Api-Key": KEY },
});
if (!r.ok) throw new Error(`dierum: ${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://dierum.io/v1/quarter?region=US&date=2027-02-15&fiscal_start=7");
Console.WriteLine(json);

Response

{ "quarter": "Q3", "quarter_start": "2027-01-01", "quarter_end": "2027-03-31",
  "business_days_total": 61, "business_days_elapsed": 32, "business_days_remaining": 29 }

GET /v1/tenor

Add a financial tenor (2W, 3M, 1Y) the way settlement systems do: land on the nominal date, then apply a roll convention. Modified-following rolls forward unless that crosses a month boundary, in which case it rolls back; the end-of-month rule keeps month-end starts on month-ends. This is the arithmetic behind deposit maturities, swap schedules, and net-90 terms that must stay in the right month.

ParameterNotes
tenor<n>D | <n>W | <n>M | <n>Y, n up to 999
conventionfollowing | modified-following | preceding | modified-preceding | unadjusted; default modified-following
eomend-of-month rule, default true; a month-end start plus months lands on the target month-end
curl "https://dierum.io/v1/tenor?region=GB&start=2027-02-26&tenor=1M&convention=modified-following" -H "X-Api-Key: $KEY"
import requests

r = requests.get("https://dierum.io/v1/tenor",
    headers={"X-Api-Key": KEY},
    params={'region': 'GB', 'start': '2027-02-26', 'tenor': '1M', 'convention': 'modified-following'})
r.raise_for_status()
print(r.json())
const r = await fetch("https://dierum.io/v1/tenor?region=GB&start=2027-02-26&tenor=1M&convention=modified-following", {
  headers: { "X-Api-Key": KEY },
});
if (!r.ok) throw new Error(`dierum: ${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://dierum.io/v1/tenor?region=GB&start=2027-02-26&tenor=1M&convention=modified-following");
Console.WriteLine(json);

Response

{ "start": "2027-02-26", "tenor": "1M", "convention": "modified-following",
  "eom": true, "result": "2027-03-31" }

GET /v1/day-count

The day count and year fraction between two dates under the five conventions interest math actually uses. 30/360 US and 30E/360 apply their month-end adjustments; ACT/ACT ISDA splits the range at year boundaries so leap years weight correctly.

ParameterNotes
basisACT/360 (default) | ACT/365F | 30/360 | 30E/360 | ACT/ACT
curl "https://dierum.io/v1/day-count?from=2027-01-31&to=2027-07-31&basis=30/360" -H "X-Api-Key: $KEY"
import requests

r = requests.get("https://dierum.io/v1/day-count",
    headers={"X-Api-Key": KEY},
    params={'from': '2027-01-31', 'to': '2027-07-31', 'basis': '30/360'})
r.raise_for_status()
print(r.json())
const r = await fetch("https://dierum.io/v1/day-count?from=2027-01-31&to=2027-07-31&basis=30/360", {
  headers: { "X-Api-Key": KEY },
});
if (!r.ok) throw new Error(`dierum: ${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://dierum.io/v1/day-count?from=2027-01-31&to=2027-07-31&basis=30/360");
Console.WriteLine(json);

Response

{ "from": "2027-01-31", "to": "2027-07-31", "basis": "30/360",
  "days": 180, "fraction": 0.5 }

GET /v1/installments

An amount split into installments that sum back to the total exactly, in cents, with every due date rolled off weekends and holidays. The remainder cents go to the earliest payments, so three payments of $100.00 come out 33.34 + 33.33 + 33.33, never 99.99 or 100.02.

ParameterNotes
amount_centstotal in minor units, 1-100,000,000
count2-60 payments
firstfirst due date
cadencemonthly (default) | biweekly | weekly
rollforward (default) | backward
curl "https://dierum.io/v1/installments?region=US&amount_cents=10000&count=3&first=2027-05-31&cadence=monthly" -H "X-Api-Key: $KEY"
import requests

r = requests.get("https://dierum.io/v1/installments",
    headers={"X-Api-Key": KEY},
    params={'region': 'US', 'amount_cents': '10000', 'count': '3', 'first': '2027-05-31', 'cadence': 'monthly'})
r.raise_for_status()
print(r.json())
const r = await fetch("https://dierum.io/v1/installments?region=US&amount_cents=10000&count=3&first=2027-05-31&cadence=monthly", {
  headers: { "X-Api-Key": KEY },
});
if (!r.ok) throw new Error(`dierum: ${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://dierum.io/v1/installments?region=US&amount_cents=10000&count=3&first=2027-05-31&cadence=monthly");
Console.WriteLine(json);

Response

{ "amount_cents": 10000, "count": 3, "total_check": 10000, "installments": [
  { "date": "2027-06-01", "amount_cents": 3334 },
  { "date": "2027-06-30", "amount_cents": 3333 },
  { "date": "2027-08-02", "amount_cents": 3333 } ] }

GET /v1/elapsed

Business days since a date, not counting the start day itself. "Opened 12 business days ago" for ticket queues, invoice aging buckets, and SLA clocks that should not tick on Sundays.

ParameterNotes
sinceyyyy-MM-dd
untildefaults to today, UTC
curl "https://dierum.io/v1/elapsed?region=US&since=2027-11-19" -H "X-Api-Key: $KEY"
import requests

r = requests.get("https://dierum.io/v1/elapsed",
    headers={"X-Api-Key": KEY},
    params={'region': 'US', 'since': '2027-11-19'})
r.raise_for_status()
print(r.json())
const r = await fetch("https://dierum.io/v1/elapsed?region=US&since=2027-11-19", {
  headers: { "X-Api-Key": KEY },
});
if (!r.ok) throw new Error(`dierum: ${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://dierum.io/v1/elapsed?region=US&since=2027-11-19");
Console.WriteLine(json);

Response

{ "region": "US", "since": "2027-11-19", "until": "2027-11-29",
  "business_days_elapsed": 5 }

GET /v1/long-weekends

Every stretch of three or more consecutive days off in a year, with the holidays that make it happen. Travel demand planning, staffing forecasts, and "book one day, get five" content.

ParameterNotes
year2020-2035, defaults to the current year
curl "https://dierum.io/v1/long-weekends?region=DE&year=2027" -H "X-Api-Key: $KEY"
import requests

r = requests.get("https://dierum.io/v1/long-weekends",
    headers={"X-Api-Key": KEY},
    params={'region': 'DE', 'year': '2027'})
r.raise_for_status()
print(r.json())
const r = await fetch("https://dierum.io/v1/long-weekends?region=DE&year=2027", {
  headers: { "X-Api-Key": KEY },
});
if (!r.ok) throw new Error(`dierum: ${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://dierum.io/v1/long-weekends?region=DE&year=2027");
Console.WriteLine(json);

Response

{ "region": "DE", "year": 2027, "long_weekends": [
  { "start": "2027-03-26", "end": "2027-03-29", "days": 4,
    "holidays": ["Karfreitag", "Ostermontag"] }, ...] }

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://dierum.io/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://dierum.io/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://dierum.io/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(`dierum: ${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://dierum.io/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://dierum.io/v1/add?region=DE&start=2027-03-24&days=5" -H "X-Api-Key: $KEY"
import requests

r = requests.get("https://dierum.io/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://dierum.io/v1/add?region=DE&start=2027-03-24&days=5", {
  headers: { "X-Api-Key": KEY },
});
if (!r.ok) throw new Error(`dierum: ${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://dierum.io/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://dierum.io/v1/paydays?region=US&year=2027&rule=semi:15,last" -H "X-Api-Key: $KEY"
import requests

r = requests.get("https://dierum.io/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://dierum.io/v1/paydays?region=US&year=2027&rule=semi:15,last", {
  headers: { "X-Api-Key": KEY },
});
if (!r.ok) throw new Error(`dierum: ${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://dierum.io/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://dierum.io/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://dierum.io/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://dierum.io/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(`dierum: ${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://dierum.io/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.