Legacy This page is reference for integrations already built on the Order Submit API. It remains supported. New integrations use the WHCC API.
There are two types of webhook to expect, Status and Event. This page documents the V2 (JSON) payload format. If your integration receives application/x-www-form-urlencoded bodies instead of JSON, you're on the legacy V1 format — see V1 Webhook Format.
Every notification below can be sent more than once for the same order. Key on (ConfirmationId, SequenceNumber, event type) before acting on a notification — ConfirmationId alone is shared between the halves of a split order — and treat a repeat as a reconcile rather than a discard, because a later delivery can carry more data than the earlier one. See Delivery, Retries & Idempotency.
Four fields appear on every notification below and together identify what the notification is about:
| Field | Meaning |
|---|---|
ConfirmationId |
The confirmation the notification belongs to. Not unique per order — when an order is split, the resulting orders share it. |
SequenceNumber |
Distinguishes orders that share a ConfirmationId. A split produces suffixed values such as "1" and "1.2", each with its own OrderNumber and its own tracking. |
EntryId |
Your own reference for the order, echoed back as submitted. |
EventType |
What happened, as a single unambiguous name: order.accepted, order.rejected, order.shipped or order.cancelled. Always the last field in the body. |
EventType, not on EventEvent alone does not name the event. An accepted order and a rejected one both arrive as "Event": "Processed", and only Status separates them — so any code that switches on Event by itself treats a rejection as an acceptance. EventType is the single field that tells them apart, and it is the same vocabulary you use to select events when subscribing.
EventType |
Arrives as |
|---|---|
order.accepted |
"Event": "Processed" with "Status": "Accepted" |
order.rejected |
"Event": "Processed" with "Status": "Rejected" |
order.shipped |
"Event": "Shipped" |
order.cancelled |
"Event": "Order Cancelled" |
EventType is always last, and nothing else changed. Every field before it keeps the same name, value and position it had before the field existed — nothing was removed, renamed, reordered or reformatted. The body is not byte-identical, because the property that used to be last now ends with a comma and the closing brace moved to the end; what is stable is the fields and their values.
⚠️ Whether your integration keeps working depends on how it handles unknown fields. A parser that ignores them is unaffected. A parser configured to reject them fails on every version 2 delivery — and some libraries reject by default, notably Jackson, whose FAIL_ON_UNKNOWN_PROPERTIES is on unless you turn it off. Configure yours to ignore unknown fields: more may be added the same way.
A V1 delivery never carries EventType. The key does not appear at all. V1 has its own EventId field, and it is a different vocabulary — order.received there means order.accepted here. Do not match the two on the strength of them both having a dot in them. See V1 Webhook Format.
The status webhook lets you know if your order has been completely accepted or rejected. It is possible for an order to be rejected if there is an issue accessing the image assets included in the order request JSON.
1
2
3
4
5
6
7
8
9
10
11
{
"Status": "Accepted",
"Errors": [],
"OrderNumber": 99000341,
"Event": "Processed",
"ConfirmationId": "f245d035-0c0d-446c-81f4-dbe1e2802801",
"EntryId": "1687452093",
"Reference": "1298447712",
"SequenceNumber": "0",
"EventType": "order.accepted"
}
A rejected order has no OrderNumber, since one was never assigned.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
{
"Status": "Rejected",
"Errors": [{
"ErrorCode": "400.01",
"Error": "Image hash value doesn't match, order canceled.",
"AssetPath": "https://images.example-partner.com/27aa22c4-4cf4-44c8-b80a-ad1f80540443.jpg"
}],
"Event": "Processed",
"ConfirmationId": "da99f6f0-2ba7-4bee-a348-8f5ba59fed77",
"EntryId": "c2496f39-849d-4017-a9bf-a43c646b7f88",
"Reference": "EP-Q-c2496f39",
"SequenceNumber": "1",
"EventType": "order.rejected"
}
See Errors for the full list of ErrorCode values.
The event webhook lets you know about a change in production status of your order. The Event field tells you which one you received: Shipped or Order Cancelled. Look for a specific event value when processing this webhook type — more may be added in the future.
Sent when an order (or part of an order) ships. ShippingInfo is an array of tracking entries. A multi-package order can arrive either way: as a single Shipped webhook whose ShippingInfo array holds several entries, or as several separate Shipped webhooks, one per package. Expect one or more Shipped webhooks per order, and process every entry in ShippingInfo — each webhook carries the complete tracking list known at the moment it was sent. That list grows: a second Shipped webhook with the same key, sent moments later, routinely carries additional tracking numbers as more packages are scanned. Merge ShippingInfo on repeat rather than discarding it, as described in Delivery, Retries & Idempotency.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
{
"ShippingInfo": [{
"Carrier": "FedEx",
"ShipDate": "2026-05-08T16:59:59-05:00",
"TrackingNumber": "9261200011223344556677",
"TrackingUrl": "https://www.fedex.com/fedextrack/?trknbr=9261200011223344556677",
"Weight": 1.0
}],
"OrderNumber": 99000918,
"Event": "Shipped",
"ConfirmationId": "a501c238-e91d-4766-853e-598dc6851338",
"EntryId": "prspctr-Zq8mWkTn3XcRpLFB6-301488-1",
"Reference": "ETSY_COM:5183660044-198372640551",
"SequenceNumber": "1",
"EventType": "order.shipped"
}
Weight is a float. Whole-pound shipments are still serialized with a decimal, e.g. 1.0, not 1.
Sent when an order is canceled. V2 integrations only — V1 integrations never receive this event.
1
2
3
4
5
6
7
8
9
{
"Event": "Order Cancelled",
"OrderNumber": 99000201,
"ConfirmationId": "f7889680-3aed-4dad-8942-090f6b3ce979",
"EntryId": "prspctr-Xk2mQTn7YRbLpEFA9-452193-1",
"Reference": "#1005-8091234567890",
"SequenceNumber": "1",
"EventType": "order.cancelled"
}
Delivery, Retries & Idempotency covers the retry schedule, timeout, and why you must deduplicate.
Security and Signatures describes the process to validate the callback requests