Skip to main content

Executors

An executor defines how a job runs when it fires. A job points at one executor; an executor can serve many jobs.

typeRuns the job byNeeds a public endpoint?
webhook_urlSending an HTTP request to webhookUrlYes
cloud_functionInvoking an AWS Lambda, Azure Function or Google Cloud FunctionYes
localThe scheduler0 CLI on your machine pulling jobs and running commandNo

Executor object​

{
"id": 1,
"accountId": 123,
"name": "Production Webhook",
"description": "Sends transactional email to customers",
"tags": ["email", "notifications"],
"type": "webhook_url",
"webhookUrl": "https://api.example.com/webhook",
"webhookMethod": "POST",
"payloadAggregation": false,
"dateCreated": "2026-01-15T10:30:00Z",
"createdBy": "user123"
}
FieldDescription
nameRequired.
typeRequired: webhook_url, cloud_function or local.
description, tagsOptional free text / labels. POST /ai/schedule uses them to pick the executor that matches a prompt.
webhookUrl, webhookMethodRequired for webhook_url. Method is GET, POST, PUT or DELETE.
webhookSecretOptional. Sent to your endpoint as the X-Webhook-Secret header.
cloudProvideraws, azure or gcp for cloud_function.
cloudResourceUrlLambda function ARN, or the Azure/GCP function URL.
regionAWS region (Lambda only).
cloudApiKey, cloudApiSecretAWS access key ID / secret access key for Lambda; cloudApiKey is the function key (x-functions-key) for Azure. Not used for GCP, whose function URL must accept unauthenticated POSTs.
command, workingDirFor local: the shell command to run for each job and the directory to run it from. command is required.
payloadAggregationWhen true, jobs on this executor that fire at the same time are delivered in one call.

webhookSecret, cloudApiKey and cloudApiSecret are write-only: they are stored encrypted and appear in exactly one response, the 201 from POST /executors. GET, list and PUT responses omit them.

Endpoints​

MethodPathScopeNotes
GET/executorsreadPaginated; orderBy: id, date_created, date_modified, created_by, modified_by, deleted_by
POST/executorswrite201, includes secrets once
GET/executors/{id}read
PUT/executors/{id}writeSame fields as create plus modifiedBy
DELETE/executors/{id}writeBody {deletedBy} → 204
POST/executors/{id}/test-invokeexecuteFire a synthetic job now; not for local
POST/local-executorswriteRegister a local executor → 201 {id}
GET/local-executors/{id}/jobsreadUsed by the CLI to pull jobs
POST/local-executors/{id}/executionsexecuteUsed by the CLI to report results

Payload delivered to your code​

Webhook and cloud-function executors receive the job wrapped in an envelope with its last execution status:

{
"job": {
"id": 123,
"projectId": 456,
"executorId": 789,
"spec": "0 0 2 * * *",
"data": "{\"action\": \"process_data\"}",
"timezone": "UTC",
"retryMax": 3,
"status": "active",
"accountId": 1,
"dateCreated": "2026-01-15T10:30:00Z",
"createdBy": "user123"
},
"lastExecutionDateTime": "2026-01-14T02:00:00Z",
"lastExecutionStatus": "success"
}

data is the JSON string you stored on the job; parse it in your handler.

With payloadAggregation: true, when more than one job on the executor fires at the same scheduled time they arrive in a single call. The shape is distinguishable by the top-level aggregated key, and all jobs in the batch succeed or fail (and retry) together:

{
"aggregated": true,
"jobs": [
{ "job": { "id": 123 }, "lastExecutionDateTime": "...", "lastExecutionStatus": "success" },
{ "job": { "id": 124 }, "lastExecutionDateTime": "...", "lastExecutionStatus": "success" }
]
}

Delivery rules:

  • Webhook: request uses webhookMethod, Content-Type: application/json, and X-Webhook-Secret when a secret is set. Any response status >= 400 counts as a failure and triggers the job's retry policy.
  • AWS Lambda: invoked with the AWS SDK using region, cloudApiKey (access key ID) and cloudApiSecret (secret access key); cloudResourceUrl is the function ARN. A function error is a failure.
  • Azure Functions: POST to cloudResourceUrl with x-functions-key: <cloudApiKey>.
  • Google Cloud Functions: POST to cloudResourceUrl, no credentials attached.

Create a webhook executor​

curl -X POST "https://api.scheduler0.com/api/v1/executors" \
-H "Content-Type: application/json" \
-H "X-API-Key: YOUR_API_KEY" \
-H "X-Secret-Key: YOUR_SECRET_KEY" \
-H "X-Account-ID: YOUR_ACCOUNT_ID" \
-d '{
"name": "Production Webhook",
"description": "Sends transactional email to customers",
"tags": ["email", "notifications"],
"type": "webhook_url",
"webhookUrl": "https://api.example.com/webhook",
"webhookMethod": "POST",
"webhookSecret": "secret_key_123",
"createdBy": "user123"
}'

The 201 response is the executor object including webhookSecret; this is the only time it is returned.

Create an AWS Lambda executor​

curl -X POST "https://api.scheduler0.com/api/v1/executors" \
-H "Content-Type: application/json" \
-H "X-API-Key: YOUR_API_KEY" \
-H "X-Secret-Key: YOUR_SECRET_KEY" \
-H "X-Account-ID: YOUR_ACCOUNT_ID" \
-d '{
"name": "Data Processing Lambda",
"type": "cloud_function",
"cloudProvider": "aws",
"region": "us-east-1",
"cloudResourceUrl": "arn:aws:lambda:us-east-1:123456789012:function:data-processor",
"cloudApiKey": "AKIAIOSFODNN7EXAMPLE",
"cloudApiSecret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
"createdBy": "user123"
}'

For Azure use "cloudProvider": "azure", the function URL in cloudResourceUrl and the function key in cloudApiKey. For GCP use "cloudProvider": "gcp" and the function URL in cloudResourceUrl.

Local executors​

A local executor runs jobs as a shell command on a machine you control, with no inbound network access required. The scheduler0 CLI polls the API for the jobs assigned to the executor, runs command for each trigger, and reports results back in batches. It keeps a local SQLite cache so it can keep executing when the server is unreachable and flush results later.

Register one with the dedicated endpoint (the CLI's scheduler0 local-executor register does this for you). name, command and createdBy are required; type is set to local by the server.

curl -X POST "https://api.scheduler0.com/api/v1/local-executors" \
-H "Content-Type: application/json" \
-H "X-API-Key: YOUR_API_KEY" \
-H "X-Secret-Key: YOUR_SECRET_KEY" \
-H "X-Account-ID: YOUR_ACCOUNT_ID" \
-d '{
"name": "My Local Executor",
"command": "/usr/local/bin/process-job.sh",
"workingDir": "/home/deploy/myapp",
"createdBy": "user123"
}'
{ "success": true, "data": { "id": 42 } }

Assign jobs to it with "executorId": 42, then run scheduler0 local-executor start on the machine. For each trigger the CLI runs command with:

  • the job's data string on stdin, and
  • environment variables SCHEDULER0_JOB_ID, SCHEDULER0_JOB_DATA (same string as stdin), SCHEDULER0_JOB_SPEC and SCHEDULER0_EXEC_UNIQUE_ID.

A non-zero exit status marks the execution failed. See CLI — Local executor for the setup walkthrough.

The two CLI-facing endpoints, for anyone building their own runner:

  • GET /local-executors/{id}/jobs → data: Job[], the active jobs assigned to the executor. 400 if the executor is not of type local.
  • POST /local-executors/{id}/executions with a JSON array of { "jobId", "uniqueId", "state", "lastExecutionTime", "nextExecutionTime", "executionVersion", "jobQueueVersion" } where state is 0 scheduled, 1 success, 2 failed → 200 { "committed": N }. Reported executions count toward the account's execution quota.

List, get, update, delete​

curl "https://api.scheduler0.com/api/v1/executors?limit=10&offset=0" \
-H "X-API-Key: YOUR_API_KEY" \
-H "X-Secret-Key: YOUR_SECRET_KEY" \
-H "X-Account-ID: YOUR_ACCOUNT_ID"

The list response is { "total", "offset", "limit", "executors": [...] }; fields that are zero or empty are omitted.

curl -X PUT "https://api.scheduler0.com/api/v1/executors/1" \
-H "Content-Type: application/json" \
-H "X-API-Key: YOUR_API_KEY" \
-H "X-Secret-Key: YOUR_SECRET_KEY" \
-H "X-Account-ID: YOUR_ACCOUNT_ID" \
-d '{
"name": "Production Webhook",
"type": "webhook_url",
"webhookUrl": "https://new-api.example.com/webhook",
"webhookMethod": "POST",
"modifiedBy": "user123"
}'

curl -X DELETE "https://api.scheduler0.com/api/v1/executors/1" \
-H "Content-Type: application/json" \
-H "X-API-Key: YOUR_API_KEY" \
-H "X-Secret-Key: YOUR_SECRET_KEY" \
-H "X-Account-ID: YOUR_ACCOUNT_ID" \
-d '{"deletedBy": "user123"}'

Test-invoke an executor​

POST /executors/{id}/test-invoke sends a synthetic job through the executor immediately and synchronously, so you can check that your endpoint or function receives the payload. Nothing is created, scheduled or logged. Local executors return 400.

The body is optional:

FieldDescription
jobJob attributes to place in the payload (spec, data, timezone, retryMax, ...). Server-managed fields are overridden.
ageGo duration string such as "24h"; sets the synthetic job's dateCreated/lastExecutionDate to now - age.
executionTimeRFC3339 time used as the payload's lastExecutionDateTime. Defaults to now.
curl -X POST "https://api.scheduler0.com/api/v1/executors/1/test-invoke" \
-H "Content-Type: application/json" \
-H "X-API-Key: YOUR_API_KEY" \
-H "X-Secret-Key: YOUR_SECRET_KEY" \
-H "X-Account-ID: YOUR_ACCOUNT_ID" \
-d '{
"job": { "spec": "0 0 2 * * *", "data": "{\"action\": \"process_data\"}", "timezone": "UTC" },
"age": "24h"
}'

The HTTP status is 200 whenever the invocation ran; whether the target accepted it is in data.success:

{
"success": true,
"data": {
"test": true,
"executorId": 1,
"executorType": "webhook_url",
"success": true,
"startedAt": "2026-01-15T02:00:00Z",
"finishedAt": "2026-01-15T02:00:00.142Z",
"durationMs": 142,
"payload": {
"job": { "spec": "0 0 2 * * *", "data": "{\"action\": \"process_data\"}", "timezone": "UTC", "executorId": 1, "status": "active" },
"lastExecutionDateTime": "2026-01-15T02:00:00Z",
"lastExecutionStatus": "scheduled"
}
}
}

On failure data.success is false and data.error explains why.