Skip to main content

API Reference

Base URL: https://runlater.eu/api/v1

Interactive docs: Try the API directly in your browser with our Swagger UI →

Authentication

All API requests require an API key. Include it in the Authorization header:

Authorization: Bearer pk_live_xxx.sk_live_yyy

Tasks API

Create and manage one-time tasks. Run immediately, after a delay, or at a specific time. For recurring cron schedules, see the Schedules API below.

GET /tasks

List all tasks for your organization.

curl https://runlater.eu/api/v1/tasks \
  -H "Authorization: Bearer pk_live_xxx"
GET /tasks/:id

Get a single task by ID.

curl https://runlater.eu/api/v1/tasks/task_abc123 \
  -H "Authorization: Bearer pk_live_xxx"
POST /tasks

Create a new task. The type is inferred from the parameters you pass: omit timing fields for immediate execution, use delay to defer, or run_at for a specific time. For recurring cron schedules, use POST /schedules.

Headers

Header Type Description
Idempotency-Key string Unique key to prevent duplicate requests. If the same key is sent again within 24 hours, the original response is returned without creating a new task. (optional)

Request Body

Field Type Description
url string The URL to call (required)
name string Display name (auto-generated if omitted)
method string HTTP method: GET, POST, PUT, PATCH, DELETE (default: POST)
headers object Custom headers to send (optional)
body string Request body, max 256KB (optional)
delay string Delay before execution: "30s", "5m", "2h", "1d". Runs immediately if omitted. (optional)
run_at string ISO 8601 timestamp for one-time scheduled execution (optional)
timeout_ms integer Request timeout in milliseconds (default: 30000)
retry_attempts integer Retry attempts for one-time tasks (default: 5)
callback_url string URL to receive a POST callback when execution completes. See Callbacks. (optional)
lane string Lane for serialized execution. Tasks in the same lane run one at a time within your organization — the next task won't start until the current one finishes. Leave empty for default parallel execution. (optional)
enabled boolean Whether the task is active (default: true)
notify_on_failure boolean | null Override org-level failure notification setting. null = use org default, true = always notify, false = never notify. (optional)
notify_on_recovery boolean | null Override org-level recovery notification setting. null = use org default, true = always notify, false = never notify. (optional)
expected_status_codes string Comma-separated status codes that count as success, e.g. "200,201". Empty means any 2xx. (optional)
expected_body_pattern string Response body must contain this text to count as success. Empty means any body. (optional)
on_failure_url string URL to POST to when the task fails. Receives a JSON payload with task and execution details. (optional)
on_recovery_url string URL to POST to when the task recovers after a failure. Receives a JSON payload with task and execution details. (optional)
script string Lua script with on_response function. Runs after execution completes. Pro only. See Lua Scripting. (optional)
debounce string Fixed debounce window: "30s", "5m", "2h", "1d". The first request executes at the end of the window. Subsequent requests within the same window replace it — but the scheduled time stays fixed (no sliding). Requires debounce_key and lane. (optional)
debounce_key string Key to group debounced requests. Requests with the same lane + debounce_key supersede each other within the fixed window — only the last one runs. Requires debounce and lane. (optional)
curl -X POST https://runlater.eu/api/v1/tasks \
  -H "Authorization: Bearer pk_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://myapp.com/api/webhook",
    "method": "POST",
    "body": "{\"event\": \"test\"}"
  }'
curl -X POST https://runlater.eu/api/v1/tasks \
  -H "Authorization: Bearer pk_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://myapp.com/api/charge",
    "method": "POST",
    "body": "{\"user_id\": 42}",
    "lane": "payments"
  }'
curl -X POST https://runlater.eu/api/v1/tasks \
  -H "Authorization: Bearer pk_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://myapp.com/api/remind",
    "delay": "15m"
  }'
# Fixed-window debounce: the first call schedules at now + 30s.
# Subsequent calls replace it but keep the same scheduled time.
curl -X POST https://runlater.eu/api/v1/tasks \
  -H "Authorization: Bearer pk_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://myapp.com/api/sync-user",
    "body": "{\"userId\": 123}",
    "lane": "sync",
    "debounce": "30s",
    "debounce_key": "user-123"
  }'
curl -X POST https://runlater.eu/api/v1/tasks \
  -H "Authorization: Bearer pk_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Send reminder",
    "url": "https://myapp.com/api/remind",
    "run_at": "2026-03-01T09:00:00Z"
  }'
PUT /tasks/:id

Update a task. Only include the fields you want to change.

curl -X PUT https://runlater.eu/api/v1/tasks/task_abc123 \
  -H "Authorization: Bearer pk_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://myapp.com/api/new-endpoint",
    "timeout_ms": 60000
  }'
DELETE /tasks/:id

Delete a task and all its execution history.

curl -X DELETE https://runlater.eu/api/v1/tasks/task_abc123 \
  -H "Authorization: Bearer pk_live_xxx"
POST /tasks/:id/trigger

Trigger a task to run immediately. Creates a new execution that runs right away.

curl -X POST https://runlater.eu/api/v1/tasks/task_abc123/trigger \
  -H "Authorization: Bearer pk_live_xxx"
POST /tasks/batch

Create many tasks at once. Each task in the tasks array defines its own url and can optionally override method, headers, body, and name. Top-level fields serve as defaults. Use the lane name with DELETE /tasks?lane=name to cancel them as a group.

Request Body

Field Type Description
lane string Lane name that groups the batch — used for bulk cancel (required)
tasks array Array of task objects (max 1000). Each must have a url and can include method, headers, body, name. (required)
method string Default HTTP method for tasks (default: POST)
headers object Default headers merged into each task (optional)
run_at string ISO 8601 timestamp — schedule all tasks for this time (optional)
delay string Delay before execution: "30s", "5m", "2h", "1d" (optional)
timeout_ms integer Default request timeout in milliseconds (default: 30000)
retry_attempts integer Default retry attempts per task (default: 5)
callback_url string Default URL to receive a POST callback per task on completion (optional)
curl -X POST https://runlater.eu/api/v1/tasks/batch \
  -H "Authorization: Bearer pk_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "lane": "march-newsletter",
    "method": "POST",
    "headers": { "Authorization": "Bearer xxx" },
    "run_at": "2026-03-01T09:00:00Z",
    "tasks": [
      { "url": "https://myapp.com/api/send-email", "body": { "to": "user1@example.com", "name": "Alice" } },
      { "url": "https://myapp.com/api/send-email", "body": { "to": "user2@example.com", "name": "Bob" } }
    ]
  }'
# Response (201 Created)
{
  "data": {
    "lane": "march-newsletter",
    "created": 2,
    "scheduled_for": "2026-03-01T09:00:00Z"
  },
  "message": "2 tasks created"
}
DELETE /tasks?lane=name

Cancel all tasks in a lane. Soft-deletes every non-deleted task matching the lane name and removes their pending executions. Use this to cancel a batch you created earlier.

Query Parameters

Field Type Description
lane string The lane name to cancel (required)
curl -X DELETE "https://runlater.eu/api/v1/tasks?lane=march-newsletter" \
  -H "Authorization: Bearer pk_live_xxx"
# Response (200 OK)
{
  "data": {
    "cancelled": 1000
  },
  "message": "1000 tasks cancelled"
}

Executions

GET /tasks/:id/executions

Get execution history for a task.

Query Parameters

Field Type Description
limit integer Max results to return, 1-100 (default: 50)
# Response
{
  "data": [{
    "id": "exec_123",
    "status": "success",
    "scheduled_for": "2026-02-06T10:00:00Z",
    "started_at": "2026-02-06T10:00:01Z",
    "finished_at": "2026-02-06T10:00:01Z",
    "status_code": 200,
    "duration_ms": 145,
    "attempt": 1
  }]
}

Schedules API

Create and manage recurring cron schedules. Schedules run on a cron expression and are managed separately from one-time tasks.

GET /schedules

List all schedules for your organization.

curl https://runlater.eu/api/v1/schedules \
  -H "Authorization: Bearer pk_live_xxx"
GET /schedules/:id

Get a single schedule by ID.

curl https://runlater.eu/api/v1/schedules/sched_abc123 \
  -H "Authorization: Bearer pk_live_xxx"
POST /schedules

Create a new recurring schedule. Requires a cron expression.

Request Body

Field Type Description
url string The URL to call (required)
cron string Cron expression for recurring execution (required)
name string Display name (auto-generated if omitted)
method string HTTP method: GET, POST, PUT, PATCH, DELETE (default: GET)
headers object Custom headers to send (optional)
body string Request body, max 256KB (optional)
timeout_ms integer Request timeout in milliseconds (default: 30000)
enabled boolean Whether the schedule is active (default: true)
notify_on_failure boolean | null Override org-level failure notification setting. (optional)
notify_on_recovery boolean | null Override org-level recovery notification setting. (optional)
expected_status_codes string Comma-separated status codes that count as success, e.g. "200,201". (optional)
script string Lua script with on_response function. Pro only. (optional)
curl -X POST https://runlater.eu/api/v1/schedules \
  -H "Authorization: Bearer pk_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Daily backup",
    "url": "https://myapp.com/api/backup",
    "cron": "0 6 * * *"
  }'
PUT /schedules/:id

Update a schedule. Only include the fields you want to change.

curl -X PUT https://runlater.eu/api/v1/schedules/sched_abc123 \
  -H "Authorization: Bearer pk_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "cron": "0 7 * * *",
    "enabled": false
  }'
DELETE /schedules/:id

Delete a schedule and all its execution history.

curl -X DELETE https://runlater.eu/api/v1/schedules/sched_abc123 \
  -H "Authorization: Bearer pk_live_xxx"
POST /schedules/:id/trigger

Trigger a schedule to run immediately. Creates a new execution that runs right away.

curl -X POST https://runlater.eu/api/v1/schedules/sched_abc123/trigger \
  -H "Authorization: Bearer pk_live_xxx"
GET /schedules/:id/executions

Get execution history for a schedule.

Query Parameters

Field Type Description
limit integer Max results to return, 1-100 (default: 50)

Monitors API

CRUD operations for heartbeat monitors (dead man's switches). See the Cron Monitoring docs for details.

GET /monitors

List all monitors for your organization.

curl https://runlater.eu/api/v1/monitors \
  -H "Authorization: Bearer pk_live_xxx"
GET /monitors/:id

Get a single monitor by ID. Response includes the ping_url.

curl https://runlater.eu/api/v1/monitors/mon_abc123 \
  -H "Authorization: Bearer pk_live_xxx"
POST /monitors

Create a new monitor.

Request Body

Field Type Description
name string Display name (required)
schedule_type string "interval" or "cron" (required)
interval_seconds integer Expected interval, 60-604800 (required for interval type)
cron_expression string Cron expression (required for cron type)
grace_period_seconds integer Grace period before alerting, 0-3600 (default: 300)
enabled boolean Whether monitoring is active (default: true)
notify_on_failure boolean | null Override org-level failure notification setting. null = use org default. (optional)
notify_on_recovery boolean | null Override org-level recovery notification setting. null = use org default. (optional)
on_failure_url string URL to POST to when the monitor goes down. Receives a JSON payload with monitor details. (optional)
on_recovery_url string URL to POST to when the monitor recovers after downtime. Receives a JSON payload with monitor details. (optional)
curl -X POST https://runlater.eu/api/v1/monitors \
  -H "Authorization: Bearer pk_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Nightly Backup",
    "schedule_type": "interval",
    "interval_seconds": 86400,
    "grace_period_seconds": 1800
  }'
PUT /monitors/:id

Update a monitor. Only include the fields you want to change.

curl -X PUT https://runlater.eu/api/v1/monitors/mon_abc123 \
  -H "Authorization: Bearer pk_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "grace_period_seconds": 3600
  }'
DELETE /monitors/:id

Delete a monitor and all its ping history.

curl -X DELETE https://runlater.eu/api/v1/monitors/mon_abc123 \
  -H "Authorization: Bearer pk_live_xxx"
GET /monitors/:id/pings

Get recent ping history for a monitor.

Query Parameters

Field Type Description
limit integer Max results to return, 1-100 (default: 50)
# Response
{
  "data": [{
    "id": "ping_123",
    "received_at": "2026-02-06T02:05:00Z"
  }]
}

Ping Monitor

Record a ping from your cron job. No API key needed — the token in the URL is the authentication. Accepts both GET and POST.

GET POST /ping/:token

Record a ping. Returns the monitor name and status. No authentication header needed.

Responses

Status Meaning
200 Ping recorded successfully
404 Invalid token
410 Monitor is paused/disabled
curl -fsS --retry 3 https://runlater.eu/ping/pm_your_token_here

Endpoints API

Inbound webhook endpoints receive events from external services and forward them to your app. See the Endpoints docs for the full guide.

GET /endpoints

List all endpoints for your organization.

curl https://runlater.eu/api/v1/endpoints \
  -H "Authorization: Bearer pk_live_xxx"
GET /endpoints/:id

Get a single endpoint by ID. Response includes the inbound_url.

curl https://runlater.eu/api/v1/endpoints/ep_abc123 \
  -H "Authorization: Bearer pk_live_xxx"
POST /endpoints

Create a new inbound endpoint.

Request Body

Field Type Description
name string Display name (required)
forward_urls array List of URLs to forward events to (required, at least one)
retry_attempts integer Retry attempts for forwarding, 0-10 (default: 5)
use_lane boolean Serialized delivery (one at a time). false for parallel. (default: true)
enabled boolean Whether the endpoint accepts events (default: true)
forward_headers object Custom headers merged with the original inbound headers when forwarding. (optional)
forward_body string Custom body replacing the original inbound body when forwarding. (optional)
forward_method string Custom HTTP method replacing the original inbound method when forwarding: GET, POST, PUT, PATCH, DELETE. (optional)
on_failure_url string URL to POST to when forwarding fails. Receives a JSON payload with endpoint and execution details. (optional)
on_recovery_url string URL to POST to when forwarding recovers after a failure. Receives a JSON payload with endpoint and execution details. (optional)
script string Lua script for webhook processing. Define optional functions: verify(), filter(), transform(), route(). See Lua Scripting. (optional, Pro only)
curl -X POST https://runlater.eu/api/v1/endpoints \
  -H "Authorization: Bearer pk_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Stripe webhooks",
    "forward_urls": ["https://myapp.com/webhooks/stripe"],
    "retry_attempts": 5,
    "use_lane": true
  }'
PUT /endpoints/:id

Update an endpoint. Only include the fields you want to change.

curl -X PUT https://runlater.eu/api/v1/endpoints/ep_abc123 \
  -H "Authorization: Bearer pk_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "retry_attempts": 0,
    "use_lane": false
  }'
DELETE /endpoints/:id

Delete an endpoint and all its inbound events.

curl -X DELETE https://runlater.eu/api/v1/endpoints/ep_abc123 \
  -H "Authorization: Bearer pk_live_xxx"
GET /endpoints/:id/events

Get inbound event history for an endpoint.

Query Parameters

Field Type Description
limit integer Max results to return, 1-100 (default: 50)
# Response
{
  "data": [{
    "id": "evt_123",
    "method": "POST",
    "source_ip": "1.2.3.4",
    "received_at": "2026-02-06T10:00:00Z",
    "execution_id": "exec_456",
    "execution_status": "success"
  }]
}
POST /endpoints/:id/events/:event_id/replay

Replay an inbound event. Creates a new forwarding execution for the original payload.

curl -X POST https://runlater.eu/api/v1/endpoints/ep_abc123/events/evt_456/replay \
  -H "Authorization: Bearer pk_live_xxx"

Declarative Sync

Push your entire configuration in one call. Perfect for infrastructure-as-code workflows.

PUT /sync

Sync your entire project configuration. This is idempotent - safe to call repeatedly with the same config.

Request Body

Field Type Description
schedules array Array of recurring schedule configurations
schedules[].key string Unique key for this schedule (your identifier)
schedules[].name string Display name for this schedule
schedules[].url string The URL to call
schedules[].method string HTTP method (default: GET)
schedules[].cron string Cron expression for recurring execution
schedules[].headers object Custom headers (optional)
schedules[].body string Request body, max 256KB (optional)
monitors array Array of monitor configurations (optional)
monitors[].key string Unique key for this monitor (your identifier)
monitors[].name string Display name for this monitor
monitors[].schedule_type string "cron" or "interval"
monitors[].cron_expression string Cron expression (when schedule_type is "cron")
monitors[].interval_seconds integer Expected ping interval in seconds (when schedule_type is "interval")
monitors[].grace_seconds integer Grace period before alerting (default: 300)
delete_removed boolean Delete schedules/monitors not in config (default: false)
curl -X PUT https://runlater.eu/api/v1/sync \
  -H "Authorization: Bearer pk_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "schedules": [{
      "key": "daily-backup",
      "name": "Daily backup",
      "url": "https://myapp.com/api/backup",
      "cron": "0 6 * * *"
    }],
    "monitors": [{
      "key": "nightly-etl",
      "name": "Nightly ETL",
      "schedule_type": "cron",
      "cron_expression": "0 2 * * *",
      "grace_seconds": 600
    }],
    "delete_removed": true
  }'

Limits

Limit Value Description
Request body size 256 KB Maximum size of the body field sent to webhooks
Response body storage 256 KB Responses larger than this are truncated in execution history
Request timeout 1s - 5min Configurable per task (default: 30s)
Retry attempts 0 - 10 For one-time tasks only (default: 5)

Errors

The API returns standard HTTP status codes:

Code Meaning
200 Success
201 Created
202 Accepted (for async operations like queue/trigger)
204 No content (successful delete)
400 Bad request - check your parameters
401 Unauthorized - invalid API key
404 Not found
422 Validation error
429 Rate limited - slow down
500 Server error - try again

Error responses include details:

{
  "error": {
    "message": "Invalid cron expression",
    "field": "cron"
  }
}