Nine small endpoints. That's the whole API.
Everything lives under https://supercrontab.com/v1. Create a token on your account page (read-only tokens are available) and send it as Authorization: Bearer <token> on every call. Request and response bodies are JSON. Field names are snake_case, like status_code; camelCase works too. Each token can make 600 requests a minute, and the X-RateLimit-Remaining header tells you how many are left.
Errors always look the same: an HTTP status plus { "error": { "code": "...", "message": "..." } }, where the message says in plain words what to fix.
/jobsList your jobs
Returns every cron job on your account, 100 at a time.
More about this call
Use it to check what is scheduled, or to find a job id for the other calls. If there are more than 100, the response includes a next_cursor; send it back as ?cursor= to get the next page.
| Field | Type | Notes |
|---|---|---|
| cursor | string | Optional. The next_cursor value from the previous page. |
| status | enum | Optional. Show only active or only paused jobs. |
curl https://supercrontab.com/v1/jobs \ -H "Authorization: Bearer tk_live_..."Response 200
{
"data": [{
"id": "job_8f2k1abcd0ef",
"name": "Warm homepage cache",
"url": "https://shop.example.com/cron/warm",
"method": "GET",
"schedule": "*/5 * * * *",
"timezone": "UTC",
"status": "active",
"next_run_at": "2026-09-16T09:05:00Z"
}],
"next_cursor": null
}/jobsCreate a job
Tell us which URL to call and when, and we call it on schedule from then on.
More about this call
You get the new job back with its first next_run_at. If the schedule fires more often than your plan allows, the call fails with 422 and a message saying so.
| Field | Type | Notes |
|---|---|---|
| name | string | Required. A label you will recognise in the dashboard and in alerts. |
| url | string | Required. The URL we call. Must start with https://. |
| schedule | string | Required. Standard 5-field cron, for example 0 2 * * * for 02:00 every day. |
| timezone | string | Optional. An IANA name like Europe/Berlin. Defaults to UTC. |
| method | enum | Optional. GET, POST, PUT or DELETE. Defaults to GET. |
| headers, body | object, string | Optional. Extra request headers and a request body to send with each call. |
| notify | object | Optional. Where to tell you about failures: { "email": "..." } and/or { "webhook": "https://..." }. |
| auth | object | Optional. Credentials we attach to each call. See "Authentication for jobs" below. |
curl -X POST https://supercrontab.com/v1/jobs \
-H "Authorization: Bearer tk_live_..." \
-H "Content-Type: application/json" \
-d '{
"name": "Nightly invoice export",
"url": "https://api.example.com/tasks/export",
"method": "POST",
"schedule": "0 2 * * *",
"timezone": "Europe/Berlin",
"auth": { "type": "bearer", "token": "tk_..." },
"notify": { "webhook": "https://hooks.example.com/sc" }
}'Response 201{
"id": "job_9a1zzq7r2m4n",
"status": "active",
"next_run_at": "2026-09-17T00:00:00Z"
}/jobs/{id}/runsSee what happened on each run
The history of one job, newest run first.
More about this call
Each entry tells you when the run started, how long it took, whether it succeeded, the HTTP status your server answered with, how many attempts we made, and the beginning of the response body. Filter with ?status=failed to see only the runs that went wrong.
| Field | Type | Notes |
|---|---|---|
| since | ISO-8601 | Optional. Only runs that started after this time. |
| status | enum | Optional. ok or failed. |
curl "https://supercrontab.com/v1/jobs/job_8f2k1abcd0ef/runs?status=failed" \ -H "Authorization: Bearer tk_live_..."Response 200
{
"data": [{
"id": "run_01j8xk3m9p2q",
"started_at": "2026-09-16T08:55:00Z",
"duration_ms": 30000,
"status": "failed",
"http_status": null,
"error": "timeout",
"attempts": 3,
"response_body": ""
}],
"next_cursor": null
}/jobs/{id}/runRun a job right now
Triggers one extra run straight away without touching the schedule.
More about this call
Handy after a deploy, or to check a new job works before its first scheduled time. The run is queued and usually starts within a few seconds; watch it arrive in the run history. Calling this twice within 5 seconds only queues one run.
| Field | Type | Notes |
|---|---|---|
| none | No request body needed. |
curl -X POST https://supercrontab.com/v1/jobs/job_8f2k1abcd0ef/run \ -H "Authorization: Bearer tk_live_..."Response 202
{ "run_id": "run_01j8yq2w8c5d", "status": "queued" }Authentication for jobs
If the URL you want us to call needs credentials, put them in auth when you create or update the job, and we attach them on every call. Secrets are encrypted at rest and never shown again: when you read the job back you see ••••••••. When you update a job, send that masked value back (or leave auth out) to keep the existing secret; send a new value to replace it. The same auth shapes work on mock endpoints, where they say what callers must present.
{ "type": "basic", "username": "u", "password": "p" }bearer: We send Authorization: Bearer <token>.{ "type": "bearer", "token": "..." }api_key: We send the key in a header, or in the query string when in is "query".{ "type": "api_key", "in": "header", "name": "X-Api-Key", "value": "..." }oauth2_cc: We fetch a token with the client-credentials flow first, reuse it until it expires, then send it as a Bearer token.{ "type": "oauth2_cc", "tokenUrl": "https://auth.example.com/token", "clientId": "...", "clientSecret": "...", "scope": "read" }hmac: We sign the raw request body with HMAC-SHA256 and put the hex signature in the header you name.{ "type": "hmac", "secret": "...", "header": "X-Signature", "prefix": "sha256=" }/endpointsCreate a mock endpoint
Creates a URL that answers with exactly what you configure and logs everything it receives.
More about this call
Point a webhook or a cron job at it to see what your code sends, and to test how your code copes when the other side is slow or failing. The URL is https://{slug}.supercrontab.com/ and the slug is generated for you. Limits per account: Free 3 endpoints, 30 requests a minute, 500 a day; Pro 25, 300 a minute, 10,000 a day; Team 100, 1,000 a minute, 50,000 a day. Over the limit the endpoint answers 429 with a Retry-After header.
| Field | Type | Notes |
|---|---|---|
| name | string | Required. A label for the dashboard. |
| methods | string | Optional. ANY (default) or a list like GET,POST. Other methods get 405. |
| status_code | int | Optional. The status to answer with. Defaults to 200. |
| content_type | string | Optional. Defaults to application/json. |
| body | string | Optional. The response body, up to 64 KB. |
| response_headers | object | Optional. Extra headers to add to every response. |
| delay_ms | int | Optional. Wait this long before answering, up to 30000. Good for testing timeouts. |
| error_rate, error_status | int | Optional. Answer error_status (default 500) on this percentage of requests, picked at random. Good for testing retries. |
| sequence | object | Optional. A scripted list of steps per Idempotency-Key, for reproducing one exact failure. See "Fault sequences" below. |
| auth | object | Optional. Require callers to authenticate: basic, bearer, api_key or hmac. Wrong or missing credentials get 401. |
| log_requests | bool | Optional. Keep a log of incoming requests. Defaults to true. |
curl -X POST https://supercrontab.com/v1/endpoints \
-H "Authorization: Bearer tk_live_..." \
-H "Content-Type: application/json" \
-d '{ "name": "Order webhook", "status_code": 202, "body": "{\"received\":true}", "auth": { "type": "bearer", "token": "s3cret" } }'Response 201{
"data": {
"id": "ep_7hx2k9q4m1p3",
"slug": "kq7mx2p9tz",
"url": "https://kq7mx2p9tz.supercrontab.com/",
"status_code": 202,
"auth": { "type": "bearer", "token": "••••••••" }
}
}/endpointsList your endpoints
Every mock endpoint on your account with its URL, current settings and hit count, 100 at a time.
More about this call
GET /endpoints/{id} returns a single one in the same shape.
| Field | Type | Notes |
|---|---|---|
| cursor | string | Optional. The next_cursor value from the previous page. |
curl https://supercrontab.com/v1/endpoints \ -H "Authorization: Bearer tk_live_..."Response 200
{
"data": [{
"id": "ep_7hx2k9q4m1p3",
"slug": "kq7mx2p9tz",
"url": "https://kq7mx2p9tz.supercrontab.com/",
"name": "Order webhook",
"methods": "ANY",
"status_code": 202,
"delay_ms": 0,
"error_rate": 0,
"sequence": null,
"hits": 12,
"last_hit_at": "2026-09-17T10:12:03Z"
}],
"next_cursor": null
}/endpoints/{id}Change or delete an endpoint
Send only the fields you want to change; everything else stays as it is.
More about this call
The URL never changes, so anything already pointing at the endpoint keeps working with the new behaviour from the next request. To remove an endpoint and its log for good, call DELETE /endpoints/{id}; its URL then answers 404.
| Field | Type | Notes |
|---|---|---|
| any field from create | Optional. Send auth as the masked value you received to keep the existing secret. |
curl -X PATCH https://supercrontab.com/v1/endpoints/ep_7hx2k9q4m1p3 \
-H "Authorization: Bearer tk_live_..." \
-H "Content-Type: application/json" \
-d '{ "delay_ms": 3000, "error_rate": 10 }'Response 200{
"data": {
"id": "ep_7hx2k9q4m1p3",
"url": "https://kq7mx2p9tz.supercrontab.com/",
"status_code": 202,
"delay_ms": 3000,
"error_rate": 10,
"error_status": 500
}
}/endpoints/{id}/requestsRead the request log
Everything the endpoint has received, newest first: method, path, query string, headers, the first 16 KB of the body, the caller IP and the status we answered with.
More about this call
Authorization, Cookie and API key headers are shown as [redacted] because we never store them. To empty the log, call DELETE on the same path.
| Field | Type | Notes |
|---|---|---|
| cursor | string | Optional. The next_cursor value from the previous page. |
curl https://supercrontab.com/v1/endpoints/ep_7hx2k9q4m1p3/requests \ -H "Authorization: Bearer tk_live_..."Response 200
{
"data": [{
"received_at": "2026-09-17T10:12:03Z",
"method": "POST",
"path": "/",
"headers": { "content-type": "application/json", "authorization": "[redacted]" },
"body": "{\"order\":42}",
"status": 202
}],
"next_cursor": null
}/endpoints/{id}/sequenceRestart a fault sequence
Forgets which step every key has reached, so the next request with any key starts again at step 1.
More about this call
Call it at the beginning of a test run to make sure the scenario plays out the same way every time. Saving the endpoint with a different sequence restarts it too, and keys that have not been seen for 7 days are forgotten automatically.
| Field | Type | Notes |
|---|---|---|
| none | No request body needed. |
curl -X DELETE https://supercrontab.com/v1/endpoints/ep_7hx2k9q4m1p3/sequence \ -H "Authorization: Bearer tk_live_..."Response 204
(empty)
Fault sequences
A fault sequence is a short script for what the endpoint does on the first delivery, the second, the third and so on, so you can reproduce one exact failure on purpose and put it in a test. Requests with the same Idempotency-Key header count as retries of the same delivery.
| Action | What the caller sees |
|---|---|
| respond | Answer normally. You can set status, body and delay_ms for this step; anything you leave out uses the endpoint settings. |
| drop | Log the request, then cut the connection before sending a body. Your code sees a network error instead of an HTTP status, like a server that crashed after it saved your data. |
| timeout | Keep the connection open for delay_ms (default and maximum 30 seconds), then cut it. Tests what your code does when the other side never answers. |
How it works, step by step
A mock endpoint can answer in three ways. The simplest is a fixed answer: the same status and body every time. The second is a random error rate, good for finding out whether your code retries at all. The third is the sequence: deterministic, so the same test gives the same result every run.
You give the endpoint a list of steps. Each incoming request is matched to a delivery by the value of its Idempotency-Key header (or another header you choose). The first request with a given key gets step 1, the second request with the same key gets step 2, and so on. A request with a new key starts again at step 1, and requests without the header all share one counter.
The example on the right reproduces the classic duplicate-order bug: the first delivery is logged and then the connection is cut, so your code cannot tell whether it went through. If your code retries with the same key, it gets 200. If it retries with a new key, it gets cut again, and you have found a bug.
| Field | Type | Notes |
|---|---|---|
| steps | array | Required. 1 to 20 steps, each with an action and optional status, body and delay_ms. |
| key_header | string | Optional. Which request header identifies a delivery. Defaults to Idempotency-Key. Authorization and Cookie are not allowed. |
| on_end | enum | Optional. What happens after the last step: repeat_last (default) keeps answering with the last step; loop starts again from step 1. |
Good to know: while a sequence is set, the endpoint's error rate is ignored. Every response carries an X-Supercrontab-Sequence-Step header so you can see which step you hit, and dropped requests show as dropped in the request log. Key values are stored as hashes, never as the raw header. One limit of running at the edge: a drop cuts the connection after the status line, so most HTTP clients report it as an unexpected end of the response rather than a connection refused.
{
"key_header": "Idempotency-Key",
"on_end": "repeat_last",
"steps": [
{ "action": "drop" },
{ "action": "respond", "status": 200, "body": "{\"received\":true}" }
]
}Webhook on failure
Set notify.webhook on a job and we POST a message like this to your URL when a run has failed three times in a row, and once more when the job succeeds again. Check the X-Supercrontab-Signature header (HMAC-SHA256 of the body with your webhook secret) to be sure the message came from us.
POST https://hooks.example.com/sc
X-Supercrontab-Signature: sha256=3f1c...
{
"event": "job.failed",
"job": { "id": "job_8f2k1abcd0ef", "name": "Warm homepage cache" },
"run": { "id": "run_01j8xk3m9p2q", "http_status": 504, "duration_ms": 30000, "attempts": 3 },
"response_excerpt": "<html>504 Gateway Time-out</html>",
"dashboard_url": "https://supercrontab.com/dashboard"
}