API Keys

API keys are how you authenticate to the Serveka API. Each key is scoped to a specific workspace and carries permissions based on the role of the user who created it.

Key format

All Serveka API keys start with srvk_ followed by a random string.

Example key: srvk_ABCdefGHIjklMNOpqrSTUvwxYZ0123456789abcd

Keys are workspace-scoped. One key belongs to exactly one workspace. When you make a request, Serveka resolves the workspace automatically from the key — you never pass a workspace_id in request bodies for resource operations.

Sending your key

Pass the key in the X-API-Key request header on every request:

bash
curl https://api.serveka.com/api/v1/bots \
  -H "X-API-Key: srvk_your_key_here"
javascript
fetch('https://api.serveka.com/api/v1/bots', {
  headers: {
    'X-API-Key': 'srvk_your_key_here',
    'Content-Type': 'application/json'
  }
})
python
import requests
 
headers = {
    "X-API-Key": "srvk_your_key_here",
    "Content-Type": "application/json"
}
response = requests.get("https://api.serveka.com/api/v1/bots", headers=headers)

Creating a key

Create a key via POST /api/v1/api-keys:

bash
curl -X POST https://api.serveka.com/api/v1/api-keys \
  -H "X-API-Key: srvk_your_existing_key" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Production Bot Key",
    "expires_at": "2027-01-01T00:00:00Z"
  }'

Response 201:

json
{
  "id": 42,
  "name": "Production Bot Key",
  "prefix": "srvk_a1b2",
  "workspace_id": "aaaaaaaa-0000-0000-0000-000000000001",
  "created_at": "2026-05-12T10:00:00Z",
  "last_used_at": null,
  "expires_at": "2027-01-01T00:00:00Z",
  "key": "srvk_ABCdefGHIjklMNOpqrSTUvwxYZ0123456789abcd"
}

Important: The key field is returned only at creation time and never again. Copy it immediately and store it in a secrets manager (AWS Secrets Manager, Vault, environment variable, etc.). Subsequent GET requests return only metadata — the prefix for identification but not the full secret.

Listing keys

List keys (metadata only, no secrets):

bash
curl https://api.serveka.com/api/v1/api-keys \
  -H "X-API-Key: srvk_your_key_here"

Response 200:

json
[
  {
    "id": 42,
    "name": "Production Bot Key",
    "prefix": "srvk_a1b2",
    "workspace_id": "aaaaaaaa-0000-0000-0000-000000000001",
    "created_at": "2026-05-12T10:00:00Z",
    "last_used_at": "2026-05-12T11:30:00Z",
    "expires_at": null
  }
]

Getting a single key

Get key metadata by ID:

bash
curl https://api.serveka.com/api/v1/api-keys/42 \
  -H "X-API-Key: srvk_your_key_here"

Response 200:

json
{
  "id": 42,
  "name": "Production Bot Key",
  "prefix": "srvk_a1b2",
  "workspace_id": "aaaaaaaa-0000-0000-0000-000000000001",
  "created_at": "2026-05-12T10:00:00Z",
  "last_used_at": "2026-05-12T11:30:00Z",
  "expires_at": null
}

Updating a key

Update key name or expiry via PATCH /api/v1/api-keys/{key_id}:

bash
curl -X PATCH https://api.serveka.com/api/v1/api-keys/42 \
  -H "X-API-Key: srvk_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Staging Key",
    "expires_at": "2028-01-01T00:00:00Z"
  }'

Response 200:

json
{
  "id": 42,
  "name": "Staging Key",
  "prefix": "srvk_a1b2",
  "workspace_id": "aaaaaaaa-0000-0000-0000-000000000001",
  "created_at": "2026-05-12T10:00:00Z",
  "last_used_at": "2026-05-12T11:30:00Z",
  "expires_at": "2028-01-01T00:00:00Z"
}

Only name and expires_at can be updated. The secret itself cannot be changed — revoke and recreate if you need a new secret.

Revoking a key

Revoke a key permanently via DELETE /api/v1/api-keys/{key_id}:

bash
curl -X DELETE https://api.serveka.com/api/v1/api-keys/42 \
  -H "X-API-Key: srvk_your_key_here"

Response 204: No content

Revocation is immediate — any in-flight requests using the revoked key will start returning 401. This action cannot be undone.

Key expiry

Keys without an expires_at never expire. If you set an expiry, the key becomes invalid at that UTC datetime and starts returning 401 Unauthorized.

To rotate a key: create a new one, update your services to use it, then revoke the old one.

Permission tiers

Operations are gated based on the caller's role in the workspace:

RoleCan do
memberRead all resources (GET endpoints)
adminRead + create/update/delete bots, meetings, API keys
ownerFull access including member management, webhooks, workspace settings

The key itself inherits the role of the user who created it. A key created by an admin has admin-level access.

Authentication errors

StatusWhen it happens
401 UnauthorizedMissing X-API-Key header
401 UnauthorizedKey not found in the database
401 UnauthorizedKey has been revoked
401 UnauthorizedKey has passed its expires_at timestamp
403 ForbiddenKey is not bound to a workspace (for workspace-scoped operations)
403 ForbiddenCaller's role is insufficient for the operation

Example error body:

json
{ "detail": "Invalid or expired API key." }

Security best practices

  • Never expose keys in client-side code. API keys give full workspace access — they belong server-side only.
  • Use one key per environment. Separate keys for development, staging, and production make it easy to revoke one without affecting the others.
  • Set expiry dates for long-lived keys. Rotating keys reduces blast radius if one is ever leaked.
  • Check last_used_at regularly. If a key you expected to be inactive has recent activity, investigate immediately.
  • Revoke compromised keys instantly. Go to your workspace dashboard, find the key by its prefix, and delete it.
Updated May 2026Edit on GitHub