Search docs ⌘K
esc
Type to search across all documentation pages
Jobs

Jobs

One primitive replaces three services. Queue, Task, and Cron are all the same object — what differs is the trigger.

30-second handler constraint: SaaSignal runs on Cloudflare Workers, which impose a 30 s limit on outbound subrequests. Your handler URL must respond with 2xx within 30 s. For long work, respond immediately with 202 Accepted and POST results to callback_url when done.
trigger.type
Concept
Example use case
immediate
One-off task
Send email on signup, call webhook
delayed
Delayed task
Send reminder 24h from now
scheduled
Cron
Nightly billing digest, cache warm-up
queue
Push queue
Fan-out pipeline, rate-limited workers
pull
Pull queue
Work-stealing pool, mobile job claiming

Create Job

POST
/infra/jobs
jobs:write0.0000018 tokens

Create a job. Payload max 256 KB, name max 256 chars, queue max 128 chars, handler/callback_url must be HTTPS public URLs, max_attempts 1-20, timeout 1-30s, priority 1-10.

curl
curl -X POST https://api.saasignal.saastemly.com/infra/jobs \
  -H "Authorization: Bearer sk_live_..." \
  -H "Content-Type: application/json" \
  -d '{"trigger":{"type":"immediate"},"payload":{"id":1}}'
json — 202 Accepted
{ "status": "ok" }
typescript
await ss.infra.jobs.create({
  trigger: { type: 'immediate' },
  handler: 'https://app.acme.com/api/task',
  payload: { id: 1 },
  max_attempts: 3,
  backoff: 'exponential',
})
  1. Open Dashboard and select your project
  2. Go to Jobs → click Create Job
  3. Select a trigger type and enter the handler URL
  4. Add your payload and configure retry settings
  5. Click Create
The dashboard also shows job status, run history, and allows manual triggers.
Body field
Type
Description
trigger required
object
Trigger config. { type: "immediate" }, { type: "delayed", delay_seconds }, { type: "scheduled", schedule, timezone? }, { type: "queue", queue }, or { type: "pull", queue }.
handler
string
HTTPS URL to POST when the job fires. Must respond within 30s.
payload
any JSON
Job payload (max 256 KB serialized)
name
string
Display name (max 256 chars)
max 256 chars
timeout
integer
Handler timeout in seconds. Range 1–30, default 30.
range ≥1 .. ≤30default 30
max_attempts
integer
Max retry attempts. Range 1–20, default 3.
range ≥1 .. ≤20default 3
backoff
string
Retry strategy: exponential, linear, or fixed. Default exponential.
values: exponential, linear, fixeddefault exponential
priority
integer
Priority level. Range 1–10, default 5. Lower = higher priority.
range ≥1 .. ≤10default 5
callback_url
string
HTTPS URL to POST results when the job completes
idempotency_key
string
Unique key to prevent duplicate jobs (max 128 chars)
max 128 chars
enabled
boolean
Whether the job is active. Default true.
default true
Error responses
401 Unauthorized
402 Insufficient tokens
429 Rate limited

Batch Create

POST
/infra/jobs/batch
jobs:write0.0000018 tokens per job

Create up to 100 jobs.

curl
curl -X POST https://api.saasignal.saastemly.com/infra/jobs/batch \
  -H "Authorization: Bearer sk_live_..." \
  -H "Content-Type: application/json" \
  -d '{"jobs":[]}'
json — 202 Accepted
{ "status": "ok" }
typescript
await ss.infra.jobs.batchCreate([
  { trigger: { type: 'immediate' }, handler: 'https://app.acme.com/api/task-a', payload: { id: 1 } },
  { trigger: { type: 'immediate' }, handler: 'https://app.acme.com/api/task-b', payload: { id: 2 } },
])
  1. Batch create is an API-only feature
  2. Use the REST API or TypeScript SDK for bulk job creation
You can create jobs individually in DashboardJobs
Body field
Type
Description
jobs required
array
Array of job definitions (max 100). Each uses the same schema as Create Job.
max 100 items
Error responses
401 Unauthorized
402 Insufficient tokens
429 Rate limited

List Jobs

GET
/infra/jobs
jobs:read

List jobs with optional status, trigger type, and queue filters. Supports cursor-based pagination. Max 500 results per page.

curl
curl https://api.saasignal.saastemly.com/infra/jobs \
  -H "Authorization: Bearer sk_live_..."
json — 200 OK
{ "status": "ok" }
typescript
const jobs = await ss.infra.jobs.list({ status: 'pending', limit: 50 })
  1. Open Dashboard and select your project
  2. Go to Jobs to see all jobs with filters for status and trigger type
Query param
Type
Description
status
string
Filter by status: pending, running, completed, failed, cancelled, dead
values: pending, queued, running, completed, failed, dead, cancelled
trigger_type
string
Filter by trigger: immediate, delayed, scheduled, queue, pull
values: immediate, delayed, scheduled, queue, pull
queue
string
Filter by queue name
limit
integer
Max results per page. Range 1–500, default 50.
range ≥1 .. ≤500default 50
cursor
string
Pagination cursor from a previous response
Error responses
401 Unauthorized
402 Insufficient tokens
429 Rate limited

Get Job

GET
/infra/jobs/{job_id}
jobs:read

Retrieve a single job by ID, including its current status, trigger, and payload.

curl
curl https://api.saasignal.saastemly.com/infra/jobs/{job_id} \
  -H "Authorization: Bearer sk_live_..."
json — 200 OK
{
  "id": "job_01JNXS...",
  "status": "completed",
  "trigger": { "type": "immediate" },
  "handler": "https://app.acme.com/api/on-signup",
  "attempts": 1,
  "max_attempts": 3,
  "created_at": "2026-03-04T12:00:00Z",
  "completed_at": "2026-03-04T12:00:01Z"
}
typescript
const job = await ss.infra.jobs.get('job_01JNXS...')
  1. Open Dashboard and select your project
  2. Go to Jobs and click on any job to view its details
Path param
Type
Description
job_id required
string
Job ID
1–256 chars
Error responses
401 Unauthorized
402 Insufficient tokens
404 Not found
429 Rate limited

Update Job

PATCH
/infra/jobs/{job_id}
jobs:write

Update a job's handler, payload, enabled state, or trigger schedule. Only pending or scheduled jobs can be updated.

curl
curl -X PATCH https://api.saasignal.saastemly.com/infra/jobs/{job_id} \
  -H "Authorization: Bearer sk_live_..." \
  -H "Content-Type: application/json" \
  -d '{}'
json — 200 OK
{ "status": "ok" }
typescript
await ss.infra.jobs.update('job_01JNXS...', {
  trigger: { schedule: '0 */2 * * *' },
  enabled: true,
})
  1. Open Dashboard and select your project
  2. Go to Jobs and click on the job you want to update
  3. Edit the schedule, handler, or toggle enabled/disabled
  4. Click Save
Path param
Type
Description
job_id required
string
Job ID
1–256 chars
Body field
Type
Description
handler
string
Updated handler HTTPS URL
payload
any JSON
Updated payload (max 256 KB)
enabled
boolean
Enable or disable the job
trigger
object
Updated trigger config (schedule, timezone, delay_seconds)
Error responses
401 Unauthorized
402 Insufficient tokens
404 Not found
409 Conflict
429 Rate limited

Cancel Job

DELETE
/infra/jobs/{job_id}
jobs:write

Cancel a pending or scheduled job. Running jobs cannot be cancelled.

curl
curl -X DELETE https://api.saasignal.saastemly.com/infra/jobs/{job_id} \
  -H "Authorization: Bearer sk_live_..."
json — 200 OK
{ "status": "ok" }
typescript
await ss.infra.jobs.cancel('job_01JNXS...')
  1. Open Dashboard and select your project
  2. Go to Jobs and click on the job
  3. Click Cancel
Path param
Type
Description
job_id required
string
Job ID to cancel
1–256 chars
Error responses
401 Unauthorized
402 Insufficient tokens
404 Not found
409 Conflict
429 Rate limited

Claim Job

POST
/infra/jobs/claim
jobs:write

Claim a pull-type job for processing. Supports work-stealing pools where multiple workers compete for jobs.

curl
curl -X POST https://api.saasignal.saastemly.com/infra/jobs/claim \
  -H "Authorization: Bearer sk_live_..." \
  -H "Content-Type: application/json" \
  -d '{"queue":"..."}'
json — 200 OK
{ "status": "ok" }
typescript
const jobs = await ss.infra.jobs.claim({ queue_name: 'mobile-tasks', limit: 5 })
  1. Claim is an API-only operation for pull-type job processing
  2. Use the REST API or TypeScript SDK
Body field
Type
Description
queue required
string
Queue name to claim from
count
integer
Number of jobs to claim. Range 1–10, default 1.
range ≥1 .. ≤10default 1
visibility_timeout
integer
Seconds before unclaimed job becomes available again. Range 1–3600, default 30.
range ≥1 .. ≤3600default 30
Error responses
401 Unauthorized
402 Insufficient tokens
429 Rate limited

Acknowledge Job

POST
/infra/jobs/{job_id}/ack
jobs:write

Acknowledge a claimed job as completed or failed. Only the token that claimed the job can acknowledge it.

curl
curl -X POST https://api.saasignal.saastemly.com/infra/jobs/{job_id}/ack \
  -H "Authorization: Bearer sk_live_..." \
  -H "Content-Type: application/json" \
  -d '{"status":"completed"}'
json — 200 OK
{ "status": "ok" }
typescript
await ss.infra.jobs.ack('job_01JNXS...', {
  status: 'completed',
  result: { processed: 42 },
})
  1. Acknowledge is an API-only operation for completing claimed jobs
  2. Use the REST API or TypeScript SDK
Path param
Type
Description
job_id required
string
Job ID to acknowledge
1–256 chars
Body field
Type
Description
status required
string
Outcome: completed or failed
values: completed, failed
result
any JSON
Result data (for completed jobs)
error
string
Error message (for failed jobs)
Error responses
401 Unauthorized
402 Insufficient tokens
403 Forbidden
404 Not found
429 Rate limited

Trigger Job

POST
/infra/jobs/{job_id}/trigger
jobs:write0.0000018 tokens per execution

Manually trigger a scheduled job to run now.

curl
curl -X POST https://api.saasignal.saastemly.com/infra/jobs/{job_id}/trigger \
  -H "Authorization: Bearer sk_live_..."
json — 202 Accepted
{
  "job_id": "job_01JNXS...",
  "run_id": "run_01JNXS...",
  "triggered_at": "2026-03-05T12:00:00Z"
}
typescript
await ss.infra.jobs.trigger('job_01JNXS...')
  1. Open Dashboard and select your project
  2. Go to Jobs and click on the scheduled job
  3. Click Trigger Now to run it immediately
Path param
Type
Description
job_id required
string
Job ID to trigger immediately
1–256 chars
Error responses
400 Bad request
401 Unauthorized
402 Insufficient tokens
404 Not found
429 Rate limited

Retry Job

POST
/infra/jobs/{job_id}/retry
jobs:write

Retry a failed or dead job. Resets the job to pending and re-enqueues it.

curl
curl -X POST https://api.saasignal.saastemly.com/infra/jobs/{job_id}/retry \
  -H "Authorization: Bearer sk_live_..."
json — 200 OK
{ "status": "ok" }
typescript
await ss.infra.jobs.retry('job_01JNXS...')
  1. Open Dashboard and select your project
  2. Go to Jobs and click on the failed job
  3. Click Retry to re-enqueue it
Path param
Type
Description
job_id required
string
Job ID to retry
1–256 chars
Error responses
401 Unauthorized
402 Insufficient tokens
404 Not found
409 Conflict
429 Rate limited

Run History

GET
/infra/jobs/{job_id}/runs
jobs:read

List execution runs for a job with cursor-based pagination. Max 500 results per page.

curl
curl https://api.saasignal.saastemly.com/infra/jobs/{job_id}/runs \
  -H "Authorization: Bearer sk_live_..."
json — 200 OK
{
  "runs": [
    {
      "id": "run_01JNXS...",
      "job_id": "job_01JNXS...",
      "scheduled_at": "2026-03-05T09:00:00Z",
      "started_at": "2026-03-05T09:00:01Z",
      "completed_at": "2026-03-05T09:00:02Z",
      "status": "completed",
      "duration_ms": 1023,
      "handler_status": 200,
      "error": null
    }
  ],
  "next_cursor": null
}
typescript
const runs = await ss.infra.jobs.runs('job_01JNXS...')
// runs.runs, runs.next_cursor
  1. Open Dashboard and select your project
  2. Go to Jobs and click on any job
  3. The Run History tab shows all execution attempts with timing and status
Path param
Type
Description
job_id required
string
Job ID
1–256 chars
Query param
Type
Description
limit
integer
Max runs to return. Range 1–500, default 50.
range ≥1 .. ≤500default 50
cursor
string
Pagination cursor
Error responses
401 Unauthorized
402 Insufficient tokens
404 Not found
429 Rate limited