Getting Started & Integration FAQ
The conventions that apply across the whole Retraced Public API - authentication, the response envelope, pagination, dates, versioning, and the questions integrators ask most often. Read this once before building; the resource guides (Products, Orders, Materials, …) then only cover what is specific to them.
Authentication
The API is authenticated with an API key, passed in the companyapikey request header. There is no OAuth flow and no per-request signing.
curl "https://publicapi.retraced.com/api/v2/styles?level=style" \
-H "companyapikey: your-api-key"
To create a key, log in to the Retraced Platform and go to Developers HQ → API Keys → Create. Copy the key somewhere safe - it is shown only once and cannot be retrieved again. If you don't see Developers HQ in the sidebar, ask your Customer Success Manager to enable it.
- The key is scoped to a single company. Every request is automatically limited to that company's data - you only ever see and manage your own records.
- No IP allow-listing is required. You can call the API from any host.
Shell gotcha: if your key contains
$characters, wrap it in single quotes so the shell doesn't expand them:-H 'companyapikey: $2b$10$...'. Double quotes turn$2binto an empty string and you get a401.
Base URL
All requests are served from the Base URL https://publicapi.retraced.com/api/v2 and run against your live Retraced data. If you'd like a safe place to build and test your integration before going live, contact your Customer Success Manager and we'll set you up with the option that best fits your rollout.
The response envelope
Every response - success or error - uses the same envelope: a metadata object plus a data payload.
Success:
{
"metadata": { "success": true },
"data": { }
}
List success - metadata also carries pagination:
{
"metadata": {
"success": true,
"pagination": { "page": 1, "limit": 20, "total": 42, "totalPages": 3 }
},
"data": [ ]
}
Error - metadata.success is false, and the body carries a numeric statusCode, a stable machine-readable code, and a human-readable message:
{
"metadata": { "success": false },
"statusCode": 404,
"code": "not_found",
"message": "Resource not found"
}
Branch your error handling on statusCode (or the stable code string) - never on the message text, which may change.
Common errors
| Status | Meaning | What to do |
|---|---|---|
400 |
Validation failure - missing/unknown field, bad enum value, malformed date, etc. | Fix the request against the endpoint's parameter/field docs. |
401 |
Missing or invalid companyapikey. |
Check the header name (all lowercase) and the key value. |
403 |
Authenticated, but not allowed to access this specific resource. | The record belongs to, or is restricted to, another company. |
404 |
The resource doesn't exist or isn't visible to your key. | Verify the ID; remember hard-deleted records are gone for good. |
429 |
Too many requests (see Rate limits). | Back off and retry. |
Pagination, sorting & incremental sync
List endpoints are paginated with 1-based page numbers.
page- 1-based; defaults to1.limit- page size,1–100. Defaults to20on every endpoint.sort/order- sort column and direction (ASC/DESC); the acceptedsortcolumns vary per endpoint.
Page through a full result set until page reaches metadata.pagination.totalPages:
page=1
while : ; do
resp=$(curl -s "https://publicapi.retraced.com/api/v2/styles?level=style&page=$page&limit=100" \
-H "companyapikey: $API_KEY")
echo "$resp" | jq '.data[]'
total=$(echo "$resp" | jq '.metadata.pagination.totalPages')
[ "$page" -ge "$total" ] && break
page=$((page + 1))
done
Incremental sync
Endpoints that expose updatedAfterUnixMs (and updatedBeforeUnixMs) let you pull only what changed since your last sync instead of re-fetching everything. The value is a Unix timestamp in milliseconds (not seconds):
# Everything updated since 2026-07-01T00:00:00Z
curl "https://publicapi.retraced.com/api/v2/orders?updatedAfterUnixMs=1782777600000" \
-H "companyapikey: $API_KEY"
Store the largest updatedAt you have seen and pass it as updatedAfterUnixMs on the next run.
Rate limits
Last updated: 2026-08-03.
Each API key has its own request allowance per rolling minute. The allowance is per key, not per endpoint - every call the key makes draws on the same budget, across all API versions.
Every response tells you where you stand:
| Header | Meaning |
|---|---|
X-RateLimit-Limit |
Your key's allowance for a one-minute window. |
X-RateLimit-Remaining |
Calls left in the current window. |
X-RateLimit-Reset |
Unix time (seconds) when the window resets. |
Exceed it and the call is refused with 429 Too Many Requests plus a Retry-After header giving the seconds to wait:
{
"code": "too_many_requests",
"statusCode": 429,
"message": "Too Many Requests"
}
To stay well inside your allowance:
- Honour
Retry-After. Treat429as transient: wait the advertised seconds, then retry (with exponential backoff if it repeats) rather than failing the job. - Watch
X-RateLimit-Remainingand slow down as it approaches zero, instead of waiting to be refused. - Prefer incremental sync over re-pulling entire datasets, and avoid firing requests in parallel bursts.
Allowances are generous and sized so that a normal integration never notices them. If yours legitimately needs a higher limit, contact your Customer Success Manager.
Dates & time
Two kinds of date fields exist, and they behave differently:
- Business dates (e.g.
orderDate,agreedDeliveryDate,deliveryDate,shippingDate) are calendar dates inYYYY-MM-DDform with no time and no timezone. They are stored and returned exactly as written -2026-07-01always reads back as2026-07-01, regardless of the reader's timezone. - System timestamps (
createdAt,updatedAt) are full ISO 8601 UTC date-times (e.g.2026-07-02T10:30:00.000Z), set by the server. Use these for incremental sync.
On write, business-date fields are validated as
YYYY-MM-DD; in responses they come back as plain strings. Send exactlyYYYY-MM-DD- a full date-time is rejected with a400.
Pull model - no webhooks
The API is pull-only. There are no webhooks or server push, so Retraced will not call your systems when data changes. To stay in sync, poll on a schedule that suits your use case and use incremental sync to keep each poll cheap:
- Run a periodic job (e.g. hourly or daily).
- Request each resource with
updatedAfterUnixMsset to the last sync's high-water mark. - Persist the largest
updatedAtyou saw for the next run.
Archiving vs. deleting
These are two different operations - know which one an endpoint gives you:
- Archiving (
isArchived) is a reversible soft state. Archived records stay in the system and keep all their data, but drop out of the default lists and are excluded from the analytics and reporting views in the Retraced platform. You unarchive to restore them. On resources that support it, filter withisArchived=trueto see archived records andisArchived=falsefor active ones (omit the parameter on/ordersto get both; on/stylesthe default is active-only). - Deleting is permanent. Where an endpoint exposes
DELETE(for exampleDELETE /orders/:id), the record - and its children - are hard-deleted and cannot be recovered. A deleted record simply returns404afterwards.
Prefer archiving when you might need the record back; delete only when you are certain.
Reference data
Many write fields take an ID from a Retraced-managed list, not free text. Sending a display name (or an invented string) is the single most common integration mistake, so look the IDs up first - each of these endpoints is read-only, paginated, and safe to cache:
| Endpoint | Gives you | Used for |
|---|---|---|
GET /facility-processes |
Facility process IDs (CUT_MAKE_TRIM, WEAVING_MILL, …) |
buyerFacilityProcess / supplierFacilityProcess / receiverFacilityProcess on orders |
GET /production-processes |
Production process IDs (MANUFACTURING, FABRIC_PROCESSING, …) |
The parent stage of a facility process; supply-chain tier labels derive from its depthLevel |
GET /style-types |
styleTypeId values |
Creating and updating products |
GET /style-properties?type=… |
Brand / department / season / collection IDs | The brands, departments, seasons, collections fields on products |
GET /bom-placements |
placementId values |
Where a component sits on a BOM line |
curl "https://publicapi.retraced.com/api/v2/facility-processes?limit=100" \
-H "companyapikey: $API_KEY"
There are more facility processes than fit on one page, so page to totalPages instead of taking the first page as the complete list. Facility and production processes are the same for every account and change rarely - fetch them once and cache. Product-scoped lists (style types, style properties, BOM placements) belong to your own account.
⚠️ IDs and display names are not interchangeable. Responses often carry a human-readable
namealongside theid- for example supply chain nodes expose facility process names like"Cut make trim (CMT)". Always write theid(CUT_MAKE_TRIM); an unrecognised value is rejected with a400.
API versions
The current API is v2, served under /api/v2. The interactive API Reference also carries v0 and v1 specifications (switch between them with the source selector at the top of the page) - these are legacy and kept only for existing integrations. Build new integrations on v2.
Write conventions
- Prefer omitting an optional field over sending
null. On several resourcesnullis meaningful: it clears a value, and on products (styles/variants/SKUs) setting an inheritable field tonullre-enables inheritance from the parent. If you don't intend to change a field, leave it out of the request body entirely. - Some updates replace, not merge. A few write endpoints treat an array or object you send as the complete desired state (for example a product's
codes, or an order'slines). Check the resource guide before sending partial data - see the Products Guide and Orders & Order Lines Guide.
FAQ
How do I map my ERP's company code to a Retraced company ID?
Search /companies by the code you already store, then keep the Retraced id from the match. The filter parameter takes a URL-encoded JSON object:
# filter = {"internalCompanyCode":"123"}
curl "https://publicapi.retraced.com/api/v2/companies?filter=%7B%22internalCompanyCode%22%3A%22123%22%7D" \
-H "companyapikey: $API_KEY"
Supported keys and how each one matches:
| Key | Matching |
|---|---|
internalCompanyCode |
Substring, case-insensitive |
name |
Substring, case-insensitive |
officialName |
Substring, case-insensitive |
city |
Substring, case-insensitive |
country |
Exact ISO 3166-1 alpha-2 code. Comma-separate for several: "DE,IT" |
Two behaviours to design around:
- Substring keys over-match. Searching
internalCompanyCodefor"123"also returns"1234"and"ABC123". Compare the field on each result before trusting it, or treat more than one match as ambiguous. - A malformed
filteris ignored, not rejected. Invalid JSON returns an unfiltered list rather than a400, so encode it carefully and sanity-check the result count.
What does an order's status mean?
Nothing, as far as Retraced is concerned. IN_PROGRESS, IN_REVIEW and COMPLETED are stored and returned untouched - no platform behaviour depends on them, so the meaning is yours to define.
How do I know what changed in the API?
The release notes list every change to the public API.
Related reading
- Products Guide - the Style → Variant → SKU model, codes, filters, inheritance
- Orders & Order Lines Guide - orders, lines, parties, archiving
- Materials Guide and BOM Guide - composition and bills of materials
- DPP / Label Provider Guide and LCA Provider Guide - partner integration walkthroughs
- API Reference - interactive endpoint and schema documentation
- All integration guides