One-shot scheduling
A one-shot schedule fires once: you give SchedStack a destination and a time, and it owns delivery from there — retried until it lands, never silently lost. You pick the time in whichever form fits your code:
delay— a relative duration from now ("24h","90s").fire_at— an absolute RFC3339 instant ("2026-07-01T09:00:00Z").local_fire_at+timezone— a wall-clock time in an IANA zone, mapped to the correct instant across DST.
A POST with a cron field instead makes a recurring schedule — see
Recurring schedules.
Pick exactly one timing source
Section titled “Pick exactly one timing source”delay, fire_at, local_fire_at, and cron are mutually exclusive. You must send
exactly one:
- Send none →
422 missing_timing. - Send more than one →
400 multiple_timing.
Everything else on the request (method, headers, body, ttl, retry_policy,
metadata, idempotency_key) is shared across all three forms and optional. The only
other required field is the destination: an inline endpoint (an https URL) or an
endpoint_id referencing a saved endpoint profile.
The whole API request body is capped at 1 MB (400 invalid_json if larger), and the
delivery body it carries is capped at 256 KB (422 payload_too_large). See
Limits & constraints.
delay — relative
Section titled “delay — relative”The simplest form: fire this many time-units from now. delay is a Go
time.ParseDuration string, so units are ns,
us/µs, ms, s, m, h and you can combine them ("1h30m").
curl -X POST https://api.schedstack.com/v1/schedules \ -H "Authorization: Bearer sk_test_…" \ -H "Content-Type: application/json" \ -d '{ "endpoint": "https://acme.dev/hooks/reminder", "delay": "24h", "body": "{\"kind\":\"trial_ending\"}" }'{ "id": "sch_01J9ZK3F8Q", "object": "schedule", "mode": "test", "kind": "one_shot", "state": "active", "endpoint": "https://acme.dev/hooks/reminder", "method": "POST", "header_keys": [], "fire_at": "2026-06-28T18:42:11Z", "cron": null, "timezone": null, "next_fire_at": "2026-06-28T18:42:11Z", "next_runs": ["2026-06-28T18:42:11Z"], "ttl": null, "retry_policy": { "max_attempts": 8, "strategy": "exponential", "base": "5s", "factor": 2, "max": "1h", "jitter": true }, "metadata": {}, "created_at": "2026-06-27T18:42:11Z", "updated_at": "2026-06-27T18:42:11Z"}The response resolves your delay to a concrete fire_at (now + the duration) so you can
confirm the exact instant.
fire_at — absolute instant
Section titled “fire_at — absolute instant”When you already know the exact UTC instant, send it as strict RFC3339. It must be in the future and no more than 10 years out.
curl -X POST https://api.schedstack.com/v1/schedules \ -H "Authorization: Bearer sk_test_…" \ -H "Content-Type: application/json" \ -d '{ "endpoint": "https://acme.dev/hooks/invoice", "fire_at": "2026-07-01T09:00:00Z", "body": "{\"invoice\":\"inv_204\"}" }'{ "id": "sch_01J9ZK7M2D", "object": "schedule", "kind": "one_shot", "state": "active", "fire_at": "2026-07-01T09:00:00Z", "next_fire_at": "2026-07-01T09:00:00Z", "next_runs": ["2026-07-01T09:00:00Z"], "timezone": null, "cron": null}local_fire_at — wall-clock time
Section titled “local_fire_at — wall-clock time”When the time means “9am where the user is”, send an offset-less local timestamp
plus an IANA timezone. SchedStack maps the wall-clock time to the correct absolute
instant for that zone — including across daylight-saving transitions.
curl -X POST https://api.schedstack.com/v1/schedules \ -H "Authorization: Bearer sk_test_…" \ -H "Content-Type: application/json" \ -d '{ "endpoint": "https://acme.dev/hooks/digest", "local_fire_at": "2026-07-01T09:00:00", "timezone": "America/New_York", "body": "{\"digest\":\"daily\"}" }'{ "id": "sch_01J9ZKA4WP", "object": "schedule", "kind": "one_shot", "state": "active", "fire_at": "2026-07-01T13:00:00Z", "timezone": "America/New_York", "next_fire_at": "2026-07-01T13:00:00Z", "next_runs": ["2026-07-01T13:00:00Z"], "cron": null}09:00 in America/New_York (EDT, UTC−4 in July) resolves to 13:00:00Z. The response
always reports the resolved absolute fire_at in UTC alongside the timezone you sent.
After it’s created
Section titled “After it’s created”A one-shot schedule is created in state: active and carries a single occurrence. Track
that occurrence — scheduled → succeeded, or dead-lettered / expired — and replay it from
the delivery, in Schedule lifecycle.
-
Preview before committing. Want to confirm the instant without creating anything? The MCP
preview_scheduletool validates timing and returns the next fire time. See MCP server. -
Make retries safe. Delivery is at-least-once, so your receiver should verify the
Sched-Signatureand dedupe on theIdempotency-Keyheader — see Verifying signatures. -
Bound how long it can run. Add a
ttl(a duration) to set a deliver-by deadline; past it, the occurrence is markedexpiredrather than retried forever.
Related
Section titled “Related”- Recurring schedules — fire on a
cronschedule instead of once. - Schedule lifecycle — reschedule, pause, cancel, and replay.
- Endpoint profiles — reuse a destination and policy via
endpoint_id.