API keys allow your applications and SDKs to authenticate with Togul without using user credentials. Each key is scoped to a specific project environment and carries one of three permission scopes.
Scopes
| Scope | Use case |
|---|
server | Backend flag evaluation via POST /api/v1/evaluate |
sdk | Client-side flag evaluation and SSE stream subscription |
stream | SSE stream subscription only (GET /api/v1/stream) |
Choose the least-privilege scope for each use case. A stream-scoped key cannot call the evaluation endpoint.
Using an API key
Pass the key in the X-API-Key header:
curl -X POST http://localhost:8080/api/v1/evaluate \
-H "X-API-Key: tgl_srv_abc123xyz..." \
-H "Content-Type: application/json" \
-d '{"flag_key": "new-dashboard", "environment_key": "production"}'
Creating an API key
Send POST /api/v1/projects/{project_id}/api-keys. Requires the api_keys.write permission.
curl -X POST http://localhost:8080/api/v1/projects/$PROJECT_ID/api-keys \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"environment_id": "env-uuid-here",
"name": "Production server key",
"scope": "server",
"expires_at": null
}'
Response:
{
"api_key": {
"id": "key-uuid-here",
"project_id": "proj-uuid-here",
"environment_id": "env-uuid-here",
"name": "Production server key",
"scope": "server",
"key_prefix": "tgl_srv_",
"last_used_at": null,
"last_used_ip": null,
"expires_at": null,
"revoked_at": null,
"created_at": "2024-03-15T10:03:00Z",
"updated_at": "2024-03-15T10:03:00Z"
},
"secret": "tgl_srv_abc123xyz..."
}
The secret value is returned only once at creation time. Store it securely immediately — you cannot retrieve it again. If lost, rotate the key to generate a new secret.
Request fields
| Field | Type | Required | Description |
|---|
environment_id | string (UUID) | Yes | The environment this key is scoped to |
name | string | Yes | A human-readable label for the key |
scope | string | Yes | One of server, sdk, or stream |
expires_at | string (ISO 8601) | No | Optional expiry date-time |
APIKey schema
| Field | Type | Description |
|---|
id | string (UUID) | Unique key identifier |
project_id | string (UUID) | The project this key belongs to |
environment_id | string (UUID) | The environment this key is scoped to |
name | string | Human-readable label |
scope | string | server, sdk, or stream |
key_prefix | string | Visible prefix (e.g. tgl_srv_) — not the full secret |
last_used_at | string | Timestamp of the most recent authenticated request |
last_used_ip | string | IP address of the most recent authenticated request |
expires_at | string | Expiry date-time, or null if the key does not expire |
revoked_at | string | Date-time the key was revoked, or null |
created_at | string | Creation timestamp |
updated_at | string | Last-updated timestamp |
Listing API keys
Retrieve all keys for a project with GET /api/v1/projects/{project_id}/api-keys. Requires the api_keys.read permission.
curl http://localhost:8080/api/v1/projects/$PROJECT_ID/api-keys \
-H "Authorization: Bearer $TOKEN"
The list response returns metadata only. Plaintext secrets are never included after the initial creation response.
Rotating an API key
Rotation generates a new secret and immediately invalidates the previous one. Use this to replace a compromised or expired key without deleting and recreating it. Requires the api_keys.write permission.
curl -X POST http://localhost:8080/api/v1/projects/$PROJECT_ID/api-keys/$KEY_ID/rotate \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"expires_at": null}'
Response:
{
"api_key": { ... },
"secret": "tgl_srv_newSecret456..."
}
Update your application configuration with the new secret before discarding the old one.
Revoking an API key
Delete a key permanently with DELETE /api/v1/projects/{project_id}/api-keys/{id}. Requires the api_keys.delete permission.
curl -X DELETE http://localhost:8080/api/v1/projects/$PROJECT_ID/api-keys/$KEY_ID \
-H "Authorization: Bearer $TOKEN"
Revoked keys are rejected immediately on the next request.
Required permissions
| Action | Permission |
|---|
| List API keys | api_keys.read |
| Create or rotate an API key | api_keys.write |
| Revoke an API key | api_keys.delete |
Best practices
- Rotate keys regularly. Schedule rotation before
expires_at to avoid outages.
- Use the least-privilege scope. A backend service that only evaluates flags needs
server, not sdk or stream.
- Monitor
last_used_at. Keys that have not been used recently may be orphaned and can be safely revoked.
- Store secrets in a secrets manager. Never commit API keys to source control or include them in client-side bundles.