---
title: "Create a schedule"
method: POST
path: "/v1/schedules"
---

# Create a schedule

`POST /v1/schedules`

## Request

- Base URL: `https://docs.greatwait.dev` (the document declares no server; this is the origin it was published from)
- URL: `https://docs.greatwait.dev/v1/schedules`
- Auth: one of:
  - HTTP bearer
  - HTTP bearer and API key in header `Greatwait-Environment` and API key in header `Greatwait-Project`

Creates a schedule and returns it together with its first planned occurrence. Give exactly one of `at`, `delaySeconds`, `everySeconds` and `cron`. An optional `partitionKey` selects a fairness lane inside this project and environment; it is fixed after create. Add a verified `endpoint` to deliver each occurrence there. Instead of `endpoint`, give a `url`: the service uses this project and environment's existing endpoint at exactly that address, or creates one silently. Its signing secret is never returned; the response's `endpointSigningSecret` says where a signed-in member reveals it. Reusing an endpoint needs only `schedules:write`; creating one also needs `endpoints:write`, and without it the request is refused as `scope_missing`. Optional JSON `data` is encrypted before PostgreSQL persistence, placed in the signed callback, and returned as given by a schedule read. Optional `http` selects POST (default), PUT, or bodyless GET and schedule header overrides. Omitted HTTP settings preserve the signed structured envelope; `body: { mode: 'json', value: ... }` sends that JSON directly without interpolation. Ordinary headers remain readable and secret values are encrypted and write-only. Schedule headers override endpoint defaults case-insensitively, with `suppress` to omit an inherited header and `remove` to resume inheritance. Product signing, content and transport headers are reserved. Raw JSON and GET carry asynchronous completion details in reserved Callback-Completion headers. `at` and `delaySeconds` fire once; a delay is converted to an absolute instant when the request is accepted, so a schedule created either way reads back the same afterwards. `everySeconds` is a fixed duration and its first occurrence falls one interval after acceptance — it stays the same length across a daylight-saving change, and takes no timezone for that reason. `cron` is a wall clock: it is read against the IANA `timeZone` sent with it, `UTC` when none is, and the first occurrence is the first instant the expression names after acceptance. Where the clocks go forward and the wall time named does not exist that day, the occurrence falls at the first instant after the gap; where they go back and it happens twice, it falls once, at the earlier of the two. A recurring schedule is materialized one occurrence at a time: the next one is planned once the current one is due, so a read always shows one occurrence still to come. `lateness.policy` decides what happens when an occurrence reaches its first attempt after its planned instant: `skipAhead` never carries a recurring arrival across its next scheduled instant (and a shorter custom window may retire it earlier), while `catchUp` admits one arrival within `maxStalenessSeconds` even after later recurrence instants passed. A one-shot has no next recurrence, so either explicit policy uses its window and the default is `catchUp` with 24 hours; recurring schedules default to `skipAhead`, and a `catchUp` without an override has a one-interval window. A retry already in progress is exempt because it arrived and failed; its retry and give-up policy still decide the outcome. The organization, project and environment come from the verified principal; a body cannot name them, and the endpoint must belong to the same tuple, so a credential issued for one project can only ever create schedules in that project. Send an `Idempotency-Key` to make a retry safe: the identical request returns the schedule that key already created, marked `Idempotency-Replayed: true`, and creates nothing further; the same key with a different request is refused `idempotency_key_reused`. A replay reports the schedule **as it stands now**, not a frozen copy of the first response — if it was paused in between, the replay says so. Some calls need more: endpoints:write is required as well when the request names a `url` this project and environment has no endpoint at yet, and the call is refused `scope_missing` without it.

## Headers

- `Idempotency-Key` string

## Request body

- object
  - `autoPauseAfterFailures` union: Consecutive failed runs before automatic pause: 1–100 or "never". Defaults to 5 on create; omission on replace preserves the setting. One-shot schedules are unaffected.
    - integer
    - 'never'
  - `http` object
    - `method` 'POST' | 'PUT' | 'GET'
    - `body` union
      - object
        - `mode` 'envelope', required
      - object
        - `mode` 'json', required
        - `value` Schema0, required (unresolved $ref)
    - `headers` union[]
      - union
        - object
          - `action` 'set', required
          - `name` string, required
          - `value` string, required
          - `secret` boolean
        - object
          - `action` 'keep', required
          - `name` string, required
        - object
          - `action` 'remove', required
          - `name` string, required
        - object
          - `action` 'suppress', required
          - `name` string, required
  - `at` string
  - `cron` string
  - `data` Schema1 (unresolved $ref)
  - `delaySeconds` integer
  - `delivery` object
    - `onOverlap` 'skip' | 'queue'
    - `completion` 'response' | 'callback'
    - `maxDurationSeconds` integer: How long the receiver may take to answer, in seconds
  - `everySeconds` integer
  - `endpoint` string
  - `url` string, uri
  - `latencyClass` 'realtime' | 'bulk'
  - `lateness` object
    - `maxStalenessSeconds` integer
    - `policy` 'skipAhead' | 'catchUp'
  - `partitionKey` string
  - `name` string
  - `external_identifier` string: Host application identifier, matched exactly and case-sensitively; at most 256 UTF-8 bytes. Readable by schedule readers; do not include secrets.
  - `tags` string[]: Up to 16 distinct searchable tags. Omission preserves tags on replacement; [] clears them.
  - `timeZone` string

## Response `201`

Create a schedule

- object
  - `occurrence` object, required
    - `attemptCount` integer, required
    - `firstAttemptLatenessMs` integer
    - `firstAttemptStartedAt` string
    - `timingEligibility` 'eligible' | 'customer_blocked' | 'platform_blocked'
    - `timingEligibilityReason` string
    - `timingPolicyVersion` string
    - `generation` integer, required
    - `id` string, required
    - `plannedFor` string, required
    - `schedule` string, required
    - `sequence` integer, required
    - `settledAt` string
    - `state` 'planned' | 'due' | 'dispatching' | 'retry_wait' | 'ambiguous' | 'succeeded' | 'terminal_failed' | 'cancelled' | 'skipped_stale', required
  - `schedule` object, required
    - `autoPauseAfterFailures` union: Consecutive failed runs before automatic pause: 1–100 or "never". Defaults to 5 on create; omission on replace preserves the setting. One-shot schedules are unaffected.
      - integer
      - 'never'
    - `consecutiveFailedRuns` integer
    - `autoPauseReason` object, nullable
      - `failedRuns` integer, required
      - `status` integer
      - `diagnostic` string, required
      - `pausedAt` string, required
    - `http` object
      - `method` 'POST' | 'PUT' | 'GET', required
      - `body` union, required
        - object
          - `mode` 'envelope', required
        - object
          - `mode` 'none', required
        - object
          - `mode` 'json', required
          - `value` Schema0 (unresolved $ref)
      - `headers` union[], required
        - union
          - object
            - `name` string, required
            - `secret` false, required
            - `value` string, required
          - object
            - `name` string, required
            - `secret` true, required
            - `configured` true, required
          - object
            - `name` string, required
            - `suppressed` true, required
    - `archivedAt` string
    - `data` Schema1 (unresolved $ref)
    - `createdAt` string, required
    - `delivery` object
      - `completion` 'response' | 'callback', required
      - `maxDurationSeconds` integer, required
      - `onOverlap` 'skip' | 'queue', required
    - `endpoint` string
    - `endpointUrl` string, uri
    - `generation` integer, required
    - `id` string, required
    - `latencyClass` 'realtime' | 'bulk', required
    - `lateness` object, required
      - `maxStalenessSeconds` integer
      - `policy` 'skipAhead' | 'catchUp', required
    - `name` string
    - `external_identifier` string: Host application identifier, matched exactly and case-sensitively; at most 256 UTF-8 bytes. Readable by schedule readers; do not include secrets.
    - `tags` string[]: Up to 16 distinct searchable tags. Omission preserves tags on replacement; [] clears them.
    - `partitionKey` string
    - `nextDueAt` string
    - `recurrence` union, required
      - object
        - `kind` 'at', required
      - object
        - `everySeconds` integer, required
        - `kind` 'every', required
      - object
        - `cron` string, required
        - `kind` 'cron', required
        - `timeZone` unknown, required
    - `status` 'active' | 'paused' | 'cancelled' | 'completed', required
    - `updatedAt` string, required
    - `version` integer, required
  - `endpointSigningSecret` object
    - `guidance` string, required
    - `returned` false, required
    - `revealUrl` string, uri

## Other responses

- `400`: Problem document. Possible codes at this status: invalid_request.
- `401`: Problem document. Possible codes at this status: authentication_required, credential_expired, credential_revoked.
- `403`: Problem document. Possible codes at this status: scope_missing.
- `404`: Problem document. Possible codes at this status: not_found.
- `409`: Problem document. Possible codes at this status: idempotency_key_reused, plan_limit_reached, project_archived, state_conflict.
- `429`: Problem document. Possible codes at this status: rate_limited.
- `503`: Problem document. Possible codes at this status: capability_not_configured, service_unavailable.

---

[API](https://skmtc.dev/greatwait/apis/greatwait-v1.md) · [All operations](https://skmtc.dev/greatwait/apis/greatwait-v1/llms.txt) · [OpenAPI document](https://skmtc.dev/greatwait/apis/greatwait-v1/revisions/6855bce23e72?raw)
