Anvil › Docs › /v1/cron/explain
Cron explainer API: plain-English schedule + next runs
Paste a cron expression and get back what it means in one sentence, which values each field expands to, a warning when day-of-month and day-of-week are ORed, and the next times it will fire in the zone you name. Same rules as crontab, Kubernetes CronJobs and Tooltern's browser cron explainer — useful from a script, CI job or admin page.
/v1/cron/explain?expr=%2A/15%209-17%20%2A%20%2A%20mon-fri&tz=UTC&count=5 returns JSON. No key, CORS on, 60 requests a minute./v1/cron/explain
Explain a cron schedule in plain English, with next runs. Change the values and press Send request to call the live API.
Parameters
| Name | Type | What it does | Default |
|---|---|---|---|
expr required | string | 5-field cron expression or @daily, @hourly… | — |
tz | string | Time zone the schedule runs in | UTC |
count | integer | Next runs to list, 1 to 50 | 5 |
from | string | Start after this moment (ISO 8601 / Unix) | now |
Example
Request:
GET https://api.oddlathe.com/v1/cron/explain?expr=%2A/15%209-17%20%2A%20%2A%20mon-fri&tz=UTC&count=5
Response (generated by the real code when these docs were last built; random or time-based values will differ for you):
{
"expr": "*/15 9-17 * * mon-fri",
"shortcut": null,
"description": "Every 15 minutes, between 09:00 and 17:59, on Monday through Friday.",
"fields": [
{
"name": "minute",
"raw": "*/15",
"any": false,
"values": [
0,
15,
30,
45
],
"values_text": "0, 15, 30, 45"
},
{
"name": "hour",
"raw": "9-17",
"any": false,
"values": [
9,
10,
11,
12,
13,
14,
15,
16,
17
],
"values_text": "9, 10, 11, 12, 13, 14, 15, 16, 17"
},
{
"name": "day of month",
…
Code examples
curl -G 'https://api.oddlathe.com/v1/cron/explain' \
--data-urlencode 'expr=*/15 9-17 * * mon-fri' \
--data-urlencode 'tz=UTC' \
--data-urlencode 'count=5'const params = new URLSearchParams({
expr: "*/15 9-17 * * mon-fri",
tz: "UTC",
count: "5"
});
const res = await fetch(`https://api.oddlathe.com/v1/cron/explain?${params}`);
if (!res.ok) throw new Error((await res.json()).error.message);
const data = await res.json();
console.log(data);import json, urllib.parse, urllib.request
params = urllib.parse.urlencode({"expr": "*/15 9-17 * * mon-fri", "tz": "UTC", "count": "5"})
url = "https://api.oddlathe.com/v1/cron/explain?" + params
# Send a User-Agent: the edge network refuses Python's default one.
req = urllib.request.Request(url, headers={"User-Agent": "my-script/1.0"})
with urllib.request.urlopen(req, timeout=10) as r:
data = json.load(r)
print(data)When it's useful
- Showing "next backup at…" with a human label in an admin UI
- CI checks that a CronJob or crontab change still means what you think
- Teaching the day-of-month OR day-of-week rule before someone ships Friday-the-13th-only by mistake
- Sanity-checking schedules that never run (30 February) before deploy
Good to know
- Five fields: minute, hour, day of month, month, day of week. Lists (
1,15), ranges (9-17), steps (*/15), names (mon-fri,jan), 7 as Sunday, and@hourly,@daily,@weekly,@monthly,@yearly/@annually,@midnight. descriptionis one plain-English sentence.fieldslists each field withraw,any, the expandedvaluesand a shortvalues_text.- The OR rule: if both day-of-month and day-of-week are restricted, a day matching either one counts. The response sets
dom_dow_or: trueand adds adom_dow_orwarning. Example:0 0 13 * 5runs on every 13th and every Friday. - Times skipped when clocks go forward are left out; times that repeat when clocks go back run once. Encode spaces as
%20(or use curl-G --data-urlencode). - Prefer next-run times only? Use sibling
/v1/cron/next. Prefer a page to an API? Tooltern's cron expression explainer runs entirely in your browser.
Sibling of /v1/cron/next and of Tooltern's cron explainer: breaks each field down, writes one plain-English sentence, lists the next runs (DST-aware) and warns when day-of-month and day-of-week are ORed. Lists, ranges, steps, month/weekday names, 7 as Sunday, and @hourly/@daily/@weekly/@monthly/@yearly. Pure parsing; nothing is stored.
Errors
Errors are JSON like {"error": {"code": "…", "message": "…"}}. The ones this endpoint can return:
missing_param(400): a required parameter is missing or emptybad_param(400): a value is the wrong type or out of range (the message says which)bad_timezone(400): the zone isn't a known IANA namebad_cron(400): the expression can't be parsed; the message names the fieldrate_limited(429): over 60 requests a minute; wait for Retry-After seconds
Questions
How is this different from /v1/cron/next?
Both return next runs. This endpoint also returns a plain-English description, a per-field breakdown and OR-rule warnings — everything Tooltern's cron page shows, as JSON.
Does it support seconds or a year field?
No. Six- or seven-field formats are Quartz/Spring extensions; this API reads classic 5-field Vixie cron.
What about @reboot?
It returns bad_cron: @reboot fires once when the daemon starts, so there is no repeating schedule to explain.
Which time zone should I use?
Match the machine (or CRON_TZ) that will run the job. Servers are usually UTC; GitHub Actions schedules are UTC and often start a few minutes late under load.
Related endpoints
/v1/cron/nextWhen will a cron schedule run next?/v1/date/diffAge, duration and ISO week maths between two dates/v1/timeCurrent time (or any moment) in a time zone, with next DST change/v1/time/convertConvert a local time between time zones
Prefer a page to an API?
- Cron expression explainer on Tooltern: same job, nothing leaves your browser.
- Guide: Cron every 5 minutes (and other common schedules)
Published , updated · OpenAPI 3.1 spec · Limits and privacy