Any calendar window can come back as JSON, as a spreadsheet, or as a calendar file. All three are rendered from the same payload, so they cannot disagree about what a window contains.
curl -s "https://api.timesys.pro/v1/calendar\ ?jurisdictions=SE&from=2027-01-01&to=2027-12-31&format=ics" \ -H "X-API-Key: $TIMESYS_KEY" -o sweden-2027.ics
format takes json (the default),
csv or ics, and works on
/v1/calendar and
/v1/exchanges/{mic}/calendar. Both non-JSON formats come back
with a Content-Disposition filename.
One row per event, flattened. The nesting that makes the JSON pleasant
makes a CSV useless, so jurisdiction is repeated on every row
— which is what a pivot table needs anyway.
| Column | What it holds |
|---|---|
jurisdiction | The code you asked about. |
date / nominal_date | Observed date, and the original where a substitution moved it. |
name_en / name_local | English, and the name in the jurisdiction's own language and script. |
origin | Which jurisdiction in the chain the holiday came from — the country, for an inherited one. |
closes | true or
false: whether anything actually shuts. |
precision, assurance,
assurance_declared | The vocabulary travels with the export. A spreadsheet that has lost the assurance column is a spreadsheet of unlabelled claims. |
Events are all-day, with no timezone attached. That is deliberate and it is the thing most holiday feeds get wrong: a public holiday is a civil date belonging to its own jurisdiction, so shifting it into the reader's zone would put Christmas in Tokyo on the 24th for a reader in London. That is not a rendering preference, it is a wrong answer.
| Detail | What we do, and why |
|---|---|
DTSTART;VALUE=DATE | All-day, never
DATE-TIME, and no VTIMEZONE anywhere in the
file. |
DTEND | Exclusive, as the spec requires — a
one-day holiday on the 25th is DTSTART 25,
DTEND 26. Emitting 25 makes a zero-length event that several
clients silently drop. |
TRANSP:TRANSPARENT | A Swedish holiday is information to a reader in Chicago, not an appointment. Free/busy is what schedulers consult, and a subscribed holiday feed should not mark you unavailable for the year. |
UID | Stable across exports, derived from jurisdiction, observance and date. Re-fetching updates events instead of duplicating them. |
| Line folding | At 75 octets, not characters, so folding a name in Arabic, Thai or Japanese does not split a UTF-8 sequence into mojibake. |
DESCRIPTION | Carries assurance, precision, operational status, the origin jurisdiction, and the nominal date where a substitution moved it. An estimated Islamic date says so inside your calendar, where you will actually be looking at it. |
Because an .ics is only worth having if a calendar client
can subscribe to it, and subscribing means re-fetching a URL on the
client's own schedule. That needs a server emitting
text/calendar at a stable address. A file built in a browser
is a one-time download — the least useful form of the feature, and the form
that leaves every non-browser caller with nothing.
Pre-generating files is not an option either: 241 countries × any window ×
assurance floor × categories × closures_only is millions of
files to serve a handful of them. By the time the serializer runs, the rows
are already assembled — this is a rendering step, not a second
pipeline.
.ics today. You cannot yet point Google Calendar or Outlook at
a timesys URL, because a calendar client cannot send an
X-API-Key header — it just fetches a URL. That needs a
separate, revocable feed token in the URL itself, scoped to one saved query
and revocable without touching your API key. It is not built yet, and until
it is, this page will not pretend otherwise.
Split by jurisdiction if you are subscribing. One file per country makes a cleaner calendar than one file with six countries' holidays interleaved — and lets a reader turn one off.
Consider closures_only=true for a work calendar.
Without it you also get the observed-but-open days, which is right for
planning meetings and noisy for planning cover.