Skip to main content

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:

ColumnDescription
NameDescriptive key name
Key PreviewKey identifier (sk-proj-xxxx...xxxx)
TypeInference or Management
API ScopesEnabled API scopes for the key
CreatedCreation date
ExpiresExpiration date (if set)
Last UsedMost recent usage
Usage CountNumber of times the key has been used
StatusActive 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

  1. Click Create Key
  2. Enter a Name (e.g., "Production Backend")
  3. Choose a Key Type
  4. Select the key's API Scopes
  5. Optionally set an Expiration Date — use the quick-select options (30 days, 90 days, 1 year, or no expiry) or pick a custom date
  6. Optionally expand Advanced settings to apply constraints (see Constraints)
  7. Click Create
  8. Copy the key immediately
warning

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 ScopeAccess
inference:chatChat completions
inference:completionsText completions
inference:embeddingsEmbeddings
inference:imagesImage generation
models:listModel listing
models:retrieveSingle model metadata
jobs:stats_ownRead your own async job statistics
jobs:read_ownRead your own async jobs
jobs:cancel_ownCancel 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 ScopeAccess
usage:read_currentCurrent usage
usage:read_historyUsage history
usage:read_summaryUsage summary
usage:read_reportUsage report export data
usage:read_breakdownPer-user tenant usage breakdown (admin/owner only)
billing:read_currentCurrent billing (admin/owner only)
billing:read_cyclesBilling cycles (admin/owner only)
billing:read_invoicesBilling invoices (admin/owner only)
billing:read_summaryBilling summary (admin/owner only)
profile:readCurrent profile
rate_limits:readCurrent rate limits
budgets:read_ownRead your own spend limit
budgets:update_ownUpdate 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 ScopeWhat it returns
usage:read_currentCurrent-month usage summary with request, token, model, duration, and cost totals. Defaults to the key owner's personal usage.
usage:read_historyIndividual usage events with optional date, model, endpoint, limit, and offset filters. Defaults to the key owner's personal usage.
usage:read_summaryAggregated usage summary for a required start_date/end_date range. Defaults to the key owner's personal usage.
usage:read_reportTime-series usage report for a required date range, grouped hourly, daily, weekly, or monthly. Defaults to the key owner's personal usage.
usage:read_breakdownPer-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_currentThe 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_cyclesA 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_invoicesA 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_summaryMulti-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:readThe key owner's current public profile.
rate_limits:readThe current effective rate limits for the key owner/tenant.
budgets:read_ownThe key owner's personal daily spend limit.
budgets:update_ownUpdates 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.

ConstraintWhat it does
Model allowlistRestrict 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 allowlistRestrict 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 capCap 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 Backend
  • Staging - Testing
  • Development - 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:

  1. Create a new key
  2. Update your applications
  3. Verify new key works
  4. 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

  1. Click the trash icon
  2. Confirm deletion
  3. Key is immediately revoked
danger

Deletion is immediate and irreversible. Any applications using this key will stop working.

Key Limits

LimitValue
Max keys per userSet by your organization's tenant quota (platform default: 10; unlimited if configured so)
Key name length2–255 characters
Key expirationOptional; 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

ParameterTypeRequiredDescription
namestringYesDescriptive name (2–255 chars)
key_typestringNoinference or management; defaults to inference
scopesstring[]NoAPI scope list for the selected key type
expires_atdatetimeNoISO 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"
}
warning

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

  1. Check if key is expired
  2. Verify key is copied correctly (no extra spaces)
  3. Ensure Bearer prefix in Authorization header
  4. 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