Docs menu

Reference

REST API

Conventions

Response shape, paging, money, percentages, dates, ids, upserts, rate limits and versioning.

Requests and responsesLink to this section#

  • Requests and responses are JSON. Send Content-Type: application/json with a body.
  • Field names are camelCase: listPrice, accountCode, nextOffset.
  • Query parameters are plain strings: ?limit=20&status=new.

Every successful response is an object with data:

json
{
  "data": [],
  "nextOffset": 50,
  "currency": "GBP"
}
FieldWhen it’s thereMeaning
dataAlwaysThe object or list you asked for.
nextOffsetLists that pagePass it as offset to get the next page. null on the last page.
currencyResponses with prices in the workspace currencyISO 4217 code for every money field in data.

Orders carry their own currency field, fixed when the order was placed.

PagingLink to this section#

Lists take limit and offset:

ParameterDefaultMaximum
limitthe maximum50 for products, 100 for everything else
offset0none

Keep requesting with offset=nextOffset until nextOffset is null:

js
let offset = 0
const all = []
while (offset !== null) {
  const res = await fetch(
    `https://tradecatalog.app/api/v1/products?limit=50&offset=${offset}`,
    {
      headers: { Authorization: `Bearer ${process.env.TRADECATALOG_API_KEY}` },
    },
  )
  const page = await res.json()
  all.push(...page.data)
  offset = page.nextOffset
}

On /products, nextOffset is set whenever a page is full. If the catalogue size is an exact multiple of limit, the last request returns an empty data list with nextOffset: null.

Some lists are capped. GET /orders covers the 200 most recent matching orders, and GET /price-changes the 100 most recent.

MoneyLink to this section#

Money is an integer in minor units of the currency, so there’s no rounding error:

ValueCurrencyMeans
1234GBP£12.34
1850EUR€18.50
500JPY¥500 (no minor unit)

Divide by 10 to the power of the currency’s decimal places to display it. In JavaScript, Intl.NumberFormat does it for you:

js
const format = (minor, currency) => {
  const f = new Intl.NumberFormat('en-GB', { style: 'currency', currency })
  const digits = f.resolvedOptions().maximumFractionDigits
  return f.format(minor / 10 ** digits)
}
format(1234, 'GBP') // "£12.34"

Prices are before tax. The workspace’s wording for this (for example “ex VAT”) is taxLabel on GET /workspace.

PercentagesLink to this section#

Percentages are basis points: hundredths of a percent, as integers.

ValueMeans
125012.5%
350035%
10000100%

DatesLink to this section#

Dates are ISO 8601 strings in UTC, like 2026-09-27T08:15:00.000Z. The workspace’s own timezone is timezone on GET /workspace.

IdsLink to this section#

Ids are UUID strings. Wherever an endpoint takes a customer, you can pass the customer’s id or their account code (case-insensitive), whichever your system has:

bash
curl "https://tradecatalog.app/api/v1/prices?customer=OAK01&sku=HX-8510" \
  -H "Authorization: Bearer $TRADECATALOG_API_KEY"

Creating and updating (PUT)Link to this section#

PUT /products and PUT /customers create or update in one call, up to 100 rows at a time:

  • Products are matched by SKU (case-insensitive).
  • Customers are matched by account code, else email, else name.

Both are safe to repeat. Sending the same rows twice gives the same result; the second call only reports them as updated.

A PUT writes the fields you send. Some optional product fields are cleared when you leave them out, others are kept. Each endpoint’s page lists which.

Rate limitsLink to this section#

Each key can make 120 requests a minute. Over that, you get 429 rate_limited with Retry-After: 60. Wait and try again. Errors has a retry helper.

Batch writes where you can: one PUT with 100 products counts as one request.

VersioningLink to this section#

The version is in the path: /api/v1.

  • Within v1 we only make additive changes: new endpoints, new optional parameters, new fields in responses. Write your code to ignore fields it doesn’t know.
  • A breaking change would get a new version (/api/v2), with v1 kept running and the change announced in the changelog.