API Key Authentication
Last updated: Phase 8.5
Overview
API keys authenticate requests to the Integration API (/api/v1/integration/*). Each key is bound to exactly one tenant. Keys are hashed with HMAC-SHA256 — the raw key is returned only once at creation.
Creating an API Key
Endpoint: POST /api/v1/tenant/api-keysAuth: Bearer token with tenant ability
json
{
"name": "Production Server"
}Response (201):
json
{
"data": {
"id": "key-uuid",
"name": "Production Server",
"key": "vx_a1b2c3d4e5f6...",
"status": "active",
"created_at": "2026-03-30T10:00:00.000000Z"
},
"meta": {
"request_id": "uuid",
"api_version": "1"
}
}Important: Save the key value immediately. It will never be shown again.
Using an API Key
Include the key in the X-API-Key header:
POST /api/v1/integration/licenses/VX-ACME-abc123/validate
X-API-Key: vx_a1b2c3d4e5f6...
Content-Type: application/jsonHow Resolution Works
- Backend extracts
X-API-Keyheader - Computes HMAC-SHA256 hash using the application key
- Looks up the hash in the
api_keystable (status must beactive) - Resolves the associated tenant
- Validates tenant is active (not suspended or closed)
- Switches database connection to tenant's isolated DB
- Updates
last_used_attimestamp
Revoking an API Key
Endpoint: DELETE /api/v1/tenant/api-keys/{id}Auth: Bearer token with tenant ability
Response (200):
json
{
"data": { "deleted": true, "id": "key-uuid" },
"meta": { "request_id": "uuid", "api_version": "1" }
}Revoked keys immediately stop working. Revocation is audit-logged.
Error Codes
| Code | HTTP | Description |
|---|---|---|
AUTH.INVALID_API_KEY | 401 | Missing, invalid, or revoked key |
TENANT.STATUS.SUSPENDED | 403 | Tenant associated with the key is suspended |
Security Notes
- Keys use
vx_prefix for easy identification - Raw keys are 64 hex characters (32 bytes of entropy)
- Keys are stored as HMAC-SHA256 hashes — even database access doesn't reveal raw keys
- Each key is scoped to one tenant — no cross-tenant access
- Rotate keys by creating a new key and revoking the old one