POST requests when OVRSEA observes a change
to a shipment’s client-visible status.
Configure your endpoint
In Hermes, open API Integration → API → Shipment webhooks. For Lyseo/Fatton accounts without the API Integration menu, open Account settings → Shipment webhooks. An account owner or admin can save, replace, remove and test one URL for their own client account. The URL receives status events for that client’s shipments across ocean, air, rail and truck. Configuration requires direct access to that exact account; access through a parent, child or shared account does not grant this permission. OneChain and logistic-agent accounts cannot configure these webhooks. Accounts with an existing bespoke webhook integration must arrange its migration first. Use a publicly reachable HTTPS URL, for examplehttps://integrations.example.com/shipment-webhooks. Credentials in the URL,
query strings and fragments are rejected. Loopback, private, link-local,
metadata and reserved IP addresses are blocked, including addresses returned
by DNS. Redirects are not followed; configure the final destination.
Saving the URL makes it eligible for delivery immediately. Saving it sends no
historical snapshot or backfill. Replacing or removing it cancels pending work
for the former configuration, although a delivery attempt already in progress can finish
at the former URL.
Keep the signing secret
Creation and secret rotation show the new signing secret once. Copy it directly to your receiver’s secret store. Reading the configuration or replacing its URL does not reveal or rotate the secret. If you lose it, rotate it. The signing secret is separate from your REST API token; keep it out of URLs and logs. Rotation takes effect for future signing attempts, including retries. Each attempt uses the current secret. A request signed before rotation may still arrive with the previous key; coordinate receiver updates and, if needed, keep a short, bounded verification overlap for those requests. Rotation does not cancel pending deliveries.Event and payload
The supported event type isshipment.status_changed, with this V1 payload:
Every field is required. V1 contains no tracking details or previous status.
Cancellation uses
status: "cancelled" in the same event. Quotation-only states
are excluded. Status observations can fill intermediate progression stages,
but they do not form a complete history of business transitions.
shipmentId is not a file reference or the UUID used by the REST shipment and
tracking routes. Those routes do not accept this numeric internal ID.
Verify each request
Requests useContent-Type: application/json and these four webhook headers:
Compute HMAC-SHA256 with the signing secret’s UTF-8 bytes as the key. Use the
secret’s text as shown, even though it looks hexadecimal; do not hex-decode it.
The signed message is the UTF-8 header prefix followed by the exact raw body bytes:
eventId matches the header. The signed mode must be validated too.
We recommend rejecting timestamps more than five minutes in the past or future,
with synchronized receiver clocks. This tolerance is a receiver recommendation,
not a sender policy. Use the header timestamp, not emittedAt; retries have a
fresh timestamp and signature for the same event ID and body.
Node.js verification example
This Node.js example uses Zod for payload validation (npm install zod). Pass a
Headers instance and a Buffer containing the unmodified request body. In a
Node HTTP handler, capture bytes with buffer(request) from
node:stream/consumers before any JSON middleware; in a handler using a Web
Request, use Buffer.from(await request.arrayBuffer()). Configure request size
and read-time limits at your ingress or HTTP server.
test to
an acknowledgement without shipment updates, notifications or other business
effects. For live, complete the durable processing described below before
returning 2xx.
Acknowledge and handle duplicates
Store processedeventId values durably for this integration. Enforce uniqueness
and commit the event ID with its business changes in the same database
transaction. Concurrent requests must not apply the effect twice. An in-memory
set does not protect against restarts or multiple receiver instances. If the
effect calls another system, give that system a durable idempotency key based
on eventId before acknowledging completion.
Authenticate every attempt, including duplicates. An authenticated retry of an
already completed event should receive 2xx again without repeating its effect.
Do not permanently reject an event ID just because it was seen before: the
previous acknowledgement may have been lost. A stale or unauthenticated replay
must not trigger processing. If processing fails, leave it retryable and return
a non-2xx response rather than recording the event as completed.
Any 2xx acknowledges delivery; a small empty 204 response is sufficient.
Redirects, other status codes, timeouts and network failures do not acknowledge
it. DNS resolution and HTTP share a ten-second attempt budget, and the response
body is capped at 64 KiB.
Live deliveries have at most four attempts: the initial attempt and retries
eligible after 60, 600 and 3600 seconds from the preceding attempt’s completion.
Polling and backlog can delay them further, and a failed signing step can
consume an attempt. Delivery is best effort: ordering, capture of every status
transition and exactly-once receipt are not guaranteed. Handle duplicates and
avoid assuming that arrival order is shipment progression order.
Test your receiver
An owner or admin can send a test from Shipment webhooks after saving the URL. Enter the shipment file reference shown in Hermes, for exampleBB-ABCD-3. Hermes resolves it to the internal numeric shipment ID used by the
test request. The shipment must belong to the same exact client account;
visibility through a parent, child or shared account does not grant testing
permission. A REST shipment UUID is not a file reference. Choose a transport
shipment in a supported status; quotation-only states cannot be tested.
A test sends the selected shipment’s current status to your configured URL with
the signed X-Ovrsea-Webhook-Mode: test header. Each test has a fresh event ID,
uses the same verification steps as a live request and has one synchronous
attempt with no automatic retry. It does not change the shipment or activate
the endpoint. Your receiver must acknowledge it without business effects.
The test result shows success or failure, attempt time, HTTP status when
available, duration and a sanitized error category. Check these alongside your
receiver’s acknowledgement and durable processing records; the remote response
body is not shown.