Skip to main content

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

ConceptDescription
JobA named schedule that fires an HTTP target at computed times
Schedule typeHow fire times are computed: cron, one-shot, or recurring interval
TargetThe HTTP endpoint and payload the job delivers to on each firing
StateLifecycle of the job: SCHEDULE_STATE_ACTIVE, SCHEDULE_STATE_PAUSED, SCHEDULE_STATE_DELETED
ExecutionA single firing record — captures status, HTTP result, attempt number, and duration
Auto-pauseAutomatic pause after N consecutive failures — prevents runaway retries against a broken target
Retry policyExponential backoff between delivery attempts within a single firing

Schedule Types

TypeFieldWhen to use
SCHEDULE_TYPE_CRONcron_expressionRepeating schedule aligned to calendar time (e.g. every weekday at 9 AM)
SCHEDULE_TYPE_ONCEscheduled_atFire exactly once at a specific UTC timestamp
SCHEDULE_TYPE_RECURRING_INTERVALinterval_secondsFire 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:

ExpressionMeaning
0 9 * * 1-5Weekdays at 9:00 AM
*/15 * * * *Every 15 minutes
0 0 1 * *First day of each month at midnight
@dailyShorthand for 0 0 * * *
@hourlyShorthand 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 changes

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" }'
note

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:

FieldDescription
statusEXECUTION_STATUS_SUCCESS, EXECUTION_STATUS_FAILED, EXECUTION_STATUS_MALFORMED, EXECUTION_STATUS_DISCARDED (retries exhausted), or EXECUTION_STATUS_CANCELLED (operator cancellation)
http_statusHTTP status code returned by the target
attemptAttempt number (1-based) within this firing
duration_msEnd-to-end duration of the delivery attempt
errorError message on FAILED or MALFORMED outcomes
scheduled_timeWhen the execution was supposed to fire
started_at / completed_atActual start and completion times
response_bodyTruncated HTTP response body captured on failed dispatches (4 KiB cap). Empty for successful dispatches.
response_headersAllowlisted response headers from the failed dispatch: content-type, content-length, retry-after, x-request-id, date.
response_truncatedtrue when response_body was clipped at the 4 KiB cap.
response_size_bytesOriginal 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.

FieldDefaultDescription
max_attempts10Total delivery attempts including the initial one
initial_backoff_ms5000Backoff before the first retry (5 seconds)
max_backoff_ms1800000Maximum 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_threshold is omitted or set to 0)
  • Valid override range: 3–100
  • When auto-paused, the job state becomes SCHEDULE_STATE_PAUSED and paused_reason records the cause

Resume the job with resume-job once the target is healthy.