Accounts & billing
API keys
Create, limit, inspect, rotate and revoke the inference keys that authenticate model requests.
On this page
An inference key authenticates requests to the compatible API. It belongs to one account, is charged in one permanent currency, and can carry its own spending limit.
Numes has two kinds of key:
| Kind | Can call | Created in |
|---|---|---|
| Inference | Models, chat, embeddings, media, GET /key, GET /generation | Dashboard, or the API with a management key |
| Management | GET /key, the key-management endpoints and GET /credits | Dashboard only |
This page covers inference keys. For management keys, see Management keys.
Create a key in the dashboard
Open Keys
Sign in, choose the account the key should belong to in the account switcher, and open Keys. Choose Create key.
Fill in the form
Field What it does Name A label for you, 1–100 characters, such as production-backend. You can rename the key later.Type Inference runs models, billed to the account balance. Management manages keys through the API and can't run models. Currency USD or BTC, when your account has both. Permanent: the key is always charged in this currency. Spend limit An exact amount in the key's currency. Leave it empty for no limit. Limit resets No reset, Daily, Weekly or Monthly. With No reset, the limit is a lifetime total.
The list shows each key's name, masked label, type, Usage in the current window, Limit and Status (Active or Disabled, plus the expiry date when one is set).
The billing currency is permanent
Each inference key is charged in one currency, chosen at creation:
Prices from
GET /models,usage.costandprovider.max_priceare in the key's currency. For BTC keys,1is one sat.Only offers priced in that currency are eligible. There's no conversion between USD and BTC and no fallback to the other balance.
To spend both balances, create one key per currency. See Bitcoin payments for BTC keys.
Spending limits
A key's limit caps what that key can spend. It counts settled spend plus the funds held for requests still running. When the next request would exceed it, the API returns 402 insufficient_credits, the same response as an empty balance. Compare limit_remaining from GET /key with your balance in Billing to tell them apart.
| Period | Resets at |
|---|---|
| Daily | 00:00 UTC every day |
| Weekly | 00:00 UTC every Monday |
| Monthly | 00:00 UTC on the first day of the month |
| No reset | Never; the limit is a lifetime total |
Key limits apply alongside the account-wide spending limit for each currency. Whichever is reached first stops new requests.
Expiry
You can set an expiry only when you create a key through the API with a management key (expires_at). The dashboard shows Expires or Expired with the date. An expired key returns 401 and can't be extended; create a replacement.
Key format
A key is a prefix followed by 64 lowercase hexadecimal characters. Inference keys start with sk- and management keys with mk-, for example sk-example-v1-. Don't parse keys beyond that.
Every key also has two non-secret identifiers:
a label: the prefix plus the first and last four hex characters, for example
sk-example-v1-3f9a...c21d;a hash: the SHA-256 hex digest of the full key. The management endpoints address keys by this value, and you can compute it from a leaked key to disable it.
Inspect the current key
Call GET /key with any inference or management key to read its metadata, limit and spend.
curl "https://api.numes.ai/api/v1/key" \ -H "Authorization: Bearer $NUMES_API_KEY"{ "data": { "hash": "3b7c9e1f5a2d4c6e8f0a1b3c5d7e9f1a2b4c6d8e0f1a3b5c7d9e1f2a4b6c8d0e", "label": "sk-example-v1-3f9a...c21d", "name": "production-backend", "billing_currency": "USD", "disabled": false, "limit": 100, "limit_remaining": 58.231907, "limit_reset": "monthly", "usage": 311.402116, "usage_daily": 3.120044, "usage_weekly": 12.874511, "usage_monthly": 41.768093, "created_at": "2026-07-01T09:12:44Z", "updated_at": "2026-09-02T16:40:03Z", "expires_at": null, "is_management_key": false }}Response `data`
hashstringNon-secret identifier of the key. Use it with the management endpoints.
labelstringMasked display label. Safe to log.
namestringThe key's name.
billing_currencystringUSDorBTC. Omitted for management keys.disabledbooleantruewhen the key is disabled and can't authenticate.limitnumber | nullSpending limit in the key's currency, or
nullfor no limit.limit_remainingnumber | nulllimitminus settled spend in the current reset window (lifetime spend when there's no reset), never below0.nullwhen there's no limit.limit_resetstring | nulldaily,weekly,monthly, ornullfor a lifetime limit.usagenumberSettled spend over the key's lifetime.
usage_dailynumberSettled spend since 00:00 UTC today.
usage_weeklynumberSettled spend since 00:00 UTC on Monday.
usage_monthlynumberSettled spend since 00:00 UTC on the first of the month.
created_atstringCreation time.
updated_atstring | nullLast change to name, state or limit;
nullif never changed.expires_atstring | nullExpiry time, or
null.is_management_keybooleantruefor a management key.
Money values are exact decimals written as JSON numbers; parse them as decimals. For BTC keys they're in sats.
Why a key is rejected
Every authentication failure returns 401 invalid_credentials with the same message, so the response doesn't reveal which check failed. Check these causes:
| Cause | What to do |
|---|---|
Missing or malformed Authorization header | Send exactly Authorization: Bearer <key> |
| Wrong key kind | Use an inference key for models, a management key for /keys and /credits |
| Key disabled | Enable it in Keys or with PATCH /keys/{hash} |
| Key deleted or expired | Create a new key |
| Account closed | Use a key from an active account |
| Creator removed from the organization or suspended | An owner or administrator issues a new key |
Repeated failed authentications are throttled with 429 rate_limited; wait for Retry-After. Don't retry a key that returned 401.
Disable, delete and rotate
Disable is a reversible stop. Choose Disable in the key's menu; requests get 401 until you choose Enable.
Delete permanently revokes the key. Clients using it stop authenticating immediately, and the key can't be restored. Past usage stays in Activity and Logs.
Requests already running when you disable or delete a key still finish and are charged.
To rotate a key without downtime:
Revoke the old key
When traffic on the old key stops in Activity (filter by API key), delete it. If you suspect a leak, disable it first.
To automate rotation, see Management keys.
Who can see which keys
In a personal account you see all keys. In an organization:
Owners and administrators see and manage every key.
Other members see and manage only the keys they created.
A key stops working when its creator is removed from the organization or their account is suspended. If a suspended person is restored, their keys work again, except keys that were deleted, disabled or have expired. See Organizations.
Best practices
One key per application and environment. You get separate limits, separate Activity breakdowns and a smaller blast radius if one leaks.
Keep keys server-side. Never ship a key in browser or mobile code. The API rejects browser requests from third-party origins with
403cors_forbidden.Never put a key in a URL. The API accepts keys only in the
Authorizationheader.Set a limit on every key. A monthly limit bounds the cost of a bug or a leak.
Log the
labelorhash, never the secret. When contacting support, quote theX-Request-Idresponse header.Use expiring keys for temporary access. Create them with
expires_atthrough the management API.