Skip to content
Numes

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:

KindCan callCreated in
InferenceModels, chat, embeddings, media, GET /key, GET /generationDashboard, or the API with a management key
ManagementGET /key, the key-management endpoints and GET /creditsDashboard only

This page covers inference keys. For management keys, see Management keys.

Create a key in the dashboard

  1. Open Keys

    Sign in, choose the account the key should belong to in the account switcher, and open Keys. Choose Create key.

  2. Fill in the form

    FieldWhat it does
    NameA label for you, 1–100 characters, such as production-backend. You can rename the key later.
    TypeInference runs models, billed to the account balance. Management manages keys through the API and can't run models.
    CurrencyUSD or BTC, when your account has both. Permanent: the key is always charged in this currency.
    Spend limitAn exact amount in the key's currency. Leave it empty for no limit.
    Limit resetsNo reset, Daily, Weekly or Monthly. With No reset, the limit is a lifetime total.
  3. Save the secret

    Choose Create key. The Save this key now dialog shows the full secret once. Copy it into your secret manager or an environment variable, then choose I saved it. The secret can't be recovered after the dialog closes; if you lose it, create a new key.

    Shell
    export NUMES_API_KEY="sk-..."

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.cost and provider.max_price are in the key's currency. For BTC keys, 1 is 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.

PeriodResets at
Daily00:00 UTC every day
Weekly00:00 UTC every Monday
Monthly00:00 UTC on the first day of the month
No resetNever; 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.

GET/api/v1/keyReference →
curl "https://api.numes.ai/api/v1/key" \  -H "Authorization: Bearer $NUMES_API_KEY"
Response
{  "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`

hashstring

Non-secret identifier of the key. Use it with the management endpoints.

labelstring

Masked display label. Safe to log.

namestring

The key's name.

billing_currencystring

USD or BTC. Omitted for management keys.

disabledboolean

true when the key is disabled and can't authenticate.

limitnumber | null

Spending limit in the key's currency, or null for no limit.

limit_remainingnumber | null

limit minus settled spend in the current reset window (lifetime spend when there's no reset), never below 0. null when there's no limit.

limit_resetstring | null

daily, weekly, monthly, or null for a lifetime limit.

usagenumber

Settled spend over the key's lifetime.

usage_dailynumber

Settled spend since 00:00 UTC today.

usage_weeklynumber

Settled spend since 00:00 UTC on Monday.

usage_monthlynumber

Settled spend since 00:00 UTC on the first of the month.

created_atstring

Creation time.

updated_atstring | null

Last change to name, state or limit; null if never changed.

expires_atstring | null

Expiry time, or null.

is_management_keyboolean

true for 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:

CauseWhat to do
Missing or malformed Authorization headerSend exactly Authorization: Bearer <key>
Wrong key kindUse an inference key for models, a management key for /keys and /credits
Key disabledEnable it in Keys or with PATCH /keys/{hash}
Key deleted or expiredCreate a new key
Account closedUse a key from an active account
Creator removed from the organization or suspendedAn 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:

  1. Create the replacement

    Create a new key with the same currency and limit, in the dashboard or with POST /keys.

  2. Deploy it

    Update your secret store and roll out the new key. Call GET /key from each environment and check the returned name or label.

  3. 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 403 cors_forbidden.

  • Never put a key in a URL. The API accepts keys only in the Authorization header.

  • Set a limit on every key. A monthly limit bounds the cost of a bug or a leak.

  • Log the label or hash, never the secret. When contacting support, quote the X-Request-Id response header.

  • Use expiring keys for temporary access. Create them with expires_at through the management API.

Next steps