# Create a schedule

- **OpenAPI Version:** `3.2.0`
- **API Version:** `3.1.0`
- **Contact:** Syndai <https://syndai.ai>

## Contents

**Operations**

- [POST /api/v1/external/coding/schedules](#scalar-operation-post-apiv1externalcodingschedules)

**Schemas**

- [ScheduleCreateRequest](#scalar-schema-schedulecreaterequest)
- [ScheduleTriggerSpec](#scalar-schema-scheduletriggerspec)
- [ScheduleRead](#scalar-schema-scheduleread)
- [ScheduleOccurrenceRead](#scalar-schema-scheduleoccurrenceread)
- [ProblemDetail](#scalar-schema-problemdetail)
- [ExternalErrorCode](#scalar-schema-externalerrorcode)

<a id="scalar-context-global-servers"></a>

## Servers

- **URL:** `https://api.syndai.ai`

<a id="scalar-context-global-authentication"></a>

## Authentication

- **CustomerApiKey**: HTTP bearer (`API Key`)

  Customer API key sent as a bearer token

## Tags

### Schedules

Recurring runs on a cron trigger. Create, update, pause, resume, fire now or delete a schedule. Every fire is a normal run that spends credits, and a schedule that may merge or push re-checks its writer's consent at each fire.

## Operations

<a id="scalar-operation-post-apiv1externalcodingschedules"></a>

### Create a schedule

- **Method:** `POST`
- **Path:** `/api/v1/external/coding/schedules`
- **Operation ID:** `createSchedule`
- **Tags:** Schedules

Create a recurring coding-run schedule. Each fire runs the saved prompt as a coding run, with the saved `policy_config`.

Supervised or autonomous is `policy_config.autonomy`:

| You want                   | `policy_config.autonomy`                                   | What each fire does                                                                           |
| -------------------------- | ---------------------------------------------------------- | --------------------------------------------------------------------------------------------- |
| Review every change        | `auto` (or omit: the project default applies at fire time) | Opens a PR; while it is unmerged the next slot rests                                          |
| Approve before a PR exists | `gated`                                                    | Holds for approval up to 24 h, then cancels; later slots skip while it holds                  |
| Fully autonomous           | `merge`                                                    | Lands when every gate is green, while the key or person that saved the policy may still merge |
| Fully autonomous, no PR    | `push`                                                     | Fast-forwards the default branch (API only)                                                   |

- `trigger` is a 5-field cron with an IANA timezone, at most every 15 minutes; runs start within 5 minutes of the slot.
- Scheduled runs never ask clarifying questions and never hold for plan review. They get one design direction.
- `occurrence_budget_usd` caps each fire.
- `from_coding_run_id` repeats an existing run: the schedule runs that run's original, full prompt on its repository. Omit `prompt` and `coding_repository_id` with it; send both without it.
- With `skip_if_no_new_commits` (default `true`) a slot rests while the default branch has not moved since the last successful run, so closing a PR without merging keeps the job resting until the next commit. Send `false` for jobs driven by the outside world (news, registry bumps).
- Merging stands only while its consent does: the API key that saved the policy must stay unrevoked, or the person must stay an owner or admin. Otherwise the fire opens a PR and its occurrence summary says so; re-saving the policy restores merging.
- Out of credits or over the monthly spend ceiling, a fire is skipped with a summary that says so, and the next slot retries on its own.
- A schedule needs an existing repository: create one with a New-project run (`new_repository`), or connect GitHub.
- Fires spend nothing until `schedule_paid_on` is `true`: only a workspace owner or admin (or a key one of them created) may set it (403 otherwise), and it needs `occurrence_budget_usd` (400 otherwise). A fire without that consent does not run.
- Send `client_request_id` to make the create safe to retry: a replay returns 409 with a `Location` header naming the existing schedule.

**Servers:** [Inherited servers](#scalar-context-global-servers)

**Authentication:** [Global authentication](#scalar-context-global-authentication)

#### Query parameters

- **`customer_id`**: `string | null`, format: `uuid`

#### Request body

**Required:** `true`

**Content type:** `application/json`

[ScheduleCreateRequest](#scalar-schema-schedulecreaterequest)

**Example:**

```json
{
  "client_request_id": "weekly-deps-storefront",
  "coding_repository_id": "8a1d4e2f-5b6c-4d7e-8f9a-0b1c2d3e4f50",
  "prompt": "Update dependencies and fix anything the upgrade breaks.",
  "skip_if_no_new_commits": true,
  "trigger": {
    "expr": "0 9 * * 1",
    "kind": "cron",
    "timezone": "Europe/London"
  }
}
```

#### Responses

##### 201 Document created, URL follows

**Content type:** `application/json`

[ScheduleRead](#scalar-schema-scheduleread)

**Example:**

```json
{
  "cadence_label": "Weekly on Monday at 9:00 AM",
  "coding_repository_id": "8a1d4e2f-5b6c-4d7e-8f9a-0b1c2d3e4f50",
  "consecutive_failures": 0,
  "created_at": "2026-10-27T09:00:00Z",
  "id": "7d6c5b4a-3928-4f17-8e6d-5c4b3a291807",
  "next_fire_at": "2026-11-02T09:00:00Z",
  "prompt": "Update dependencies and fix anything the upgrade breaks.",
  "repo_name": "storefront",
  "schedule_paid_on": false,
  "skip_if_no_new_commits": true,
  "status": "active",
  "trigger": {
    "expr": "0 9 * * 1",
    "kind": "cron",
    "timezone": "Europe/London"
  }
}
```

##### 400, 401, 403, 404

- `400` Bad request syntax or unsupported method
- `401` Invalid or missing customer API key
- `403` Insufficient scope or forbidden customer access
- `404` Resource not found

**Content type:** `application/problem+json`

[ProblemDetail](#scalar-schema-problemdetail)

RFC 7807 problem detail returned for public CaaS errors.

<a id="scalar-example-1"></a>

**Generated example:**

```json
{
  "code": "BUDGET_EXHAUSTED",
  "detail": null,
  "existing_run_id": null,
  "instance": null,
  "status": 1,
  "title": "",
  "type": "about:blank",
  "additionalProperty": "anything"
}
```

##### 409 Idempotency replay

**Headers:**

- **`Location`**

  Canonical URL for the existing resource

  `string`

**Content type:** `application/problem+json`

[ProblemDetail](#scalar-schema-problemdetail)

RFC 7807 problem detail returned for public CaaS errors.

[Generated example](#scalar-example-1)

##### 429 Rate limit exceeded

**Headers:**

- **`Retry-After`**

  Seconds to wait before retrying the request

  `integer`

**Content type:** `application/problem+json`

[ProblemDetail](#scalar-schema-problemdetail)

RFC 7807 problem detail returned for public CaaS errors.

[Generated example](#scalar-example-1)

##### default Unexpected error

**Content type:** `application/problem+json`

[ProblemDetail](#scalar-schema-problemdetail)

<a id="scalar-example-2"></a>

**Generated example:**

```json
null
```

## Schemas

<a id="scalar-schema-schedulecreaterequest"></a>

### ScheduleCreateRequest

**Type:** `object`

- **`trigger` (required)**: [ScheduleTriggerSpec](#scalar-schema-scheduletriggerspec)
- **`client_request_id`**: `string | null`, minLength: `1`, maxLength: `160`
- **`coding_repository_id`**: `string | null`, format: `uuid`
- **`from_coding_run_id`**: `string | null`, format: `uuid`
- **`occurrence_budget_usd`**: `number | null`
- **`policy_config`**: `object`
- **`prompt`**: `string | null`
- **`schedule_paid_on`**: `boolean`, default: `false`
- **`skip_if_no_new_commits`**: `boolean`, default: `true`

**Example:**

```json
{
  "client_request_id": "weekly-deps-storefront",
  "coding_repository_id": "8a1d4e2f-5b6c-4d7e-8f9a-0b1c2d3e4f50",
  "prompt": "Update dependencies and fix anything the upgrade breaks.",
  "skip_if_no_new_commits": true,
  "trigger": {
    "expr": "0 9 * * 1",
    "kind": "cron",
    "timezone": "Europe/London"
  }
}
```

<a id="scalar-schema-scheduletriggerspec"></a>

### ScheduleTriggerSpec

**Type:** `object`

- **`expr` (required)**: `string`
- **`kind` (required)**: `string`
- **`timezone` (required)**: `string`

<a id="scalar-example-3"></a>

**Generated example:**

```json
{
  "expr": "",
  "kind": "",
  "timezone": ""
}
```

<a id="scalar-schema-scheduleread"></a>

### ScheduleRead

**Type:** `object`

- **`cadence_label` (required)**: `string`
- **`coding_repository_id` (required)**: `string`, format: `uuid`
- **`consecutive_failures` (required)**: `integer`
- **`created_at` (required)**: `string`, format: `date-time`
- **`id` (required)**: `string`, format: `uuid`
- **`prompt` (required)**: `string`
- **`skip_if_no_new_commits` (required)**: `boolean`
- **`status` (required)**: `string`
- **`trigger` (required)**: [ScheduleTriggerSpec](#scalar-schema-scheduletriggerspec)
- **`last_occurrence`**: [ScheduleOccurrenceRead](#scalar-schema-scheduleoccurrenceread) | `null`
- **`last_run_at`**: `string | null`, format: `date-time`
- **`next_fire_at`**: `string | null`, format: `date-time`
- **`occurrence_budget_usd`**: `number | null`
- **`pause_reason`**: `string | null`
- **`policy_config`**: `object`
- **`repo_name`**: `string | null`
- **`schedule_paid_on`**: `boolean`, default: `false`
- **`upcoming`**: `array`

  **Items:**

  `string`, format: `date-time`

**Example:**

```json
{
  "cadence_label": "Weekly on Monday at 9:00 AM",
  "coding_repository_id": "8a1d4e2f-5b6c-4d7e-8f9a-0b1c2d3e4f50",
  "consecutive_failures": 0,
  "created_at": "2026-10-27T09:00:00Z",
  "id": "7d6c5b4a-3928-4f17-8e6d-5c4b3a291807",
  "next_fire_at": "2026-11-02T09:00:00Z",
  "prompt": "Update dependencies and fix anything the upgrade breaks.",
  "repo_name": "storefront",
  "schedule_paid_on": false,
  "skip_if_no_new_commits": true,
  "status": "active",
  "trigger": {
    "expr": "0 9 * * 1",
    "kind": "cron",
    "timezone": "Europe/London"
  }
}
```

<a id="scalar-schema-scheduleoccurrenceread"></a>

### ScheduleOccurrenceRead

**Type:** `object`

- **`created_at` (required)**: `string`, format: `date-time`
- **`disposition` (required)**: `string`
- **`slot_ts` (required)**: `string`, format: `date-time`
- **`coding_run_id`**: `string | null`, format: `uuid`
- **`summary`**: `string | null`

<a id="scalar-example-4"></a>

**Generated example:**

```json
{
  "coding_run_id": "",
  "created_at": "",
  "disposition": "",
  "slot_ts": "",
  "summary": ""
}
```

<a id="scalar-schema-problemdetail"></a>

### ProblemDetail

**Type:** `object`

RFC 7807 problem detail returned for public CaaS errors.

- **`code` (required)**: `string`, possible values: `"BUDGET_EXHAUSTED", "QUOTA_EXCEEDED", "RUN_CONCURRENCY_LIMIT", "CUSTOMER_DISABLED", "REPO_NOT_BOUND", "IDEMPOTENCY_REPLAY", "CONFLICT", "MISSION_BUSY_RETRY", "HITL_REQUEST_CONFLICT", "HITL_REQUEST_SETTLED", "RUN_TERMINATED_BEFORE_RESPONSE", "INVALID_POLICY", "INVALID_SCOPE", "RATE_LIMITED", "INSTALLATION_INCOMPLETE", "SUBSCRIPTION_USAGE_UNAVAILABLE", "INVALID_TOKEN", "ROLE_REQUIRED", "PLAN_UPGRADE_REQUIRED", "EMAIL_MISMATCH", "EXPIRED_TOKEN", "NOT_FOUND", "OVERSCOPE_ACK_REQUIRED", "VERIFY_FAILED", "PUBLISH_IN_FLIGHT", "PUBLISH_UNSUPPORTED_REPO", "PUBLICATION_NOT_LIVE", "NO_APP_DATA", "FEATURE_REQUESTS_NEEDS_MEMBERS", "EMPTY_UPDATE", "BAD_CURSOR", "HUMAN_APPROVAL_REQUIRED", "PROTECTED_PATHS_MANAGED_ONLY", "RUN_IN_FLIGHT", "TEXT_EDIT_REFUSED", "CLI_UPGRADE_REQUIRED", "PRODUCTION_STEP_UP_REQUIRED", "PRICES_UPDATING", "GITHUB_UNAVAILABLE", "PUBLISH_NOT_SET_UP", "VERSION_NOT_DEPLOYED", "INTERNAL_ERROR"`

  Stable error codes surfaced to public CaaS clients.
- **`status` (required)**: `integer`
- **`title` (required)**: `string`
- **`detail`**: `string | null`, default: `null`
- **`existing_run_id`**: `string | null`, default: `null`
- **`instance`**: `string | null`, default: `null`
- **`type`**: `string`, default: `"about:blank"`

<a id="scalar-example-5"></a>

**Generated example:**

```json
{
  "code": "BUDGET_EXHAUSTED",
  "detail": null,
  "existing_run_id": null,
  "instance": null,
  "status": 1,
  "title": "",
  "type": "about:blank",
  "additionalProperty": "anything"
}
```

<a id="scalar-schema-externalerrorcode"></a>

### ExternalErrorCode

**Type:** `string`, possible values: `"BUDGET_EXHAUSTED", "QUOTA_EXCEEDED", "RUN_CONCURRENCY_LIMIT", "CUSTOMER_DISABLED", "REPO_NOT_BOUND", "IDEMPOTENCY_REPLAY", "CONFLICT", "MISSION_BUSY_RETRY", "HITL_REQUEST_CONFLICT", "HITL_REQUEST_SETTLED", "RUN_TERMINATED_BEFORE_RESPONSE", "INVALID_POLICY", "INVALID_SCOPE", "RATE_LIMITED", "INSTALLATION_INCOMPLETE", "SUBSCRIPTION_USAGE_UNAVAILABLE", "INVALID_TOKEN", "ROLE_REQUIRED", "PLAN_UPGRADE_REQUIRED", "EMAIL_MISMATCH", "EXPIRED_TOKEN", "NOT_FOUND", "OVERSCOPE_ACK_REQUIRED", "VERIFY_FAILED", "PUBLISH_IN_FLIGHT", "PUBLISH_UNSUPPORTED_REPO", "PUBLICATION_NOT_LIVE", "NO_APP_DATA", "FEATURE_REQUESTS_NEEDS_MEMBERS", "EMPTY_UPDATE", "BAD_CURSOR", "HUMAN_APPROVAL_REQUIRED", "PROTECTED_PATHS_MANAGED_ONLY", "RUN_IN_FLIGHT", "TEXT_EDIT_REFUSED", "CLI_UPGRADE_REQUIRED", "PRODUCTION_STEP_UP_REQUIRED", "PRICES_UPDATING", "GITHUB_UNAVAILABLE", "PUBLISH_NOT_SET_UP", "VERSION_NOT_DEPLOYED", "INTERNAL_ERROR"`

Stable error codes surfaced to public CaaS clients.
