Billing
Plan, credits, top-ups, Stripe checkout.
4 operations, each listing how it authenticates. This is the session-authenticated API the web app uses; if you have an API key, use the v1 API instead (see the overview). Responses use the standard envelope; the overview also covers shapes and error codes.
/billing/checkoutStart a Stripe checkout
Returns a Stripe checkout URL the caller redirects to. Owner-only.
Auth: your signed-in session (cookie __Secure-next-auth.session-token). API keys are not accepted.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
plan | "pro" | "team" | "enterprise" | yes | |
interval | "monthly" | "annual" | no | |
successUrl | string (uri) | no | |
cancelUrl | string (uri) | no |
Responses
200- Checkout URL.400- Validation failed. `error.code = VALIDATION_ERROR`. `error.details.errors` lists per-field issues from zod.401- No valid credentials for this operation's `security` requirement. `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/billing/checkout \
-H 'Cookie: __Secure-next-auth.session-token=<session cookie>' \
-H 'Content-Type: application/json' \
-d '{ ... }'/billing/creditsGet the active org's credit balance
Auth: your signed-in session (cookie __Secure-next-auth.session-token). API keys are not accepted.
Responses
200- Credit balance.400- Validation failed. `error.code = VALIDATION_ERROR`. `error.details.errors` lists per-field issues from zod.401- No valid credentials for this operation's `security` requirement. `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/billing/credits \
-H 'Cookie: __Secure-next-auth.session-token=<session cookie>'/billing/portalOpen the Stripe customer portal
Auth: your signed-in session (cookie __Secure-next-auth.session-token). API keys are not accepted.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
returnUrl | string (uri) | no |
Responses
200- Portal URL.400- Validation failed. `error.code = VALIDATION_ERROR`. `error.details.errors` lists per-field issues from zod.401- No valid credentials for this operation's `security` requirement. `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/billing/portal \
-H 'Cookie: __Secure-next-auth.session-token=<session cookie>' \
-H 'Content-Type: application/json' \
-d '{ ... }'/billing/topupBuy a credit top-up
Either pick a fixed `pack` (small/medium/large) or pass a custom credit amount. Top-up credits never expire.
Auth: your signed-in session (cookie __Secure-next-auth.session-token). API keys are not accepted.
Request body
Field Type Required Description pack"small" | "medium" | "large"yes Field Type Required Description creditsintegeryes
Responses
200- Stripe checkout URL.400- Validation failed. `error.code = VALIDATION_ERROR`. `error.details.errors` lists per-field issues from zod.401- No valid credentials for this operation's `security` requirement. `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/billing/topup \
-H 'Cookie: __Secure-next-auth.session-token=<session cookie>' \
-H 'Content-Type: application/json' \
-d '{ ... }'