Skip to content

Ship an order

Open .md

Read first: Shipping, for shipments, labels and the packages they make.

A shipment sends some or all of a sales order’s lines to one address. Buying or recording a label makes its packages, one per parcel. You can buy labels through GoShippo, if your team has connected it, or record labels you bought elsewhere.

  1. 1. Create a shipmentFor one address on a sales order
  2. 2. Add the lines to shipSome or all of the order’s lines
  3. 3. Get ratesLive GoShippo rates for each carrier and service
  4. 4. Buy or record the labelBuying spends your team’s GoShippo money. Either way, the label makes the packages
  5. 5. Print the labelsDownload them as PDFs
  6. 6. Track and finishFollow the tracking and finish the shipment
Step 4 spends money: have a person approve the carrier, service and price first.
POST Create a shipment for a sales order /v2/api/store/{team_slug}/v2/sales_order/{unique_key}/shipment
Terminal window
curl https://secure.yoprint.com/v2/api/store/your-team/v2/sales_order/V4keXwwxMQyXw7/shipment \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Accept: application/json" \
-H "X-Yoprint-Decimal-Format: exact-v1" \
-H "Content-Type: application/json" \
-d '{
"operation_key": "order-1001-shipment-1",
"shipping_address_id": "cwwkmbgJK3eE5A",
"delivery_notes": "Leave at the loading dock"
}'
  • shipping_address_id is one of the customer’s shipping addresses.
  • operation_key is optional and makes this create safe to retry: sending the same key with the same body returns the shipment it already made, instead of a second one. The same key with a different body is refused.

To list an order’s shipments, use the order’s id (not its unique key):

GET List the shipments of a sales order /v2/api/store/{team_slug}/v2/sales_order/{unique_key}/shipment

A shipment line points at an order line, by the order line’s id, with how many go in this shipment. Here, 24 of an order line:

POST Add a line to a shipment /v2/api/store/{team_slug}/v2/shipment/{unique_key}/item
{
"product": { "type": "order_item", "properties": { "id": "ZJTJ2uF5dMiArL" } },
"quantity": { "type": "unit", "total": { "value": 24, "dp": 0 } },
"position": 100
}
  • The path’s {unique_key} is the shipment’s id, from step 1’s answer.
  • The rest of the line ships later, in another shipment.

To add, change or remove several lines at once:

POST Add, change and remove shipment lines at once /v2/api/store/{team_slug}/v2/shipment/{unique_key}/item/bulk

Ask GoShippo for rates. This is free: nothing is bought, and nothing is saved in YoPrint.

POST Get shipping rates /v2/api/store/{team_slug}/v2/shipment_rate/goshippo

The rate request isn’t tied to the YoPrint shipment. You send both addresses and the parcels yourself, YoPrint doesn’t compare them with the shipment, and the label is bought for exactly what you send here.

  1. address_fromThe brand profile’s Ship From, or your company location, with its own name and the team’s email and phone
  2. address_toThe shipment’s Ship To address, with the receiver contact’s name, email and phone
  3. parcelsOne per box: dimensions, weight and units
  4. RatesEach rate’s object_id is what you buy in step 4
You build each part from the shipment's records, the way the web app does.

Where each part comes from:

Part Read Take
address_to The shipment’s shipping_address_id (a customer address) and receiver_contact_id The street, city, state, postcode and country from the address. email and phone from the contact. name from the contact, or else the address’s label
address_from The shipment’s customer_profile_id, the brand profile, when it’s set. Otherwise your company location and the team’s settings The profile’s Ship From address, company name, email and phone. Or the location’s own address and name, with the team’s email and phone (locations have no email or phone of their own)
parcels Nothing: they’re your boxes One entry per box: its dimensions, weight and units

The shipment names these records by id but doesn’t include them, so read it first, then each record:

The reads, and YoPrint’s address fields in Shippo’s namesGET Get a shipment /v2/api/store/{team_slug}/v2/shipment/{unique_key}GET Get a customer address /v1/api/store/{team_slug}/customer/{hash_id}/address/{id}GET Get a contact by id /v1/api/store/{team_slug}/contact/{id}GET Get a brand profile /v1/api/store/{team_slug}/customer/{hash_id}/profile/{id}GET List company locations /v1/api/store/{team_slug}/setting/locationGET Get your company details /v1/api/store/{team_slug}/setting/detail
YoPrint address Shippo address
address1 street1
address2 street2
city city
state_code state, as a code such as TX
postcode zip
country_code country, as a code such as US
From the contact, brand profile or team name, phone, email

Then ask for rates:

Terminal window
curl https://secure.yoprint.com/v2/api/store/your-team/v2/shipment_rate/goshippo \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "X-Yoprint-Decimal-Format: exact-v1" \
-d '{
"address_from": { "name": "Northwind Apparel", "street1": "100 Example Street", "city": "Austin", "state": "TX", "zip": "78701", "country": "US", "phone": "+1 201 555 0123" },
"address_to": { "name": "Alex Rivera", "street1": "200 Example Street", "city": "Denver", "state": "CO", "zip": "80202", "country": "US", "email": "alex@example.com" },
"parcels": [{ "length": 12, "width": 10, "height": 4, "distance_unit": "in", "weight": 2, "mass_unit": "lb" }]
}'
  • Both addresses need name, street1, city, state, zip and country.
  • Options you want on the label, such as insurance or a signature, go in extra here. The purchase can’t add them later.
  • The answer is Shippo’s own shipment, with status 201 and without YoPrint’s usual status, success and data wrapper. Each entry in rates has an object_id: that’s the rate id you buy in step 4.
  • A rate’s amount is a decimal string, such as "12.40", in the rate’s currency (Shippo’s own format: parse it as a decimal). See Money and quantities.
  • A 201 can still have no rates. Check status and messages.

Rates are quotes. Buy soon after you get them. If a purchase fails because a rate is no longer valid, get rates again.

To save the rates on the YoPrint shipment, for a person to choose from later:

POST Save a shipping estimate /v2/api/store/{team_slug}/v2/shipment/{hash_id}/shipment_estimate/goshippo GET List the shipping estimates of a shipment /v2/api/store/{team_slug}/v2/shipment/{hash_id}/estimates

The API has no approval step: the approval happens in your app. Show a person the rates (carrier, service and price), and buy only the one they choose. Before you buy, check:

  1. The rate’s address_from, address_to and parcels match the YoPrint shipment, its Ship To and its brand profile or location.
  2. A person approved the carrier, the service and the price.
  3. The order is a published sales order, your team has connected GoShippo, and your role can view the order (all orders, or your own and assigned ones).
POST Buy a shipping label (charges your Shippo account) /v2/api/store/{team_slug}/v2/shipment/{hash_id}/label/goshippo
Terminal window
curl https://secure.yoprint.com/v2/api/store/your-team/v2/shipment/2Q4hJk2S8JjRQ6/label/goshippo \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "X-Yoprint-Decimal-Format: exact-v1" \
-d '{ "rate_id": "RATE_OBJECT_ID_FROM_STEP_3", "create_shipping_cost_line_item": true }'

create_shipping_cost_line_item: true adds a “Shipping Cost” line to the shipment, priced at the label’s cost, so you can bill it. On an order with Auto Invoice, the line also reaches the invoice. Its price is a decimal pair, like every order line. Leave the field out and no line is added. The answer’s shipping_cost_line_item.status says what happened: created, existing, not_requested, skipped_third_party_billing (a third party pays for the label), or failed. A failed line doesn’t undo the purchase: the label is bought, so add the line yourself instead of buying again.

YoPrint refuses the purchase when:

  • The shipment belongs to a quote (“Shipping labels can’t be bought for a quote. Convert it to a sales order first.”).
  • The order isn’t published.
  • The team hasn’t connected GoShippo (422 with goshippo_not_enabled).
  • You sent a shipment_estimate_id that isn’t one of this shipment’s estimates.
  • Your role can’t view the order (403, user_is_not_authorized).

The answer lists the new packages, one per parcel. The first is the master package. Each package has the label, and its cost in charges, in thousandths: 12400 is 12.40 (see Money and quantities). Shippo quotes one price for all the parcels together, so every package of a multi-parcel shipment carries that same total. Read the master package’s charges. Don’t add the packages up.

Merge the labels of up to 40 packages into one PDF to print. Take the packages’ ids from the shipment’s package list:

GET List the packages of a shipment /v2/api/store/{team_slug}/v2/shipment/{hash_id}/packages POST Download labels as one PDF /v2/api/store/{team_slug}/v2/shipment_package/labels/compile
{ "shipment_package_ids": ["o6foWpSAayc79D", "UDsG6yjZAVrRNv"] }

The answer is the PDF itself. Packages without a GoShippo label are skipped.

If you bought postage outside YoPrint, record the label on the shipment. This doesn’t spend anything through YoPrint:

POST Record a label bought elsewhere /v2/api/store/{team_slug}/v2/shipment/{hash_id}/label/external PATCH Get live tracking for a package /v1/api/store/{team_slug}/shipment_package/{id}/track

Move the shipment through its statuses as it ships:

PUT Change the status of a shipment /v2/api/store/{team_slug}/v2/sales_order/{hash_id}/shipment/{id}/status GET List shipment statuses /v1/api/store/{team_slug}/setting/status/shipment

A status change fires shipment.status_changed. On an order synced from Shopify, moving to the final status can fulfil the order in Shopify.

Deleting a package asks Shippo to refund its label, in the background. Like buying, it needs permission to view the order, and so does the bulk package operation:

DELETE Delete a package (voids its label) /v2/api/store/{team_slug}/v2/shipment_package/{hash_id} POST Change and delete packages at once /v2/api/store/{team_slug}/v2/shipment/{unique_key}/package/bulk

Deleting the whole shipment needs permission to edit the order:

DELETE Delete a shipment /v2/api/store/{team_slug}/v2/shipment/{unique_key}

Shippo and the carrier can refuse the refund, and YoPrint doesn’t report a refused refund back. Check your Shippo account.

  • Labels cost money, and there’s no undo in the API. Confirm with a person before you buy.
  • Package charges repeat the multi-parcel total. On a multi-parcel label, each package’s charges shows the full rate cost in thousandths (12400 is 12.40), not a fraction of it. Read the master package. Don’t sum the packages. See Money and quantities.
  • No GoShippo labels on quotes or drafts. Convert the quote and publish the order first. A label bought elsewhere can be recorded on a draft sales order, but not on a quote.
  • Retries can buy twice. YoPrint’s guard lasts only 10 seconds from the first attempt’s start. Wait for each purchase’s answer, however long it takes, and read the packages before you retry, and never buy a fresh rate to “retry”.
  • Rates use the addresses you type. Build them from the shipment and your location, and compare before you buy.
  • Seeing the order is enough to buy. Any role that can view the order can buy its labels, even without edit rights. Limit who holds keys.
  • Deleting a package only asks for a refund. It may be refused.
  • List shipments by the order’s id. With the order’s unique key, the list comes back empty.
  • Use operation_key on shipment creates so a retry doesn’t make a second shipment.