API Keys & Provisioning
Issue and manage plm_ API keys, and provision child keys with a management key for automation.
The /v1/keys and /v1/management-keys endpoints are for dashboard management and authenticate with your logged-in session's JWT access token (Authorization: Bearer $PLEUM_SESSION_TOKEN). They cannot be called with a plm_ key or an SDK-compatible token. The plm_ keys you create here are what you then use for OpenAI / Anthropic SDK calls.
plm_ key for model inference. A plmk_ management key is only for issuing automation child keys through /v1/provisioning/keys. Both secret key types are shown once at creation.Personal keys#
Create a new key with POST /v1/keys. All body fields are optional; omitted fields fall back to their defaults.
| Parameter | Type | Required | Description |
|---|---|---|---|
| name | string | null | Optional | Key name. Defaults to "Default". |
| allowed_models | string[] | null | Optional | Allowlist of model IDs this key may call. Empty or null allows all models. |
| monthly_budget_krw | integer | null | Optional | Monthly limit in KRW. null means unlimited. |
| weekly_budget_krw | integer | null | Optional | Weekly limit in KRW. Rolling 7 days in UTC. null means unlimited. |
| daily_budget_krw | integer | null | Optional | Daily limit in KRW. Rolling 24 hours. null means unlimited. |
| monthly_token_limit | integer | null | Optional | Monthly cap on combined input+output tokens. null means unlimited. Exceeding returns 402. |
| expires_at | datetime | null | Optional | Key expiry time (ISO 8601). null means no expiry. |
| pii_masking_enabled | boolean | Optional | Whether outbound PII masking is applied. Defaults to true. |
| response_cache_mode | string | Optional | off | exact | semantic. Defaults to off. See "Key scopes" below. |
| scopes | string[] | null | Optional | Permission scopes. Any combination of "chat", "usage:read", "images", "video", "audio", and "3d"; other values return 422. |
| ip_allowlist | string[] | null | Optional | Allowed IP/CIDR list (e.g. 203.0.113.0/24). null means no restriction. Invalid entries return 422. |
curl https://apirouter.pleum.ai/v1/keys \
-H "Authorization: Bearer $PLEUM_SESSION_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "production",
"allowed_models": ["gpt-5.5", "claude-sonnet-4-6"],
"monthly_budget_krw": 50000,
"weekly_budget_krw": 20000,
"daily_budget_krw": null,
"expires_at": null,
"pii_masking_enabled": true,
"response_cache_mode": "off",
"scopes": ["chat"],
"ip_allowlist": ["203.0.113.0/24"]
}'The response includes the key metadata plus key (the full secret). The full key is shown only once at creation — afterward only the key_prefix (e.g. plm_a1b2) is retrievable. Store it somewhere safe right away.
{
"id": "3f9b2c1e-7a4d-4e8b-9c6a-1d2e3f4a5b6c",
"name": "production",
"key_prefix": "plm_a1b2",
"key": "plm_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6",
"allowed_models": ["gpt-5.5", "claude-sonnet-4-6"],
"monthly_budget_krw": 50000,
"weekly_budget_krw": 20000,
"daily_budget_krw": null,
"monthly_token_limit": null,
"is_active": true,
"pii_masking_enabled": true,
"response_cache_mode": "off",
"scopes": ["chat"],
"ip_allowlist": ["203.0.113.0/24"],
"created_at": "2026-06-27T09:00:00Z",
"expires_at": null
}pii_masking_enabled=false, nor turn masking off — doing so returns a 403.Key scopes#
When scopes is set, each API requires its matching permission: "chat" for model calls, "images" for image generation/editing, "video" for video generation, "audio" for speech/audio APIs, and "3d" for 3D generation. "usage:read" allows the read-only usage report ( GET /v1/usage/report). Reading a generation job also requires that job's modality scope. null (the default) keeps the legacy behavior with no per-route scope restriction, except that GET /v1/usage/report always requires the usage:read scope.
| Parameter | Type | Required | Description |
|---|---|---|---|
| scopes | string[] | null | Optional | Any combination of "chat", "usage:read", "images", "video", "audio", and "3d". null = legacy (no per-route restriction, except the usage report). |
| ip_allowlist | string[] | null | Optional | Restricts key usage to these IP/CIDR ranges. Enforced at every key auth point; null means no restriction. |
| response_cache_mode | string | Optional | off (default) | exact (exact request match) | semantic (exact match + embedding similarity). On a cache hit the response is served without a provider call, nothing is billed, and the response carries "cached": true. |
Management & provisioning keys#
Issue a plmk_ management key with POST /v1/management-keys (body {name}). A management key is used to provision child keys, and the full key is shown only once at creation. It supports GET · POST (201) · DELETE.
The provisioning endpoint (/v1/provisioning/keys) authenticates with the plmk_ management key, not a JWT (Authorization: Bearer plmk_xxxxxxxxxxxxxxxx). It is meant for CI / automation that needs to mint keys without a dashboard session. It supports GET (list the owner's keys) · POST (201, create a child key) · DELETE.
export PLEUM_MANAGEMENT_KEY=plmk_xxxxxxxxxxxxxxxx
curl https://apirouter.pleum.ai/v1/provisioning/keys \
-H "Authorization: Bearer $PLEUM_MANAGEMENT_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "ci-runner",
"monthly_budget_krw": 20000
}'A child key created through provisioning accepts only name, monthly_budget_krw, and monthly_token_limit — you cannot set allowed_models, pii_masking_enabled, or expires_at.