Overview
v2.0.0. The session-authenticated API used by the Switchy web app. It accepts the browser session cookie set when you sign in, not API keys. For programmatic access with an API key, use the v1 API, specified at /api/v1/openapi.json.
Which API?
Switchy has two HTTP APIs, and they authenticate differently.
| v1 API | v2 API (this reference) | |
|---|---|---|
| Built for | Your code: scripts, backends, CI | The Switchy web app |
| Authenticates with | An API key, as Authorization: Bearer <key> | The session cookie your browser gets when you sign in |
| Base URL | https://switchy.build/api/v1 | https://switchy.build/api |
| Spec | /api/v1/openapi.json | /api/openapi.json (OpenAPI 3.1.0) |
If you have an API key, use v1. No v2 endpoint accepts one. They never read the Authorization header, so a request that carries a key but no session cookie gets 401 AUTH_ERROR. Local dev serves both APIs at http://localhost:3000.
Authentication
v1: API keys
Pass the key as a Bearer token:
Authorization: Bearer <your key>An owner or admin of an org mints an org-wide sk_live_… key for it. The key is shown once. The minting endpoint belongs to v2, so it takes your signed-in session rather than a key:
curl -X POST https://switchy.build/api/org/<orgId>/api-keys \
-H 'Cookie: __Secure-next-auth.session-token=<your session cookie>' \
-H 'Content-Type: application/json' \
-d '{"name":"CI pipeline"}'
# → { "data": { "key": "sk_live_...", ... } } shown once, never retrievable againOwners and admins create these keys in Settings → Team → Developer API keys. (The separate API keys tab holds MCP keys for Claude Code, Cursor and ChatGPT, which do not work on these endpoints.) Which kind of key each v1 endpoint accepts is set out in the BearerAuth scheme of the v1 spec.
v2: the session cookie
Every operation in this reference authenticates with the cookie Switchy sets when you sign in: __Secure-next-auth.session-token in production, or next-auth.session-token on plain-HTTP local dev. A signed-in browser sends it automatically. Each operation states its auth, both in the spec's security field and on its reference page, and the cURL examples there pass the cookie explicitly.
Response envelope
Every response, success or failure, follows the same shape:
// Success
{
"success": true,
"data": { ... },
"metadata": { "timestamp": "2026-04-19T12:34:56.789Z" }
}
// Failure
{
"success": false,
"error": { "code": "VALIDATION_ERROR", "message": "...", "details": { ... } },
"metadata": { "timestamp": "2026-04-19T12:34:56.789Z" }
}Branch on error.code - the codes are stable. The HTTP status mirrors the code: 4xx for caller errors, 5xx for ours.
Error codes
| Code | HTTP | When |
|---|---|---|
AUTH_ERROR | 401 | Not signed in, or the session has expired. API keys do not authenticate v2, so a request carrying only a key gets this too. |
FORBIDDEN | 403 | Authenticated but the caller is not allowed (wrong role, not a Project member, wrong org). |
NOT_FOUND | 404 | The resource does not exist or is invisible to the caller. |
VALIDATION_ERROR | 400 | Body or query failed zod validation. Per-field details in error.details.errors. |
CONFLICT | 409 | Duplicate slug, race, or invalid state transition. |
RATE_LIMIT | 429 | Rate limit hit. Retry after the value in the Retry-After header. |
INTERNAL_ERROR | 500 | Unexpected server error. requestId is logged on our side. |
Retries and duplicates
There is no Idempotency-Key support: retrying a POST can repeat its effect. Memory writes are the exception — creating a memory whose content already exists returns 409 DUPLICATE_CONTENT instead of storing it twice, so retrying a memory create is safe.
Rate limits
API-key requests to v1 are rate limited per plan, per minute and per day. Hitting a limit returns 429 with a Retry-After header. There's no soft burst - pace your client. MCP tool calls (tools/call) are governed by per-tool quotas inside the MCP server, not the HTTP API.
Pagination
List endpoints take page (1-based) and limit (1–100, default 20). Cursor-based endpoints use before (a resource id) instead. Both styles return data.total when known.
Resource reference
- Spaces - Projects (formerly "Spaces") — containers of scoped memory, Slack/Teams channel mappings, and tasks inside an org. Internally still called "projects" in URLs (see migration guide).
- Sessions - Conversation threads inside a Project.
- Messages - Posts within a session — human or AGENT-authored.
- Memory - Embedded notes with PRIVATE / PROJECT / ORG visibility.
- Org - Members + invitations.
- Billing - Plan, credits, top-ups, Stripe checkout.
- MCP - External MCP integrations bound to Projects.
- Keys - Manage API keys. Like everything in this document these endpoints take your session; the keys they mint authenticate the v1 API (`/api/v1`) and the MCP server, not these endpoints.
SDKs
The JS / TS (@switchy-ai/sdk) and Python (switchy-sdk) SDKs authenticate with an API key, which the v2 endpoints in this reference do not accept. From 0.4.0 they are clients for the v1 API: client.memory lists, creates, searches, and deletes memories with an sk_live_… key. Their McpClient talks to the MCP server, which takes an MCP key. The 0.3.x SDKs called v2 endpoints, so every resource call returned 401. Upgrade to 0.4.0. For v1 endpoints the SDKs don't model, call the v1 API directly.
Webhooks
The only incoming webhook is the Stripe one at /api/webhooks/stripe; you don't configure it. Org-event webhooks (member added, invitation accepted, etc.) ship in a later wave.