Per-key credit limits
Every API key can carry a credit limit. It caps what that one key can spend; the account balance and your other keys are untouched. Use it to fence off a script, a staging environment or a customer-facing integration so a bug or a runaway loop cannot drain the account.
How it works#
- A key has an optional
credit_limitin credits.nullmeans no limit, which is the default. - Usage is counted per key: every charge the key makes (a fresh fetch, a paid cache hit, a top-up when a dearer data route was needed) adds to its
credits_used. Every refund (source failure, not found) is given back to the key. Calls made before the key had a limit, or before limits existed, are not counted. - The limit is enforced before charging, in the same atomic check as the account balance, so two concurrent requests cannot both squeeze under it.
- A call the limit cannot cover answers
402 KEY_BUDGET_EXCEEDEDand nothing is charged. Running out of account credits is still402 INSUFFICIENT_CREDITS; thetypetells you which one it was.
Setting a limit#
In the dashboard, each key has a Set limit action. Enter a number of credits and save; Remove limit clears it. A revoked key cannot be given a limit.
The dashboard calls the account API, which needs a signed-in browser session (cookie plus a CSRF header), not an API key. The same route is available to your own tooling once you are signed in:
# set the limit (whole or fractional credits, above 0, at most 1,000,000,000)
curl -X PUT "https://api.onekey.dev/v1/keys/KEY_ID/budget" \
-b "session cookie from the dashboard" -H "x-weft-csrf: 1" -H "origin: https://your-dashboard-origin" \
-H "content-type: application/json" -d '{"credit_limit": 500}'
# clear it
curl -X PUT "https://api.onekey.dev/v1/keys/KEY_ID/budget" \
-b "session cookie from the dashboard" -H "x-weft-csrf: 1" -H "origin: https://your-dashboard-origin" \
-H "content-type: application/json" -d '{"credit_limit": null}'
# read the limit and what the key has used
curl "https://api.onekey.dev/v1/keys/KEY_ID/budget" -b "session cookie from the dashboard"{
"id": "KEY_ID",
"label": "ci",
"prefix": "ok_live_ab12",
"created_at": "2026-09-01T10:00:00+00:00",
"last_used_at": null,
"revoked": false,
"credit_limit": 500,
"credits_used": 0
}KEY_ID is the key's id as listed by GET /v1/keys (and in /v1/me), not the secret itself. Both listings show each key's credit_limit.
Reading it from the API side#
GET /v1/account, called with the key, reports the calling key's own limit and usage, free:
curl "https://api.onekey.dev/v1/account" -H "x-api-key: YOUR_API_KEY"{
"account_id": "...",
"key": { "id": "KEY_ID", "prefix": "ok_live_ab12", "kind": "live", "credit_limit": 500, "credits_used": 40 },
"balance_credits": 837.8,
"balance_millicredits": 837800,
"blocked": false
}When the limit is reached#
curl "https://api.onekey.dev/v1/github/profile?username=torvalds" -H "x-api-key: YOUR_API_KEY"
# HTTP/1.1 402 Payment Required{
"success": false,
"data": null,
"metadata": { "request_id": "1a0a591e117d41bf8240ca677f7b43cc" },
"error": {
"code": "key_budget_exceeded",
"type": "KEY_BUDGET_EXCEEDED",
"message": "This API key has reached its credit budget",
"request_id": "1a0a591e117d41bf8240ca677f7b43cc",
"doc_url": "https://onekey.dev/errors/KEY_BUDGET_EXCEEDED"
}
}Raise or clear the limit, or use another key. Do not retry the same call until then: it fails the same way.
Edge cases#
- Refunds restore the limit. A call that is refunded (source failure, not found) is not counted against the key, so a run of failures does not eat the budget.
- Free calls are free here too. Cache hits at 0 credits,
GET /v1/accountand rejected requests do not count. A cached response over 100 KB (0.2 credit) does. - A key near its limit can still make cheaper calls. The check is per call: a 5-credit search may be refused while a 1-credit lookup on the same key still goes through.
- Validation. The limit must be above 0 and at most 1,000,000,000 credits; anything else is
422 INVALID_PARAMS, as is setting a limit on a revoked key.
What it costs#
Nothing. Setting, reading and clearing a limit are free dashboard operations, and a refused call (402) is never charged.