FulfillbotDocs
Menu
MarkdownDownload

Authentication

Every request needs an API key in the Authorization header:

Authorization: Bearer pak_...

The word Bearer is not case-sensitive. Keys are read only from this header, never from query parameters or cookies; the API doesn't use your portal session.

Permissions

Each key has a list of permissions chosen when you create it. A call without the permission it needs returns 403 insufficient_scope. GET /v1/me works with any valid key and lists the key's permissions.

Permission What it allows In "Read only" In "Read and create orders" Endpoints
wallet:read View wallet balance and transactions Yes Yes GET /v1/wallet, GET /v1/wallet/ledger, GET /v1/wallet/top-ups
catalog:read View products and inventory Yes Yes GET /v1/products, GET /v1/products/{id}, GET /v1/inventory
orders:read View orders Yes Yes GET /v1/orders, GET /v1/orders/{id}, POST /v1/orders/preview
purchase_orders:read View purchase orders Yes Yes GET /v1/purchase-orders, GET /v1/purchase-orders/{id}
shipments:read View shipments Yes Yes GET /v1/shipments, GET /v1/shipments/{id}, POST /v1/shipments/estimate
requests:read View sourcing requests Yes Yes GET /v1/requests, GET /v1/requests/{id}
quotes:read View quotes Yes Yes GET /v1/quotes, GET /v1/quotes/{id}
catalog:write Map your SKUs to products No No POST /v1/sku-mappings
orders:write Create, change and cancel orders No Yes POST /v1/orders, PATCH /v1/orders/{id}, POST /v1/orders/{id}/cancel
shipments:write Request, cancel and confirm shipments No No POST /v1/shipments, POST /v1/shipments/{id}/cancel, POST /v1/shipments/{id}/confirm
requests:write Submit sourcing and reorder requests No No POST /v1/requests/sourcing, POST /v1/requests/reorder

The access levels you can choose when you create a key:

Access level Permissions
Read only wallet:read, catalog:read, orders:read, purchase_orders:read, shipments:read, requests:read, quotes:read
Read and create orders wallet:read, catalog:read, orders:read, purchase_orders:read, shipments:read, requests:read, quotes:read, orders:write
Custom The ones you tick

Give each integration the smallest set it needs. Permissions can't be changed later: create a new key and revoke the old one.

Why a key is refused

Keys are checked on every request, so revoking a key or turning API access off takes effect at once.

Situation Status Code
No Authorization header, not a Bearer value, or a malformed, unknown or revoked key 401 invalid_api_key
The portal user who created the key was deactivated or no longer belongs to your account 401 invalid_api_key
API access is turned off for your account 403 api_not_enabled
The user who created the key must change a temporary password: sign in to the portal and finish that step 403 account_action_required
The key lacks the permission the endpoint needs 403 insufficient_scope
Your account is on hold: writes are refused, reads keep working 403 account_on_hold

Keys don't expire. Changing your portal password doesn't revoke them. When API access is turned off your keys are kept, and they work again when it is turned back on.

Failed attempts are rate limited

Requests with a malformed, unknown, revoked or no longer valid key (its creator was deactivated or left the account) count as failed attempts for the network (IP address) they come from: 30 an hour and 200 a day. After that, failed attempts get 429 rate_limited with Retry-After. A request without a Bearer Authorization header doesn't count, and a valid key is never blocked by this, even from the same network. See Rate limits.

Managing keys

Settings → API access lists each key with its name, the start of the key, its permissions, when it was created and when it was last used (updated every few minutes at most). Revoke keys there. We email your account when a key is created. Keys and webhook endpoints can only be managed in the portal, so a program that has a key can't create more keys or add webhook endpoints.

Keep keys out of browsers

The API sends no CORS headers: calls from a web page fail, and a key in a web page or app is visible to anyone who opens it. Call the API from your server.