GET, PATCH and DELETE /keys/{hash}
Reading, updating and revoking a single key
Addresses one key by its hash: reads it, changes its name, limit or on/off state, or revokes it permanently. All three methods require a management key.
GET https://openrouter.myip.co.kr/api/v1/keys/{hash}
PATCH https://openrouter.myip.co.kr/api/v1/keys/{hash}
DELETE https://openrouter.myip.co.kr/api/v1/keys/{hash}Why a hash addresses the key
The plaintext key leaves our system exactly once, in the creation response; we store only sha256(key). That hash is therefore the only name a key has. openrouter is built the same way, so we kept the field name hash.
# If you still hold the plaintext, you can compute the hash yourself
printf '%s' "sk-mo-v1-8f2b6d1e…" | sha256sumIf the plaintext is gone, get the hash from the GET /keys listing. The other direction — hash back to plaintext — is impossible for anyone, administrators included.
Authentication
Authorization: Bearer sk-mo-mgmt-v1-…. Management keys only. An inference key returns 401 invalid_api_key.
A management key can only see keys on its own account. Passing another user's key hash returns 404: an unknown hash and someone else's hash produce identical responses, so the endpoint never reveals whether a hash exists.
Path parameter
hashstringrequiredsha256(plaintext key) as 64 hex characters. Use the hash field from a GET/POST /keys response verbatim.
GET — read
Returns a single key object with exactly the same fields as an item in GET /keys.
curl "https://openrouter.myip.co.kr/api/v1/keys/9f2c1d0a7b3e4f5061728394a5b6c7d8e9f0112233445566778899aabbccddee" \
-H "Authorization: Bearer $MYIP_MANAGEMENT_KEY"{
"data": {
"created_at": "2026-09-01T02:11:40.881Z",
"updated_at": null,
"hash": "9f2c1d0a7b3e4f5061728394a5b6c7d8e9f0112233445566778899aabbccddee",
"label": "sk-mo-v1-au7…890",
"name": "production",
"disabled": false,
"limit": 100000,
"usage": 25500
}
}hashstringThe hash you requested, echoed back.
labelstringThe masked string. It cannot be used to authenticate.
disabledbooleantrue means the key cannot run inference. It merges the user's own off switch with every non-active status: suspended for lack of credit, suspended by an administrator, or revoked.
limitnumber | nullSpend limit in won. null means unlimited.
usagenumberSpend during the limit period, in won, with boundaries in Asia/Seoul.
Revoked keys do not appear in the GET /keys listing, but a revoked key whose hash you know is still readable here, so that a revocation can be confirmed after the fact. Requests made with that key still get 401.
PATCH — update
Changes only the fields you send; omitted fields are left alone.
namestringA new name. An empty or whitespace-only value returns 400.
disabledbooleantrue switches the key off, false switches it back on. A non-boolean returns 400.
limitnumber | nullA new spend limit in won. Sending an explicit null removes the limit. Omitting the field and sending null mean different things.
curl -X PATCH "https://openrouter.myip.co.kr/api/v1/keys/9f2c1d0a7b3e4f5061728394a5b6c7d8e9f0112233445566778899aabbccddee" \
-H "Authorization: Bearer $MYIP_MANAGEMENT_KEY" \
-H "Content-Type: application/json" \
-d '{"name": "production (paused)", "disabled": true, "limit": 200000}'The response is the key object after the update.
{
"data": {
"created_at": "2026-09-01T02:11:40.881Z",
"updated_at": "2026-09-04T05:40:12.907Z",
"hash": "9f2c1d0a7b3e4f5061728394a5b6c7d8e9f0112233445566778899aabbccddee",
"label": "sk-mo-v1-au7…890",
"name": "production (paused)",
"disabled": true,
"limit": 200000,
"usage": 25500
}
}To clear a limit and nothing else:
curl -X PATCH "https://openrouter.myip.co.kr/api/v1/keys/$KEY_HASH" \
-H "Authorization: Bearer $MYIP_MANAGEMENT_KEY" \
-H "Content-Type: application/json" \
-d '{"limit": null}'DELETE — revoke
Revokes the key permanently.
curl -X DELETE "https://openrouter.myip.co.kr/api/v1/keys/9f2c1d0a7b3e4f5061728394a5b6c7d8e9f0112233445566778899aabbccddee" \
-H "Authorization: Bearer $MYIP_MANAGEMENT_KEY"{ "data": { "success": true } }successbooleanAlways true. Revoking an already-revoked key is not an error; the call is idempotent.
Revoking a key leaves its usage records and ledger entries intact: deleting money that has already been charged would break the accounting. So total_usage from GET /credits does not go down after a revocation.
Errors
| Status | error_type | When |
|---|---|---|
| 400 | invalid_request | Body is not valid JSON. name is an empty string. disabled is not a boolean. limit is neither a number nor null |
| 401 | invalid_api_key | No header. Called with an inference key. The management key is unknown, switched off, or revoked |
| 401 | expired_api_key | The management key has expired |
| 402 | insufficient_credits | The management key is suspended_no_credit |
| 403 | key_suspended | An administrator suspended the management key |
| 404 | not_supported | No key with that hash, or the key belongs to another user |
| 500 | server | Any other server-side failure |
The 404 body looks like this. A hash that does not exist and a hash that belongs to someone else produce byte-identical responses, closing the path by which response differences would reveal that a hash exists.
{
"error": {
"code": 404,
"message": "지원하지 않는 경로입니다: key 9f2c1d0a7b3e4f50…",
"metadata": { "error_type": "not_supported" }
}
}message is written in Korean, the service's primary locale. Branch on metadata.error_type, not on the message text.
Related
- GET and POST /keys — list and issue keys
- GET /key and /auth/key — the state of the key you are using
- Limits and 402 — how limits, balance and key suspension interact
- Errors and debugging — the full
error_typetable
Last updated Sep 5, 2026