Management API
Last updated
Create, change and revoke virtual keys, and read your Gateway usage, from your own scripts, CI jobs or infrastructure-as-code, with a management key. It comes with the Gateway Pro, Scale and Enterprise plans.
Management keys
A management key is a separate kind of credential from a virtual key. It can manage virtual keys but can't call models, and a virtual key can't call the management API. Management keys are prefixed tmk_, stored hashed, and shown to you once, when you create them.
Create one in the Portal:
- For your own account: Gateway → Keys → Management keys. It manages your personal virtual keys.
- For an organization: Organization → Org keys → Management keys. Only owners and admins can create one, and it manages the organization's shared virtual keys.
Choose what each key can do when you create it:
| Scope | Allows |
|---|---|
keys:read | Listing and reading virtual keys. |
keys:write | Creating, changing and revoking virtual keys. |
usage:read | Reading usage and cost. |
A management key can also have an expiry date and an IP allowlist, set the same way as a virtual key's (see what a virtual key scopes). An account can have up to 10 active management keys. Management keys are only made in the Portal; the API can't create another one.
For an organization:
- Every change a management key makes is recorded in the audit log (Organization → Compliance) under that management key's label.
- When a member is removed, or an owner or admin is made a member, the management keys they created are revoked. Virtual keys those management keys created keep working.
Making requests
The base URL is https://api.temprhq.io/v1/management. Send the management key as a bearer token:
curl https://api.temprhq.io/v1/management/keys \
-H "Authorization: Bearer tmk_xxxxxxxxxxxxxxxxxxxxxxxx"
Request and response bodies are JSON with snake_case field names. Response timestamps are Unix seconds. expires_at in a request is an ISO 8601 date and time, for example 2027-01-31T00:00:00Z.
Each management key can make 300 requests a minute. Over that, the API answers 429 until the next minute starts.
List keys
GET /v1/management/keys (scope keys:read) returns the account's virtual keys, newest first. The Portal's Playground key and the keys Tempr creates for team members' IDE sessions aren't included.
| Query parameter | Meaning |
|---|---|
limit | Keys per page, 1 to 100. Default 20. |
after | A key id from the previous page (its last_id); the page starts after it. |
include_revoked | true to include revoked keys. By default only active and expired keys are listed. |
{
"object": "list",
"data": [ { "id": "6f1c2b0e-…", "object": "virtual_key", "label": "ci", … } ],
"first_id": "6f1c2b0e-…",
"last_id": "6f1c2b0e-…",
"has_more": false
}
Create a key
POST /v1/management/keys (scope keys:write) creates a virtual key. label is required; every other field is optional. The response is 201 with the key object, plus the raw key in key. It isn't shown again, so store it now.
curl https://api.temprhq.io/v1/management/keys \
-H "Authorization: Bearer tmk_xxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"label": "ci",
"allowed_models": ["anthropic/claude-sonnet-4-5"],
"max_budget_usd": 25,
"rpm_limit": 60,
"expires_at": "2027-01-31T00:00:00Z"
}'
{
"id": "6f1c2b0e-…",
"object": "virtual_key",
"label": "ci",
"masked_key": "tvk_...a1b2",
"status": "active",
"created_at": 1790000000,
"expires_at": 1801353600,
"last_used_at": null,
"revoked_at": null,
"allowed_models": ["anthropic/claude-sonnet-4-5"],
"allowed_mcp_servers": null,
"fallback_chains": null,
"max_budget_usd": 25,
"rpm_limit": 60,
"tpm_limit": null,
"guardrail_mode": null,
"llm_guardrail_enabled": null,
"prompt_caching_enabled": null,
"content_capture_enabled": null,
"allowed_ips": [],
"key": "tvk_xxxxxxxxxxxxxxxxxxxxxxxx"
}
A personal account can have up to 3 active virtual keys; an organization has no such limit.
Get a key
GET /v1/management/keys/{id} (scope keys:read) returns one key. status is active, expired or revoked.
Change a key
PATCH /v1/management/keys/{id} (scope keys:write) changes the fields you send and leaves the rest as they are. Send a field as null to clear it, which removes that limit or goes back to the account default. label can be changed but not cleared. A revoked key can't be changed.
curl -X PATCH https://api.temprhq.io/v1/management/keys/6f1c2b0e-… \
-H "Authorization: Bearer tmk_xxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{ "rpm_limit": 120, "max_budget_usd": null }'
Revoke a key
POST /v1/management/keys/{id}/revoke (scope keys:write) revokes a key and returns it. Requests with the key stop authenticating at once. Revoking a key that's already revoked changes nothing.
Key fields
| Field | Type | Meaning |
|---|---|---|
label | string | A name for the key, up to 100 characters. |
allowed_models | array of strings | The provider/model values the key may call. Empty or null allows any model. |
allowed_mcp_servers | array of strings | The MCP server slugs the key may reach through the MCP proxy. Empty or null allows any. |
fallback_chains | object | Aliases mapped to ordered lists of candidates, for example {"fast": ["groq/llama-3.3-70b-versatile", "openai/gpt-4o-mini"]}. See fallback chains. |
max_budget_usd | number | The most the key may spend, in US dollars. |
rpm_limit, tpm_limit | integer | Requests and tokens per minute. |
guardrail_mode | string | off, flag_only or block. Null uses the account's setting. |
llm_guardrail_enabled | boolean | Whether the LLM guardrail check runs. Null uses the account's setting. |
prompt_caching_enabled | boolean | Whether the Gateway adds prompt-cache breakpoints. Null uses the account's setting. |
content_capture_enabled | boolean | Whether request and response bodies are kept in the logs. Null uses the account's setting. |
expires_at | date and time | When the key stops working, at most five years ahead. |
allowed_ips | array of strings | Addresses or CIDR ranges the key may be used from, up to 50. Empty or null allows any address. |
The model and MCP server lists take up to 200 entries each. A field the API doesn't know is an error rather than being ignored, so a typo doesn't pass unnoticed.
Usage
GET /v1/management/usage (scope usage:read) totals the account's Gateway requests over a range of days.
| Query parameter | Meaning |
|---|---|
start, end | UTC dates (yyyy-MM-dd), both included. The range can be up to 90 days. By default it's the last 30 days, ending today. |
group_by | day (the default, oldest first), key or model (both by cost, highest first). |
{
"object": "usage",
"start": "2026-09-01",
"end": "2026-09-30",
"group_by": "model",
"data": [
{
"date": null,
"key_id": null,
"model": "anthropic/claude-sonnet-4-5",
"requests": 1204,
"errors": 3,
"prompt_tokens": 5120331,
"completion_tokens": 402118,
"cost_usd": 21.3714
}
]
}
Each row fills in the field it's grouped by (date, key_id or model) and leaves the other two null. errors counts requests that got a 4xx or 5xx answer. Usage covers the days your plan keeps logs for.
Errors
Errors use the same shape as the rest of the Gateway API, and param names the field at fault when there is one:
{
"error": {
"message": "The RPM limit can't be negative.",
"type": "invalid_request_error",
"code": "invalid_value",
"param": "rpm_limit"
}
}
| Status | Type | Code | Meaning |
|---|---|---|---|
400 | invalid_request_error | invalid_body | The body isn't a JSON object. |
400 | invalid_request_error | invalid_value | A field or query parameter is missing, unknown, the wrong type or out of range. message says which. |
400 | invalid_request_error | invalid_cursor | after isn't the id of a key in the list. |
401 | authentication_error | missing_management_key | No Authorization: Bearer header. |
401 | authentication_error | invalid_management_key | The key doesn't exist or has been revoked. A virtual key gets this too. |
401 | authentication_error | management_key_expired | The management key is past its expiry date. |
403 | permission_error | ip_not_allowed | The request came from an address outside the management key's IP allowlist. |
403 | permission_error | plan_required | The account isn't on a paid-up Pro, Scale or Enterprise plan. |
403 | permission_error | insufficient_scope | The management key doesn't have the scope the call needs. |
404 | invalid_request_error | key_not_found | No virtual key with that id belongs to this account. |