Request each country's holiday list for the year, collect the closed dates in one map, and read off the weekdays on which nobody is closed. The API has one holiday endpoint per country and year, so a team across four countries makes four requests and gets the clear days from one loop.
Ask when a country is next closed
GET /v1/calendars/holidays/{country}/next returns the first holiday on or after from_date. This request asks for Japan from 9 November 2026.
curl -s -H "Authorization: Bearer $NARWHAL_API_KEY" \
"https://api.narwhalapi.com/v1/calendars/holidays/JPN/next?from_date=2026-11-09"{
"country": "JPN",
"coverage": [
{
"scope": "national_public",
"subdivision_codes": []
}
],
"holiday": {
"date": "2026-11-23",
"name": "Labor Thanksgiving Day",
"holiday_key": "labor_thanksgiving_day",
"local_name": "勤労感謝の日",
"scope": "national_public",
"subdivision_codes": []
}
}The holiday is Labor Thanksgiving Day on 23 November, with scope national_public. local_name carries the Japanese name and holiday_key is the stable key for the kind of day. For a single country this answers the planning question in one call. For several countries, ask each one and keep the earliest answer, or read the whole year as the next section does.
Find the clear days across countries in one pass
- Get an API key Get an API key at signup and keep it in
NARWHAL_API_KEY. - List the countries and the window The script uses
USA,DEU,JPNandIDN, from 9 to 30 November, and looks for 3 clear business days in a row. Three days is an example, so use the length your release or maintenance window needs. Change the list and the dates for your own teams. - Collect the closed dates One request per country returns the year's holidays. The script stores each
datein a map from the date to the set of countries that are closed. A date shared by two countries holds both codes. - Walk the weekdays and report The script lists the weekdays with at least one closure and then finds the first run of clear business days.
import os from collections import defaultdict from datetime import date, timedelta import requests HEADERS = {"Authorization": f"Bearer {os.environ['NARWHAL_API_KEY']}"} COUNTRIES = ["USA", "DEU", "JPN", "IDN"] START, END, NEED = date(2026, 11, 9), date(2026, 11, 30), 3 closed = defaultdict(set) # date -> countries closed that day for country in COUNTRIES: r = requests.get( f"https://api.narwhalapi.com/v1/calendars/holidays/{country}/{START.year}", headers=HEADERS, timeout=10, ) r.raise_for_status() for h in r.json()["holidays"]: closed[h["date"]].add(country) days, day = [], START while day <= END: if day.weekday() < 5: days.append((day, sorted(closed.get(day.isoformat(), [])))) day += timedelta(1) for day, who in days: if who: print(day.strftime("%a %d %b"), "closed:", ", ".join(who)) for i in range(len(days) - NEED + 1): if all(not who for _, who in days[i:i + NEED]): print(f"first {NEED} clear business days in a row start:", days[i][0].strftime("%a %d %b")) break
Wed 11 Nov closed: USA
Mon 23 Nov closed: JPN
Thu 26 Nov closed: USA
first 3 clear business days in a row start: Thu 12 NovAmong the 16 weekdays between 9 and 30 November, 3 have a closure and 13 are clear in all four countries. The first run of 3 clear business days begins on Thursday 12 November. The script uses no scope filter, so Indonesia's collective leave days would count as closed. Add scope=national_public to that country's request to leave them out.
The closed days to keep out of the plan
| Date | Country | Holiday |
|---|---|---|
| Wed 11 Nov | USA | Veterans Day |
| Mon 23 Nov | JPN | Labor Thanksgiving Day |
| Thu 26 Nov | USA | Thanksgiving Day |
A release set for Wednesday 11 November would meet a closed United States office. The two Thanksgiving days are different holidays in different countries, with the holiday_key values labor_thanksgiving_day and thanksgiving_day, and each closes only its own country. Matching on the key rather than the name keeps them apart.
To put the closed days in front of the people who schedule work, create a calendar feed with include_holidays true and include_releases false through POST /v1/calendars/subscriptions. The calendar subscriptions documentation describes the request. This page leaves it unrun because the call creates a feed.
What each scope covers in this comparison
| Country | What the list holds | Effect on the schedule |
|---|---|---|
| USA | The federal_government scope | Veterans Day and Thanksgiving appear as closed |
| JPN | The national_public scope | Labor Thanksgiving Day appears as closed |
| DEU | The national_public scope | No closure in this window |
| IDN | national_public and collective_leave | No closure in this window |
Read coverage in each response before you rely on a list. It names the scopes and the subdivisions the calendar covers, and the scopes differ by country. A country whose entries carry subdivision codes, such as the United Kingdom, needs one more check: keep an entry when its list is empty or holds the office's region.
Do weekend holidays matter for scheduling?
Not for the weekday walk. A holiday on a Saturday or Sunday is skipped because the script only looks at Monday to Friday. Some countries move the day to a weekday and mark the new entry observed, and that entry has a weekday date, so it appears as a closure.
What if my team works in a country with regional holidays?
Filter by subdivision_codes in your code, because the year endpoint has no region parameter. An empty list means the holiday is nationwide. For the United Kingdom each bank holiday appears once per group of nations, so one date can have several entries.
How many requests does a window across years need?
One request per country and year. A window that crosses 31 December needs the next year's list for each country as well, and a year with no published calendar returns a 404 with the code calendar_not_published. Plan for that response in a long-range schedule, and keep each year's list in a cache so repeated runs do not ask again.
Published .