Send the weekly report
Rung one fired once. This rung fires forever — the same schedule primitive, given a recurrence rule instead of a single instant. A reporting agent should run every Monday at 09:00 in the buyer's own timezone, indefinitely, without anyone re-registering it each week. You hand us a cron expression and an IANA timezone once; we spawn each occurrence in turn.
The story
A finance agent produces a weekly summary and posts it to a channel every Monday
morning. It shouldn't stay resident for a week between runs, and daylight-saving
shifts shouldn't drag the run to 08:00 or 10:00. So it registers a recurring
schedule — 0 9 * * MON in Europe/Paris — and lets AIGears wake it each week.
Each fire is a schedule.fired webhook that starts a fresh instance.
Solve it
Go to Schedules → New schedule, choose Recurring, and enter a cron
expression plus a timezone. The form shows a live cron preview — the next
three fire times in your chosen timezone — so you can confirm the rule reads the
way you meant before saving. Paste the webhook_url to POST to and save.
POST /v1/schedules/ with recurrence (a cron expression) and recurrence_tz
(an IANA timezone). The server evaluates the cron in that timezone, so 0 9 * *
MON stays at 09:00 local across daylight-saving shifts, and computes the first
fire_at for you.
curl https://aigears.example.com/v1/schedules/ \
-H "Authorization: Bearer aigears_live_..." \
-H "Content-Type: application/json" \
-d '{
"recurrence": "0 9 * * MON",
"recurrence_tz": "Europe/Paris",
"webhook_url": "https://hooks.example.com/aigears",
"payload": {"report": "weekly-summary"}
}'
Before committing to a rule, dry-run it with POST /v1/schedules/cron-preview/
({"cron": ..., "tz": ...}) — it returns the next occurrences, creates nothing,
and touches no quota. The runnable version, which previews then creates, is
examples/python/schedules_agent.py
and
examples/typescript/schedulesAgent.ts:
preview = preview_cron(client, cron="0 9 * * 1", tz="Europe/Paris")
# ... confirm the occurrences read right, then:
recurring = create_recurring_schedule(
client,
recurrence="0 9 * * 1",
recurrence_tz="Europe/Paris",
webhook_url=webhook_url,
payload={"kind": "standup"},
)
Ask the agent for the cadence in words; it maps it onto a schedule_create call
with recurrence + recurrence_tz.
"Send the weekly report every Monday at 9am, Paris time."
schedule_create(
recurrence="0 9 * * MON",
recurrence_tz="Europe/Paris",
webhook_url="https://hooks.example.com/aigears",
payload={"report": "weekly-summary"},
)
→ { "id": "01J9Z8XKQR...", "status": "pending",
"recurrence": "0 9 * * MON",
"fire_at": "2026-07-06T07:00:00Z" }
Understanding the series
A recurring schedule is not fifty-two records booked up front. At any moment a
live series has exactly one pending occurrence. When that occurrence
resolves — whether it fired successfully or failed to deliver — we spawn its
successor, computed from the moment it actually fired, so a backlog never
snowballs into a burst of catch-up callbacks. The occurrences sharing a rule are
joined by a recurrence_series_id, and GET /v1/schedules/?series_id=<uuid>
walks them.
The rule worth internalising: cancelling the pending occurrence terminates the series. There is no separate "delete the series" action — cancel the one live occurrence and no successor is spawned, so the whole recurrence stops.
Variations
- Stop after it has served its purpose. To end the series, cancel its pending
occurrence (
schedule_cancel/POST /v1/schedules/{id}/cancel/). No successor spawns. - Change the cadence. There is no in-place edit of a recurrence rule: cancel
the current series and create a new one with the new cron. The new series gets
its own
recurrence_series_id.
Next rung
Renew the certificate — when "fire and forget" isn't enough and you need an obligation that tracks completion.