Parse and validate cron expressions via REST API
You're building an admin panel where users schedule recurring jobs. They type a cron expression
into a text field, hit save, and expect the system to do the right thing. The problem: cron syntax
is cryptic. */15 * * * * is clear enough, but what about 0 9 1-15 * 1-5?
Most users (and many developers) can't read that at a glance.
You need to show users what their expression means *before* they save it. A description like "At 09:00 on days 1 through 15, Monday through Friday" is worth more than a tooltip linking to crontab.guru.
Botoi's cron parser API does three things in a single POST request: validates the expression, generates a human-readable description, and returns the next scheduled run times. No cron libraries to install, no parsing logic to maintain.
The parse endpoint
Send a cron expression to /v1/cron/parse and get back a structured breakdown.
curl -X POST https://api.botoi.com/v1/cron/parse \
-H "Content-Type: application/json" \
-d '{"expression": "*/15 * * * *"}' Response:
{
"success": true,
"data": {
"isValid": true,
"description": "Every 15 minutes",
"nextRuns": [
"2026-03-26T18:30:00Z",
"2026-03-26T18:45:00Z",
"2026-03-26T19:00:00Z",
"2026-03-26T19:15:00Z",
"2026-03-26T19:30:00Z"
],
"parts": {
"minute": "*/15",
"hour": "*",
"dayOfMonth": "*",
"month": "*",
"dayOfWeek": "*"
}
}
}
The response includes everything you need: an isValid flag, a plain-English
description, the next five run times in UTC, and the individual parts
broken out by field. You can display the description directly in your UI and use the
nextRuns array to show a preview of upcoming executions.
Get more upcoming runs
If you need more than five preview dates, or you only care about the schedule and not the
description, use the /v1/cron/next endpoint. Pass a count parameter
to control how many future run times you get back.
curl -X POST https://api.botoi.com/v1/cron/next \
-H "Content-Type: application/json" \
-d '{"expression": "0 9 * * MON-FRI", "count": 5}' Response:
{
"success": true,
"data": {
"nextRuns": [
"2026-03-27T09:00:00Z",
"2026-03-30T09:00:00Z",
"2026-03-31T09:00:00Z",
"2026-04-01T09:00:00Z",
"2026-04-02T09:00:00Z"
]
}
}
Notice the gap between March 27 (Friday) and March 30 (Monday). The expression
0 9 * * MON-FRI skips weekends, and the API reflects that correctly.
Build a cron preview widget
Here's how to wire the parse endpoint into a frontend input field. As the user types a cron expression, the widget calls the API and shows the description and upcoming runs in real time.
async function parseCron(expression) {
const res = await fetch("https://api.botoi.com/v1/cron/parse", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ expression }),
});
return res.json();
}
// Example: user types "0 9 * * MON-FRI" into a text input
const input = document.querySelector("#cron-input");
const preview = document.querySelector("#cron-preview");
input.addEventListener("input", async (e) => {
const { data } = await parseCron(e.target.value);
if (data.isValid) {
preview.innerHTML = `
<p class="text-green-600">\${data.description}</p>
<ul>
\${data.nextRuns
.map((run) => `<li>\${new Date(run).toLocaleString()}</li>`)
.join("")}
</ul>
`;
} else {
preview.innerHTML = '<p class="text-red-600">Invalid expression</p>';
}
}); For production use, add a debounce (200-300ms) so you don't fire a request on every keystroke. The API responds in under 50ms from Cloudflare's edge, so the preview feels instant once the request goes out.
React / Preact version
If you're using React or Preact, here's a component that wraps the same logic with an
AbortController to cancel stale requests.
import { useState, useEffect } from "react";
function CronPreview({ value }) {
const [result, setResult] = useState(null);
useEffect(() => {
if (!value.trim()) {
setResult(null);
return;
}
const controller = new AbortController();
fetch("https://api.botoi.com/v1/cron/parse", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ expression: value }),
signal: controller.signal,
})
.then((r) => r.json())
.then(({ data }) => setResult(data))
.catch(() => {});
return () => controller.abort();
}, [value]);
if (!result) return null;
if (!result.isValid) {
return <p className="text-red-600">Invalid expression</p>;
}
return (
<div>
<p className="font-medium">{result.description}</p>
<p className="text-sm text-gray-500 mt-1">
Next run: {new Date(result.nextRuns[0]).toLocaleString()}
</p>
</div>
);
} Validate user input before saving
Client-side previews are great for UX, but you should also validate on the server before
persisting a cron job. Call the parse endpoint from your backend and check the
isValid flag.
async function saveCronJob(name, expression) {
// Validate the expression before saving
const res = await fetch("https://api.botoi.com/v1/cron/parse", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ expression }),
});
const { data } = await res.json();
if (!data.isValid) {
throw new Error("Invalid cron expression: " + expression);
}
// Save to your database with the parsed metadata
await db.cronJobs.create({
name,
expression,
description: data.description,
nextRun: data.nextRuns[0],
});
return { description: data.description, nextRun: data.nextRuns[0] };
} When a user submits an invalid expression, the API returns a clean response you can act on:
{
"success": true,
"data": {
"isValid": false,
"description": null,
"nextRuns": [],
"parts": null
}
}
No exceptions to catch, no regex to write. Check data.isValid and return an error
message to the user. You can also store the description and nextRun
alongside the raw expression in your database, so you can display them in listing views without
calling the API again.
Common cron expressions and what the API returns
| Expression | Description |
|---|---|
* * * * * | Every minute |
*/15 * * * * | Every 15 minutes |
0 * * * * | Every hour |
0 9 * * MON-FRI | At 09:00 on Monday through Friday |
0 0 1 * * | At midnight on the 1st of every month |
30 4 * * SUN | At 04:30 on Sunday |
0 9,17 * * * | At 09:00 and 17:00 every day |
0 0 * * 0 | At midnight on Sunday |
Each of these expressions returns the same structured response: validity flag, description, next runs, and parsed parts. You can use the table above as test cases when integrating the API.
Why offload cron parsing to an API?
- No library dependency. Cron parsing libraries exist for every language, but they add bundle size (frontend) or dependency maintenance (backend). A single HTTP call replaces the library.
- Consistent behavior across services. If your system has a Node.js scheduler, a Python worker, and a Go microservice, they all parse cron expressions differently. One API gives you a single source of truth.
- Human-readable descriptions for free. Generating natural language from cron syntax is harder than parsing the schedule. The API handles both in one call.
- Instant preview for users. Sub-50ms edge responses make real-time validation practical, even on every keystroke with debouncing.
Frequently asked questions
- Does the cron parser API support non-standard expressions like @daily or @weekly?
- Yes. The parse endpoint accepts both standard five-field cron expressions and common shorthand aliases like @yearly, @monthly, @weekly, @daily, and @hourly. The response normalizes them into the standard five-field format.
- What timezone are the nextRuns timestamps in?
- All timestamps in the response are in UTC (ISO 8601 format). Convert them to the user's local timezone on the client side using Intl.DateTimeFormat or a library like date-fns.
- Is there a limit on how many next runs I can request?
- The /v1/cron/next endpoint accepts a count parameter. You can request up to 100 upcoming run times in a single call. The default is 5 if you omit the parameter.
- Do I need an API key to use the cron parser?
- No. Anonymous access is available at 5 requests per minute with IP-based rate limiting. For higher throughput, sign up for an API key at botoi.com/api.
- Can I use day names like MON-FRI in cron expressions?
- Yes. The parser supports three-letter day abbreviations (SUN, MON, TUE, WED, THU, FRI, SAT) and month abbreviations (JAN through DEC) in the appropriate fields.
Try this API
Cron Parser API — interactive playground and code examples
More tutorial posts
Start building with botoi
150+ API endpoints for lookup, text processing, image generation, and developer utilities. Free tier, no credit card.