Events
The envelope
Section titled “The envelope”Every event has the same five fields:
| Field | Type | Meaning |
|---|---|---|
id |
UUID | The event’s id, also in the Quatlas-Event-Id header. The same fact told to the same company always has the same id: dedupe on it. |
type |
string | The event’s type, also in Quatlas-Event-Type. |
occurredAt |
date-time (UTC) | When the fact became true. |
livemode |
boolean | false for a sandbox event and for webhook.test. |
data |
object | The records the event is about, and the few facts its type carries. |
data always has seven identifying fields, each null when it does not apply:
| Field | Type | Meaning |
|---|---|---|
shipmentRequestId |
UUID or null | The request. |
requestNumber |
string or null | The request’s reference number (REQ-048213). |
externalReference |
string or null | Your own reference for the request, only when your company owns it (the shipper side). |
dealId |
UUID or null | The deal, once there is one. |
dealNumber |
string or null | The deal’s reference number (DEAL-206447), once there is one. |
quoteNumber |
string or null | The winning quote’s reference number (QTE-731905) once there is a deal; on request.bid_received, the offer that arrived. |
shipmentNumber |
string or null | The operation’s reference number (SHPT-012618), once the deal went live. |
Bodies are thin on purpose: never a price, a party’s name, a place or a document’s content. Read the details through the API, with the scope named below.
When the event is sent to the company that owns the request and the request has metadata, data also carries metadata, your own fields. It is never sent to anyone else: the carrier’s deliveries of the same deal never carry it.
Catalogue
Section titled “Catalogue”| Event | Sent when | Sent to | Extra data |
Read more with |
|---|---|---|---|---|
request.published |
A request went out to the market. | The request’s owner | GET /shipment-requests/{id} (requests:read) |
|
request.bid_received |
An offer arrived on a request. | The request’s owner | bidCount |
GET /shipment-requests/{id} (requests:read) |
request.awarded |
A request was awarded and a deal opened. | The request’s owner and the carrier whose offer won | GET /deals/{id} (deals:read) |
|
request.cancelled |
A request was cancelled, in the app or through the API. | The request’s owner | reason |
GET /shipment-requests/{id} (requests:read) |
request.updated |
A request’s listing was amended (in the app or through the API), or its metadata, purchase order or cost centre changed through the API. One update through the API raises one event, naming everything it moved. | The request’s owner | changedFields, revision |
GET /shipment-requests/{id} (requests:read) |
deal.live |
The closing room finished and the operation started. | Both parties | GET /deals/{id} (deals:read) |
|
shipment.milestone |
A milestone was recorded. | Both parties | milestoneType, milestoneAt |
GET /deals/{id}/tracking (tracking:read) |
shipment.eta_changed |
The carrier revised the delivery estimate. | Both parties | GET /deals/{id}/tracking (tracking:read) |
|
shipment.delivered |
The run ended with the goods handed over, in whole or in part. | Both parties | GET /deals/{id}/tracking (tracking:read) |
|
document.uploaded |
A document was uploaded to a deal. | Both parties | documentId, category |
GET /deals/{id}/documents (documents:read) |
cost.approved |
An additional cost was approved. | Both parties | GET /deals/{id}/costs (costs:read) |
|
invoice.issued |
A commission invoice was issued to your company. | The invoice’s recipient only | invoiceId, invoiceNumber |
In the app (v1 has no invoice endpoint) |
webhook.test |
Someone pressed Send test. | The subscription tested | subscriptionId, integrationId |
A subscription names the event types it wants; webhook.test is never subscribed to, it is sent on request. New event types can be added within v1; a type is never removed or renamed. Ignore types you do not know.
Extra fields
Section titled “Extra fields”| Field | In | Type | Meaning |
|---|---|---|---|
bidCount |
request.bid_received |
integer | Open offers on the request right now. A count only: never who made an offer or what it was. |
reason |
request.cancelled |
string or null | The reason the owner gave, if any. |
changedFields |
request.updated |
array of strings | What moved: origin, destination, transportMode, modePolicy, cargo, schedule, incoterm or notes (the listing), purchaseOrderNumber, costCenter or metadata (your bookkeeping). |
revision |
request.updated |
integer | The listing’s revision after the change; it moves only when the listing changes. |
metadata |
Any event sent to the request’s owner | object of strings | Your metadata on the request, when it has some. Never sent to another company. |
milestoneType |
shipment.milestone |
string | Loaded, Departed, Arrived, InTransit, AtCustoms, ModeHandover, OutForDelivery, Delivered or Exception. |
milestoneAt |
shipment.milestone |
date-time (UTC) | When the milestone happened. |
documentId |
document.uploaded |
UUID | The document, for GET /documents/{id}/download. |
category |
document.uploaded |
string | The document’s category, for example CommercialInvoice, PackingList or BillOfLading. |
invoiceId |
invoice.issued |
UUID | The invoice. |
invoiceNumber |
invoice.issued |
string | The invoice’s number. |
subscriptionId |
webhook.test |
UUID | The subscription that was tested. |
integrationId |
webhook.test |
UUID | Its integration. |
New fields can be added to data within v1. Ignore the ones you do not know.
Examples
Section titled “Examples”{ "id": "<event-id>", "type": "request.bid_received", "occurredAt": "2026-10-13T10:02:11Z", "livemode": true, "data": { "shipmentRequestId": "<request-id>", "requestNumber": "REQ-048213", "externalReference": "EBA-2026-000123", "dealId": null, "dealNumber": null, "quoteNumber": "QTE-731905", "shipmentNumber": null, "bidCount": 3 }}{ "id": "<event-id>", "type": "request.updated", "occurredAt": "2026-10-13T11:15:42Z", "livemode": true, "data": { "shipmentRequestId": "<request-id>", "requestNumber": "REQ-048213", "externalReference": "EBA-2026-000123", "dealId": null, "dealNumber": null, "quoteNumber": null, "shipmentNumber": null, "changedFields": ["cargo", "schedule"], "revision": 2, "metadata": { "costCenter": "LOJ-210" } }}{ "id": "<event-id>", "type": "request.awarded", "occurredAt": "2026-10-14T09:02:10Z", "livemode": true, "data": { "shipmentRequestId": "<request-id>", "requestNumber": "REQ-048213", "externalReference": null, "dealId": "<deal-id>", "dealNumber": "DEAL-206447", "quoteNumber": "QTE-731905", "shipmentNumber": null }}{ "id": "<event-id>", "type": "document.uploaded", "occurredAt": "2026-10-15T13:20:05Z", "livemode": true, "data": { "shipmentRequestId": "<request-id>", "requestNumber": "REQ-048213", "externalReference": "EBA-2026-000123", "dealId": "<deal-id>", "dealNumber": "DEAL-206447", "quoteNumber": "QTE-731905", "shipmentNumber": "SHPT-012618", "documentId": "<document-id>", "category": "PackingList" }}{ "id": "<event-id>", "type": "webhook.test", "occurredAt": "2026-10-13T08:00:00Z", "livemode": false, "data": { "subscriptionId": "<subscription-id>", "integrationId": "<integration-id>" }}The generated API reference lists every event with its headers.
