Schedules API
Recurring schedules are available on the Premium+ plan only. Attempting to use these endpoints on a Basic or Standard plan returns 403 PLAN_FEATURE_UNAVAILABLE. To upgrade, visit your billing settings.
Schedules let you send a notification on a repeating cadence using a standard cron expression. Each schedule references a template and one or more channels, and fires according to the cron expression evaluated in the specified IANA timezone.
POST /api/v1/schedules
Creates a new recurring schedule.
Request Body
{
"cron_expression": "0 9 * * 1",
"timezone": "America/New_York",
"template_id": "tpl_a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"channel_ids": ["ch_11111111-2222-3333-4444-555555555555"],
"target": { "type": "all" },
"active": true
}
| Field | Type | Required | Description |
|---|---|---|---|
cron_expression | string | Yes | A valid 5-field cron expression (minute hour day-of-month month day-of-week). |
timezone | string | Yes | An IANA timezone name (e.g. America/New_York, Europe/London, UTC). |
template_id | string | Yes | UUID of an existing notification template. |
channel_ids | array of strings | Yes | One or more channel UUIDs the notification will be sent through. |
target.type | string | Yes | Recipient targeting strategy. Currently supports "all" (all active subscribers). |
active | boolean | No | Whether the schedule should fire immediately. Defaults to true. |
Response — 201 Created
{
"id": "sch_a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"cron_expression": "0 9 * * 1",
"timezone": "America/New_York",
"template_id": "tpl_a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"channel_ids": ["ch_11111111-2222-3333-4444-555555555555"],
"target": { "type": "all" },
"active": true,
"created_at": "2026-04-25T12:00:00Z",
"next_run_at": "2026-04-27T13:00:00Z"
}
Error Codes
| Status | Reason |
|---|---|
| 401 | Missing or invalid bearer token. |
| 403 | Your plan does not include recurring schedules (PLAN_FEATURE_UNAVAILABLE). |
| 422 | cron_expression is not a valid 5-field cron string, timezone is not a recognised IANA timezone, or template_id does not refer to an existing template. |
403 response body
{
"error": "PLAN_FEATURE_UNAVAILABLE",
"message": "Recurring schedules require the Premium plan."
}
GET /api/v1/schedules
Returns a paginated list of schedules for the authenticated tenant.
Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
page | integer | 1 | Page number (1-based). |
per_page | integer | 20 | Number of results per page. |
active | boolean | — | Optional. When true, returns only active schedules. When false, returns only paused schedules. Omit to return all. |
Response — 200 OK
{
"data": [
{
"id": "sch_a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"cron_expression": "0 9 * * 1",
"timezone": "America/New_York",
"template_id": "tpl_a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"channel_ids": ["ch_11111111-2222-3333-4444-555555555555"],
"target": { "type": "all" },
"active": true,
"created_at": "2026-04-25T12:00:00Z",
"next_run_at": "2026-04-27T13:00:00Z"
}
],
"total": 4,
"page": 1
}
GET /api/v1/schedules/:id
Retrieves a single schedule by its UUID.
Response — 200 OK
{
"id": "sch_a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"cron_expression": "0 9 * * 1",
"timezone": "America/New_York",
"template_id": "tpl_a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"channel_ids": ["ch_11111111-2222-3333-4444-555555555555"],
"target": { "type": "all" },
"active": true,
"created_at": "2026-04-25T12:00:00Z",
"next_run_at": "2026-04-27T13:00:00Z"
}
Error Codes
| Status | Reason |
|---|---|
| 401 | Missing or invalid bearer token. |
| 404 | No schedule found with that ID, or it belongs to a different tenant. |
PATCH /api/v1/schedules/:id
Partially updates an existing schedule. All fields are optional; only the fields you supply are updated. Omitted fields retain their current values.
Request Body
{
"cron_expression": "0 */6 * * *",
"timezone": "UTC",
"template_id": "tpl_a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"channel_ids": ["ch_11111111-2222-3333-4444-555555555555"],
"active": false
}
| Field | Type | Required | Description |
|---|---|---|---|
cron_expression | string | No | Replacement cron expression. |
timezone | string | No | Replacement IANA timezone. |
template_id | string | No | Replacement template UUID. |
channel_ids | array of strings | No | Replacement list of channel UUIDs. Replaces the entire array, not merged. |
active | boolean | No | Set to false to pause the schedule; true to resume. |
Response — 200 OK
Returns the full updated schedule object (same shape as GET /api/v1/schedules/:id).
Error Codes
| Status | Reason |
|---|---|
| 401 | Missing or invalid bearer token. |
| 403 | Plan downgrade detected; recurring schedules are not available on the current plan (PLAN_FEATURE_UNAVAILABLE). |
| 404 | Schedule not found or cross-tenant access attempted. |
| 422 | cron_expression is invalid or timezone is not a recognised IANA timezone. |
DELETE /api/v1/schedules/:id
Permanently deletes a schedule. The schedule will not fire again after deletion.
Deletion is irreversible. If you only want to stop the schedule temporarily, set active: false via PATCH /api/v1/schedules/:id instead.
Response — 204 No Content
An empty body is returned on success.
Error Codes
| Status | Reason |
|---|---|
| 401 | Missing or invalid bearer token. |
| 404 | Schedule not found or cross-tenant access attempted. |
Cron Expression Reference
Schedules use the standard 5-field cron format:
┌───────────── minute (0–59)
│ ┌───────────── hour (0–23)
│ │ ┌───────────── day of month (1–31)
│ │ │ ┌───────────── month (1–12)
│ │ │ │ ┌───────────── day of week (0–7, Sunday = 0 or 7)
│ │ │ │ │
* * * * *
| Expression | Meaning |
|---|---|
0 9 * * 1 | Every Monday at 9:00 AM |
0 */6 * * * | Every 6 hours |
30 8 1 * * | 1st of every month at 8:30 AM |
0 12 * * 1-5 | Weekdays at noon |
0 0 * * * | Daily at midnight |
All times are evaluated in the timezone you specify on the schedule. See the Recurring Notifications guide for timezone best practices and DST considerations.