HTTP API

Manage endpoints, read events, and trigger replays from your own code.

Advanced Available on All plans, with read only or read and write keys Updated 18 October 2026

These pages describe ShellOrbit as it runs today. Breaking changes to the HTTP API are announced before they ship, and existing request and response shapes stay supported.

How do I authenticate?

Bearer token. Create a key in the dashboard, store it as a secret, and send it on every request.

bash
curl https://api.shellorbit.com/v1/endpoints \
  -H "authorization: Bearer $SHELLORBIT_API_KEY"

Keys carry a scope, either read or read and write, and can be revoked individually. A revoked key stops working immediately.

What are the main resources?

HTTP API: Method and path, What it does
Method and pathWhat it does
GET /v1/endpointsList endpoints
POST /v1/endpointsCreate an endpoint
GET /v1/endpoints/{id}Read one endpoint with its configuration
PATCH /v1/endpoints/{id}Update destinations, retry policy, or alerts
DELETE /v1/endpoints/{id}Delete an endpoint and stop new receipts
POST /v1/endpoints/{id}/eventsSend an event through the endpoint, as a provider would
GET /v1/eventsList events, filtered by endpoint, status, type, or time
GET /v1/events/{id}Read one event with headers, body, and attempts
POST /v1/events/{id}/replayReplay one event
POST /v1/replaysReplay a filtered set
GET /v1/recoveriesList recovery jobs, with a cursor for older history
POST /v1/recoveriesPrepare a saved selection of retained failed deliveries
POST /v1/recoveries/{id}Request a canary, continue after success, or cancel
GET /v1/recoveries/{id}/itemsRead per-destination recovery results, with a cursor
GET /v1/usageCurrent period volume and projected overage
GET /v1/alertsRead alert settings, with webhook URLs masked
PATCH /v1/alertsUpdate alert settings
POST /v1/alerts/testSend a test alert down every saved channel and report each result

How is a list paginated?

Cursor based. A response carries next_cursor when more rows exist.

json
{
  "data": [ { "id": "evt_9c41f0", "status": "delivered", "attempts": 3 } ],
  "next_cursor": "ZXZ0Xzk1MmEx"
}

Pass it back as cursor to continue. Cursors are stable across inserts, so paging through a busy endpoint does not skip or repeat rows.

How does a filtered replay work?

POST /v1/replays traverses every page in the selected time range, including empty filtered pages. It fixes the upper time bound when the request starts. A successful response includes events, queued, run_id, and truncated: false. Rate pacing counts destination deliveries, so an event with two enabled destinations queues two deliveries.

This endpoint queues work during the HTTP request. A timeout or storage/queue error can occur after some deliveries have already been queued. Check event attempts before repeating the selection; retrying the whole request creates a new replay run and can repeat those deliveries. Use the saved recovery workflow for large selections of failed deliveries.

How does saved recovery work?

Prepare a selection with POST /v1/recoveries:

json
{"endpoint_id":"ep_example","since":"2026-09-29T12:00:00Z","rate_per_second":10}

An optional destination_id restricts the selection to an enabled destination. The rate must be an integer from 1 to 100. The upper time bound is fixed when preparation starts. Poll the job list until its state is ready; preparation sends no requests.

Send {"action":"canary"} to POST /v1/recoveries/{id} to test up to five distinct event–destination pairs. A pair can have several retry attempts. If the test succeeds and more deliveries remain, the state becomes awaiting_approval. Send {"action":"continue"} to recover the rest, or {"action":"cancel"} to stop pending requests. Requests already in flight may finish. Selections of five or fewer deliveries complete after a successful canary.

total, queued, delivered, failed, and skipped count destination deliveries, not events or HTTP attempts. queued includes reserved work waiting for queue submission. The item endpoint exposes the individual state and any skipped reason. A failed or unavailable delivery stops the job; a 24-hour deadline from creation also bounds preparation, pauses, and approval waits. History lasts 30 days, without extending payload retention.

Work proceeds in bounded pages. The requested rate spaces deliveries within each batch; it is not a global destination limit or a guaranteed request rate. Automatic retries can change timing. Recovery still uses at-least-once delivery, so application handlers need idempotency.

What do errors look like?

json
{
  "error": {
    "type": "invalid_request",
    "message": "destination_url must use https",
    "param": "destination_url"
  }
}

Status codes follow the usual meanings: 400 for a bad request, 401 for a missing or revoked key, 403 for a scope problem, 404 for an unknown id, 429 when rate limited, and 5xx for our failures. Retry reads with backoff for 429 and 5xx. Before retrying a write, check whether it already took effect; filtered replays can partially queue work as described above.

Is there a CLI?

There is a small one for local development: the ShellOrbit CLI (npx @shellorbit/cli listen) forwards the events an endpoint receives to a server on your machine. Everything else is the plain HTTP API above, so a few lines of curl or your language’s HTTP client does the same job, and that is what the examples show.