Public HTTP API#
The production service origin is https://backend.remind.teamofsilicons.com.
Ordinary routes begin with /api/v1. JSON requests use
Content-Type: application/json; JSON errors contain error.code,
error.message, and normally error.request_id. Quote the request ID when
investigating a failed call. Bodies are bounded by the deployment's request limit.
Authentication and organization selection#
Authenticate with Authorization: Bearer <application-access-token> and
X-Org-ID: <org-handle>. These are IAM Application tokens for tos>remind.
Remind introspects each request through the official silicon-iam-client and
requires matching application audience, organization, principal, membership,
expiry, and testing plane. An IAM refresh token cannot authorize reminder actions.
An unavailable IAM dependency fails closed; it does not become a fabricated user.
Every current member can read their organization's reminders. Only the owner Silicon can create, edit, pause, resume, archive, or configure its webhook. Carbon access is read-only for reminders, even if that Carbon is an org owner. An org owner/admin can administer test environments; their reminder permissions are still those of a Carbon.
A request carrying X-Remind-Test-Key: <32-character-key> uses an isolated Remind
sandbox. Its bearer must be from the linked IAM sandbox. Invalid keys never fall
through to production. Environment lifecycle management uses production identity
and rejects this test header. See testing environments.
Application sessions#
| Method and path | Request | Result |
|---|---|---|
GET /auth/iam |
No session; optional test key | Public app_id, iam_url, and iam_environment_id (null in production); no credentials |
POST /auth/login |
{"slt":"…"} |
Access/refresh tokens, expiry seconds, actor and optional org |
POST /auth/refresh |
{"refresh_token":"…"} |
Successor access and rotating refresh tokens |
POST /auth/logout |
{"token":"…"} |
204; refresh token revokes the whole family |
GET /auth/me |
Bearer and org headers | Current identity, disclosed org role and reminder-write capability |
GET /auth/organizations |
Bearer; no org header required | items containing identities for organizations currently authorized through IAM |
The three POST endpoints accept a token in their JSON body. Remind's Application
secret stays on the server. They do not ask for an IAM password, email, phone,
OTP, or a browser redirect. Pass an Idempotency-Key on login and refresh when a
retry must replay the same logical exchange. It must be 16–255 visible ASCII
characters. Session responses use Cache-Control: no-store.
Browser sign-in sends only app_id=tos>remind and redirect_uri to IAM; it must
not send org_id or org_ids. The user chooses the authorized organizations in
IAM. After exchanging the resulting unscoped SLT, use /auth/organizations to
discover that explicit grant list, then choose one as X-Org-ID for ordinary
requests. Membership alone does not grant application access. Legacy scoped
sessions remain usable within their original organization.
Example, with a short-lived token supplied from a protected file:
curl --request POST "$REMIND_URL/api/v1/auth/login" \
--header 'Content-Type: application/json' \
--header "Idempotency-Key: $MUTATION_KEY" \
--data-binary @login.json
login.json contains {"slt":"the-token-from-IAM"}. Keep tokens out of application
logs. Access and refresh tokens are separate: do not retry a spent refresh token
with a different idempotency key after a successful rotation.
Webhook configuration and Silicon discovery#
| Method and path | Behavior |
|---|---|
PUT /webhook |
Set the webhook endpoint for the authenticated Silicon |
GET /webhook |
Read its endpoint URL and version, without the signing secret |
DELETE /webhook |
Disable the endpoint; returns 204 |
POST /webhooks |
Add another independent webhook subscription |
GET /webhooks |
List active subscriptions, possibly empty |
DELETE /webhooks/{subscription_id} |
Disable one subscription; returns 204 |
GET /silicons?after=<uuid>&limit=50 |
List registered Silicons in this org with reminder counts |
Configuration input is {"endpoint_url":"…","signing_secret":"…"}; omit signing_secret for unsigned delivery. Use any URL
and an optional textual signing_secret chosen for the receiver. The backend validates the endpoint
as an absolute HTTP(S) URL and verifies the Silicon's canonical public ID.
See the exact sender and receipt contract.
Ownership and public routing identity are derived from IAM, never supplied by a
public caller. Endpoint URL and signing secret are encrypted at rest.
Webhook subscriptions are optional. Reminders can be created with no configured receiver and will begin fan-out delivery when subscriptions are added.
Reminders#
| Method and path | Required input | Result |
|---|---|---|
POST /schedules |
text, kind, cron; Idempotency-Key |
201 reminder |
GET /schedules |
Optional filters below | Page of reminders |
GET /schedules/{id} |
Reminder UUID | Visible reminder |
PATCH /schedules/{id} |
Changed fields; Idempotency-Key |
Updated reminder |
PATCH /schedules |
schedule_ids, status; Idempotency-Key |
Atomic results in supplied ID order |
DELETE /schedules/{id} |
Owner identity | 204; archives the reminder |
GET /schedules/{id}/executions |
Optional cursor and limit | Delivery history |
Creation example:
{
"text": "Check the build results",
"kind": "recurring",
"cron": "*/15 * * * *",
"timezone": "Asia/Kolkata"
}
kind is recurring or one_time. Both use five-field Linux cron in the order
minute, hour, day of month, month, day of week. One-time means the first future
matching occurrence, not a separate timestamp format. Omitted timezone means UTC.
Use an IANA identifier such as Asia/Kolkata, not a display name or fixed offset.
Cron supports Linux/Vixie lists, ranges, steps and named months/weekdays. Sunday
is 0 or 7. When both day-of-month and day-of-week are restricted, either may
match. Quartz extensions such as L, W and # are rejected. A nonexistent DST
wall-clock time is skipped; both real instants in a repeated interval are
eligible. The next occurrence is recalculated in UTC after each trigger.
Text must be nonblank and no more than 100,000 UTF-8 bytes. Responses include the UUID, org, public Silicon ID, text, kind, cron, timezone, status, section, next UTC occurrence, archive/deletion deadline, and creation/update timestamps.
Listing filters are silicon_id, section=current|archived,
status=active|paused|completed, cursor, and limit (1–100). Current is the
default section. Pass next_cursor unchanged into the next request, keeping the
same filters and organization. An empty result has items: [].
PATCH accepts text, timezone, kind, cron and status. Omitted fields are unchanged.
Cron cannot be cleared. Timing changes recalculate the next future occurrence;
a text-only change preserves it. Only active and paused are client-writable
statuses. completed is assigned by the backend when a one-time occurrence is
materialized. Archived reminders are immutable.
For atomic pause/resume, send 1–100 distinct UUIDs:
{"schedule_ids":["0198f74d-7ef7-7c9f-95bf-7d403a61e5ca"],"status":"paused"}
All IDs must identify current reminders owned by the caller. Any invalid owner,
missing reminder, or invalid lifecycle state fails the entire batch. Pausing
suppresses future materialization; already-materialized occurrences retain their
delivery lifecycle. Resuming calculates the next future cron match. Reapplying
the same state is a no-op. Reuse the same idempotency key only with the exact same
operation and input; changing input returns 409 idempotency_conflict.
Delivery, archive and retention#
The worker stores an immutable occurrence before sending it to the configured webhook endpoint. Execution ID is stable across retries; it is also webhook's idempotency identifier. The snapshot contains the reminder text at trigger time, schedule identity, Silicon ID, timezone, and intended trigger instant. Transient/ambiguous failures retry with bounded backoff; terminal errors are retained in execution history.
The owner can archive a reminder at any time. One-time reminders automatically enter the archive when their occurrence is materialized. Archived reminders and history remain readable for 45 days. Read and delivery queries enforce that expiry even if the cleanup worker is delayed. Before permanent removal, the worker writes one JSON text line with reminder, trigger and creator snapshots; the ledger retains the newest 100,000 records within that database/schema. The deletion ledger is backend-internal and is not exposed by the client or CLI.
Environment lifecycle#
See the dedicated sandbox guide for setup and
permissions. For new sandboxes send the IAM application app_secret in X-Remind-Test-Key; GET /testing-environment discovers its metadata automatically. Ordinary operations require a sandbox user bearer and its actual permissions. IAM owns cleanup and retirement. The following management operations are retained for legacy manually paired sandboxes:
| Method and path | Result |
|---|---|
POST /test-environments |
{environment, key} |
GET /test-environments |
Page; include_deleted, UUID after, and 1–100 limit |
GET /test-environments/{id} |
Metadata |
GET /test-environments/{id}/key |
{environment_id, key} |
POST /test-environments/{id}/key-rotations |
New key; previous key revoked |
DELETE /test-environments/{id} |
204; retires for 30-day recovery |
POST /test-environments/{id}/restorations |
Fresh key and restored environment |
GET /testing-environment |
Selected sandbox metadata (app_secret or legacy key) |
POST /testing-environment/cleanings |
Root-key-only atomic clear; 204 |
Errors and operational endpoints#
401 means missing, expired, revoked or mismatched authority. 403 means a
recognized actor lacks the action's permission. 404 also hides resources in
other organizations. 409 reports lifecycle/idempotency conflicts, absent
webhook configuration, duplicate active environment names, or the sandbox's
legacy 100-reminder limit. 422 reports invalid data. 429 may include Retry-After.
503 means an authority or storage dependency could not answer safely.
Origin-relative /health/live reports process liveness. /health/ready verifies
production schema readiness. /metrics is an operational endpoint and should be
restricted by deployment networking. The IAM receiver is the origin-relative
POST /webhook/; it verifies signed raw bodies and is not the user configuration
route /api/v1/webhook.
Legacy manual sandbox creation accepts an optional iam_app_secret. If omitted, root metadata,
cleaning and configuration are available immediately; authenticated actions wait
for PUT /testing-environment/iam with {"iam_app_secret":"<test-only-secret>"}
and the Remind root header. That route returns 204 and requires no actor bearer.
See the sandbox setup guide.
Wire version negotiation#
GET /api/versions is relative to the server origin and advertises supported protocols and lifecycle state. Send X-Remind-API-Version: 1 with /api/v1 requests; unsupported or conflicting selections return 406 before execution. The selected version appears on responses. See version policy for the compatibility matrix and seven-day idle sunset rule.
Reports and operational telemetry#
POST /api/v1/reports accepts { "message": "reproduction details", "pr": null } with bearer, organization, and Idempotency-Key headers. Maximum message length is 16384 UTF-8 bytes and the rate limit is 10 new reports per actor per hour. An optional PR must point to this repository's pull request. Returns HTTP 202 with {id,status,failure_reason}; replaying the same key/body returns HTTP 200 with the same receipt, and changing the body returns 409. GET /api/v1/reports/{id} is visible only to the submitting actor in the same organization/environment. Missing production Postmark configuration returns 503. Test reports immediately return simulated.
POST /api/v1/telemetry/events accepts only the bounded TelemetryEvent schema in OpenAPI and requires the same normal IAM session. X-Remind-Telemetry: off disables observations for any request. Production uses Space Station; testing writes only its own telemetry_events table. Telemetry submission itself is excluded from request observations to prevent recursion. Diagnostics and operator setup.