Every team that touches payroll, delivery promises, support SLAs, or renewal dates eventually writes the same fragile function: loop forward a day at a time, skip Saturday and Sunday, check a holiday list, repeat. The holiday list is the easy part. You can get one for free, and you should, because raw lookup was never the hard part.
The bugs live in the rules around the list. Independence Day falls on a Saturday, so the office actually closes on the Friday, and your loop counts the Friday as a business day. A client's team works a Friday to Saturday weekend. Your own company shuts down between Christmas and New Year, a closure that exists in no public dataset anywhere. And when a customer asks why their deadline landed on Tuesday instead of Monday, "the function said so" is not an answer anyone can audit.
DayRules is the API we built for that function. It adds, counts, and steps business days across country and exchange calendars, applies the caller's own calendar rules, and explains every date it skips, unless you ask it not to.
What it does
- Add or subtract business days (up to plus or minus 10,000), count business days between two dates, find the next or previous business day, and classify a single date with the reason for the verdict
- Holiday lists by country, subdivision, or exchange calendar, by year or range. Subdivisions are real calendars, not decoration: Bavaria is DE-BY, England is GB-ENG, and a Bavarian holiday like Corpus Christi is answered by the subdivision calendar, not the national one
- Custom weekends per request, including a Friday and Saturday weekend or no weekend at all
- Caller-supplied closures and extra holidays, and forced workdays for the dates your team actually worked
- An observed toggle, so observed and substitute holidays are a choice in the request instead of a hidden assumption baked into the data
- Holiday type filters (public, bank, school) where the bundled data supports them
- Batch: up to 100 add, between, and is-business-day operations in one call, and the batch counts as one request
The bundled dataset serves 250 country calendars and 30 exchange calendars. That number is library coverage, and we label it that way rather than dressing it up as verified coverage: the /v1/countries endpoint publishes a coverage flag for every calendar, 34 of the 250 country calendars are flagged partial, and any response that touches partial coverage carries a notice. Before launch we spot-checked the 2026 calendars for ten countries (US, GB, DE, FR, JP, CA, AU, IN, BR, ES) against official sources. Every response also carries a data_version field, currently holidays-0.107+registry.2, so you always know which dataset produced an answer.
A taste
Ask for one business day after Thursday, July 2, 2026, in the US calendar:
curl -X POST "https://dayrules.p.rapidapi.com/v1/business-days/add" \
-H "X-RapidAPI-Key: YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"country": "US", "start": "2026-07-02", "days": 1}'
You land on Monday, July 6, and the response shows its work:
{
"data_version": "holidays-0.107+registry.2",
"calendar_id": "US",
"start": "2026-07-02",
"days_requested": 1,
"result": "2026-07-06",
"calendar_days_elapsed": 4,
"skipped": [
{
"date": "2026-07-03",
"primary_reason": "holiday",
"reasons": [
{
"kind": "holiday",
"name": "Independence Day (observed)",
"type": "public",
"observed": true,
"substitute_for": "2026-07-04"
}
]
},
{
"date": "2026-07-04",
"primary_reason": "holiday",
"reasons": [
{ "kind": "holiday", "name": "Independence Day", "type": "public", "observed": false, "substitute_for": null },
{ "kind": "weekend" }
]
},
{
"date": "2026-07-05",
"primary_reason": "weekend",
"reasons": [ { "kind": "weekend" } ]
}
]
}
Friday the 3rd is the observed closure for the Saturday holiday, and the response says exactly that, including what the observed date substitutes for. That explanation is the default behavior of every math endpoint: DayRules explains every date it skips, unless you ask it not to. If you are counting business days across a ten-year range and would rather not ship the list back and forth, set include_skipped to false and you get skip counts by reason, with a flag in the response saying the detail was suppressed at your request.
The between endpoint breaks a range into calendar days, weekend days, holiday days, and closure days alongside the business-day total, so a count is never a bare number you have to take on faith.
How it is built
FastAPI, with the calendar logic kept pure and separate from the web layer, and built to deploy on the free tier of Render. The holiday data comes from the python-holidays rule engine, pinned to a fixed version and bundled with the service. That choice is deliberate: the API makes no network calls at runtime, so an answer never depends on a third-party holiday service being awake, and the same request against the same data_version always returns the same result. Updating the data is one atomic change: raise the pin, regenerate the coverage registry, run the test suite, and the data_version moves with it.
The limits, plainly, because every DSP listing has a Limits section and this post should too. The data is planning-grade. It is community-maintained, governments declare one-off holidays that any dataset can lag, and calculated dates can shift. Treat the coverage flags as part of the answer, and verify independently before a date drives a legal filing or a payroll cutoff. Counts are whole days; there is no half-day accounting and no business-hours math. And if all you need is a list of holidays for one country, free lookup services exist and you should use one. What DayRules charges for is the arithmetic, the caller-calendar rules, and the explanation.
Pricing
Every endpoint is available on every plan, including the free tier. The countries, holidays, is-business-day, add, between, next, previous, and batch endpoints are all there from the start, with no Pro-only countries and no explanation feature held back to force an upgrade. Upgrading simply gets you more requests per month: start free with 1,500 requests a month (and remember, one request can carry a batch of 100 operations), move up to Pro at $9/month for 60,000, Ultra at $19/month for 300,000, or Mega at $49/month for 1,000,000. Paid plans are soft limits with small overages, so a traffic spike does not hard-stop a production integration in the middle of a payroll run. You pay for volume, not for access.
The listing is here: https://rapidapi.com/darksundarker/api/dayrules
Feedback very welcome, especially the "my calendar has a rule you do not handle" kind. Custom weekends, closures, and forced workdays are in v1 because public calendars cannot know them, and the next rule DayRules learns will probably come from the same place.
Top comments (0)