Scheduled Jobs
The Scheduler Gateway lets you create time-based jobs that invoke an HTTP endpoint on a cron schedule, at a fixed future time, or on a recurring interval. Jobs are durable — they survive restarts, track their own execution history, and retry automatically on failure.
All endpoints follow the same pattern:
POST /api/v1/scheduler/<method>
X-API-Key: sk_your_key_here
Content-Type: application/json
Concepts
| Concept | Description |
|---|---|
| Job | A named schedule that fires an HTTP target at computed times |
| Schedule type | How fire times are computed: cron, one-shot, or recurring interval |
| Target | The HTTP endpoint and payload the job delivers to on each firing |
| State | Lifecycle of the job: SCHEDULE_STATE_ACTIVE, SCHEDULE_STATE_PAUSED, SCHEDULE_STATE_DELETED |
| Execution | A single firing record — captures status, HTTP result, attempt number, and duration |
| Auto-pause | Automatic pause after N consecutive failures — prevents runaway retries against a broken target |
| Retry policy | Exponential backoff between delivery attempts within a single firing |
Schedule Types
| Type | Field | When to use |
|---|---|---|
SCHEDULE_TYPE_CRON | cron_expression | Repeating schedule aligned to calendar time (e.g. every weekday at 9 AM) |
SCHEDULE_TYPE_ONCE | scheduled_at | Fire exactly once at a specific UTC timestamp |
SCHEDULE_TYPE_RECURRING_INTERVAL | interval_seconds | Fire every N seconds, regardless of clock alignment — minimum 60 |
Creating Jobs
Cron Job
Fires on a 5- or 6-field cron expression. The timezone field controls which clock the expression is evaluated against (defaults to UTC). The target.method field defaults to POST and can be omitted in all schedule types.
curl -X POST https://api.yocaso.dev/api/v1/scheduler/create-job \
-H "X-API-Key: sk_your_key_here" \
-H "Content-Type: application/json" \
-d '{
"name": "Daily digest",
"schedule_type": "SCHEDULE_TYPE_CRON",
"cron_expression": "0 9 * * 1-5",
"timezone": "America/New_York",
"target": {
"url": "https://your-api.example.com/jobs/daily-digest",
"kind": "digest",
"payload": { "report": "daily" }
}
}'
Common cron expressions:
| Expression | Meaning |
|---|---|
0 9 * * 1-5 | Weekdays at 9:00 AM |
*/15 * * * * | Every 15 minutes |
0 0 1 * * | First day of each month at midnight |
@daily | Shorthand for 0 0 * * * |
@hourly | Shorthand for 0 * * * * |
One-Shot Job
Fires exactly once at the given timestamp. Use RFC 3339 format.
curl -X POST https://api.yocaso.dev/api/v1/scheduler/create-job \
-H "X-API-Key: sk_your_key_here" \
-H "Content-Type: application/json" \
-d '{
"name": "Send welcome email",
"schedule_type": "SCHEDULE_TYPE_ONCE",
"scheduled_at": "2026-06-10T14:00:00Z",
"target": {
"url": "https://your-api.example.com/jobs/welcome",
"kind": "notification",
"payload": { "user_id": "usr_abc123" }
}
}'
Recurring Interval Job
Fires every N seconds. Minimum interval is 60 seconds.
curl -X POST https://api.yocaso.dev/api/v1/scheduler/create-job \
-H "X-API-Key: sk_your_key_here" \
-H "Content-Type: application/json" \
-d '{
"name": "Sync cache",
"schedule_type": "SCHEDULE_TYPE_RECURRING_INTERVAL",
"interval_seconds": 300,
"target": {
"url": "https://your-api.example.com/jobs/cache-sync",
"kind": "maintenance"
}
}'
Response
All three types return the created Schedule resource directly — the same flat shape returned by get-job, pause-job, and resume-job:
{
"schedule_id": "sched_a1b2c3d4e5f60718",
"name": "Daily digest",
"state": "SCHEDULE_STATE_ACTIVE",
"schedule_type": "SCHEDULE_TYPE_CRON",
"cron_expression": "0 9 * * 1-5",
"timezone": "America/New_York",
"next_trigger_at": "2026-06-04T13:00:00Z",
"trigger_count": 0,
"failure_count": 0,
"created_at": "2026-06-03T14:00:00Z"
}
Managing Jobs
Get a Job
curl -X POST https://api.yocaso.dev/api/v1/scheduler/get-job \
-H "X-API-Key: sk_your_key_here" \
-H "Content-Type: application/json" \
-d '{ "schedule_id": "sched_a1b2c3d4e5f60718" }'
List Jobs
Returns all jobs for the authenticated tenant and project. Optionally filter by state or target kind.
curl -X POST https://api.yocaso.dev/api/v1/scheduler/list-jobs \
-H "X-API-Key: sk_your_key_here" \
-H "Content-Type: application/json" \
-d '{
"page_size": 20,
"state_filter": "SCHEDULE_STATE_ACTIVE"
}'
Update a Job
Partial update — only the fields you include are changed. Omitted fields are left unchanged.
curl -X POST https://api.yocaso.dev/api/v1/scheduler/update-job \
-H "X-API-Key: sk_your_key_here" \
-H "Content-Type: application/json" \
-d '{
"schedule_id": "sched_a1b2c3d4e5f60718",
"cron_expression": "0 10 * * 1-5"
}'
Cron expression updates may not take effect until the next worker deployment. Check effective_at in the response — it will say either immediate or next_worker_deployment.
Pause and Resume
Use pause to temporarily stop a job without deleting it. Resume returns it to SCHEDULE_STATE_ACTIVE.
# Pause
curl -X POST https://api.yocaso.dev/api/v1/scheduler/pause-job \
-H "X-API-Key: sk_your_key_here" \
-H "Content-Type: application/json" \
-d '{
"schedule_id": "sched_a1b2c3d4e5f60718",
"reason": "Target service under maintenance"
}'
# Resume
curl -X POST https://api.yocaso.dev/api/v1/scheduler/resume-job \
-H "X-API-Key: sk_your_key_here" \
-H "Content-Type: application/json" \
-d '{ "schedule_id": "sched_a1b2c3d4e5f60718" }'
Delete a Job
Soft-delete — the job stops firing immediately. Deleted jobs are retained for audit and can still be retrieved by ID.
curl -X POST https://api.yocaso.dev/api/v1/scheduler/delete-job \
-H "X-API-Key: sk_your_key_here" \
-H "Content-Type: application/json" \
-d '{ "schedule_id": "sched_a1b2c3d4e5f60718" }'
Referencing Jobs by External ID
Every job has a server-assigned schedule_id (prefixed sched_). You can also attach your own external_id at creation — a stable identifier from your own system, unique within your tenant and project, and immutable once set.
curl -X POST https://api.yocaso.dev/api/v1/scheduler/create-job \
-H "X-API-Key: sk_your_key_here" \
-H "Content-Type: application/json" \
-d '{
"name": "Daily digest",
"schedule_type": "SCHEDULE_TYPE_CRON",
"cron_expression": "0 9 * * 1-5",
"external_id": "user-42-daily-digest",
"target": { "url": "https://your-api.example.com/jobs/daily-digest", "kind": "digest" }
}'
Once set, get-job, update-job, pause-job, resume-job, and delete-job accept external_id in place of schedule_id — provide exactly one of the two. This lets you address a job by your own key without first storing the generated schedule_id.
curl -X POST https://api.yocaso.dev/api/v1/scheduler/get-job \
-H "X-API-Key: sk_your_key_here" \
-H "Content-Type: application/json" \
-d '{ "external_id": "user-42-daily-digest" }'
external_id must not start with the reserved sched_ prefix, and cannot be changed after the job is created.
Execution History
Every firing is recorded as an execution. Query the history to debug failures or monitor delivery.
curl -X POST https://api.yocaso.dev/api/v1/scheduler/list-executions \
-H "X-API-Key: sk_your_key_here" \
-H "Content-Type: application/json" \
-d '{
"schedule_id": "sched_a1b2c3d4e5f60718",
"page_size": 20,
"status_filter": "EXECUTION_STATUS_FAILED"
}'
Execution records include:
| Field | Description |
|---|---|
status | EXECUTION_STATUS_SUCCESS, EXECUTION_STATUS_FAILED, EXECUTION_STATUS_MALFORMED, EXECUTION_STATUS_DISCARDED (retries exhausted), or EXECUTION_STATUS_CANCELLED (operator cancellation) |
http_status | HTTP status code returned by the target |
attempt | Attempt number (1-based) within this firing |
duration_ms | End-to-end duration of the delivery attempt |
error | Error message on FAILED or MALFORMED outcomes |
scheduled_time | When the execution was supposed to fire |
started_at / completed_at | Actual start and completion times |
response_body | Truncated HTTP response body captured on failed dispatches (4 KiB cap). Empty for successful dispatches. |
response_headers | Allowlisted response headers from the failed dispatch: content-type, content-length, retry-after, x-request-id, date. |
response_truncated | true when response_body was clipped at the 4 KiB cap. |
response_size_bytes | Original response size in bytes (from Content-Length when present, else total bytes read before truncation). |
Retry Policy
Each firing retries independently with exponential backoff until it succeeds or exhausts max_attempts.
| Field | Default | Description |
|---|---|---|
max_attempts | 10 | Total delivery attempts including the initial one |
initial_backoff_ms | 5000 | Backoff before the first retry (5 seconds) |
max_backoff_ms | 1800000 | Maximum backoff cap (30 minutes) |
To override the defaults, include a retry_policy in your create-job request:
curl -X POST https://api.yocaso.dev/api/v1/scheduler/create-job \
-H "X-API-Key: sk_your_key_here" \
-H "Content-Type: application/json" \
-d '{
"name": "Critical alert",
"schedule_type": "SCHEDULE_TYPE_CRON",
"cron_expression": "*/5 * * * *",
"target": {
"url": "https://your-api.example.com/jobs/alert",
"kind": "alert"
},
"retry_policy": {
"max_attempts": 3,
"initial_backoff_ms": 1000,
"max_backoff_ms": 10000
}
}'
Auto-Pause
A job is automatically paused when it accumulates N consecutive failures. This prevents a broken target from accumulating unbounded retry debt.
- Default threshold: 10 consecutive failures (applied when
auto_pause_thresholdis omitted or set to0) - Valid override range: 3–100
- When auto-paused, the job state becomes
SCHEDULE_STATE_PAUSEDandpaused_reasonrecords the cause
Resume the job with resume-job once the target is healthy.
Related
- Scheduler API Reference — Full endpoint reference
- Authentication — API key setup required for all scheduler requests
- API Keys Guide — Scopes required to manage scheduled jobs