---
title: Recurring schedules API
description: Create, inspect, update, pause, resume, and delete recurring HTTP delivery schedules.
---

Schedules create normal Stormedo requests at recurring times. Each occurrence receives its own `req_` ID, delivery lifecycle, retries, and attempt history.

All schedule endpoints use the project selected by the bearer API key.

## Create a schedule

```http
POST https://api.stormedo.com/schedules
Content-Type: application/json
```

`Idempotency-Key` is required and must contain between 1 and 255 bytes.

```bash
curl --request POST \
  'https://api.stormedo.com/schedules' \
  --header "Authorization: Bearer $STORMEDO_TOKEN" \
  --header 'Content-Type: application/json' \
  --header 'Idempotency-Key: inventory-sync-schedule' \
  --data '{
    "name": "Inventory sync",
    "timing": {
      "type": "cron",
      "expression": "0 */6 * * *",
      "timezone": "Asia/Kolkata"
    },
    "request": {
      "url": "https://your-app.example/inventory/sync",
      "body": {
        "full_sync": true
      },
      "headers": {
        "Authorization": "Bearer destination-token"
      },
      "retry": 3
    }
  }'
```

### Top-level fields

| Field | Required | Description |
| --- | --- | --- |
| `name` | Yes | Display name containing 1 to 120 bytes. Leading and trailing whitespace is removed. |
| `timing` | Yes | Cron or fixed-interval timing definition. |
| `request` | Yes | HTTP request created for every occurrence. |

### Request fields

| Field | Required | Default | Description |
| --- | --- | --- | --- |
| `url` | Yes | None | Public HTTPS destination. Schedule deliveries use `POST`. |
| `body` | No | No body | Any JSON value, delivered as `application/json`, up to 256 KiB serialized. |
| `headers` | No | `{}` | Destination headers stored with the schedule. Values are redacted in detail responses. |
| `retry` | No | `0` | Additional retries after the first attempt, from `0` through `19`. |

Destination headers are limited to 64 entries and 32 KiB combined. Transport-controlled headers and `Stormedo-*` delivery headers cannot be supplied.

### Cron timing

```json
{
  "type": "cron",
  "expression": "0 9 * * *",
  "timezone": "Asia/Kolkata"
}
```

Cron expressions use exactly five fields. `timezone` must be a valid IANA timezone.

### Interval timing

```json
{
  "type": "interval",
  "every_seconds": 900,
  "starts_at": "2026-08-29T10:15:00Z"
}
```

`every_seconds` must be a whole number of minutes from 60 seconds through 30 days. On creation, `starts_at` must be a future RFC 3339 timestamp. If omitted, the first occurrence happens one complete interval after creation.

### Response

Schedule creation returns `201 Created`:

```json
{
  "success": true,
  "data": {
    "id": "sch_2dV8nB1mQ4sK7xH9pL3cF",
    "name": "Inventory sync",
    "timing": {
      "type": "cron",
      "expression": "0 */6 * * *",
      "timezone": "Asia/Kolkata"
    },
    "status": "active",
    "url": "https://your-app.example/inventory/sync",
    "retry": 3,
    "next_run_at": "2026-08-28T12:00:00Z",
    "last_run_at": null,
    "last_run_outcome": null,
    "created_at": "2026-08-28T10:15:30Z",
    "updated_at": "2026-08-28T10:15:30Z"
  },
  "error": null,
  "meta": null,
  "request_id": "95c07a5c-3d44-4b89-84a6-c5a71313bff2"
}
```

Repeating the same definition and key returns the same schedule. Reusing the key with different input returns `409 Conflict`.

## List schedules

```http
GET https://api.stormedo.com/schedules
```

Returns an array of schedule summaries for the API key project.

## Retrieve a schedule

```http
GET https://api.stormedo.com/schedules/{schedule_id}
```

Returns the summary fields plus the complete `request` definition. Destination header values appear as `[REDACTED]`.

## Update a schedule

```http
PATCH https://api.stormedo.com/schedules/{schedule_id}
Content-Type: application/json
```

Send at least one of `name`, `timing`, or `request`:

```bash
curl --request PATCH \
  'https://api.stormedo.com/schedules/sch_2dV8nB1mQ4sK7xH9pL3cF' \
  --header "Authorization: Bearer $STORMEDO_TOKEN" \
  --header 'Content-Type: application/json' \
  --data '{
    "timing": {
      "type": "interval",
      "every_seconds": 14400
    }
  }'
```

When `request` is supplied, include the complete new URL, body, and retry definition. Omitting `headers` preserves the stored destination headers. The update replaces the next timer when the schedule is active.

## Pause and resume

```http
POST https://api.stormedo.com/schedules/{schedule_id}/pause
POST https://api.stormedo.com/schedules/{schedule_id}/resume
```

Both actions return `200 OK` with an updated schedule summary. A paused schedule has `status: "paused"` and `next_run_at: null`. Existing request and attempt history remains unchanged.

## Delete a schedule

```http
DELETE https://api.stormedo.com/schedules/{schedule_id}
```

Returns `204 No Content` and cancels future occurrences. Requests created by previous occurrences remain available according to the workspace history retention period.

## Schedule outcomes and errors

`last_run_outcome` is `enqueued`, `skipped_usage_limit`, or null. Reaching the monthly request allowance skips that occurrence without pausing the schedule. Later occurrences can resume when capacity becomes available.

| Status | When it occurs |
| --- | --- |
| `401` | The project API key is missing or invalid. |
| `404` | The schedule does not exist in the API key project. |
| `409` | A schedule idempotency key was reused with a different definition. |
| `413` | The complete structured schedule request exceeds 512 KiB. |
| `422` | The name, timing, request definition, destination headers, or key is invalid. |
| `429` | Creating a schedule would exceed the workspace schedule allowance. |
| `502` or `503` | Stormedo could not durably apply the operation. |
