API access is not included on every plan. Before you build against it, check your store has it: either upgrade to a plan that includes API & Webhooks access, or add the API & Webhooks Access addon from the Addons tab on Billing. Without one, a valid token still gets
403on every/v1request and outgoing webhooks stop firing too — see API access gate below.
Every v1 request carries a personal access token in an Authorization header:
curl https://api.firearmcart.com/v1/orders \
-H "Authorization: Bearer $FIREARMCART_TOKEN" \
-H "Accept: application/json"There is no OAuth flow, no API key/secret pair, no request signing, and no session cookie. The bearer token is the entire credential.
Creating a token
- Sign in to
https://app.firearmcart.com. - Switch to the store you want the token to act on. The token is bound to whichever store is current when you create it, and this cannot be changed afterwards.
- Open Profile → API Tokens (
/user/api-tokens). - Enter a name, tick the abilities you need, and create.
Six read abilities (customers:read, orders:read, fulfillments:read, products:read, shipping:read, taxation:read) are pre-ticked as a read-only default. At least one ability must be selected — a token with no abilities cannot be created.
Token lifetime
Tokens do not expire. There is no configured expiry and no refresh flow. A token is valid until you delete it in the dashboard, which takes effect immediately.
Store tokens like passwords. A leaked token grants everything its abilities allow, for as long as it exists.
Abilities
Each route is guarded by exactly one ability. A token missing that ability gets 403 even if the token is otherwise valid and the store has API access.
| Ability | Grants | Endpoints |
|---|---|---|
customers:read |
Read customer records and their addresses | GET /v1/customers, GET /v1/customers/{customer_id} |
customers:write |
Create or update a customer by email | POST /v1/leads |
orders:read |
Read orders, line items, transactions, addresses | GET /v1/orders, GET /v1/orders/{order_id} |
orders:upsell |
Charge an add-on onto an existing paid order | POST /v1/orders/{order_id}/upsell |
fulfillments:read |
Read fulfillments and their shipments | GET /v1/fulfillments, GET /v1/fulfillments/{fulfillment_id} |
products:read |
Read the catalog, variants and media | GET /v1/products, GET /v1/products/{product_id} |
shipping:read |
Read shipping zones and their rates | GET /v1/shipping |
taxation:read |
Read manual tax zones | GET /v1/taxation |
payments:tokenize |
Open a hosted card-entry session | POST /v1/payments/tokenize |
payments:charge |
Charge a card and create an order | POST /v1/payments/charge |
subscriptions:read |
Read Reload subscriptions | GET /v1/subscriptions, GET /v1/subscriptions/{uuid} |
subscriptions:write |
Pause, resume, skip, cancel, or edit a subscription | POST /v1/subscriptions/{uuid}/pause, /resume, /skip, /cancel, PATCH /v1/subscriptions/{uuid} |
ffl:read |
Search the FFL dealer directory | GET /v1/ffl-dealers |
themes:read |
Read theme files over MCP | Theme Dev MCP server only — no v1 REST route |
themes:write |
Write theme files over MCP | Theme Dev MCP server only — no v1 REST route |
Fifteen abilities in total. Two of them — themes:read and themes:write — do not unlock any /v1 endpoint. They gate the Theme Dev MCP server at https://api.firearmcart.com/mcp/themes.
That route accepts any of the abilities it lists, so a token holding only themes:read connects normally. Write access is enforced per tool instead: a read-only token’s tools/list returns 18 tools rather than 33, because the write tools hide themselves. See Which ability connects, which ability gates for the exact semantics and Tools for the full surface. That server also has its own rate limit; see Rate limits.
Choosing abilities
Grant the narrowest set that works. Two are worth extra thought:
payments:chargelets the token move money. Anything holding it can create orders and charge stored cards.orders:upselldoes the same on an existing order, and is also the only endpoint that requires you to supply an idempotency key.
API access gate
Passing the token check is not enough. Every /v1 request also runs an access gate that checks the store’s plan and billing standing, and it can reject you with three distinct responses.
| Status | Body | Meaning |
|---|---|---|
401 |
{"error": "unauthorized", "message": "Invalid API token."} |
The credential authenticated, but did not resolve to a store. Practically: the request reached the API as something other than a store token. |
403 |
{"error": "forbidden", "message": "API access is not enabled for this team."} |
The store’s plan does not include API & Webhooks access, and it holds no API access add-on. |
403 |
{"error": "subscription_expired", "message": "Your subscription has expired. Please renew to continue using the API."} |
The store’s subscription is suspended after a failed payment, or is past its cancellation date. |
A store passes the gate if any of the following is true: it is a demo account, it has API access granted directly by an administrator, its plan includes API access, or it holds an active API access add-on.
Note: The same gate governs outgoing webhooks. If a store loses API access, queued and future webhook deliveries stop firing as well, even though the webhook rows remain configured. See Webhooks.
Note that this gate is distinct from an invalid or deleted token. A revoked, mistyped or missing token fails earlier, at the authentication guard, and produces {"message": "Unauthenticated."} — see Errors.
Always send Accept: application/json
Successful responses are JSON regardless of headers, but error responses are not. Without Accept: application/json:
- A
401becomes a302redirect to the dashboard login page. - A
422validation failure becomes a302redirect rather than a JSON error body. - Other failures render an HTML error page.
Send the header on every request, including GETs.
Revoking a token
Delete the token at Profile → API Tokens. Revocation is immediate — the next request with that token fails authentication with 401 Unauthenticated. There is no revocation endpoint; see What the API does not do.
If you suspect a leak, delete the token first and issue a replacement second. There is no way to rotate a secret in place.
Related documentation
- Rate limits — per-store request budgets
- Errors — every failure shape, per status code
- Theme Dev MCP server — the only thing the two
themes:*abilities unlock - Team members — who can reach the dashboard page that mints tokens
- Billing — plans and add-ons that satisfy the API access gate

