Keys
API keys minted for use from SDKs and external MCP clients.
5 operations. All requests need Authorization: Bearer sk_.... Responses use the standard envelope; see overview for shapes and error codes.
/keysList the calling user's API keys
Scoped to the session user, not the org — a teammate's keys are never listed here. For the org-wide v1 key inventory see `GET /org/{orgId}/api-keys`.
Responses
200- Keys (no secrets).400- Validation failed. `error.code = VALIDATION_ERROR`. `error.details.errors` lists per-field issues from zod.401- Missing or invalid auth. `error.code = AUTH_ERROR`.403- Authenticated but not allowed (wrong role, not a member, or org scope mismatch). `error.code = FORBIDDEN`.404- Resource does not exist or is invisible to the caller. `error.code = NOT_FOUND`.409- Conflict — duplicate slug, race condition, or invalid state transition. `error.code = CONFLICT`.429- Rate limit exceeded. `error.code = RATE_LIMIT`. Retry after the window listed in `Retry-After`.500- Unexpected server error. `error.code = INTERNAL_ERROR`. Logged with the `requestId` echoed in metadata.
cURL example
curl -X GET https://switchy.build/api/keys \
-H 'Authorization: Bearer sk_live_...' \/keysMint an API key
Returns the raw key once. After this response it can only be rotated, not retrieved.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
name | string | yes | |
scopes | string[] | yes |
Responses
201- Created. `secret` shown once.400- Validation failed. `error.code = VALIDATION_ERROR`. `error.details.errors` lists per-field issues from zod.401- Missing or invalid auth. `error.code = AUTH_ERROR`.403- Authenticated but not allowed (wrong role, not a member, or org scope mismatch). `error.code = FORBIDDEN`.404- Resource does not exist or is invisible to the caller. `error.code = NOT_FOUND`.409- Conflict — duplicate slug, race condition, or invalid state transition. `error.code = CONFLICT`.429- Rate limit exceeded. `error.code = RATE_LIMIT`. Retry after the window listed in `Retry-After`.500- Unexpected server error. `error.code = INTERNAL_ERROR`. Logged with the `requestId` echoed in metadata.
cURL example
curl -X POST https://switchy.build/api/keys \
-H 'Authorization: Bearer sk_live_...' \
-H 'Content-Type: application/json' \
-d '{ ... }'/org/{orgId}/api-keysList the org's v1 API keys
Metadata only — id, name, prefix, scopes, timestamps. Nothing returned here can reconstruct a key. Requires OWNER or ADMIN.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
orgId | path | yes | string | CUID |
Responses
200- Keys (no secrets).400- Validation failed. `error.code = VALIDATION_ERROR`. `error.details.errors` lists per-field issues from zod.401- Missing or invalid auth. `error.code = AUTH_ERROR`.403- Authenticated but not allowed (wrong role, not a member, or org scope mismatch). `error.code = FORBIDDEN`.404- Resource does not exist or is invisible to the caller. `error.code = NOT_FOUND`.409- Conflict — duplicate slug, race condition, or invalid state transition. `error.code = CONFLICT`.429- Rate limit exceeded. `error.code = RATE_LIMIT`. Retry after the window listed in `Retry-After`.500- Unexpected server error. `error.code = INTERNAL_ERROR`. Logged with the `requestId` echoed in metadata.
cURL example
curl -X GET https://switchy.build/api/org/:orgId/api-keys \
-H 'Authorization: Bearer sk_live_...' \/org/{orgId}/api-keysMint an org-wide v1 API key
Returns the plaintext `sk_live_...` key exactly once, in this response. It is stored only as a hash and can never be retrieved again — only revoked. The key grants org-wide access to /api/v1/**, so minting requires OWNER or ADMIN; a MEMBER gets 403.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
orgId | path | yes | string | CUID |
Request body
| Field | Type | Required | Description |
|---|---|---|---|
name | string | yes | Human label shown in the key list. |
scopes | "memory:read" | "memory:write"[] | no | Defaults to `["memory:read","memory:write"]`. |
Responses
201- Created. `key` is shown once and never again.400- Validation failed. `error.code = VALIDATION_ERROR`. `error.details.errors` lists per-field issues from zod.401- Missing or invalid auth. `error.code = AUTH_ERROR`.403- Authenticated but not allowed (wrong role, not a member, or org scope mismatch). `error.code = FORBIDDEN`.404- Resource does not exist or is invisible to the caller. `error.code = NOT_FOUND`.409- Conflict — duplicate slug, race condition, or invalid state transition. `error.code = CONFLICT`.429- Rate limit exceeded. `error.code = RATE_LIMIT`. Retry after the window listed in `Retry-After`.500- Unexpected server error. `error.code = INTERNAL_ERROR`. Logged with the `requestId` echoed in metadata.
cURL example
curl -X POST https://switchy.build/api/org/:orgId/api-keys \
-H 'Authorization: Bearer sk_live_...' \
-H 'Content-Type: application/json' \
-d '{ ... }'/org/{orgId}/api-keys/{keyId}Revoke an org API key
Idempotent — revoking an already-revoked key returns 200 with the original `revokedAt`. Keys belonging to another org return 404. Requires OWNER or ADMIN.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
orgId | path | yes | string | CUID |
keyId | path | yes | string | CUID |
Responses
200- Revoked.400- Validation failed. `error.code = VALIDATION_ERROR`. `error.details.errors` lists per-field issues from zod.401- Missing or invalid auth. `error.code = AUTH_ERROR`.403- Authenticated but not allowed (wrong role, not a member, or org scope mismatch). `error.code = FORBIDDEN`.404- Resource does not exist or is invisible to the caller. `error.code = NOT_FOUND`.409- Conflict — duplicate slug, race condition, or invalid state transition. `error.code = CONFLICT`.429- Rate limit exceeded. `error.code = RATE_LIMIT`. Retry after the window listed in `Retry-After`.500- Unexpected server error. `error.code = INTERNAL_ERROR`. Logged with the `requestId` echoed in metadata.
cURL example
curl -X DELETE https://switchy.build/api/org/:orgId/api-keys/:keyId \
-H 'Authorization: Bearer sk_live_...' \