Skip to content

Conventions

All endpoints live under https://api.tradeops.cc/v1. The same API also answers at https://tradeops.cc/api/v1, which is what links in responses use. Changes within v1 only add things: new endpoints, new optional parameters and new response fields. Clients should ignore fields they don’t know. Anything that would break a client goes into a new version, and the changelog lists every change.

Send Accept: application/json on every request, so errors come back as JSON instead of a redirect.

Send a bearer token on every call except sign-in:

Authorization: Bearer 1|Kq3…

There are two kinds of token:

  • Field-app tokens come from signing in. There’s one per device, they work on every plan and they don’t count towards API usage.
  • Integration tokens are for customers’ own systems. They need a plan with API access, and every call counts towards the organisation’s API usage.

Tokens don’t expire. Revoke one with DELETE /auth/token.

Most routes start with an organisation’s slug: /v1/{team}/customers. GET /me lists the organisations a member belongs to. Every call is checked against the member’s role in that organisation, so a rep and a manager can see different results from the same endpoint.

Dates follow the organisation’s time zone (timezone in GET /me). Timestamps are ISO 8601 in UTC.

Resources follow JSON:API and come back as application/vnd.api+json:

{
"data": {
"id": "01JC8…",
"type": "customers",
"attributes": { "name": "Half Way Tree Pharmacy", "city": "Kingston" },
"relationships": { "locations": { "data": [] } },
"links": { "self": "https://api.tradeops.cc/v1/island-grocers/customers/01JC8…" }
}
}
  • Records are identified by their ULID (id).
  • include embeds related records in included: ?include=auditType.fields,customer.
  • Sparse fieldsets trim attributes: ?fields[audit_types]=name,status.

Sign-in and the offline sync return plain JSON.

GET /{team}/assignments is paginated. Use page and per_page (up to 100, default 50) and follow links.next until it’s null. Other lists return every record.

Status Meaning
401 The token is missing, revoked or wrong.
403 The member’s role doesn’t allow it, or the organisation’s plan doesn’t include it.
404 The record doesn’t exist in this organisation.
422 The input is invalid. errors lists messages for each field.
429 Too many requests. Wait for Retry-After seconds.

Validation errors look like this:

{
"message": "The name field is required.",
"errors": { "name": ["The name field is required."] }
}

When the plan is the reason for a 403, the body says which feature is missing:

{
"message": "API access isn't included in your Growth plan. Contact TradeOps to enable it.",
"entitlement": "api_access"
}
Endpoint Limit
Everything signed in 60 requests a minute per member
POST /auth/token 5 attempts a minute per email and IP address
POST /auth/phone/code 3 codes in 15 minutes per number, 10 an hour per IP address
POST /auth/phone/token 20 attempts in 15 minutes per IP address

The texted-code limits return 422 with a message rather than 429, so the app can show it next to the field.