Integrations
Summary
Create-key body, headers, common errors — the cheat sheet.
Create a key
curl -X POST https://auth.febasi.com.br/api/v1/client-keys \
-H "Authorization: Bearer $ADMIN_JWT" \
-H "Content-Type: application/json" \
-d '{
"name": "Acme signup proxy",
"scopes": ["users:create"],
"tenantAccessLevel": "specific",
"allowedTenantIds": ["01HX0..."],
"allowedOrigins": null,
"allowedIps": ["10.0.0.0/16"]
}'Response includes the full key once — store it immediately:
{
"success": true,
"data": {
"id": "01HZ8...",
"keyPrefix": "ck_abc1234",
"fullKey": "ck_abc1234_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
...
}
}Use a key
GET /api/v1/users
X-API-Key: ck_abc1234_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
X-Tenant-Code: acmeX-API-Keycarries the secret.Authorization: ApiKey <key>also works.X-Tenant-Codeis mandatory for tenant-scoped operations. Without it, dual-auth routes reject withMISSING_TENANT_CONTEXT.
Body fields at a glance
| Field | Required | Notes |
|---|---|---|
name | yes | Human-readable identifier surfaced in usage logs. |
scopes | yes | At least one. Use the narrowest scope possible. |
tenantAccessLevel | yes | none / specific (with allowedTenantIds) / global (requires admin:*). |
allowedTenantIds | when specific | Tenant UUIDs the key can act against. |
allowedOrigins | no | Per-key CORS allowlist. null inherits from the tenant. |
allowedIps | no | Per-key source-IP allowlist (CIDR-capable). null inherits from the tenant. |
expiresAt | no | ISO 8601 timestamp. Strongly recommended for broader scopes. |
Common errors
| Code | Status | When |
|---|---|---|
MISSING_API_KEY | 401 | Dual-auth route hit without X-API-Key (and no Bearer JWT either). |
INVALID_API_KEY | 401 | Key unknown, revoked, or expired. |
MISSING_TENANT_CONTEXT | 401 | Client Key call without X-Tenant-Code, or the code does not resolve. |
INSUFFICIENT_SCOPE | 403 | Key lacks the scope the route requires. |
TENANT_ACCESS_DENIED | 403 | Key tried to act against a tenant outside its allowedTenantIds / tenantAccessLevel. |
Operational checklist
- Store the full key in a secret manager the moment it's returned. The API never reproduces it.
- Rotate on schedule and on suspected leak — revoke + create a new one, never reuse keys.
- Audit via
GET /api/v1/client-keys/:id/logsfor the last N requests + IPs. - Pin
allowedIpswhen the egress is known. PinallowedOriginsif the key is exposed to browsers.
See Client Keys for the full lifecycle and scope catalog.