- Start
- Concepts
Start
Concepts
The objects Greatwait works with, from organization and project down to a single delivery attempt, and how refusals are reported.
The terms used throughout these docs, from the largest container down to a single delivery attempt.
Organization
Your organization is the account you join when you accept an invitation. Everything you create belongs to it. Greatwait takes the organization from your signed-in session or your credential, never from anything in a request.
Project
A project holds schedules, destinations, and API credentials. A signed-in person creates projects in the dashboard: projects.create accepts only a signed-in session, never an API credential.
Environment
An environment separates work inside a project. Every resource and every API credential belongs to exactly one project and one environment.
A credential acts in exactly one project and environment, and nothing you send can widen that. The organization, project, and environment come from the verified credential, never from a request body, query string, or path. A resource that belongs to another project or environment answers not_found, exactly as if it did not exist.
API credential
An API credential lets your code, the CLI, or an agent call the API. A signed-in person creates one in the dashboard (credentials.create accepts only a signed-in session). Its secret is shown once, when it is created, and can never be read back. Keep it in an environment variable or a secret store, not on a command line.
A credential’s scopes are named resource:action and can be no wider than the creating member’s role allows.
Destination (endpoint)
A destination is the HTTPS address callbacks are delivered to. The API calls it an endpoint: endpoints.create, and identifiers that start with ep_.
- The URL must be HTTPS on port 443, contain no username, password, or fragment, and resolve only to public addresses.
- The
endpoints.createresponse is the only API response that includes the signing secret, insecret(with itskeyId, markedshownOnce: true). Your receiver uses it to verify callbacks, so store it when you create the endpoint. A signed-in member can reveal it again from the endpoint’s page in the dashboard. API credentials cannot. - A disabled endpoint receives nothing.
endpoints.enableturns it back on.
Signing keys can be rotated. See Verifying callbacks.
Schedule
A schedule (sch_) says when to call which endpoint, and what data to send. Give exactly one of:
| Field | Kind | Meaning |
|---|---|---|
at | one-shot | An instant, in RFC 3339 UTC with milliseconds, such as 2026-07-28T15:00:00.000Z |
delaySeconds | one-shot | A delay, converted to an absolute instant when the request is accepted |
everySeconds | recurring | A fixed interval |
cron | recurring | A wall-clock expression, read in the timeZone sent with it |
A schedule can be paused (schedules.pause), resumed (schedules.resume), replaced with a new definition (schedules.replace), cancelled (schedules.cancel), and archived (schedules.archive). Recurrence and time zones covers the recurring kinds.
Occurrence
An occurrence (occ_) is one planned run of a schedule, due at plannedFor. A recurring schedule plans one occurrence at a time: the next is planned once the current one is due.
state | Meaning |
|---|---|
planned | Waiting for its instant. |
due | Its instant has arrived and it is waiting to be dispatched. |
dispatching | A delivery attempt is in progress. |
retry_wait | An attempt failed in a way worth retrying, and the next attempt is waiting. |
ambiguous | The last attempt got no answer, so your receiver may have acted. It will be tried again. |
succeeded | Delivered. Final. |
terminal_failed | Delivery stopped without success. Final. |
cancelled | The schedule was cancelled before this occurrence was delivered. Final. |
skipped_stale | Not delivered: it came due too late to run, or its schedule was replaced first. Final. |
Attempt
An attempt (att_) is one try at delivering an occurrence. Attempts never change after they are recorded, so an occurrence’s attempts are its delivery history.
state | Meaning |
|---|---|
succeeded | Your receiver answered 2xx. |
retryable_failure | Your receiver answered with a status worth retrying. |
terminal_failure | Your receiver answered with a status that retrying will not change. |
ambiguous | No answer came back, for example a timeout or dropped connection. It may have run. |
Each attempt also records attemptNumber, startedAt, durationMs, responseStatus when there was a response, a diagnostic naming the classified cause, a remediation naming the next action, and a trigger: automatic for Greatwait’s own attempts, or redelivery when a person asked for the occurrence to be delivered again. Failures and retries explains how to read them.
Problem details
Every error response is an RFC 9457 problem document, served as application/problem+json.
| Field | Always present | Meaning |
|---|---|---|
code | yes | A stable, machine-readable name for the refusal, such as not_found. |
status | yes | The HTTP status. |
title | yes | A short human-readable summary. It can change. |
type | yes | about:blank. |
detail | no | A human-readable explanation. It can change. |
errors | no | Field problems, each with a JSON pointer to the field and a reason. |
retryAfterSeconds | no | How long to wait before trying again. |
traceId | no | An identifier for this request. |
Branch on code, never on title or detail. The problem codes reference lists what each code means. Of the codes, only rate_limited and service_unavailable are worth retrying unchanged.
Identifiers and time
Identifiers are opaque strings with a type prefix, such as sch_, occ_, att_, and ep_. Compare them for equality only. Instants are always RFC 3339 in UTC with millisecond precision and a literal Z.