tilwhen

Date API for developers and AI agents

Date arithmetic is where language models and scripts quietly go wrong: business days across a border, a holiday that moved because it fell on a Sunday, a countdown computed in the server's timezone instead of the user's. tilwhen answers those over plain HTTP, and every answer arrives with its own working.

No key, no account, no quota. Every endpoint is a public GET returning JSON, with Access-Control-Allow-Origin: * so it works from a browser. Requests are rate limited per IP at 300 per 60 seconds; above that you get a 429 with Retry-After. Machine-readable spec: openapi.json (OpenAPI 3.1).

Using an AI client? The same engine is hosted as a Model Context Protocol server at https://mcp.tilwhen.com/mcp, so Claude, Cursor and any other MCP client can call it directly with no key and nothing to install. Set up the MCP server.

Try it

curl "https://tilwhen.com/api/v1/business-days?date=today&days=30&cal=GB&tz=Europe/London"

Answers a plain-English question the same way:

curl "https://tilwhen.com/api/v1/parse?q=90+business+days+from+today+excluding+uk+holidays"

A link you can construct from the question

If you are an assistant handing a person a link rather than calling an endpoint, put the question straight in the path. /ask/<question-in-hyphens> resolves to whichever page already answers it, so you never have to know the route table:

https://tilwhen.com/ask/90-business-days-from-today-excluding-uk-holidays
  → 302 /business-days-calculator?n=90&dir=from&cal=GB

https://tilwhen.com/ask/days-until-2026-12-25
  → 302 /days-until/christmas

ISO dates survive the hyphens. Send Accept: application/json (or add ?format=json) and you get the parsed operation, the answer, the receipt and the URL to cite instead of a redirect. Anything the parser cannot place confidently lands on the homepage with the question loaded into the command palette rather than guessing.

These URLs are noindex and absent from the sitemap on purpose: they redirect to real pages rather than being pages, so they resolve for people without spending crawl budget. Link people to /ask/...; cite the page it resolves to.

Endpoints

Parameters marked * are required.

EndpointWhat it answersParameters
/api/v1/parse Parse a natural-language date query and answer it q* tz locale
/api/v1/add Date N calendar days after a date date days* tz
/api/v1/subtract Date N calendar days before a date date days* tz
/api/v1/diff Signed whole days between two dates (exclusive) from* to* tz
/api/v1/business-days Business days between two dates, or the date N business days from a date from to date days dir cal custom ww tz
/api/v1/invoice-due Invoice due date from net payment terms date net* roll cal custom ww tz
/api/v1/next-occurrence Next occurrence of a tracked event or weekday, strictly after the base date event weekday from tz
/api/v1/holidays Observed public holidays for a jurisdiction and year cal* year*
/api/v1/explain Full receipt plus human-readable derivation steps for any operation op*

Every answer carries its working

Responses are { answer, receipt }. The receipt names the normalized operation, the pinned input dates, the IANA timezone, the counting convention (whole calendar days, today = day 0, exclusive), the working week, the holiday calendar with each excluded holiday itemised, the primary sources with their retrieval dates, the engine and dataset versions, and a stable result ID. The ID is a deterministic hash of the normalized inputs and versions, with the timestamp deliberately excluded, so the same question under the same versions always reproduces the same ID. Engine 1.0.0, holiday dataset 2026.07.2. See how to cite a result.

Holiday calendars

Pass cal= one of: US, GB, GB-SCT, GB-NIR, IE, FR, CA, AU, UG. There is deliberately no default: omit it and no holidays are excluded, and the receipt says so rather than guessing from your timezone or IP. Supply your own organisation's calendar instead with custom= as comma-separated ISO dates. Working week is ww= (mon-fri, sun-thu, mon-sat).

Errors, caching and conventions

  • Errors are always JSON, never HTML: {"error":{"code":"...","message":"..."}} with a specific code such as invalid_date, unknown_jurisdiction, out_of_range or rate_limited.
  • Unrecognised values are rejected rather than silently defaulted. roll=yes is a 400, not a quiet "no".
  • Answers pinned to explicit dates are immutable: they carry an ETag and honour If-None-Match with a 304.
  • Answers relative to "today" expire at the next midnight in the requested timezone, via s-maxage.
  • tz= takes any IANA identifier and defaults to UTC. It is the only thing that decides which calendar day "today" is.
  • Only GET, HEAD and OPTIONS; anything else is a 405.

Model Context Protocol

If you are wiring this into an AI client rather than calling it from code, the same engine is exposed over MCP with the same receipts. See the MCP server.

Using it

The API is free and unmetered below the rate limit, and there is no plan to change that. Attribution to tilwhen.com is welcome but not required. If you are building something that needs a higher limit or a jurisdiction we do not cover yet, get in touch.