SwitchLock Docs
Companies

API Key Management

API keys authenticate your server to the SwitchLock API. They are long-lived secrets — treat them like passwords.

Keys are server secrets

Every API key is a bearer credential. Anyone who holds a valid key can read and write data for your company. The rules below are not optional — a leaked key is a full account compromise.

Never do this
  • Include a key in client-side JavaScript (browser, React Native)
  • Commit a key to version control, even in a private repo
  • Log a key in application logs or monitoring services
  • Share a single key across staging and production
Always do this
  • Store keys in environment variables or a secrets manager
  • Issue one key per environment (staging, production)
  • Revoke and reissue when a team member leaves
  • Give each key a descriptive name so you know what to revoke

Key format

All keys start with zl_sk_ followed by 32 random alphanumeric characters — 38 characters total. The prefix encodes nothing about environment; use the key's name field and your own naming convention to distinguish staging from production.

Key anatomy
zl_sk_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6
zl_sk_fixed prefix — identifies SwitchLock server keys
32 charscryptographically random — stored as SHA-256 hash

The first 8 characters of the random portion are stored as key_prefix for display in the dashboard and list API. This lets you identify a key without exposing the full secret.

How keys are stored — SHA-256 hashing

The raw key is never stored. At the moment you generate a key, SwitchLock computes a SHA-256 hash of the raw value, stores only that hash, and returns the raw key in the response body exactly once. On each subsequent API call, the incoming key is hashed and compared — the raw value is never written to disk.

If you lose a key, you cannot recover it. Revoke it and generate a replacement. There is no "show key" endpoint.

Generate a key

Generating a key requires an authenticated admin session (JWT Bearer token). Log in as a company admin first, then POST to the key endpoint. The raw key is in the response — copy it before moving on.

curl -X POST "https://api.switchlock.co.zw/v1/auth/login" \
  -H "Content-Type: application/json" \
  -d '{
    "email": "admin@acme.co.zw",
    "password": "SuperSecret123!"
  }'
Response
{
  "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "expiresIn": 3600
}
curl -X POST "https://api.switchlock.co.zw/v1/core/companies/api-keys" \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." \
  -H "x-company-id: cmp_01HXYZ..." \
  -H "Content-Type: application/json" \
  -d '{ "name": "Production Server Key" }'
Response — 201 Created
{
  "id": "key_01HXYZ...",
  "name": "Production Server Key",
  "key": "zl_sk_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6",
  "key_prefix": "a1b2c3d4",
  "is_active": true,
  "created_at": "2026-06-23T09:01:00.000Z"
}

The key field is only present in this response. Copy it to your environment variables now — it will not appear again.

FieldRequiredDescription
nameYesHuman-readable label. Use something that tells you where it's deployed, e.g. Production API Server or Staging CI.

Using a key in requests

Pass the raw key in the x-api-key header alongside x-company-id on every authenticated call.

curl "https://api.switchlock.co.zw/v1/core/companies/me" \
  -H "x-api-key: zl_sk_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6" \
  -H "x-company-id: cmp_01HXYZ..."

List API key metadata

Returns the metadata records for your company's API integrations, ordered newest first. This is used to populate your dashboard so you know which IDs to pass to the revoke endpoint. The raw key is never returned here.

curl "https://api.switchlock.co.zw/v1/core/companies/api-keys" \
  -H "x-api-key: zl_sk_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6" \
  -H "x-company-id: cmp_01HXYZ..."
Response — 200 OK
[
  {
    "id": "key_01HXYZ...",
    "name": "Production Server Key",
    "key_prefix": "a1b2c3d4",
    "is_active": true,
    "created_at": "2026-06-23T09:01:00.000Z"
  },
  {
    "id": "key_01HABC...",
    "name": "Staging CI Key",
    "key_prefix": "b5c6d7e8",
    "is_active": true,
    "created_at": "2026-06-20T08:30:00.000Z"
  }
]

The key_prefix shows the first 8 characters of the raw key — enough to identify which key is which without revealing the secret.

Revoke a key

Revoking sets is_active = false on the key record. Any subsequent request using that key returns 401 Unauthorized immediately. The key record is retained for audit purposes — it is not deleted.

curl -X POST "https://api.switchlock.co.zw/v1/core/companies/api-keys/key_01HXYZ.../revoke" \
  -H "x-api-key: zl_sk_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6" \
  -H "x-company-id: cmp_01HXYZ..."
Response — 200 OK
{ "success": true }

Revocation is scoped to your company. You can only revoke keys that belong to the company in the x-company-id header — this prevents cross-company key tampering even if you somehow obtain another company's key ID.

Best practices

One key per environment

Staging and production should use entirely separate keys — ideally separate company registrations. This limits blast radius if a key leaks.

Rotate after team member departures

When someone with access to your production key leaves, revoke it and generate a replacement before their access is removed from other systems.

Treat a leaked key as fully compromised

If a key appears in a public repository, a log file, or a Slack message — assume it has been read. Revoke it immediately, then audit recent API activity for unexpected calls.

Descriptive names save time during incidents

Name keys so you know exactly which system uses them: "Production API Server", "Staging CI Pipeline", "Webhook Relay Lambda". When something goes wrong at 2am, you want to know what you're revoking.

Quick reference

ActionMethodPathAuth
Generate keyPOST/v1/core/companies/api-keysJWT Bearer
List keysGET/v1/core/companies/api-keysx-api-key + x-company-id
Revoke keyPOST/v1/core/companies/api-keys/:id/revokex-api-key + x-company-id

Next steps