Docs
View as Markdown

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_limit in credits. null means 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_EXCEEDED and nothing is charged. Running out of account credits is still 402 INSUFFICIENT_CREDITS; the type tells 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:

shell
# 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"
json
{
  "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:

shell
curl "https://api.onekey.dev/v1/account" -H "x-api-key: YOUR_API_KEY"
json
{
  "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#

shell
curl "https://api.onekey.dev/v1/github/profile?username=torvalds" -H "x-api-key: YOUR_API_KEY"
# HTTP/1.1 402 Payment Required
json
{
  "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/account and 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.