Your First Job
This walks through creating an HTTP job, confirming it ran, and editing it live — the thing Zilean exists to make cheap.
You’ll need a running instance (Installation) and an account with
jobs:write.
1. Log in
Section titled “1. Log in”Open your instance root. You’ll be redirected to /login. Sign in with the
ADMIN_USERNAME email and the password you generated the hash from.
The API uses the same session cookie, so anything below works from the browser or from
curl with a session.
2. Create a job
Section titled “2. Create a job”The simplest possible job — call a URL every five minutes:
curl -X POST https://<your-host>/api/jobs \ -H 'Content-Type: application/json' \ -d '{ "name": "hello-httpbin", "job_type": "http", "schedule_type": "cron", "cron_expression": "*/5 * * * *", "http_method": "GET", "url": "https://httpbin.org/get" }'Everything else takes a default: 60-second timeout, retry enabled with 5 attempts, no
looping, no pooling, skip overlap policy.
In the admin UI, the same thing is Jobs → New job, a wizard that steps through job type, basics, request, authorization, loop & retry, and a review screen.
3. Confirm the schedule is understood
Section titled “3. Confirm the schedule is understood”Cron expressions are evaluated in the server’s timezone, not yours:
curl https://<your-host>/api/meta# {"timezone":"America/Los_Angeles"}If that says UTC and you expected otherwise, TZ isn’t reaching the container — see
Configuration.
4. Wait for the reconciler — or don’t
Section titled “4. Wait for the reconciler — or don’t”The scheduler picks up new and changed rows every 30 seconds. You can skip the wait:
curl -X POST https://<your-host>/api/jobs/<id>/runA manual trigger fires immediately, deliberately skipping the deduplication guard that protects scheduled firings.
5. See what happened
Section titled “5. See what happened”curl 'https://<your-host>/api/jobs/<id>/calls?limit=5'Each entry carries the queue state, attempt number, timestamps, and a last_call object
with the method, URL, status code, duration and a snippet of the response.
In the UI: the job’s row has a heartbeat bar, and the row menu offers Calls (recent
attempts) and Activity (volume and latency over time). For raw queue internals —
states, attempts, errors — use the embedded River UI at /riverui/.
Working with many jobs in the UI
Section titled “Working with many jobs in the UI”On the Jobs page, groups appear as a tree in a sidebar; select one to filter the table. Tick the checkboxes on several rows to enable, disable or delete them together with the batch actions, and use Import CSV to create jobs in bulk (CSV import). First-run and What’s new tours, a Settings overview tour, and a short tour for every Settings section can be replayed any time from Settings → Tours, which keeps the What’s new tours for the three most recent releases. Each Settings section also has a small “?” button beside its heading that starts that section’s tour in place.
6. Edit it, live
Section titled “6. Edit it, live”This is the part worth testing, because it’s the product’s whole premise. Change the URL:
# fetch the current row, change what you want, send the whole thing backcurl https://<your-host>/api/jobs/<id> > job.json# edit job.json, then:curl -X PUT https://<your-host>/api/jobs/<id> \ -H 'Content-Type: application/json' \ --data @job.jsonPUT takes the full object — there are no partial updates.
The change takes effect on the next attempt, with no restart and no reconcile wait.
The worker re-reads the job row on every attempt, so only a change to
cron_expression itself waits for the next 30-second tick.
7. Make it loop
Section titled “7. Make it loop”Looping is what separates Zilean from a cron entry. Point the job at an endpoint that reports how much work is left, and it will keep calling itself while that number stays positive:
{ "loop_enabled": true, "loop_response_path": "result.remaining", "loop_delay_ms": 2000, "loop_jitter_ms": 300, "loop_max_iterations": 100}Your endpoint returns {"result": {"remaining": 42}} while there’s work and
{"result": {"remaining": 0}} when it’s drained. The path is
gjson syntax, and only a strictly positive number
continues the loop.
Each iteration is its own attempt, so each one counts separately in the invocation counters — and can retry on its own.
8. Disable it when you’re done
Section titled “8. Disable it when you’re done”curl -X POST https://<your-host>/api/jobs/<id>/disableDisabling stops work already queued, not just future firings — the worker re-checks
enabled at execution time.
Or delete it:
curl -X DELETE https://<your-host>/api/jobs/<id>Where to go next
Section titled “Where to go next”- Job fields — every field, default and constraint.
- Loop, retry & pooling — the three mechanisms in depth.
- Script jobs — run Bash, JS/TS or Groovy instead of an HTTP call, and the security caveats that come with it.
- Monitoring jobs — heartbeats, metrics and Prometheus.