Перейти к основному содержимому

Authentication

Every Data Plane call is authenticated with a single header:

X-API-Key: <token>

The token is never stored in clear text — we keep a salted SHA-256 hash — so it is shown to you exactly once, when the key is created in the Dashboard. Lose it and you rotate it.

:::danger Never put the key in a browser The key is a bearer credential with no origin binding. Anything that reaches a browser — a fetch from your frontend, an example pasted into a console — leaks it to every script on the page. Call the API from your backend. :::

What we check, in order

A request that fails any of these stops there:

  1. The key exists (hash lookup).
  2. The key is not revoked and not expired.
  3. The key's scopes cover the endpoint → otherwise 403.
  4. The caller IP is in the key's allowlist, if one is set → otherwise 403.
  5. The rate limit for this key and endpoint → otherwise 429.

Scopes

Scopes are section:action pairs assigned when the key is created:

ScopeGrants
product:readBrowse the catalog, look up items and prices
orders:writeCreate orders and checkouts
funds:readRead balances and the transaction ledger

A key only ever gets what you gave it — there is no implicit escalation. Issue narrow keys per integration: a price-scraper key with product:read cannot spend money even if it leaks.

IP allowlist

Optional per key. Empty allowlist = no IP restriction.

Supported patterns:

FormExample
IPv4 single198.51.100.42
IPv4 CIDR203.0.113.0/24
IPv4 wildcard (legacy)10.0.*, 192.168.*.*
IPv6 single2a02:4780::1
IPv6 CIDR2a02:4780:27:1690::/64

:::caution No wildcards for IPv6 2a02:4780:* is not accepted. Use CIDR notation. :::

On mismatch you get HTTP 403 with a message naming the address we saw:

Forbidden: caller IP 2a02:4780::1 is not in this API key's allowlist

We tell you your IP but never echo the allowlist back. The single most common cause of this error: a bot deployed on a dual-stack host that egresses over IPv6, while the allowlist only contains the operator's home IPv4 address. Call GET /whoami to see what we resolve for you.

Transaction limit

A key can carry a lifetime spend cap (transactionLimit). Before every purchase we take a quote from the shop service and check:

transaction_used + quote_amount <= transaction_limit

If it does not fit, the order is refused with HTTP 409, statusCode=13 (API_KEY_LIMIT_EXCEEDED) and errorCode="api_key_transaction_limit_exceeded". The message carries attempted / remaining / limit.

:::warning This is not a temporary condition Backing off and retrying will fail forever. The cap has to be raised (or transaction_used reset) from the control plane. :::

Read transactionRemaining on the key — not status — to know whether a key can still serve an order of the size you are about to send. A key with status: active and a small remaining balance will still 409 on any larger quote.

:::info Breaking change (2026-05) Exhausting a key's transaction limit used to return 429 LIMIT_REACHED, the same code as a rate limit. It now returns 409 API_KEY_LIMIT_EXCEEDED. If your client had special handling for "key limit exhausted" hanging off 429, move it to 409 + errorCode="api_key_transaction_limit_exceeded", and leave only back-off logic on 429. :::

Content-Type enforcement

POST, PUT and PATCH must send Content-Type: application/json. A missing or different value is rejected with HTTP 415 before validation runs — so a 415 never tells you anything about your payload.