API Keys
Manage your API keys for programmatic access to the platform.
API keys are user-owned — each key belongs to the user who created it. You only see and manage the keys you created; teammates in the same organization manage their own keys separately.
Key List
View all your API keys with:
| Column | Description |
|---|---|
| Name | Descriptive key name |
| Key Preview | Key identifier (sk-proj-xxxx...xxxx) |
| Type | Inference or Management |
| API Scopes | Enabled API scopes for the key |
| Created | Creation date |
| Expires | Expiration date (if set) |
| Last Used | Most recent usage |
| Usage Count | Number of times the key has been used |
| Status | Active or Expired |
List controls
The key list has controls to help you manage many keys:
- Type filter — show All, Inference, or Management keys.
- Column show / hide — toggle which columns are visible to focus on what you care about.
- Row density — switch between comfortable and compact rows.
- Restriction badges — keys with constraints show badges (models / IPs / spend). Click a badge to reveal the exact allowlist or cap applied to that key, so you can audit restrictions without opening each key.
Creating a Key
- Click Create Key
- Enter a Name (e.g., "Production Backend")
- Choose a Key Type
- Select the key's API Scopes
- Optionally set an Expiration Date — use the quick-select options (30 days, 90 days, 1 year, or no expiry) or pick a custom date
- Optionally expand Advanced settings to apply constraints (see Constraints)
- Click Create
- Copy the key immediately
The full API key is only shown once. Copy and store it securely before closing the dialog.
Key Types and API Scopes
Choose the narrowest type and API scope set that fits the integration.
Inference Keys
Inference keys are for model calls and OpenAI-compatible SDK usage.
| API Scope | Access |
|---|---|
inference:chat | Chat completions |
inference:completions | Text completions |
inference:embeddings | Embeddings |
inference:images | Image generation |
models:list | Model listing |
models:retrieve | Single model metadata |
jobs:stats_own | Read your own async job statistics |
jobs:read_own | Read your own async jobs |
jobs:cancel_own | Cancel your own async jobs |
Async jobs are submitted through inference endpoints by setting the background/async request option. Direct POST /api/v1/jobs and DELETE /api/v1/jobs/{job_id} are not public API-key operations.
Management Keys
Management keys are for public portal automation. They cannot call inference endpoints.
| API Scope | Access |
|---|---|
usage:read_current | Current usage |
usage:read_history | Usage history |
usage:read_summary | Usage summary |
usage:read_report | Usage report export data |
usage:read_breakdown | Per-user tenant usage breakdown (admin/owner only) |
billing:read_current | Current billing (admin/owner only) |
billing:read_cycles | Billing cycles (admin/owner only) |
billing:read_invoices | Billing invoices (admin/owner only) |
billing:read_summary | Billing summary (admin/owner only) |
profile:read | Current profile |
rate_limits:read | Current rate limits |
budgets:read_own | Read your own spend limit |
budgets:update_own | Update or clear your own spend limit |
Public API keys do not create, update, or delete API keys. Use the portal session for key management.
Management Scope Details
| API Scope | What it returns |
|---|---|
usage:read_current | Current-month usage summary with request, token, model, duration, and cost totals. Defaults to the key owner's personal usage. |
usage:read_history | Individual usage events with optional date, model, endpoint, limit, and offset filters. Defaults to the key owner's personal usage. |
usage:read_summary | Aggregated usage summary for a required start_date/end_date range. Defaults to the key owner's personal usage. |
usage:read_report | Time-series usage report for a required date range, grouped hourly, daily, weekly, or monthly. Defaults to the key owner's personal usage. |
usage:read_breakdown | Per-user tenant usage breakdown. This endpoint requires the key owner to be a tenant admin or owner, so the portal only offers this scope to those roles. |
billing:read_current | The current billing cycle, including period dates, total requests/tokens/cost, final amount, invoice metadata, and payment status. Requires the key owner to be a tenant admin or owner. |
billing:read_cycles | A paginated list of billing cycle records, or one specific billing cycle by cycle_id. This is period-level billing data, not invoice line items. Requires the key owner to be a tenant admin or owner. |
billing:read_invoices | A list of generated invoice documents, or one invoice generated from a specific cycle_id. This includes invoice line items, totals, due date, paid date, and payment status. Requires the key owner to be a tenant admin or owner. |
billing:read_summary | Multi-month billing rollup with total cost, requests, tokens, average monthly cost, average cost per token, and monthly breakdown. Requires the key owner to be a tenant admin or owner. |
profile:read | The key owner's current public profile. |
rate_limits:read | The current effective rate limits for the key owner/tenant. |
budgets:read_own | The key owner's personal daily spend limit. |
budgets:update_own | Updates or clears the key owner's personal daily spend limit. |
Constraints
You can lock down how an API key is allowed to be used at creation time, and update those constraints later. The constraint set is exposed under Advanced settings on the create form.
| Constraint | What it does |
|---|---|
| Model allowlist | Restrict an inference key to selected active models. Requests for any other model are rejected with 403 Forbidden. Leaving every model unchecked grants access to every active model the user is otherwise allowed to use. |
| IP allowlist | Restrict requests to one or more source IP addresses (CIDR ranges supported). Requests from any other IP are rejected with 403 Forbidden. Empty list = no IP restriction. |
| Daily spend cap | Cap how much an inference key is allowed to spend per UTC day, in USD. Pre-request check returns 429 Too Many Requests once the cap is hit; the counter resets at the start of the next UTC day. |
Constraints are enforced by the gateway. Setting a field to empty (or sending null via the API) clears that constraint.
Use scope constraints to limit blast radius if a key is leaked: a key scoped to a single model, a single egress IP, and a $10/day cap is much less dangerous than an unscoped one.
Update a constraint via API
curl -X PATCH https://api.bulutistan.ai/api/v1/api-keys/{key_id} \
-H "Authorization: Bearer YOUR_JWT_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"model_allowlist": ["gpt-oss-120b"],
"ip_allowlist": ["203.0.113.10/32"],
"spend_cap_usd": 10.00
}'
Send null for any field to clear it. Scope changes are recorded as api_key_scope_updated audit events. See the Security section of your profile for account security information.
Naming Best Practices
Use descriptive names that include:
- Environment (Production, Staging, Development)
- Application name
- Purpose
Examples:
Production - Main BackendStaging - TestingDevelopment - Local
Key Security
Storage
- Do: Use environment variables
- Do: Use secrets managers (AWS Secrets, Vault)
- Don't: Commit to version control
- Don't: Share in plaintext
Rotation
Rotate keys regularly:
- Create a new key
- Update your applications
- Verify new key works
- Delete the old key
Key Actions
Copying the Key
The full key can only be copied from the success banner shown immediately after creation. Key rows do not have a copy action — the list shows the key preview (sk-proj-xxxx...xxxx) for identifying keys in logs and debugging.
Delete Key
- Click the trash icon
- Confirm deletion
- Key is immediately revoked
Deletion is immediate and irreversible. Any applications using this key will stop working.
Key Limits
| Limit | Value |
|---|---|
| Max keys per user | Set by your organization's tenant quota (platform default: 10; unlimited if configured so) |
| Key name length | 2–255 characters |
| Key expiration | Optional; must be a future date. The "1 year" option is a UI preset, not an enforced maximum |
Expiry Warnings
Keys that expire within the next 7 days display a small warning badge next to the expiry date showing the actual remaining days — for example, 1 day, 3 days, or 7 days. This gives you a clear signal to rotate a key before it stops working.
Keys expiring in more than 7 days show no badge, just the expiry date.
Expired Keys
Expired keys are:
- Shown with "Expired" status
- Unable to make API calls
- Kept in the list until you delete them manually
API Reference
Manage API keys programmatically with a JWT access token from login. Public API keys cannot manage API keys.
List Your API Keys
curl https://api.bulutistan.ai/api/v1/api-keys \
-H "Authorization: Bearer YOUR_JWT_ACCESS_TOKEN"
Response:
{
"data": [
{
"id": "uuid",
"name": "Production Backend",
"key_type": "inference",
"key_preview": "sk-proj-PEyx...b01a",
"scopes": ["inference:chat", "models:list"],
"created_at": "2024-01-15T10:00:00Z",
"expires_at": "2024-07-15T10:00:00Z",
"last_used_at": "2024-01-20T15:30:00Z",
"usage_count": 40,
"is_active": true
}
],
"pagination": {
"page": 1,
"limit": 20,
"total": 1,
"total_pages": 1,
"has_next": false,
"has_prev": false
}
}
Create API Key
curl -X POST https://api.bulutistan.ai/api/v1/api-keys \
-H "Authorization: Bearer YOUR_JWT_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Production Backend",
"key_type": "inference",
"scopes": ["inference:chat", "models:list"],
"expires_at": "2024-12-31T23:59:59Z"
}'
Request Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Descriptive name (2–255 chars) |
key_type | string | No | inference or management; defaults to inference |
scopes | string[] | No | API scope list for the selected key type |
expires_at | datetime | No | ISO 8601 expiration date (must be in the future) |
Response (201 Created):
{
"id": "uuid",
"name": "Production Backend",
"key_type": "inference",
"key": "sk-proj-abc123xyz789...",
"scopes": ["inference:chat", "models:list"],
"created_at": "2024-01-15T10:00:00Z",
"expires_at": "2024-12-31T23:59:59Z"
}
The key field contains the full API key and is only returned once at creation time. Store it securely.
Delete API Key
curl -X DELETE https://api.bulutistan.ai/api/v1/api-keys/{key_id} \
-H "Authorization: Bearer YOUR_JWT_ACCESS_TOKEN"
Response: 204 No Content
Python Example
import requests
from datetime import datetime, timedelta
jwt_token = "YOUR_JWT_ACCESS_TOKEN"
base_url = "https://api.bulutistan.ai"
headers = {"Authorization": f"Bearer {jwt_token}"}
# List keys
response = requests.get(f"{base_url}/api/v1/api-keys", headers=headers)
result = response.json()
keys = result["data"]
print(f"You have {result['pagination']['total']} API keys")
# Create key with 6-month expiration
expires = (datetime.utcnow() + timedelta(days=180)).isoformat() + "Z"
response = requests.post(
f"{base_url}/api/v1/api-keys",
headers={**headers, "Content-Type": "application/json"},
json={
"name": "New Production Key",
"key_type": "inference",
"scopes": ["inference:chat", "models:list"],
"expires_at": expires,
}
)
new_key = response.json()
print(f"New key created: {new_key['name']}")
print(f"Full key (save this!): {new_key['key']}")
# Delete key
key_id = keys[0]["id"]
requests.delete(f"{base_url}/api/v1/api-keys/{key_id}", headers=headers)
API Key Access Scope
Inference keys work with /v1/* OpenAI-compatible endpoints and the matching /api/v1/* direct HTTP endpoints. Management keys work only with the public management endpoints listed above. Organization, member, tenant-admin, admin portal, and API-key management endpoints require a JWT session.
Troubleshooting
Key Not Working
- Check if key is expired
- Verify key is copied correctly (no extra spaces)
- Ensure
Bearerprefix in Authorization header - Check rate limits
Can't Create Keys
- You may have reached the maximum key limit
- Your account role may not allow key creation
- Contact your organization admin