Management API keys

Provisioning and revoking keys programmatically

There are two kinds of key, and they do not overlap:

KindPrefixCan doCannot do
Inferencesk-mo-v1-Call /chat/completions, /completions, /generation, /key, /creditsCreate or revoke keys
Managementsk-mo-mgmt-v1-Create, list, update and revoke inference keysRun inference

Sending an inference key to /api/v1/keys, or a management key to /chat/completions, returns 401 invalid_api_key. The separation is deliberate: a key that can both spend money and mint new keys is a much worse thing to leak.

Getting a management key

Create one in the dashboard under Settings → API keys (/settings/keys). It is shown once, in plaintext, and never again — we store only its SHA-256 hash.

bash
export MYIP_MGMT_KEY="sk-mo-mgmt-v1-..."

Identifying a key: the hash

Keys are addressed by hash — the SHA-256 of the full plaintext key, as 64 hex characters. Since we never store the plaintext, the hash is the only handle that exists. You get it from the create and list responses.

Endpoints

All of these require Authorization: Bearer $MYIP_MGMT_KEY.

MethodPathPurpose
GET/api/v1/keysList your inference keys
POST/api/v1/keysCreate an inference key
GET/api/v1/keys/{hash}Read one key
PATCH/api/v1/keys/{hash}Rename, disable, or change the spend limit
DELETE/api/v1/keys/{hash}Revoke permanently

The list contains inference keys only, and excludes revoked ones. The management key does not list itself.

Create a key

namestringrequired

Human-readable label. Required and non-empty.

limitnumber

Spend cap for this key, in KRW. null or omitted means unlimited.

limit_resetstring

One of never, daily, weekly, monthly. Determines the window the limit applies to. Day, week and month boundaries are Asia/Seoul.

curl -X POST https://openrouter.myip.co.kr/api/v1/keys \
  -H "Authorization: Bearer $MYIP_MGMT_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "name": "batch-worker", "limit": 50000, "limit_reset": "monthly" }'

The response:

json
{
  "data": {
    "created_at": "2026-09-04T02:11:43.201Z",
    "updated_at": null,
    "hash": "9f2c…c41a",
    "label": "sk-mo-v1-au7…890",
    "name": "batch-worker",
    "disabled": false,
    "limit": 50000,
    "usage": 0
  },
  "key": "sk-mo-v1-au7c2f…c890"
}
keystring

The plaintext key. This is the only time it is returned. Store it before you close the connection.

data.hashstring

SHA-256 of the plaintext, hex. The handle for GET, PATCH and DELETE.

data.labelstring

Masked form of the key, safe to display and log.

data.usagenumber

KRW spent by this key inside the current limit_reset window. With no limit_reset, it is the all-time total.

List keys

bash
curl https://openrouter.myip.co.kr/api/v1/keys \
  -H "Authorization: Bearer $MYIP_MGMT_KEY"
json
{ "data": [ { "hash": "9f2c…c41a", "name": "batch-worker", "disabled": false, "limit": 50000, "usage": 1234.5 } ] }

Update a key

PATCH accepts name, disabled, and limit. Omitted fields are left alone; "limit": null clears the cap.

bash
# Pause a key without destroying it
curl -X PATCH https://openrouter.myip.co.kr/api/v1/keys/9f2c…c41a \
  -H "Authorization: Bearer $MYIP_MGMT_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "disabled": true }'

limit_reset is fixed at creation time. To change the window, create a new key.

Revoke a key

bash
curl -X DELETE https://openrouter.myip.co.kr/api/v1/keys/9f2c…c41a \
  -H "Authorization: Bearer $MYIP_MGMT_KEY"
json
{ "data": { "success": true } }

Inspecting the key you are currently using

An inference key can look itself up — no management key needed:

bash
curl https://openrouter.myip.co.kr/api/v1/key \
  -H "Authorization: Bearer $MYIP_API_KEY"

GET /api/v1/auth/key is an alias for the same response. It reports limit, usage, limit_remaining, limit_reset, per-period usage, and whether the key is a management key. All amounts are KRW.

Fields that exist only for wire compatibility are inert here: is_free_tier is always false, the byok_* counters are always 0 because we do not support bring-your-own-key, and rate_limit is a deprecated field that is safe to ignore.

Errors

Statuserror_typeCause
400invalid_requestMissing name, malformed JSON, bad limit_reset value
401invalid_api_keyNot a management key, or unknown / revoked key
403key_suspendedThe key was suspended by an administrator
404not_supportedNo key with that hash belonging to you. Someone else's hash returns the same 404, so the endpoint cannot be used to probe for keys

Why the dashboard uses a different API

/api/v1/* accepts bearer tokens only. The browser dashboard is authenticated with a session cookie and calls a separate endpoint that shares the same underlying key logic. Mixing cookie authentication into the SDK surface would open a CSRF hole without making anything easier — so we do not.

Last updated Sep 5, 2026