Skip to main content

API Keys

Manage API Keys for external integrations. API Keys authenticate calls to LLM, agent, and webhook endpoints.

Authentication

All API Key management endpoints require JWT authentication:

Authorization: Bearer <jwt-token>
x-tenant-id: <uuid>

Role System (RBAC)

API Keys include a role field that controls permissions across all platform endpoints — both REST API and MCP Server.

RoleREST PermissionsMCP ToolsDescription
ownerFull access (*:*)72 (all)Tenant owner
adminFull access (resource wildcards)72 (all)Administrators, integrators. Default for new keys.
editorRead + create/update (no delete, publish, versioning, secrets, members, billing)36 (consumer + builder-read)Operators, builders
memberagents:read, agents:chat, sessions:read, sessions:create only4 (consumer)End-user access

RBAC is enforced universally — the same permission check applies to both JWT and API Key authentication.

info

Role defaults to admin for backwards compatibility. All existing keys automatically have role: admin.

Anti-escalation

You cannot create an API Key with a role higher than your own. For example, an editor cannot create an admin key. Attempting to do so returns HTTP 403 ROLE_ESCALATION_DENIED.


Tier System

The tier is automatically calculated based on the configured RPM (requests per minute):

RPM ConfiguredCalculated TierApplied Rate Limit
1-10default10 req/min
11-50basic50 req/min
51-200premium200 req/min
201+enterprise1000 req/min

Limits by Plan

PlanMax RPMRPM TiersModel Tiers
free10defaulteconomical
basic50default, basiceconomical, premium
pro200default, basic, premiumeconomical, premium, flagship
enterprise1000allall
Model Tier Enforcement

Your plan also restricts which LLM models you can use. See Models - Tier Access for details. Requesting a model outside your tier returns HTTP 403 MODEL_TIER_RESTRICTED.


POST /api/keys

Create a new API Key.

Request Body:

{
"name": "My API Key",
"description": "Optional description",
"prefix": "zhn_live_",
"role": "admin",
"rateLimitPerMinute": 30,
"quotaLimit": 100000,
"expiresInDays": 365
}
FieldTypeRequiredDefaultDescription
namestringYes-Key name
descriptionstringNonullOptional description
prefixstringNozhn_live_zhn_live_, zhn_test_, or zhn_dev_
rateLimitPerMinutenumberNoplan maxRPM limit
quotaLimitnumberNonullTotal request quota (null = unlimited)
rolestringNoadminMCP role: admin, editor, or member
expiresInDaysnumberNonullDays until expiration (null = never)

Response (201):

{
"success": true,
"data": {
"id": "uuid",
"api_key": "zhn_live_abc123def456...",
"prefix": "zhn_live_",
"suffix": "...xyz",
"name": "My API Key",
"role": "admin",
"rate_limit_per_minute": 30,
"calculated_tier": "basic",
"expires_at": "2027-01-16T00:00:00Z"
},
"warning": "Store this API Key securely. It cannot be retrieved later."
}
caution

The full API Key is shown only once at creation time.


GET /api/keys

List all API Keys for the tenant.

Response:

{
"success": true,
"data": [
{
"id": "uuid",
"name": "Production API Key",
"prefix": "zhn_live_",
"suffix": "...abc",
"status": "active",
"role": "admin",
"rate_limit_per_minute": 50,
"last_used_at": "2026-01-16T10:00:00Z"
}
],
"count": 1
}

GET /api/keys/stats

API Key usage statistics.

Response:

{
"success": true,
"data": {
"total": 5,
"active": 3,
"revoked": 1,
"expired": 1,
"total_requests": 15000
}
}

GET /api/keys/:keyId

Get details of a specific API Key.

Response:

{
"success": true,
"data": {
"id": "uuid",
"name": "My API Key",
"prefix": "zhn_live_",
"suffix": "...xyz",
"status": "active",
"role": "admin",
"rate_limit_per_minute": 50,
"calculated_tier": "basic",
"expires_at": "2027-01-16T00:00:00Z",
"total_requests": 150,
"tenant": {
"id": "uuid",
"name": "My Company"
}
}
}

PATCH /api/keys/:keyId/rpm

Update the RPM of an existing API Key.

Request Body:

{
"rateLimitPerMinute": 40
}

Response:

{
"success": true,
"data": {
"key_id": "uuid",
"old_rpm": 50,
"new_rpm": 40,
"calculated_tier": "basic"
}
}

DELETE /api/keys/:keyId

Revoke an API Key permanently.

Response:

{
"success": true,
"message": "API Key revoked successfully",
"revoked_at": "2026-01-16T12:00:00Z"
}

Using API Keys

After creating an API Key, use it to authenticate external calls:

curl -X POST "https://llm.zihin.ai/api/v3/llm/public/call" \
-H "X-Api-Key: zhn_live_abc123def456..." \
-H "Content-Type: application/json" \
-d '{"prompt": "Hello!", "model": "auto"}'

Error Codes

CodeHTTPDescription
invalid_input400Missing or invalid field
not_found404API Key not found
forbidden403Access denied
plan_limit_exceeded403RPM exceeds plan limit
MODEL_TIER_RESTRICTED403Model tier not allowed for plan
ROLE_ESCALATION_DENIED403Cannot create key with role higher than caller
creation_failed500Failed to create key
revocation_failed400Failed to revoke key