API keys

Every VerifyAI request authenticates with a vai_… API key in the X-API-Key header. This page covers managing those keys: what a key looks like, how to create and revoke them, and the one rule that trips people up — the full key is shown exactly once.

For how keys are used on a request, see Authentication.

The key object

A key is scoped to a single customer account. The server stores only a SHA-256 hash of the key — never the plaintext — so a key that's lost can only be replaced, never recovered.

json
{
  "id": "key_4f9a2c",
  "name": "Production backend",
  "key_prefix": "vai_live_8x9k…",
  "scope": "full",
  "active": true,
  "customer_id": "cus_forest1",
  "rate_limit_per_minute": 100,
  "rate_limit_per_hour": 6000,
  "last_used_at": "2026-06-01T11:58:02Z",
  "created_at": "2026-05-12T14:30:00Z",
  "expires_at": null
}

Fields

FieldTypeDescription
idstringStable key identifier, prefix key_. Use this to revoke. Not the secret.
namestringHuman label you set at creation (e.g. Production backend, iOS app).
key_prefixstringThe first few characters of the key, for identifying it in lists. Never the full key.
scopestringfull or verify_only. See Scopes.
activebooleanfalse once revoked. Inactive keys return 401 Invalid API key.
customer_idstring?The customer this key acts on behalf of. See Customers.
rate_limit_per_minutenumberPer-key request cap per minute. Defaults to 100.
rate_limit_per_hournumberPer-key request cap per hour. Defaults to 6000.
last_used_atstring?ISO 8601 timestamp of the most recent authenticated request. null if never used.
created_atISO 8601When the key was created.
expires_atstring?Optional expiry. null means the key never expires until revoked.
The full key is shown once, at creation

Create returns the complete vai_… secret a single time. We store only a hash, so we cannot show it again. Copy it into your secret manager immediately. If you lose it, revoke the key and create a new one.

Managing keys in the dashboard

The fastest path is the dashboard, which is the supported way to author keys today:

  1. Open Dashboard → Settings → API keys.
  2. Click Create key, give it a name, and pick a scope.
  3. Copy the full vai_… value from the one-time reveal into your secret manager.
  4. To retire a key, click Revoke next to it. Revocation takes effect immediately — in-flight requests using that key start returning 401.

Sandbox keys are issued automatically when you sign up; their usage is free and never bills your account.

REST contract

The endpoints below expose the same operations programmatically. They are account-scoped — a key can only manage keys belonging to its own customer — and they authenticate exactly like every other VerifyAI request.

Availability

Programmatic key management is rolling out behind the same auth as the rest of the API. If a call below returns 404, manage keys from Dashboard → Settings → API keys in the meantime — the request and response shapes match what ships.

Authentication

HeaderRequiredValue
X-API-KeyYesA vai_… key with full scope. verify_only keys cannot manage keys.

List keys

text
GET /api/v1/api-keys

Returns every key on your account, newest first. The plaintext secret is never included — only id, key_prefix, and metadata.

curl https://verify.switchlabs.dev/api/v1/api-keys \
-H "X-API-Key: vai_your_api_key"
json
{
  "data": [
    {
      "id": "key_4f9a2c",
      "name": "Production backend",
      "key_prefix": "vai_live_8x9k…",
      "scope": "full",
      "active": true,
      "rate_limit_per_minute": 100,
      "rate_limit_per_hour": 6000,
      "last_used_at": "2026-06-01T11:58:02Z",
      "created_at": "2026-05-12T14:30:00Z",
      "expires_at": null
    }
  ]
}

Create a key

text
POST /api/v1/api-keys

Creates a new key on your account. The response is the only place the full secret appears.

Body parameters

ParameterTypeRequiredDescription
namestringYesA label to identify the key later (e.g. iOS app).
scopestringNofull (default) or verify_only. See Scopes.
expires_atstringNoISO 8601 expiry. Omit for a non-expiring key.
curl -X POST https://verify.switchlabs.dev/api/v1/api-keys \
-H "X-API-Key: vai_your_api_key" \
-H "Content-Type: application/json" \
-d '{ "name": "iOS app", "scope": "verify_only" }'
json
{
  "id": "key_7b1d8e",
  "name": "iOS app",
  "key": "vai_live_3q5w8r1t6y2u4i9o0a3s8x9k2m4n7p3q",
  "key_prefix": "vai_live_3q5w…",
  "scope": "verify_only",
  "active": true,
  "rate_limit_per_minute": 100,
  "rate_limit_per_hour": 6000,
  "created_at": "2026-06-01T12:00:00Z",
  "expires_at": null
}

The key field is present only on this create response. Every other endpoint returns key_prefix instead.

Revoke a key

text
DELETE /api/v1/api-keys/:id

Revokes a key by its key_ id. Revocation is immediate and permanent — the key flips to active: false and all future requests with it return 401. There is no un-revoke; create a fresh key instead.

curl -X DELETE https://verify.switchlabs.dev/api/v1/api-keys/key_7b1d8e \
-H "X-API-Key: vai_your_api_key"
json
{ "id": "key_7b1d8e", "active": false, "revoked_at": "2026-06-01T12:05:00Z" }

Scopes

A key's scope limits what it can do. Use the narrowest scope that works:

ScopeCan do
fullEverything — verify, read history, and manage keys/customers/webhooks.
verify_onlySubmit photos to /v1/verify only. Cannot list, manage keys, or delete.
Use verify-only for mobile binaries

A key embedded in a mobile app is semi-public — anyone who unpacks the binary can read it. Scope embedded keys to verify_only so a leaked key can submit photos but cannot enumerate your verifications or touch your other keys. Rotate after each major app release.

Rate limits

Each key carries its own rate_limit_per_minute (default 100) and rate_limit_per_hour (default 6000). When a key exceeds either window, requests return 429 with a Retry-After header indicating how many seconds to wait. Limits are enforced per key, so splitting traffic across keys gives each its own budget. Contact support to raise the defaults on a key.

Errors

StatusReason
400Missing name, or an invalid scope / expires_at value.
401Missing or invalid API key.
403The authenticating key is verify_only and cannot manage keys.
404No key with that id on this account.
429Rate limit — check the Retry-After header.
503Authentication service unavailable. Retry.

What's next

Get in Touch

Questions about pricing, integrations, or custom deployments? We'd love to hear from you.