Every Seller API request except GET /api/seller/v1/health requires an API key. This page covers obtaining a key, using it, scoping it, restricting it by IP, rotating it, and diagnosing every authentication failure the API can return.
Key lifecycle#
The credential#
Seller API keys are bearer tokens issued from the Avrix Console. They look like this:
avrix_sk_sbx_your_key_here
Every key begins with avrix_sk_. If your credential does not start with that prefix, it is not a
Seller API key — you may have copied a display label, a key id, or a Console session token.
A key carries four properties that together determine what it can do:
| Property | Meaning |
|---|---|
| Company | The seller company the key acts as. Fixed at creation. |
| Environment | sandbox or production. Fixed at creation and not interchangeable. |
| Scopes | The operations the key may perform. Fixed at creation. |
| Expiry | expires_at on the key record; enforced when set (401 once past). Not settable from the Console or POST /keys — console keys have no expiry, API-minted child keys inherit the parent's. |
| Allowed IPs | Optional source-address restriction. Editable after creation. |
Token prefix#
New and rotated secrets encode key type in the token itself. Auth looks keys up by hash; the
Console badge and GET /whoami remain the authoritative environment signal when the prefix is
ambiguous.
| Key type | Example prefix |
|---|---|
Live (production) | avrix_sk_live_… |
| Sandbox | avrix_sk_sbx_… |
Pre-existing keys may still show the legacy plain avrix_sk_… shape until rotated. See
Environments for host and behavioural differences.
Creating a key#
- Sign in to the Avrix Console and select your seller company.
- Go to Settings → Integrations → API Keys.
- Choose Create key.
- Set a descriptive name — the name appears in audit logs, so "checkout-service-prod" is more useful than "key 2".
- Choose the environment. Start with Sandbox. Production keys can be created only after
you sign the API Revenue Share Channel Terms under Settings → Commercial Agreements. On
api.avrix.iothose keys only succeed after Avrix has enabled production API access for your company — otherwise every request returns 403 PRODUCTION_ACCESS_NOT_APPROVED. Creating a production key without the signed terms returns 403 API_MODEL_AGREEMENT_REQUIRED. Sandbox keys are not gated. - Select the scopes you need. A key with no scopes is rejected on every request. The Console
pre-selects the base scope set (products, preview, pull, keys write, refunds, promotions,
webhooks — see Scope matrix). Deselect anything your service does not need.
seller:finance:readandseller:orders:managestay opt-in. - Optionally add allowed IPs.
- Copy the secret. Console-created keys have no expiry; see Key expiry.
API Keys are available to seller companies only. If you do not see the section, confirm you have selected a seller company in the company switcher and that your Console role includes API key management.
Making an authenticated request#
Send the raw token in an Authorization: Bearer header.
curl -s -X GET "https://api.avrix.io/api/seller/v1/whoami" \
-H "Authorization: Bearer $AVRIX_API_KEY"{
"data": {
"companyId": "9f2c1d84-...",
"companyName": "Sandbox Seller",
"environment": "sandbox",
"scopes": ["seller:products:read", "seller:keys:pull"],
"hasActiveBma": true,
"capabilities": {
"checkoutHoldEnabled": true,
"keylessEnabled": false
}
}
}
GET /whoami is the correct first call in any integration and the correct diagnostic when
something is wrong. It tells you which company you are acting as, which environment you are in,
what you are permitted to do, and which optional capabilities are enabled.
Common header mistakes#
The Authorization header is where most first-call failures originate. All of these fail:
| Wrong | Why |
|---|---|
Authorization: Bearer Bearer avrix_sk_… | Doubled prefix — your HTTP client may add Bearer for you |
Authorization: avrix_sk_… | Missing Bearer prefix |
Authorization: Bearer "avrix_sk_…" | Quotes are part of the value |
Authorization: Bearer avrix_sk_… | Trailing whitespace or newline |
| Pasted from a formatted document | Em dashes, ellipses, or non-breaking spaces substituted for ASCII |
If you see Invalid character in header content, your token contains a non-ASCII character. Copy
it again from the Console rather than from a document or chat message.
Scopes#
Scopes are explicit. A key holds exactly the scopes granted at creation, and a request that needs a
scope the key lacks returns 403 INSUFFICIENT_SCOPE (or a related forbidden code with
missingScope details).
| Scope | Grants (summary) |
|---|---|
seller:products:read | Catalog reads and GET /orders, GET /partners, GET /transactions, usage/activity |
seller:orders:preview | POST /orders/preview without fulfilment capability |
seller:keys:pull | Order creation and key retrieval. Also grants preview. |
seller:orders:manage | Revoke or regenerate fulfilments (opt-in) |
seller:refunds:write | POST /refunds (quarantine; does not refund your PSP) |
seller:refunds:read | Refund status |
seller:promotions:read | Read promotion shares and deals |
seller:promotions:respond | Accept / decline shares and respond to deals |
seller:webhooks:read | List webhook endpoints and deliveries |
seller:webhooks:write | Create, update, rotate, and test webhook endpoints |
seller:keys:write | Manage API keys programmatically, including rotate and allowed IPs |
seller:finance:read | Finance and settlement records (opt-in) |
Authority: the full endpoint-to-scope mapping is the scope matrix. Use that page when wiring scopes — this table is a short overview only.
Grant least privilege. A catalog-sync worker needs seller:products:read and nothing else. A
read-only price monitor should not hold seller:keys:pull, because that scope can pull real
inventory. Use separate keys per service rather than one key with every scope — this also means a
compromise can be contained by rotating one credential instead of stopping your whole storefront.
There is no published hard limit on how many Seller API keys a company may hold. Prefer least-privilege, per-service keys and retire unused ones.
Environments#
Keys are environment-scoped and not interchangeable.
| Sandbox | Production | |
|---|---|---|
| Base URL | https://api.avrix.io | https://api.avrix.io |
| Catalog | Shared fixture catalog, magic SKUs | Your real agreements |
| Key material | Test keys | Real keys |
| Magic SKUs | Accepted | Rejected — SANDBOX_MAGIC_VALUE_REJECTED |
| Commercial evidence | Minimal | Full set enforced |
The base URL is the same for both. The key determines the environment, not the host. Using a
sandbox key where production data is expected — or the reverse — returns KEY_ENVIRONMENT_MISMATCH.
Sandbox to production covers every behavioural difference and the cutover procedure.
IP allowlisting#
Optional, and off by default.
- No allowed IPs configured — the key is accepted from any source address.
- One or more allowed IPs configured — requests from any other address are rejected with
403 IP_NOT_ALLOWED.
An empty allowlist is not a closed allowlist. It is no restriction at all.
Discover the address Avrix sees from your infrastructure:
curl -s "https://api.avrix.io/api/seller/v1/whoami-ip"
This endpoint is unauthenticated — run it from the host that will call the API, not from your laptop. Use the address it returns, not the one your cloud console reports: NAT gateways, egress proxies, and serverless platforms frequently present a different address than expected, and an allowlist built from the wrong one locks you out of your own integration.
Update the allowlist in the Console, or via the API with a key holding seller:keys:write:
curl -s -X PATCH "https://api.avrix.io/api/seller/v1/keys/{keyId}/allowed-ips" \
-H "Authorization: Bearer avrix_sk_your_management_key" \
-H "Content-Type: application/json" \
-d '{ "allowed_ips": ["YOUR.EGRESS.IP.HERE"] }'
Returns 204 No Content. Full validation rules — accepted shapes, rejected reserved ranges, and
cache timing — are in the IP allowlist reference.
Allowlisting is a defence-in-depth control, not a substitute for protecting the secret. A leaked key with an allowlist is still a leaked key.
Storing the secret#
Treat a Seller API key as you would a payment processor secret key.
Do: store it in a managed secret store; inject it as an environment variable at runtime; use separate keys per environment and per service; rotate on a schedule and on staff changes; monitor usage through the Console audit log.
Do not: commit it to source control; put it in client-side code, a mobile app, or a browser; log it, including in request dumps and error reports; send it over email or chat; share one key across services; embed it in a container image.
If a key has ever appeared in a repository, a log, a CI output, or a support ticket, treat it as compromised and rotate it — even a private repository.
Key expiry#
Expiry is enforced whenever expires_at is set on a key record. There is currently no
integrator-facing control to set it: the Console create form has no expiry field, and
POST /api/seller/v1/keys does not accept one — child keys inherit the calling key's expiresAt.
| Setting | Behaviour |
|---|---|
| Console-created keys | expires_at is null; the key does not expire by time. Retire it with rotation or revocation. |
| API-minted keys | Inherit the calling key's expiresAt (null when the parent has none). Once past, auth rejects the key with 401 (API key expired). |
| Where to see it | GET /api/seller/v1/keys returns expiresAt per key (null when none). Check Settings → Integrations → API Keys for the key record in Console. |
Expiry is re-checked on every request (including auth-cache hits). An expired key cannot ride the ~60s auth cache.
Rotating a key#
There are two rotation mechanisms. Prefer (a) for planned rotations with zero downtime; use (b) when you must invalidate the current secret immediately (same key id).
(a) Create-then-retire (zero-downtime overlap)#
- Create a new key with the same scopes and allowed IPs.
- Deploy it to your services. Both keys are now valid.
- Verify the new key is serving traffic — check the Console audit log for requests attributed to it.
- Revoke the old key in the Console (or
DELETE /keys/{id}). - Confirm no errors follow revocation.
(b) In-place rotate (POST /keys/{id}/rotate)#
Requires seller:keys:write. Issues a new secret for the same key id and invalidates the old
secret immediately (no grace overlap). Auth caches and the revocation denylist mean other
instances reject the old secret within about 60 seconds.
curl -s -X POST "https://api.avrix.io/api/seller/v1/keys/{keyId}/rotate" \
-H "Authorization: Bearer avrix_sk_your_management_key"
The response returns the new secret once. Update every consumer before or immediately after the call — anything still using the old secret will start receiving 401.
You can also rotate from Settings → Integrations → API Keys in the Console (same immediate invalidation semantics).
Revocation and cache timing#
Revoke / delete / in-place rotate all mark the previous secret unusable. Propagation across instances is about 60 seconds (auth cache TTL + short-lived revocation denylist). In-flight requests that already authenticated may complete; new requests with the old secret fail once the denylist/cache catches up.
Rotate on a schedule — at least annually, and whenever someone with access leaves.
If a key is compromised#
Order matters. Do this immediately:
- Revoke or in-place rotate the key. Do this first, before investigating. Availability is recoverable; leaked inventory is not.
- Create a replacement (if you revoked) and deploy it — or deploy the new secret from rotate.
- Review the audit log for the compromised key: which orders were created, which keys were pulled, from which addresses.
- Contact Avrix support (
support@avrix.ioor your partner contact) with the key id and the suspected exposure window if you see unrecognised activity. Keys pulled by an attacker may be recoverable through the quarantine process if reported promptly. - Add an IP allowlist to the replacement if you did not have one.
- Find the leak — rotating without fixing the exposure only resets the clock.
Troubleshooting#
401 UNAUTHORIZED#
The key was not accepted.
| Cause | Check |
|---|---|
| Malformed header | Review the header mistakes table above |
| Revoked or rotated-away secret | Console → Settings → Integrations → API Keys |
| Expired key | expiresAt on GET /keys; create a replacement key (console keys do not expire) |
| Wrong environment | GET /whoami — compare environment to what you expect |
| Truncated secret | Compare length to what the Console displayed |
| Non-ASCII characters | Re-copy from the Console, not from a document |
{
"code": "UNAUTHORIZED",
"message": "Invalid or revoked API key",
"recoverable": true,
"hint": "Check your API key in Settings → Integrations → API Keys",
"doc_url": "https://docs.avrix.io/seller-api/errors#unauthorized",
"requestId": "req_01J8..."
}
403 INSUFFICIENT_SCOPE#
The key is valid but lacks a required scope. Scopes cannot be added to an existing key — create a new key with the correct scopes and rotate.
{
"code": "INSUFFICIENT_SCOPE",
"message": "API key is missing required scope: seller:keys:pull",
"recoverable": false,
"hint": "API key is missing a required scope (empty scopes are denied). Create a key with explicit scopes.",
"doc_url": "https://docs.avrix.io/seller-api/errors#insufficient-scope",
"requestId": "req_01J8..."
}
403 IP_NOT_ALLOWED#
Your source address is not on the key's allowlist. Call GET /whoami-ip from the failing
environment to see the address Avrix observed, then add it.
KEY_ENVIRONMENT_MISMATCH#
A sandbox key was used where production behaviour was required, or the reverse. Check environment
on GET /whoami.
Everything returns 401, including GET /whoami#
Confirm you are calling the versioned path. Unversioned paths such as /api/seller/orders issue a
redirect to /api/seller/v1/orders, and many HTTP clients drop the Authorization header (and
the request body on a POST) when they follow a redirect. Always call /api/seller/v1/…
directly.
Related#
- Quickstart — first authenticated call in context
- Scope matrix — the full endpoint-to-scope mapping
- IP allowlist — allowlist validation rules and cache timing
- Sandbox to production — environment differences and cutover
- Error reference — every error code