Skip to content
Stockroom
Documentation menu

API

Stockroom has a REST API over the same data the app uses: catalog, stock, orders, reports. It is JSON over HTTPS, versioned under /v1, and scoped to your organization — there is no cross-tenant access of any kind.

The full endpoint-by-endpoint reference is served by the API itself, so it is never out of date:

API access is included on some plans and not others — see pricing for the current matrix. If your organization is not on a qualifying plan, requests return 403 api_not_in_plan, and the message names the plans that do include it.

Create a key

Keys are created in the app, by an admin, under Admin → API keys. They are never created over the API itself — that way a leaked key cannot mint replacements for itself.

When you create one you choose:

  • A name — what it is for. You will be glad of this in a year.
  • Permissions — see below.
  • A location, or all of them. A location-restricted key behaves as though no other location exists.
  • An expiry — 30, 90 or 180 days, or a year. A key cannot last longer than a year.
  • Live or test. A test key is a live key with a lower rate limit and a distinguishing prefix. It is not a sandbox: it reads and writes the same real data.

The key is shown once, when you create it. Only a hash is stored, so nobody — including us — can recover it afterwards. If it is lost, revoke it and create another.

Authentication

Send the key as a bearer token:

curl https://api.stockroom-ims.com/v1/products \
  -H "Authorization: Bearer sk_live_your_key_here"

Permissions

A key carries scopes, which mirror the same areas roles use — see roles & permissions. Each area is granted at read or write, and write implies read:

| Scope | Grants | | --- | --- | | inventory:read / inventory:write | Products, variants, stock levels, the movement ledger | | transfers:read / transfers:write | Stock transfers between locations | | serials:read / serials:write | Serial units and their chain of custody | | customers:read / customers:write | Customers | | sales:read / sales:write | Sales orders and payments | | purchasing:read / purchasing:write | Suppliers, purchase orders, receiving | | audits:read / audits:write | Count sessions | | reports:read | P&L, valuation, best sellers, tax | | dashboard:read | Dashboard figures | | admin:read / admin:write | Organization settings | | keys:read | List this organization's keys. There is no keys:write. |

Give a key the least it needs. A request outside its scopes returns 403 insufficient_scope naming the scope that was missing.

Conventions worth reading first

These are the things integrators most often get wrong.

  • Money and quantities are strings, not JSON numbers. "19.99", not 19.99. They are exact decimals; parsing them as floats will eventually cost you a cent.
  • Stock lives on the variant, never the product. Every product has at least one variant — a simple product has one default variant. Product-level figures are sums across variants.
  • The stock ledger is append-only, which makes it safe to use as a change feed. Quantities on hand are a cache derived from it.
  • Purchase order lines are in purchase units. If you buy in cases of six, a line quantity of 2 means 12 individual units.
  • Sales order lines carry qtyFulfilled separately from qty. An order can be partially shipped, with the remainder tracked as a backorder.
  • New fields and endpoints may appear in /v1 at any time. Ignore ones you do not recognise. Removals and changes of meaning ship as /v2.

Errors

Errors are application/problem+json with a stable code. Switch on code, never on title — titles are prose and may be reworded. The full vocabulary is served at /v1/meta/errors.

| Code | Meaning | | --- | --- | | invalid_token | The key is not recognised. | | key_revoked / key_expired | The key was revoked, or reached its expiry date. | | insufficient_scope | The key is valid but lacks the scope for this endpoint. | | api_not_in_plan | Your plan does not include API access. | | feature_not_in_plan | Your plan does not include the feature this endpoint covers. | | rate_limited | Slow down; see the RateLimit-* response headers. |

Rate limits

Every response carries RateLimit-Limit, RateLimit-Remaining and RateLimit-Policy. Limits are per key, so one busy integration cannot starve another. A 429 includes Retry-After.

Revoking a key

Revoke a key under Admin → API keys. It stops working from the next request — there is no cache and no grace period. Keys also expire on their own, which is the point of the one-year ceiling: a key nobody remembers issuing is the one that leaks.

Every key shows when it was last used and how many requests it has served, so you can tell a live integration from an abandoned one before you turn it off.

Getting help

Something missing, or an endpoint you need? Get in touch — we would rather hear it than have you work around it.