Skip to main content

Run a Shipping Workflow for a Sub-account

Take the same Order → Rates → Label path you already know, and scope the steps where scope actually changes the answer.

What you'll build

  • One Order created and tagged to a Sub-account.
  • Rates evaluated against that Sub-account's carrier availability.
  • A Label purchase evaluated the same way.
  • A deliberate decision to stop sending the header once it no longer does anything.

Account and Sub-account scope

A Sub-account is an application scope beneath the authenticated Account. You select it per request with the optional X-SubAccount-Id header. It is not a second credential: the same access token authenticates every request below, and record access is decided by Account ownership whether or not the header is sent.

Prerequisites

  • An access token — see Authentication.
  • A Sub-account identifier authorized for your Account. It is prepared in the authenticated Mailhub application; the public API publishes no operation that creates, lists, or edits one.
  • Your API base URL in MAILHUB_API_BASE_URL.
  • Python examples use the requests package.

Step 1 — Create the Order and request Rates, scoped

POST/api/v2/orders

Here the header does two things at once: it tags the created Order and its Shipments, and the Rates come back evaluated against that Sub-account's carrier availability.

curl -s -X POST "${MAILHUB_API_BASE_URL}/api/v2/orders" \
-H "Authorization: Bearer ${MAILHUB_ACCESS_TOKEN}" \
-H "X-SubAccount-Id: ${SUB_ACCOUNT_ID}" \
-H "Content-Type: application/json" \
-d '{
"order": {
"fromAddress": {
"name": "Jane Sender", "street1": "123 Main St", "city": "Austin",
"state": "TX", "zip": "78701", "country": "US", "phone": "5125550100"
},
"toAddress": {
"name": "John Recipient", "street1": "456 Oak Ave", "city": "Denver",
"state": "CO", "zip": "80202", "country": "US", "phone": "3035550100"
},
"shipments": [
{"parcel": {"weight": 16, "length": 10, "width": 8, "height": 4}}
]
}
}'

Response

Trimmed to what this workflow carries forward. The Order and its Shipments are tagged with the Sub-account you sent:

{
"success": true,
"data": {
"status": "created",
"order": {
"id": "5f2c1a10-2b3d-4e5f-8a9b-0c1d2e3f4a5b",
"status": "Created",
"...": "..."
},
"shipmentRates": [
{
"shipmentId": "b91a2c3d-4e5f-6a7b-8c9d-0e1f2a3b4c5d",
"rates": [
{
"id": "c4a1b2d3-4e5f-6a7b-8c9d-0e1f2a3b4c5d",
"carrier": "USPS",
"serviceName": "USPS Ground Advantage",
"rate": 8.42,
"currency": "USD",
"...": "..."
}
]
}
]
},
"errors": null
}

Step 2 — Buy the Label with the same scope

POST/api/v1/shipments/{shipmentId}/labels

Label purchase is the second operation whose contract gives the header an effect: the purchase is evaluated against the same Sub-account's carrier availability. Send the same value you used in Step 1.

curl -s -X POST \
"${MAILHUB_API_BASE_URL}/api/v1/shipments/${SHIPMENT_ID}/labels" \
-H "Authorization: Bearer ${MAILHUB_ACCESS_TOKEN}" \
-H "X-SubAccount-Id: ${SUB_ACCOUNT_ID}" \
-H "Content-Type: application/json" \
-d '{ "rate": { "id": "c4a1b2d3-4e5f-6a7b-8c9d-0e1f2a3b4c5d" } }'

Step 3 — Stop sending the header

Download and Cancel record NoEffect in the public contract. Sending X-SubAccount-Id on them changes nothing, so the scoped part of the workflow ends after the purchase:

curl -s -o label.pdf \
"${MAILHUB_API_BASE_URL}/api/v1/labels/${LABEL_ID}/download?format=1" \
-H "Authorization: Bearer ${MAILHUB_ACCESS_TOKEN}"

Continue with Download a Label File or Cancel a Label exactly as the unscoped Recipes show them.

Use this next

data.shipmentRates[].shipmentId and the chosen data.shipmentRates[].rates[].id — the same two values every Order-with-Rates workflow carries into the purchase. The Sub-account changes which Rates you had to choose from, not what you do with the one you picked.

Expected result

An Order tagged to 3a7d9e21-6b48-4c15-9f2e-7d0c5b83a614, a Label purchased from a Rate that Sub-account could see, and a download call that carries no scope header.

Common outcomes

StatusWhat it meansWhat to do
400The header value is not a well-formed identifier.Send a UUID string, or omit the header.
404The Sub-account does not exist or does not belong to your Account.Confirm the value against the authenticated Mailhub application.
409The Sub-account is not active.Correct the selected scope rather than resending unchanged.
Missing RateCarrier availability for that Sub-account did not produce the option.Compare against the same request with the header omitted.

401, 403, 422, and 500 behave exactly as they do without the header — see Error Handling.

Next steps