Skip to content

Sandbox

A test key (qk_test_...) belongs to a test integration. Its calls follow the same authentication, scopes, IP allowlist and rate limit as a live key, and the create runs the same field validation, but everything lands in a sandbox kept for your company:

  • Answers carry "livemode": false, and webUrl points to Settings > Integrations (a sandbox request has no page of its own).
  • A sandbox request never reaches the marketplace, never notifies anyone, is never counted in a dashboard or a fee, and is deleted after 30 days.
  • Sandbox records carry reference numbers of the live shape (REQ-, and QTE-, DEAL-, SHPT- once awarded), never a live record’s number.
  • Live and sandbox never see each other: a live key cannot read a sandbox request, and a test key cannot read a live one (404).

POST /sandbox/shipment-requests/{id}/advance moves a sandbox request one step along the life a real one has. It needs a test key with requests:write; a live key gets 403 (Integration.SandboxOnly) and nothing real ever moves.

Terminal window
curl "https://app.quatlasglobal.com/api/integrations/v1/sandbox/shipment-requests/<request-id>/advance" \
-H "Authorization: Bearer $QUATLAS_KEY" \
-H "Content-Type: application/json" \
-d '{ "step": "Published" }'
Step Allowed from What happens
Published Draft status becomes Published and publishedAt is set. A create with "publish": true already did this.
BidReceived Published bidCount goes up by one. Repeat as often as you like.
Awarded Published status becomes Awarded, awardedCarrierName is “Sandbox Carrier”, dealId is set and operationStatus becomes InProgress. bidCount is at least 1.
Delivered Awarded operationStatus becomes Delivered and deliveredAt is set.

The answer is the request’s status, the same body as GET /shipment-requests/{id}. A step from the wrong state answers 409 (Integration.SandboxTransition), with the reason in detail.

Once a sandbox request is Awarded, the deal routes answer for its dealId with fixed sample data, so you can build the reading side too:

Route Sandbox answer
GET /deals/{id}, GET /deals?... Your side Shipper, 1000.00 EUR, counterparty “Sandbox Carrier”, stage Live (Completed after Delivered).
GET /deals/{id}/tracking Loaded and Departed at the award, Delivered after Delivered; planned and current delivery 3 days after the award.
GET /deals/{id}/costs No additional costs; the totals are the contract amount, 1000.00 EUR, with additionalTotal and declaredTotal at 0.00.
GET /deals/{id}/documents The records of the documents a test key uploaded to the deal.
POST /deals/{id}/documents The file is checked and scanned like a live upload, then only its record is kept: the file is never stored.
GET /documents/{id}/download 409 (Integration.SandboxFileNotKept): the sandbox keeps no file.

PATCH /shipment-requests/{id} and POST /shipment-requests/{id}/cancel follow the live rules: the listing’s fields change only while the request is Published, field values are checked as live, your metadata, purchase order and cost centre change in any state, and an Awarded request answers 409 (Integration.RequestAwarded) with its sandbox dealId. The sandbox keeps no listing, so every listing field you send counts as changed. See Updating and cancelling.

A test integration can have webhook subscriptions. Each step sends the event it stands for, with "livemode": false, to the active subscriptions of the test integration that owns the request, and to nobody else:

Step Events
Create with "publish": true, or Published request.published
BidReceived request.bid_received
Awarded request.awarded, then deal.live
Delivered shipment.milestone (Delivered), then shipment.delivered
An update request.updated
A cancel request.cancelled
An upload document.uploaded