HTTP API
Manage sources and rules, read source events and findings, and drive Leak Alarm from your own code.
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.
Authenticate
Bearer token. Create a key in the dashboard, store it as a secret, and send it on every request.
curl https://api.shellorbit.com/v1/sources \
-H "authorization: Bearer $SHELLORBIT_API_KEY"Keys are read only or read and write. A revoked key stops working at once.
Sources and rules
| Method and path | What it does |
|---|---|
GET /v1/sources | List sources |
POST /v1/sources | Create one: {"name":"AWS production","kind":"aws","silent_hours":24}; kind github, aws, okta, auth0, app, or custom, with signature_format and inbound_secret for a custom source |
GET /v1/sources/{id} | Read one source with its configuration |
PATCH /v1/sources/{id} | Update its name, silent hours, IP allowlist, masked fields, or switched off rules |
DELETE /v1/sources/{id} | Delete a source; its URL stops accepting events at once |
POST /v1/sources/{id}/secret/rotate | A new secret, shown once |
POST /v1/sources/{id}/test | Run a sample event of the source’s kind through its rules |
GET /v1/sources/{id}/events | The source’s events, newest first, with a cursor |
GET /v1/events/{id} | One source event with headers, body, and signature result, masked fields hidden |
GET /v1/rules/catalog | The ready-made rules: id, kind, title, severity, description |
GET /v1/rules | Your custom rules |
POST /v1/rules | Create one, as below |
PATCH /v1/rules/{id} | Change a rule, or turn it off with {"enabled":false} |
DELETE /v1/rules/{id} | Delete a rule |
GET /v1/usage | This month’s source events (fair use, never charged), log volume, tripwires, and optional overages |
PUT /v1/usage/log-overage | Owners and admins, signed in: {"on": true} keeps scanning logs past the allowance, billed per whole GB |
GET /v1/alerts | Read alert settings, with channel URLs masked |
PATCH /v1/alerts | Update alert settings |
POST /v1/alerts/test | Send a test alert down every saved channel and report each result |
A custom rule:
{
"name": "Lots of new Stripe disputes",
"source_id": "",
"severity": "high",
"conditions": [
{ "path": "body.type", "op": "eq", "value": "charge.dispute.created" }
],
"threshold": { "count": 5, "minutes": 60 },
"enabled": true
}source_id empty means any source. op is eq, ne, contains, exists, or in; threshold is optional. See rules.
Leak Alarm and Incident Alerts
Auth: Read is a session or any API key. Write needs a read and write key or a signed-in member. Member and Admin need a signed-in member, admin or owner; API keys are refused.
API keys can never create or delete API keys, schedule a revoke, or change a person’s own account (password, email, two-step verification, sessions). A leaked key cannot mint another key or act on your other providers.
| Method and path | Auth | What it does |
|---|---|---|
GET /v1/leak/overview | Read | Open findings by severity, tripwire hits, coverage, and limits |
GET /v1/leak/findings | Read | Findings from every source, with masked values and fixes, up to 200 |
POST /v1/leak/findings/{id}/status | Write | {"status":"acknowledged"}, "resolved", or "open". See findings |
POST /v1/leak/findings/{id}/revoke | Member | Schedule a revoke ten minutes out |
POST /v1/leak/findings/{id}/revoke/cancel | Write | Cancel a scheduled revoke |
GET /v1/leak/assets | Read | Watched domains and log drains with their last scan |
POST /v1/leak/scans | Write | Scan a verified domain now: {"hostname":"app.example.com"}, three times an hour per domain |
GET /v1/leak/tripwires | Read | List tripwires |
POST /v1/leak/tripwires | Write | Create one: {"name":"Users table","type":"database_row"}; type link, email, database_row, or aws_key |
DELETE /v1/leak/tripwires/{id} | Write | Delete a tripwire |
GET /v1/leak/tripwires/hits | Read | Recent hits |
GET /v1/leak/drains | Read | List log drains |
POST /v1/leak/drains | Write | Create one: {"name":"Prod","provider":"vercel","secret":"…","verify":"…"}; provider vercel, netlify, supabase, cloudflare, or cloudwatch |
DELETE /v1/leak/drains/{id} | Write | Delete a drain |
GET /v1/leak/sdk/projects | Read | List SDK projects with their DSNs |
POST /v1/leak/sdk/projects | Write | Create one: {"name":"Checkout API"} |
POST /v1/leak/sdk/projects/{id}/rotate | Write | New key and DSN; the old one stops at once |
DELETE /v1/leak/sdk/projects/{id} | Write | Delete a project and its tripwire |
GET /v1/leak/accounts | Read | Connected accounts for revoke |
PUT /v1/leak/accounts/{provider} | Admin | Connect aws, openai, supabase, or github |
PATCH /v1/leak/accounts/{provider} | Admin | Turn automatic revoke on or off: {"auto_revoke":true} |
DELETE /v1/leak/accounts/{provider} | Admin | Disconnect and delete the credential |
GET /v1/leak/incidents | Read | Incidents affecting you, and the last 90 days of advisories with their state |
GET /v1/leak/incidents/{id} | Read | One advisory and every match |
GET /v1/leak/stack | Read | Your stack, declared and detected |
GET /v1/leak/stack/catalog | Read | Products you can declare |
POST /v1/leak/stack | Write | Declare: {"product":"php","version":"8.1","label":"billing API"} |
DELETE /v1/leak/stack/{id} | Write | Remove a declared item, or dismiss a detected one |
Intake
Used by the SDK and logging platforms, not by API keys.
| Method and path | Auth | What it does |
|---|---|---|
POST /v1/intake/{project}/findings | Authorization: DSN <key> | Report masked findings, up to 50 a request |
POST /v1/intake/{project}/fingerprints | DSN | Register salted fingerprints of your keys |
GET /v1/intake/{project}/salt | DSN | The project’s fingerprint salt |
GET /v1/intake/{project}/tripwire | DSN | A fake AWS key to plant |
POST /v1/intake/{project}/runtime | DSN | Node.js and OpenSSL versions, platform, and architecture |
POST /v1/intake/{project}/outbound | DSN | Hostnames the app and its packages connect to, up to 200 a request. See outbound traffic watch |
POST /v1/drains/{token} | The token in the URL, plus the drain’s secret | One log batch from a platform |
Pagination
Cursor based. A response carries next_cursor when more rows exist.
{
"data": [ { "id": "evt_9c41f0", "received_at": "2026-10-25T06:12:04Z", "signature_verified": true } ],
"next_cursor": "ZXZ0Xzk1MmEx"
}Pass it back as cursor. Cursors are stable across inserts, so no row is skipped or repeated.
Errors
{
"error": {
"type": "invalid_request",
"message": "Choose a kind: github, aws, okta, auth0, app, or custom.",
"param": "kind"
}
}| Status | Meaning |
|---|---|
| 400 | Bad request |
| 401 | Missing or revoked key |
| 403 | Scope or role problem |
| 404 | Unknown id |
| 429 | Rate limited; retry with backoff |
| 5xx | Our failure; retry reads with backoff, and check a write took effect before repeating it |