Skip to content

How to run a cron job without a server

Call any URL or API on a schedule without running a server: every few minutes, daily or on weekdays. Every call is logged and retried, with failure alerts.

Updated

Plenty of jobs just need a URL called on a timer: refresh a cache every hour, ping an endpoint that sends a daily digest, pull new records from an API every morning, or keep a free-tier app awake. The classic answer is a cron job, which needs a server that's always on. This guide sets up the same thing without one: a schedule starts the workflow, and an HTTP request step calls your URL, with every call logged and retried if it fails.

  1. Trigger

    On a schedule

    Every 15 minutes, every day at 09:00, or on chosen weekdays, in your timezone.
  2. Step 1

    HTTP request

    POST https://api.example.com/jobs/refresh
The workflow you'll build: a schedule and one request.

Before you start

  • A Foliot account. The free plan covers schedules up to about every 2 hours (see the run math below).
  • The URL to call, and its method: GET, POST, PUT, PATCH or DELETE.
  • If the API needs a key, the header that carries it, such as Authorization: Bearer …. Foliot can store it encrypted as a connection, so it never appears in your run history.

Set it up

1. Create the workflow and pick a schedule

Create a new workflow and choose On a schedule as its trigger. Pick one of three kinds:

  • Every few minutes or hours: for example every 15 minutes, or every 6 hours. The shortest is every minute.
  • Every day: at a time you choose, like 09:00.
  • On certain days of the week: for example Monday to Friday at 08:30.

Choose the timezone the times are in. Foliot keeps them right through daylight-saving changes, so a 09:00 job stays at 09:00 local time all year. There's no cron syntax to write: you pick the schedule in plain words.

2. Add the HTTP request step

Click + after the trigger and choose HTTP request. Set the Method and URL, then add anything else the endpoint expects:

  • Query parameters and Headers as name and value pairs.
  • A Body as JSON fields or form fields. Each field can be fixed text or data from the trigger, such as Trigger → scheduledAt, the time the run was scheduled for.
  • For an API key, pick or add a connection under Authentication (optional). Foliot adds its headers to the request and keeps the value out of the stored history.

For a POST with a small JSON body, the request Foliot sends looks like this:

POST https://api.example.com/jobs/refresh
Content-Type: application/json
Authorization: Bearer ••••••

{ "source": "foliot", "scheduledAt": "2026-10-15T09:00:00.000Z" }

3. Test the step, then turn the workflow on

Test this step sends the request for real and shows the response: status, headers and body. When it looks right, switch the workflow on. From then on, Foliot calls the URL on schedule, and each call appears in the run history with what was sent and what came back.

How many runs a schedule uses

Each time the schedule fires is one run, however many steps the workflow has. The free plan includes 500 runs a month; Pro includes 10,000 for $12 a month. Over a 30-day month:

Every minute

Runs a month
43,200
Plan
Too many for one workflow on Pro

Every 5 minutes

Runs a month
8,640
Plan
Pro

Every 15 minutes

Runs a month
2,880
Plan
Pro

Every hour

Runs a month
720
Plan
Pro

Every 2 hours

Runs a month
360
Plan
Free

Every day

Runs a month
30
Plan
Free

Weekdays at 08:30

Runs a month
About 22
Plan
Free

If one schedule would use more than you need, a slower one with a For each loop often does the same job: fetch a list once an hour and handle every item in that one run.

Useful variations

Know when the endpoint is down

You don't need extra steps for this. A response of 400 or above, or no response at all, fails the run (after the retries above), and Foliot emails you with the status and error. To be told about something the endpoint reports while still answering 200, like {"status": "degraded"}, add a Branch on Step 1 → body → status and put Post to Slack or Send email on its Yes path. This is a simple check, not a full uptime monitor: there's no status page, and every check comes from one place.

Fetch data, then do something with each item

Use a GET request to pull a list, then For each on Step 1 → body → items to add a row to Google Sheets or call another API for every item (up to 100 per run).

Reshape the response

A Code step can turn the response into what the next step needs: total some numbers, format a date, or build a short summary for Slack. The Code step can't make network calls itself; requests go through the HTTP request step.

Only continue when there's something to do

A Filter step such as “Step 1 → body → count is greater than 0” stops the run quietly when there's nothing new, without counting as a failure.

Good to know

  • Runs start within about a minute of their scheduled time. If slots are missed, for example during an outage, Foliot runs once for the first missed time (that's the scheduledAt it carries), then carries on with the next upcoming slot. It doesn't catch up on every missed slot.
  • Each request times out after 15 seconds, and request and response bodies are limited to 1 MB.
  • Requests can only go to public addresses. Foliot blocks private and internal networks, so it can't call something on localhost or inside your office network.
  • The request body is built from fields, so you can't paste a raw JSON document as the body.

Other ways to do it

  • crontab on your own server. Free if you already run a server, and as flexible as it gets. You're responsible for keeping the machine up, logging and alerts.
  • cron-job.org. A free, donation-funded service that calls a URL as often as once a minute, with failure notifications and a history of past calls (cron-job.org, checked October 15, 2026). If all you need is a plain URL called on time, it's a good choice. Foliot is the better fit when the call is one step of a bigger job: checking the response, looping over results, posting to Slack or adding rows to a sheet.
  • GitHub Actions schedules. Free for many repositories and handy if your code already lives on GitHub. GitHub's docs say the shortest interval is every 5 minutes, runs can be delayed when GitHub is busy, and schedules in public repositories are disabled after 60 days without activity (GitHub Docs, checked October 15, 2026).
  • Your hosting platform's cron feature. Many hosts can call a route of your app on a schedule. Check the plan limits, which often restrict how often jobs may run.

Questions

Can I run a cron job without a server?

Yes. A hosted scheduler calls your URL on a timer, so nothing of yours needs to stay running. In Foliot, a workflow with the On a schedule trigger and an HTTP request step does this, from every minute up to weekly.

How often can a scheduled request run?

As often as every minute. Keep the run count in mind: every 5 minutes is about 8,640 runs a month, which needs the Pro plan (10,000 runs for $12 a month). Every 2 hours or less often fits the free plan's 500 runs.

Do I need to write a cron expression?

No. You choose every few minutes or hours, every day at a time, or certain days of the week, plus a timezone.

What happens if the API is down when the job runs?

GET, PUT and DELETE requests are retried after 1 minute and again after 5 minutes when there's a network error, a timeout or a temporary response (408, 425, 429, 500, 502, 503, 504). POST and PATCH requests are only retried when they certainly didn't arrive, so nothing runs twice. If the run still fails, you get an email and can re-run it later.