Buy a Label from a Selected Rate
Spend a Rate identifier on a Shipment and get back the Label identifier every later Label operation accepts.
What you'll build
- One purchase request carrying nothing but the Rate you chose.
- The Label identifier, read from the right field of the response.
- A branch for the case where the purchase is still running when the response arrives.
Prerequisites
- An access token — see Authentication.
- A
shipmentIdand arate.id, both from Create an Order and Get Rates in One Call. - Python examples use the
requestspackage.
Step 1 — Purchase the Label
POST/api/v1/shipments/{shipmentId}/labels
The body is the selected Rate, nested. Nothing else is sent.
{ "rate": { "id": "c4a1b2d3-4e5f-6a7b-8c9d-0e1f2a3b4c5d" } }
- cURL
- JavaScript
- Python
- Java
curl -s -X POST "${MAILHUB_API_BASE_URL}/api/v1/shipments/${SHIPMENT_ID}/labels" \
-H "Authorization: Bearer ${MAILHUB_ACCESS_TOKEN}" \
-H "Content-Type: application/json" \
-d '{"rate": {"id": "'"${SELECTED_RATE_ID}"'"}}'
const response = await fetch(
`${process.env.MAILHUB_API_BASE_URL}/api/v1/shipments/${shipmentId}/labels`,
{
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.MAILHUB_ACCESS_TOKEN}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({rate: {id: selectedRateId}}),
},
);
if (response.status === 202) {
// Still running. Recover through the Order rather than purchasing again.
return {pending: true};
}
const {data} = await response.json();
// data.id is the Shipment. The Label is the nested one.
const labelId = data.postageLabel.id;
import os
import requests
response = requests.post(
f"{os.environ['MAILHUB_API_BASE_URL']}/api/v1/shipments/{shipment_id}/labels",
headers={"Authorization": f"Bearer {os.environ['MAILHUB_ACCESS_TOKEN']}"},
json={"rate": {"id": selected_rate_id}},
)
if response.status_code == 202:
# Still running. Recover through the Order rather than purchasing again.
label_id = None
else:
data = response.json()["data"]
# data["id"] is the Shipment. The Label is the nested one.
label_id = data["postageLabel"]["id"]
// Java 11+ java.net.http — no MailHub package to install and no third-party client.
var request = HttpRequest.newBuilder()
.uri(URI.create(System.getenv("MAILHUB_API_BASE_URL")
+ "/api/v1/shipments/" + shipmentId + "/labels"))
.header("Authorization", "Bearer " + System.getenv("MAILHUB_ACCESS_TOKEN"))
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(
"{\"rate\":{\"id\":\"" + selectedRateId + "\"}}"))
.build();
HttpResponse<String> response = HttpClient.newHttpClient()
.send(request, HttpResponse.BodyHandlers.ofString());
if (response.statusCode() == 202) {
// Still running. Recover through the Order rather than purchasing again.
} else {
// Parse response.body() with your own JSON library. The root data.id is the
// Shipment; the Label identifier is the nested data.postageLabel.id.
}
Response
A 200 means the purchase completed. Trimmed to the two identifiers that
matter:
{
"success": true,
"data": {
"id": "b91a2c3d-4e5f-6a7b-8c9d-0e1f2a3b4c5d",
"orderId": "5f2c1a10-2b3d-4e5f-8a9b-0c1d2e3f4a5b",
"postageLabel": {
"id": "f6c7d8e9-0a1b-4c2d-8e3f-4a5b6c7d8e9f",
"...": "..."
},
"...": "..."
},
"errors": null
}
Use this next
data.postageLabel.id — keep it. It is the path parameter for
Download a Label File:
GET /api/v1/labels/f6c7d8e9-0a1b-4c2d-8e3f-4a5b6c7d8e9f/download
Expected result
A 200 carrying a Shipment whose postageLabel.id is your new Label — or a
202, which is not a failure.
Common outcomes
| Status | What it means | What to do |
|---|---|---|
200 | The purchase completed. | Use data.postageLabel.id as the Label identifier. |
202 | The purchase is still running. | Do not start a replacement purchase. Continue with Recover a Label Purchase After 202. |
409 | A different purchase is already active, or the Shipment already has a Label. | Correct the request or read the Order. Do not send it again unchanged. |
422 | The purchase cannot proceed as requested. | Inspect the response and correct the request — see Label Errors. |
400, 401, 403, 404, and 500 follow the standard public error
envelope — see Error Handling.
Sending the same purchase again
Sending the same effective purchase request again replays or awaits the
existing purchase outcome instead of purchasing a second Label: 200 with the
original result once it has completed, 202 while it is still running.
The request carries no key that makes this so, and the behavior has bounded exceptions — Buy a Label has the full treatment. Treat repetition as safe only within your own bounded budget, and never as a loop.
Next steps
- Recover a Label Purchase After 202 — when the response arrives before the purchase does.
- Download a Label File — spend the Label identifier you just kept.
- Create shipping label in the API Reference — the complete request and response schema.
- Buy a Label — prerequisites, repeat semantics, and every documented failure.