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

# Shipping

Version 1.7 &middot; Updated 2026-10-13

Every call to `POST /v1/commerce/submissions` and `POST /v1/commerce/submissions/calculate` needs a `shipping` object, and both accept the same values. The one difference is that `shipping.address` is optional on calculate, so you can price a basket before checkout collects an address (see [Response Bodies](https://www.whcc.com/developer/docs/api/responses/#calculate-no-address)).

## The `shipping` object

- **`address`** (object, required on submit): Where the order ships: `name`, `addr1`, `addr2`, `city`, `state`, `zip`, `country` (2-letter code), and optionally `attn` (an attention line), `email` and `phone`. There is no `company` field: sending one returns `400`. International destinations may also need a `phone` in E.164 format, for example `+15551234567`. Optional on calculate only.Every address needs `name`, `addr1` and `city`. Send `country` every time too: an address without one is read as a US address, not reported as incomplete. A US address also needs a 2-letter `state` and a `zip` of at least 5 characters. Outside the US, `state` and `zip` are optional. Submit with a field missing and you get a `400` (`submission.not_submittable`) with one `invalidParams[]` entry per field, named like `shipping.address.zip`. Calculate with a partial address still answers `200`, with `validation.isValidForSubmit: false` and the same entries in `validation.invalidParams[]`, so you can check an address before you submit. A `zip` under 5 characters or a 1-letter `state` also makes `isValidForSubmit` false, with an entry whose reason gives the length rule (`Must be at least 5 characters.`, `Must be 2 characters.`). See [what WHCC checks](https://www.whcc.com/developer/docs/api/shipping/#address-checks).
- **`type`** (string, optional): `dropship` ships straight to your customer. `studio` ships to you. Leave it out and it defaults to `dropship`, or follows `priority` when you send one: `studio_*` means `studio`, `dropship_*` means `dropship`. If you send both, they must agree. If your account can't use that type for these products, the request is rejected with a `400` naming `shipping.type`.Studio shipping goes to US and Canadian street addresses only: not to a PO Box, and not outside the US and Canada.
- **`priority`** (string, optional): The shipping method. Which methods a basket can use depends on the type, the address and the products in it, so take the value from `options.shipping[]` on a calculate response for that address ([see below](https://www.whcc.com/developer/docs/api/shipping/#options)). Leave it out and WHCC uses the least expensive method the destination offers. A priority from the other type, or one the destination doesn't offer, is rejected with a `400` (see the note at the end of this page).
- **`returnAddress`** (object, optional): The return address WHCC prints on the shipping label of a drop-ship order. Leave it out and the label carries the address on your WHCC account. See [Return address](https://www.whcc.com/developer/docs/api/shipping/#return-address).

## Which methods an address offers

Call calculate with the basket, `shipping.type` and the address, and no `priority`. The response prices the basket with the least expensive method for that destination, and `options.shipping[]` lists every method the address offers, each with its price:

```json
{
	"shippingType": "dropship",
	"shippingPriority": "dropship_lowest_cost",
	"options": {
		"shipping": [
			{ "id": "dropship_lowest_cost", "type": "dropship", "priority": "dropship_lowest_cost", "label": "Economy", "price": { "value": "7.95", "code": "USD" } },
			{ "id": "dropship_expedited", "type": "dropship", "priority": "dropship_expedited", "label": "Expedited", "price": { "value": "20.61", "code": "USD" } },
			{ "id": "dropship_one_day_standard", "type": "dropship", "priority": "dropship_one_day_standard", "label": "Standard One-Day", "price": { "value": "31.34", "code": "USD" } },
			{ "id": "dropship_one_day_priority", "type": "dropship", "priority": "dropship_one_day_priority", "label": "Priority One-Day", "price": { "value": "40.48", "code": "USD" } }
		]
	}
}
```

Show your customer the `label` and `price` of each entry. To ship with one of them, send its `priority` as `shipping.priority` on submit, with the same `type`. To take the cheapest, leave `priority` out. Either way, `shippingType` and `shippingPriority` on the response tell you what the order is using, and `totalPrice.subtotals.shipping.label` names it. See [Response Bodies](https://www.whcc.com/developer/docs/api/responses/#calculate).

A few things to expect from the list:

- It changes with the destination, and some destinations offer a single method. Don't carry a priority from one address to another; ask calculate again.
- A priority names a level of service, not a carrier or a delivery date. For a territory, Canada or another country the `label` can name the carrier.
- Calculate without an address returns no `options.shipping[]`, because the choices depend on where the order is going (see [calculating with no address](https://www.whcc.com/developer/docs/api/responses/#calculate-no-address)).

## Return address on a drop-ship label

`shipping.returnAddress` is optional. A drop-ship label already carries the address on your WHCC account as its return address, so send this only to print a different one on an order, such as a studio you ship for or your own warehouse. There's no setting to turn on: when the field is present, WHCC uses it.

```json
{
	"type": "dropship",
	"priority": "dropship_lowest_cost",
	"address": {
		"name": "Jordan Rivera",
		"addr1": "100 Main Street",
		"city": "Minneapolis",
		"state": "MN",
		"zip": "55401",
		"country": "US"
	},
	"returnAddress": {
		"name": "Example Photo Co",
		"addr1": "250 Studio Lane",
		"addr2": "Suite 4",
		"city": "Eagan",
		"state": "MN",
		"zip": "55121",
		"country": "US",
		"phone": "5555550123"
	}
}
```

The rules:

- `name`, `addr1`, `city`, `state`, `zip` and `country` are required once you send the object. `addr2` and `phone` are optional.
- `country` must be `US`. WHCC prints return addresses for US senders only. If you ship from outside the US, leave `returnAddress` out and the label carries your account address.
- `phone`, if sent, is exactly 10 digits, with no spaces or punctuation: `5555550123`, not `555-555-0123`.
- Those are the only keys. Any other key, such as `attn` or `email`, returns `400` naming the key. This is stricter than `shipping.address`, and it is checked as soon as you send it: a bad `returnAddress` is a validation `400` on submit and on calculate alike, not an incomplete-address result on calculate.
- It is for drop-ship only. A studio order ships to you, so there is no label to change. With `shipping.type` set to `studio`, with a `priority` that starts with `studio_`, or with account shipping settings that resolve the order to studio, the request returns `400` with an `invalidParams[]` entry named `shipping.returnAddress`. Its reason reads `shipping.returnAddress is not allowed with studio shipping. Return addresses apply to drop-ship orders only; remove it, or use shipping settings that resolve to drop-ship.` A `studio_*` priority counts as studio even when `type` is `dropship`.
- Only the shipping label changes. Packing slips, inserts and notification emails do not use it. It doesn't change the shipping price or sales tax, which depend only on the destination.

Calculate accepts the same `shipping` object, so you can check a `returnAddress` before you submit. It returns the same `400`s, and its response doesn't echo the address. The submit response and `GET /v1/commerce/submissions/{submissionId}` return it as `returnAddress`, exactly as you sent it, and leave the key out when you sent none (see [Response Bodies](https://www.whcc.com/developer/docs/api/responses/#submission-root-fields)). With no `returnAddress`, the label carries your account address, which `GET /account` returns (see [Reading your account](https://www.whcc.com/developer/docs/api/fulfillment/#account)).

Coming from the Order Submit API? This is its `ShipFromAddress` with `FromAddressValue` set to `2`. There is no `FromAddressValue` field to send here. See [Order Request Schema](https://www.whcc.com/developer/docs/legacy/order-submit-api/order-request-schema/index.html.md) and the `shipFromAddress` field of the [Editor API order export](https://www.whcc.com/developer/docs/legacy/editor-api/order-export/index.html.md).

## When the price is final

Calculate gives you today's price for the items and address you send, but it doesn't hold that price. WHCC prices the order again when it places it, and that's the amount you're billed. For most US addresses the two match.

Some destinations price differently, and nothing in the response marks a value as provisional. [Response Bodies](https://www.whcc.com/developer/docs/api/responses/#submission-root-fields) covers how sales tax and destination fees appear.

## What WHCC checks on an address

Calculate and submit check that the required fields are present. They don't verify that the address exists, that the `zip` belongs to the `state`, or that `phone` and `email` are well formed. Validate the address in your own checkout before you send it.

- `country` left out or empty is treated as `US`, with no `invalidParams[]` entry for it. The US rules for `state` and `zip` then apply. A code that isn't a real country is not rejected: it is priced as an international destination.
- `country` and `state` are accepted in either case and returned as you sent them. Send codes, not names: a name such as `United States` or `Minnesota` returns `400`.
- Calculate puts no limit on the length of `name`, `addr1`, `addr2` or `city` and doesn't screen their characters: markup, emoji and control characters come back as sent. Labels print from the Windows-1252 character set (see [Metadata & Reference](https://www.whcc.com/developer/docs/api/metadata/#reference)), so send plain text that fits on a label.
- A `state` or `zip` WHCC can't place leaves sales tax as `"TBD"`. A `"TBD"` response doesn't carry the `submission.pricing.total_excludes_tax` guidance note.
- A US address with a PO Box in `addr1` is offered a single `dropship` method, and no `studio` method.

> **If you send both `type` and `priority`, make them agree.** A priority belongs to the type in its name: `dropship_*` to `dropship`, `studio_*` to `studio`. A pair that disagrees is rejected with a `400` whose `invalidParams[]` names both `shipping.type` and `shipping.priority`. A value that isn't shaped like any priority is rejected the same way, naming `shipping.priority`.
>
> A well-formed priority that the destination doesn't offer (one from a Canadian address sent with a US address, say) is also rejected once you've sent an address: `400` with `code: "submission.shipping_priority_unsupported"`, and the reason lists the priorities of the same shipping type that are available, if there are any. The list can be missing even when other priorities are on offer. Calculate without an address never fails this check. To avoid it, [ask calculate](https://www.whcc.com/developer/docs/api/shipping/#options) what the address offers and pick from that.

> ### What's Next
>
> See the submission shape this produces on [Response Bodies](https://www.whcc.com/developer/docs/api/responses/#submission), or how to carry your own order identifiers alongside it on [Metadata & Reference](https://www.whcc.com/developer/docs/api/metadata/index.html.md).