API key management
This recipe shows how to manage API keys for your tenant. API keys are long-lived credentials suitable for server-to-server integrations where OAuth 2.0 is impractical (e.g., legacy systems, embedded devices, batch jobs).
Endpoints
GET /v1/tenants/{id}/api-keys # List all API keys (metadata only)
POST /v1/tenants/{id}/api-keys # Create a new API key
DELETE /v1/tenants/{id}/api-keys/{keyId} # Revoke an API key
POST /v1/tenants/{id}/api-keys/{keyId}/rotate # Rotate an API key
API key secrets are returned only at creation or rotation time. They are never retrievable after the initial response.
Prerequisites
- A valid
tenantIdand bearer JWT. - The user must have the
tenant_adminrole.
Create an API key
curl -X POST https://api.falconveritas.com/v1/tenants/$FVI_TENANT_ID/api-keys \
-H "Authorization: Bearer $FVI_JWT" \
-H "X-Tenant-Id: $FVI_TENANT_ID" \
-H "Content-Type: application/json" \
-d '{
"name": "Production ETL job",
"description": "API key for the nightly reconciliation ETL job",
"scopes": ["read:reconciliations", "write:exceptions"],
"expires_at": "2027-08-22T00:00:00Z",
"ip_allowlist": ["203.0.113.0/24"],
"idempotency_key": "apikey-fvi-$RANDOM"
}'
Response
{
"id": "key-001",
"name": "Production ETL job",
"key_id": "pk_live_abc123def456",
"key_secret": "sk_live_xyz789ghi012jkl345mno678pqr901stu234vwx567",
"scopes": ["read:reconciliations", "write:exceptions"],
"expires_at": "2027-08-22T00:00:00Z",
"ip_allowlist": ["203.0.113.0/24"],
"created_at": "2026-08-22T18:00:00Z",
"created_by": "user:admin",
"warning": "Store the key_secret securely. It will not be shown again."
}
Use the API key
curl -X GET "https://api.falconveritas.com/v1/reconciliations" \
-H "Authorization: Bearer pk_live_abc123def456.sk_live_xyz789ghi012jkl345mno678pqr901stu234vwx567" \
-H "X-Tenant-Id: $FVI_TENANT_ID"
Rotate an API key
Rotation creates a new key while keeping the old key valid for a grace period. This enables zero-downtime rotation for production integrations:
curl -X POST https://api.falconveritas.com/v1/tenants/$FVI_TENANT_ID/api-keys/key-001/rotate \
-H "Authorization: Bearer $FVI_JWT" \
-H "X-Tenant-Id: $FVI_TENANT_ID" \
-H "Content-Type: application/json" \
-d '{
"grace_period_seconds": 86400,
"idempotency_key": "apikey-rotate-fvi-$RANDOM"
}'
The response returns the new key, while the old key remains valid for 24 hours. After the grace period expires, the old key is automatically revoked.
Revoke an API key
curl -X DELETE "https://api.falconveritas.com/v1/tenants/$FVI_TENANT_ID/api-keys/key-001" \
-H "Authorization: Bearer $FVI_JWT" \
-H "X-Tenant-Id: $FVI_TENANT_ID" \
-H "Content-Type: application/json" \
-d '{
"reason": "Compromised in vendor breach",
"idempotency_key": "apikey-revoke-fvi-$RANDOM"
}'
List API keys
curl -X GET "https://api.falconveritas.com/v1/tenants/$FVI_TENANT_ID/api-keys" \
-H "Authorization: Bearer $FVI_JWT" \
-H "X-Tenant-Id: $FVI_TENANT_ID"
Returns metadata only — never the key secret. The response includes usage statistics (last used at, request count) for each key.
Best practices
- Use OAuth where possible. Prefer OAuth 2.0 with PKCE over API keys for integrations that can support redirects.
- Scope keys narrowly. Each API key should have the minimum scopes required for its purpose.
- Set IP allowlists. Restrict API keys to the IP ranges of the systems that use them.
- Set expiry. Always set an expiry date to limit the blast radius of a leaked key.
- Rotate regularly. Rotate keys at least every 90 days, or immediately on staff changes.
- Audit usage. Review API key usage logs monthly for unexpected patterns.
Use cases
- Server-to-server integrations — authenticate backend services that cannot perform OAuth flows.
- Legacy system integration — bring older systems that only support API key auth into FVI.
- Embedded devices — authenticate IoT sensors or edge devices that pull reconciliation status.
- Batch jobs — long-lived credentials for nightly ETL or reporting jobs.
Code samples
TypeScript
import { FVI } from '@falconveritas/sdk';
const fvi = new FVI({
baseUrl: 'https://api.falconveritas.com',
bearer: process.env.FVI_JWT!,
tenantId: process.env.FVI_TENANT_ID!,
});
// Create API key
const apiKey = await fvi.tenants.createApiKey(process.env.FVI_TENANT_ID!, {
name: 'Production ETL job',
scopes: ['read:reconciliations', 'write:exceptions'],
expiresAt: '2027-08-22T00:00:00Z',
idempotencyKey: `apikey-fvi-${Date.now()}`,
});
console.log('API Key ID:', apiKey.key_id);
console.log('API Key Secret (store securely!):', apiKey.key_secret);
// Rotate after 90 days
const rotated = await fvi.tenants.rotateApiKey(process.env.FVI_TENANT_ID!, apiKey.id, {
gracePeriodSeconds: 86400,
idempotencyKey: `apikey-rotate-fvi-${Date.now()}`,
});
console.log('New API Key Secret (store securely!):', rotated.key_secret);
Python
from falconveritas import FVI
client = FVI(
bearer=os.environ["FVI_JWT"],
tenant_id=os.environ["FVI_TENANT_ID"],
)
api_key = client.tenants.create_api_key(
os.environ["FVI_TENANT_ID"],
name="Production ETL job",
scopes=["read:reconciliations", "write:exceptions"],
expires_at="2027-08-22T00:00:00Z",
idempotency_key=f"apikey-fvi-{int(time.time())}",
)
print("API Key ID:", api_key.key_id)
print("API Key Secret (store securely!):", api_key.key_secret)
rotated = client.tenants.rotate_api_key(
os.environ["FVI_TENANT_ID"],
api_key.id,
grace_period_seconds=86400,
idempotency_key=f"apikey-rotate-fvi-{int(time.time())}",
)
print("New API Key Secret (store securely!):", rotated.key_secret)
Related articles
Last updated: 2026-08-22 · Page owner: Documentation · Source: src/lib/api/api-keys.ts.