Public gateway only. DownloadOpenAPI,Postman, orInsomnia. Auth is Bearer YOUR_API_KEY or, on website routes, thekv_session cookie.
GET /healthLiveness
GET /v1Gateway index
POST /v1/keysLegacy issue key by email
One-shot email key without a password account. Prefer `POST /v1/auth/register`. IP limit 5/hour. Second issue for the same email is 409. Rotate with `POST /v1/auth/rotate-key`.
{
"email": "you@example.com"
}GET /v1/auth/keysList named Kasva keys
Mask only. Never returns the full `kv_…` secret.
POST /v1/auth/keysCreate a named Kasva key
`name` required, 1–64 characters. Full `api_key` once. Duplicate active name → 409. Max 10 active keys → 400.
{
"name": "cursor"
}GET /v1/auth/keys/{id}One named key (mask only)
DELETE /v1/auth/keys/{id}Revoke a named key
Last remaining key → 400. Canonical rotate remains `POST /v1/auth/rotate-key`.
POST /v1/auth/registerCreate account and gateway key
{
"email": "you@example.com",
"password": "at-least-8-chars",
"name": "Optional",
"accepted_terms": true
}POST /v1/auth/loginSign in
{
"email": "you@example.com",
"password": "at-least-8-chars"
}POST /v1/auth/logoutSign out
POST /v1/auth/logout-allRevoke other sessions
Keeps the current cookie.
GET /v1/auth/sessionsList active sessions
GET /v1/auth/meCurrent user
POST /v1/auth/forgot-passwordRequest password reset
Valid-shaped emails always get the same generic 200.
{
"email": "you@example.com"
}POST /v1/auth/reset-passwordComplete password reset
{
"token": "…",
"password": "new-password-8+"
}POST /v1/auth/verify-email/requestSend email verification link
API stays usable unverified. No-op when mail is unset.
POST /v1/auth/verify-emailConfirm email
{
"token": "…"
}POST /v1/auth/rotate-keyRotate gateway key
Session cookie or Bearer. Returns a new `api_key` once; the previous key stops immediately. Stored BYOK moves to the new key. Limit 5/hour.
POST /v1/auth/claim-accountClaim a legacy key into an account
Same `kv_…` key is kept. `accepted_terms` required.
{
"email": "you@example.com",
"api_key": "kv_…",
"password": "at-least-8-chars",
"accepted_terms": true
}GET /v1/auth/oauth/githubStart GitHub OAuth
POST /v1/auth/oauth/githubStart GitHub OAuth
GET /v1/auth/oauth/googleStart Google OAuth
POST /v1/auth/oauth/googleStart Google OAuth
GET /v1/auth/oauth/{provider}/callbackOAuth return
GET /v1/byok/keysWhich provider keys are stored
Never returns secrets or last-4.
POST /v1/byok/keysUpsert or clear provider keys
Omit a field to leave it unchanged. Send `""` to delete that provider. `{ "enabled": { "openai": false } }` disables a stored key without resending it. Per-request provider headers are not accepted.
{
"groq": "gsk_...",
"openai": "sk-..."
}GET /v1/modelsModel list
OpenAI-compatible list. BYOK ids appear only for providers you have registered and not disabled. Hosted ids are `kasva/<catalog-id>`.
POST /v1/chat/completionsChat (OpenAI-compatible)
`stream: true` pipes OpenAI-compatible SSE. Response includes a `kasva` routing object. Image and video model ids are rejected here — use `POST /v1/images` or `POST /v1/videos`.
{
"model": "kasva/auto",
"messages": [
{
"role": "user",
"content": "Hello"
}
],
"temperature": 0.7,
"max_tokens": 1024,
"stream": false
}POST /v1/messagesChat (Anthropic Messages)
Anthropic-shaped request and response. Anthropic SDKs use base URL `https://kasva.dev`. The path is `/v1/messages`. Auth is Bearer and/or `x-api-key` with the Kasva `kv_…` key (not a provider `sk-ant-…` key). Bearer wins if both are sent. `anthropic-version` is optional. Required: `model`, `messages`, `max_tokens`.
{
"model": "kasva/auto",
"max_tokens": 1024,
"messages": [
{
"role": "user",
"content": "Hello"
}
]
}POST /v1/imagesGenerate or edit images
Hosted `kasva/image` and `kasva/image-pro` (operator, credits debit after success) plus BYOK generate. Prompt-only hosted generate (`n=1`). BYOK may add `input_references` to edit. Image models are not accepted on chat.
{
"model": "kasva/image",
"prompt": "A product photo of a ceramic mug"
}POST /v1/images/generationsAlias of POST /v1/images
{
"model": "byok/fal/flux-schnell",
"prompt": "A ceramic mug"
}POST /v1/videosCreate a video job
Hosted `kasva/video`. Returns `queued` with id prefix `vid_`. Poll `GET /v1/videos/{id}` then fetch bytes from `GET /v1/videos/{id}/content` when `completed`. Rate-limit applies to create only. Optional `seconds` is an integer 4–15 (default 5).
{
"model": "kasva/video",
"prompt": "A ceramic mug spinning on a table",
"seconds": 5
}GET /v1/videos/{id}Poll a video job
Owner-only. Unknown or other-user ids are 404. Terminal jobs return stored status with no upstream poll. Queued and in-progress jobs poll once per GET.
GET /v1/videos/{id}/contentDownload completed video bytes
MP4 bytes for the owner when status is `completed`. Otherwise 404. No JSON body.
GET /v1/usagePer-key usage stats
GET /v1/creditsCredit balance
GET /v1/credits/historyCredit pack grant history
POST /v1/credits/checkoutCredits pack checkout URL
POST /v1/billing/proPro $9/month checkout URL
GET /v1/mcp/toolsTool catalog
Catalog only; no remote execution.