Collaterate Partner API (1)

Download OpenAPI specification:

License: Proprietary

Read-only API for partners to retrieve their own order data from Collaterate.

Scoping and the 404-vs-403 rule

No <code>updatedSince</code> / no change polling

Scoping and the 404-vs-403 rule

Every partner is granted a specific set of siteIds. All reads are scoped to those sites at the database layer. An order that exists but belongs to a site you are not granted returns 404 order_not_found -- never 403. This is deliberate: a 403 would confirm the order exists in a site you cannot see, and this API never confirms that. If you see a 404 for an order number you expected to find, the two indistinguishable causes are "no such order" and "not one of your sites" -- there is no way to tell these apart from the response, by design.

No updatedSince / no change polling

This API does not offer an updatedSince filter, and none should be inferred from the updatedOn field on an order. An audit of the underlying data found that orders.updatedOn does not move when a shipment, tracking number, or item quantity changes on an existing order (25.6% of orders have a child record newer than the order itself), and a separate internal process can move an order into your site without updating that column either. Treating it as a watermark would silently hide real changes.

GET /v1/orders is therefore ordered by placedOn (set once, at order creation, and genuinely monotonic), which is safe to paginate over but cannot be used to detect that an existing order changed status or shipped. There is currently no supported way to poll for status/shipment changes on orders you have already retrieved. Do not build a polling loop keyed on updatedOn -- it will miss changes.

Retry guidance

  • Retry, with backoff: 429 (honor the Retry-After header) and 503.
  • Do not retry as-is: 400, 401, 403, 404 -- these mean the request itself needs to change (fix the input, fix the credential, or accept that the resource is not visible to you). Retrying unchanged will get you the same response every time.

Meta

Liveness and identity endpoints.

Liveness check

Unauthenticated. Returns 200 if the gateway and its edge are up. Does not touch the database, the authorizer, or anything partner-specific -- a failing /v1/me or /v1/orders alongside a healthy /v1/ping tells you the problem is in your credential or the data path, not the network.

Responses

Response samples

Content type
application/json
{
  • "status": "ok"
}

Describe the calling credential

Returns the partner identity, granted sites, and scopes resolved from your credential (bearer token or client certificate). Requires a valid credential but no particular scope. Useful as your first integration call: if this fails, the problem is authentication, not any specific endpoint; if it succeeds, grantedSiteIds here is the authoritative list of sites you may query.

Authorizations:
oauth2mtls

Responses

Response samples

Content type
application/json
{
  • "partnerId": "string",
  • "partnerName": "string",
  • "grantedSiteIds": [
    ],
  • "authMethod": "COGNITO_M2M",
  • "scopes": [
    ]
}

Orders

Site-scoped order data.

List orders across your granted sites

Keyset-paginated (never OFFSET-based) listing of orders, ordered by (placedOn, orderNumber). Follow nextCursor to page through the full result set; see the getting-started guide for a complete pagination loop.

Authorizations:
oauth2mtls
query Parameters
siteId
integer

Restrict the result to a single site. Must be one of the sites already listed in your GET /v1/me response. A siteId outside your grant is rejected as a bad request -- it is never silently ignored (which would widen the result back to all your sites) and never returns an empty page (which would look like a legitimate site with zero orders).

status
string

Restrict the result to orders with this exact status value.

cursor
string

Opaque pagination token from a previous response's nextCursor. Treat this as an opaque string: do not parse it, do not construct one yourself, and do not rely on its format, length, or encoding staying the same across releases. Pass it back exactly as received.

limit
integer [ 1 .. 200 ]
Default: 50

Page size. Defaults to 50. Values above 200 are capped at 200, not rejected.

Responses

Response samples

Content type
application/json
{
  • "orders": [
    ],
  • "nextCursor": "eyJ0IjoxNzc5MDMyMTI1MDAwLCJpIjoxMDAwMjM0fQ"
}

Get a single order by number

Returns the order only if it belongs to one of your granted sites. An order that exists in a site you cannot see returns the identical 404 order_not_found as an order number that does not exist at all -- see "Scoping and the 404-vs-403 rule" above.

Authorizations:
oauth2mtls
path Parameters
orderNumber
required
integer

Responses

Response samples

Content type
application/json
{
  • "orderNumber": 0,
  • "status": "string",
  • "placedOn": "2019-08-24T14:15:22Z",
  • "updatedOn": "2019-08-24T14:15:22Z",
  • "shippedOn": "2019-08-24T14:15:22Z",
  • "purchaseOrder": "string",
  • "projectName": "string",
  • "siteId": 0,
  • "totals": {
    },
  • "closed": true
}