API reference
Authentication
API keys, what they can reach, and the things they deliberately cannot.
Every endpoint takes a bearer token:
Authorization: Bearer <token>
Two credential types are accepted.
| Credential | Looks like | Used by | Expires |
|---|---|---|---|
| API key | sk_live_… |
scripts, CI, anything non-interactive | never, unless you set an expiry or revoke |
| Session token | a JWT | the web app itself | about an hour, auto-refreshed |
For automation you want an API key. A session token is tied to a browser login and will expire mid-pipeline.
Managing keys
# create
curl -s "$SEEDQL_API/api/keys" -X POST \
-H "Authorization: Bearer $SESSION_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name": "github-actions"}'
# list (never returns the secret)
curl -s "$SEEDQL_API/api/keys" -H "Authorization: Bearer $SESSION_TOKEN"
# revoke, takes effect immediately
curl -s -X DELETE "$SEEDQL_API/api/keys/$KEY_ID" -H "Authorization: Bearer $SESSION_TOKEN"
Creating returns the plaintext key once:
{
"id": "3f1c…",
"name": "github-actions",
"prefix": "sk_live_a1b2c3d4",
"key": "sk_live_a1b2c3d4…",
"warning": "Copy this now. It will not be shown again."
}
Listing returns only prefix, which identifies a key in a UI without being usable as one. The full value is not stored anywhere; only its SHA-256 hash is. There is no reveal endpoint, and adding one is not possible without changing what is stored.
Limit: 20 active keys per user.
What a key cannot do
Three restrictions are deliberate, not gaps.
Keys cannot manage keys. Minting and revoking require an interactive session. Otherwise a leaked key could mint replacements for itself and survive revocation, which would make revocation meaningless.
Keys cannot reach the operator console. Every /api/admin/* route refuses an API key with 403 session_required, including a key belonging to the platform owner. Keys live in CI config and shell history; the operator console can rewrite tiers and moderate content, and that blast radius requires a real login.
Keys inherit your permissions, never exceed them. A key acts as the user who created it, bounded by the same org membership and project roles. It cannot see a project you cannot see.
Failure responses
{ "detail": { "error": "invalid_token", "message": "..." } }
| Status | Meaning |
|---|---|
401 |
Missing, malformed, unknown, revoked, or expired key. All identical by design. |
403 tier_required |
Your tier does not include API access. |
403 session_required |
This route requires an interactive login. |
403 (other) |
Authenticated, but lacking the org or project role. |
Unknown, revoked and expired keys are indistinguishable in the response. That is intentional: distinguishing them turns the endpoint into an oracle for probing which keys exist.
Rotation
There is no rotate operation, because a rotate that keeps the old key alive is just two keys. Create the new one, deploy it, then revoke the old one and confirm with GET /api/keys.