> Part of [WHCC Developer Documentation](https://www.whcc.com/developer/llms.txt)

# V1 Webhook Format

WHCC sends webhook notifications in one of two payload formats, depending on when your integration was set up. This page documents the legacy **V1** format. If your integration receives JSON request bodies, see [Webhook Types](https://www.whcc.com/developer/docs/order-submit-api/webhook-types/index.html.md) for the V2 format instead.

> If you are not sure which version your integration receives, check the `Content-Type` header on an incoming webhook request. V1 is `application/x-www-form-urlencoded`. V2 is `application/json`.

## Content type and body shape

V1 webhook requests are sent with `Content-Type: application/x-www-form-urlencoded`. The body is a single query-string-style line with the following fields, always in this order:

```plaintext
Message=…&EntryId=…&ConfirmationId=…&SequenceNumber=…&Reference=…&EventId=…&json=…
```

| Field | Meaning |
| Message | Human-readable summary of the event. Format varies by EventId; see examples below. |
| EntryId | The entry identifier from your original order request. |
| ConfirmationId | WHCC's identifier for the confirmation this order belongs to. Not unique per order &mdash; split orders share it. Use it together with SequenceNumber and the event type as your deduplication key. |
| SequenceNumber | The sequence number from your original order request. When WHCC splits an order, each resulting order gets a suffixed value (for example "1" and "1.2"), which is what distinguishes orders sharing a ConfirmationId. |
| Reference | The reference value from your original order request. |
| EventId | The event, one of: order.received, order.shipped, image.upload. That is the complete list &mdash; V1 integrations never receive order-cancellation webhooks. Cancellations are V2-only. If you need them, migrate to V2. |
| json | A JSON-serialized copy of the same fields, structured for programmatic parsing. |

> ## Only `json` is URL-encoded
>
> The `json` field's value is properly percent-encoded, as you'd expect for a form-urlencoded body. The other top-level fields (`Message`, `EntryId`, `ConfirmationId`, `SequenceNumber`, `Reference`, `EventId`) are **not** encoded &mdash; they are written out with literal spaces, colons, semicolons, and braces. If `Message` itself contains an unescaped `&` or `=` (for example, an embedded URL with a query string), a naive form parser that blindly splits the whole body on `&` and `=` will misparse it.
>
> Parse the `json` field for reliable, structured access to every field on that same notification. Treat `Message` as a display string only, and don't rely on splitting the raw body around it.

## Example: `order.received`

Sent when WHCC accepts an order.

```plaintext
Message=Order Received at WHCC;OrderNumber: 99000214&EntryId=SP-20481193&ConfirmationId=72e6ebbb-b29f-4fb6-ae2b-03bd9c4c1c34&SequenceNumber=1&Reference=SP-20481193 Prints&EventId=order.received&json=%7B%22EventId%22%3A%22order.received%22%2C%22Message%22%3A%7B%22OrderNumber%22%3A%2299000214%22%2C%22Status%22%3A%22Received%22%7D%2C%22ConfirmationId%22%3A%2272e6ebbb-b29f-4fb6-ae2b-03bd9c4c1c34%22%2C%22EntryId%22%3A%22SP-20481193%22%2C%22Reference%22%3A%22SP-20481193+Prints%22%2C%22SequenceNumber%22%3A%221%22%7D
```

The `json` field, decoded:

```json
{
	"EventId": "order.received",
	"Message": {
		"OrderNumber": "99000214",
		"Status": "Received"
	},
	"ConfirmationId": "72e6ebbb-b29f-4fb6-ae2b-03bd9c4c1c34",
	"EntryId": "SP-20481193",
	"Reference": "SP-20481193 Prints",
	"SequenceNumber": "1"
}
```

## Example: `order.shipped`

Sent when an order (or part of an order) ships.

```plaintext
Message=Order has shipped;OrderNumber: 99000530;Carrier: USPS;ShipDate: 6/2/2026 10:14:27 AM CST;Tracking: {9400111899561234567890}&EntryId=SP-20481594&ConfirmationId=4853ef91-2f6c-40e9-8258-33910a511467&SequenceNumber=1&Reference=SP-20481594 Prints&EventId=order.shipped&json=%7B%22EventId%22%3A%22order.shipped%22%2C%22Message%22%3A%7B%22Carrier%22%3A%22USPS%22%2C%22OrderNumber%22%3A%2299000530%22%2C%22Status%22%3A%22Shipped%22%2C%22ShipDate%22%3A%226%2F2%2F2026+10%3A14%3A27+AM+CST%22%2C%22Tracking%22%3A%22%5B%5C%229400111899561234567890%5C%22%5D%22%7D%2C%22ConfirmationId%22%3A%224853ef91-2f6c-40e9-8258-33910a511467%22%2C%22EntryId%22%3A%22SP-20481594%22%2C%22Reference%22%3A%22SP-20481594+Prints%22%2C%22SequenceNumber%22%3A%221%22%7D
```

The `json` field, decoded (note that `Tracking` is itself a JSON array, serialized to a string):

```json
{
	"EventId": "order.shipped",
	"Message": {
		"Carrier": "USPS",
		"OrderNumber": "99000530",
		"Status": "Shipped",
		"ShipDate": "6/2/2026 10:14:27 AM CST",
		"Tracking": "[\"9400111899561234567890\"]"
	},
	"ConfirmationId": "4853ef91-2f6c-40e9-8258-33910a511467",
	"EntryId": "SP-20481594",
	"Reference": "SP-20481594 Prints",
	"SequenceNumber": "1"
}
```

## Example: `image.upload`

Sent when WHCC finishes retrieving your submitted image assets &mdash; **whether or not anything went wrong**. `Status` tells you which happened, and is the only thing that distinguishes the two cases:

Parse `Status` as free text and do not assume a single error type. Do **not** treat the arrival of an `image.upload` webhook as meaning something failed.

```plaintext
Message=Image is missing on consumer site. AssetPath : http://images.example-partner.com/Rendering/Full?orderProductId=999000417&h=8021&EntryId=30887421&ConfirmationId=45628cc7-134e-46c3-9e5e-fe0d1a9f55bd&SequenceNumber=14205817&Reference=30887421-701&EventId=image.upload&json=%7B%22EventId%22%3A%22image.upload%22%2C%22Message%22%3A%7B%22Status%22%3A%22Image+is+missing+on+consumer+site.+AssetPath+%3A+http%3A%2F%2Fimages.example-partner.com%2FRendering%2FFull%3ForderProductId%3D999000417%26h%3D8021%22%7D%2C%22ConfirmationId%22%3A%2245628cc7-134e-46c3-9e5e-fe0d1a9f55bd%22%2C%22EntryId%22%3A%2230887421%22%2C%22Reference%22%3A%2230887421-701%22%2C%22SequenceNumber%22%3A%2214205817%22%7D
```

The `json` field, decoded &mdash; and the example above of why you should parse it instead of the raw body: the `AssetPath` URL's own `&h=8021` query parameter would be mistaken for a top-level form field by a naive `&`-splitting parser.

```json
{
	"EventId": "image.upload",
	"Message": {
		"Status": "Image is missing on consumer site. AssetPath : http://images.example-partner.com/Rendering/Full?orderProductId=999000417&h=8021"
	},
	"ConfirmationId": "45628cc7-134e-46c3-9e5e-fe0d1a9f55bd",
	"EntryId": "30887421",
	"Reference": "30887421-701",
	"SequenceNumber": "14205817"
}
```

The same `image.upload` event is also sent with `Status` set to the literal string `"Assets Downloaded"`. This means the asset-download step finished with **no errors recorded against that notification**. It is not a follow-up to an earlier failure, and it does not indicate that a previously missing asset has since been retrieved &mdash; the two are unrelated events. Do not treat `"Assets Downloaded"` as clearing a failure you were told about earlier.

> **Only the first error is reported.** When several assets fail on one order, the `image.upload` payload names just one of them. Fixing the asset in the message does not mean the order is clear &mdash; re-check every asset you submitted.

> ## What's Next
>
> [Delivery, Retries & Idempotency](https://www.whcc.com/developer/docs/order-submit-api/webhook-delivery/index.html.md) covers the retry schedule and why your deduplication key must be (`ConfirmationId`, `SequenceNumber`, event type).
>
> [Security and Signatures](https://www.whcc.com/developer/docs/order-submit-api/webhook-security/index.html.md) describes how V1 signatures differ from V2.