Skip to content

Examples

Each recipe is one API call you can paste, plus the settings that matter for it. The first seven are crons (recurring requests). The last three are jobs (one-off requests).

Before you start:

  • Set DELAY_TOKEN to your API token (see the quick start) and replace the https://api.yourapp.com/... URLs with your own.
  • Crons default to GET and jobs to POST.
  • A cron’s payload is a string, usually JSON. A job’s payload is a JSON object.
  • Cron schedules run in UTC.
  • The API can’t set success assertions or queue settings. Add those in the dashboard after you create the cron or send the first job.
  • Every run, retries included, counts toward your monthly requests: 1,000 requests a month on the free plan. See runs and usage.

Health check every minute

Call your health endpoint every minute and get an alert when it fails twice in a row.

Terminal window
curl -X POST https://app.delay.run/api/crons \
-H "Authorization: Bearer $DELAY_TOKEN" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
"name": "API health check",
"url": "https://api.yourapp.com/health",
"cron_expression": "* * * * *",
"timeout_seconds": 10,
"alert_threshold": 2
}'
  • Check the body too: open the cron, click Edit, and under Success assertions click Add assertion. For example, JSON path equals with status=ok if the endpoint returns {"status": "ok"}, or Response time under (ms) with 2000. See success assertions.
  • Alerts: crons don’t retry, so a threshold of 2 rides out a single blip. The first failure only raises a warning. See set up alerts.
  • Usage: every minute is 44,640 requests in a 31-day month. Every 5 minutes (*/5 * * * *) is 8,928.

Nightly backup at 03:00 UTC

Start a backup once a day at 03:00 UTC.

Terminal window
curl -X POST https://app.delay.run/api/crons \
-H "Authorization: Bearer $DELAY_TOKEN" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
"name": "Nightly backup",
"url": "https://api.yourapp.com/tasks/backup",
"method": "POST",
"payload": "{\"type\": \"full\"}",
"cron_expression": "0 3 * * *",
"timeout_seconds": 60,
"alert_threshold": 1
}'
  • Payload: a cron’s payload is a string. When the cron runs, Delay parses it and sends the JSON as the request body.
  • Long tasks: Delay waits at most timeout_seconds (300 at most). Return 202 as soon as the backup has started and do the work in the background. See endpoint design.
  • No retries: a failed backup waits until the next night, so alert on the first failure.

Weekday morning report

Send a report at 08:00 UTC, Monday to Friday.

Terminal window
curl -X POST https://app.delay.run/api/crons \
-H "Authorization: Bearer $DELAY_TOKEN" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
"name": "Daily sales report",
"url": "https://api.yourapp.com/reports/daily-sales",
"method": "POST",
"payload": "{\"recipients\": \"sales-team\"}",
"cron_expression": "0 8 * * 1-5",
"alert_threshold": 1
}'
  • Days: 1-5 is Monday to Friday (0 is Sunday). Day names work too: 0 8 * * MON-FRI.
  • Daylight saving time: schedules stay in UTC all year. 08:00 UTC is 09:00 in London in summer and 08:00 in winter. See cron schedules.
  • Hear back: add "callback_url": "https://api.yourapp.com/webhooks/delay" to get a POST with the outcome after every run. See callbacks.

Poll an API that has no webhooks

When a provider can’t push changes to you, have Delay call your sync endpoint on a schedule. The endpoint fetches what changed and stores it.

Terminal window
curl -X POST https://app.delay.run/api/crons \
-H "Authorization: Bearer $DELAY_TOKEN" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
"name": "Sync orders",
"url": "https://api.yourapp.com/sync/orders?source=warehouse",
"headers": {"X-Api-Key": "your-endpoint-key"},
"cron_expression": "*/15 * * * *",
"timeout_seconds": 120,
"alert_threshold": 3
}'
  • Query string: this is a GET (the cron default), and Delay calls the URL with its query string as written.
  • Headers: headers is a JSON object sent with every run. Use it for a key your endpoint checks, or verify Delay’s signature instead.
  • Overlap: Delay doesn’t wait for one run to finish before starting the next. If a sync can take longer than 15 minutes, make the endpoint skip the run when a sync is already in progress.
  • Usage: every 15 minutes is 2,976 requests in a 31-day month.

Post to Slack every weekday

Slack incoming webhooks accept a JSON POST, so a cron can post to a channel with no code on your side.

Terminal window
curl -X POST https://app.delay.run/api/crons \
-H "Authorization: Bearer $DELAY_TOKEN" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
"name": "Standup reminder",
"url": "https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX",
"method": "POST",
"payload": "{\"text\": \"Standup starts in 10 minutes.\"}",
"cron_expression": "50 9 * * 1-5"
}'
  • Webhook URL: create an incoming webhook for the channel in Slack and paste its URL. Anyone with the URL can post, so keep it private.
  • Content type: Delay sends the payload as a JSON body with Content-Type: application/json, which is what Slack expects.
  • Discord: a Discord channel webhook works the same way. Use its URL and a payload of "{\"content\": \"Standup starts in 10 minutes.\"}".
  • This is separate from Delay’s own Slack alerts, which you set up in set up alerts.

Warm a cache every 10 minutes

Rebuild cached pages before visitors ask for them.

Terminal window
curl -X POST https://app.delay.run/api/crons \
-H "Authorization: Bearer $DELAY_TOKEN" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
"name": "Warm page cache",
"url": "https://api.yourapp.com/cache/warm",
"method": "POST",
"payload": "{\"pages\": [\"/\", \"/pricing\", \"/docs\"]}",
"cron_expression": "*/10 * * * *",
"timeout_seconds": 60
}'
  • Use the final URL: Delay doesn’t follow redirects, so a 301 from http:// to https://, or to a www. host, counts as a failure. Use the address that answers with a 2xx.
  • Catch slow runs: add a Response time under (ms) assertion in the dashboard. See success assertions.
  • Usage: every 10 minutes is 4,464 requests in a 31-day month.

Keep a free-tier app awake

Some hosts put a free app to sleep after a stretch with no traffic. A regular request keeps it awake.

Terminal window
curl -X POST https://app.delay.run/api/crons \
-H "Authorization: Bearer $DELAY_TOKEN" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
"name": "Keep app awake",
"url": "https://api.yourapp.com/health",
"cron_expression": "*/10 * * * *",
"timeout_seconds": 60
}'
  • Interval: pick one shorter than your host’s idle timeout.
  • Timeout: an app that was asleep can take a while to start, so allow 60 seconds instead of the default 30.
  • Usage: every 10 minutes is 4,464 requests in a 31-day month, more than the 1,000 requests a month on the free plan. Hourly (0 * * * *) is 744, if your host lets an app idle that long.

Send an email in 15 minutes

When a user signs up, schedule a follow-up email. The job waits 900 seconds, then POSTs the payload to your endpoint.

Terminal window
curl -X POST https://app.delay.run/api/jobs \
-H "Authorization: Bearer $DELAY_TOKEN" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
"queue": "emails",
"url": "https://api.yourapp.com/emails/send",
"payload": {"template": "welcome-tips", "user_id": 4821},
"delay": 900
}'
  • Timing: a job with a delay over 60 seconds is picked up by a once-a-minute check, so it can start up to about a minute after its scheduled_at.
  • Retries: failed jobs are retried on the queue’s schedule (by default after 1 minute, 30 minutes and 3 hours). A timeout can still mean the email went out, so make the endpoint skip users it has already emailed. See retries and queue design.
  • Cancel: delete the job on the Jobs tab before it runs. There’s no API for that, so also have the endpoint check that the email is still wanted.

Send a reminder in 24 hours

86,400 seconds (24 hours) is the longest delay a job can have.

Terminal window
curl -X POST https://app.delay.run/api/jobs \
-H "Authorization: Bearer $DELAY_TOKEN" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
"queue": "reminders",
"url": "https://api.yourapp.com/reminders/send",
"payload": {"reminder_id": "rem_8812"},
"delay": 86400
}'
  • Further ahead: a larger delay is rejected with a 422 (“The delay cannot exceed 86400 seconds (24 hours).”). Store the reminder in your database and let a daily cron send the ones that are due, or have the endpoint schedule another 24-hour job until the date arrives.
  • Check before sending: send an ID rather than the message, and have the endpoint look the reminder up and skip it if it was cancelled in the meantime.

Charge a card, then get a callback

Run a payment request right away, with retries, and get a POST when it has succeeded or finally failed.

Terminal window
curl -X POST https://app.delay.run/api/jobs \
-H "Authorization: Bearer $DELAY_TOKEN" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
"queue": "payments",
"url": "https://api.yourapp.com/billing/charge",
"payload": {"order_id": "ord_1042", "amount_cents": 4900},
"callback_url": "https://api.yourapp.com/webhooks/delay?order=ord_1042"
}'
  • When the callback fires: once, when the job succeeds ("status": "success") or runs out of retries ("status": "dead_lettered"), not after each failed attempt. Callbacks are not retried. See callbacks.
  • Match it to the order: after a retry, the callback’s job_id is the retry’s ID, and original_job_id is the job_id the API returned. Your own ID in the callback URL, as above, also survives a replay, which gets a new ID.
  • Avoid double charges: every failure is retried, including timeouts and 4xx responses. If a timeout hides a charge that went through, the retry charges again. Pass the order ID to your payment provider as an idempotency key, or open the payments queue in the dashboard and untick Enable automatic retries. See retries and queue design.

Next steps