Skip to content

Metadata

metadata is a flat object of string keys to string values that your company keeps on a shipment request: a cost centre, a purchase order, an eBA process number, whatever your systems key the request by. It is your company’s private data: it comes back in your reads and in the webhooks sent to your company, and nowhere else.

Keys At most 20
A key 1 to 40 characters from A-Z, a-z, 0-9, _ and -
A value A string of 0 to 500 characters, without control characters such as U+0000 (tab, line feed and carriage return are fine)
In all 8 KB (keys and values, UTF-8)

Breaking a limit answers 400 with Integration.MetadataInvalid. The key that broke it is named in detail and in args.key, and nothing is written:

{
"title": "Integration.MetadataInvalid",
"status": 400,
"detail": "Metadata holds at most 20 keys; adding 'plant' makes 21.",
"code": "Integration.MetadataInvalid",
"args": { "key": "plant" }
}
{
"externalReference": "EBA-2026-000123",
"metadata": { "costCenter": "LOJ-210", "ebaProcess": "P-7781" },
"...": "the rest of the create body"
}

The metadata is kept with the request in the same step: a request created with metadata always has it. An empty object, or no metadata at all, means none.

PATCH /shipment-requests/{id} merges what you send into what is there, in any state of a request your systems created through the API (see Updating and cancelling):

You send Result
"metadata": { "plant": "Gebze" } plant is added or changed; the other keys stay.
"metadata": { "ebaProcess": null } ebaProcess is removed; the other keys stay.
"metadata": null Every key is removed.
No metadata field Nothing changes.

The limits apply to the result: adding a key to a request that already has 20 is refused. Two updates at the same moment are applied one after the other, each to what the other wrote: a key set by one is never lost to the other.

Every read of a request carries metadata, an empty object when there is none:

{
"id": "<request-id>",
"externalReference": "EBA-2026-000123",
"status": "Published",
"metadata": { "costCenter": "LOJ-210", "plant": "Gebze" },
"revision": 1,
"...": "the other status fields"
}

A webhook sent to the company that owns the request carries data.metadata when the request has some. It is never sent to anyone else: the carrier’s deliveries of the same deal never contain it. A change of metadata raises request.updated with metadata in changedFields.

Only your company, through the API. It is not shown to carriers, the marketplace, the other party of a deal, the Qai assistant, or any other company, and it is not shown in the app today. It is stored with the request under your company’s row-level security.

In the sandbox, metadata works the same way and is deleted with the sandbox request after 30 days.