Download a Label File
Turn a Label identifier into a file on disk. The successful response is binary, not the JSON envelope every other operation returns.
What you'll build
- One request that asks for the Label as a PDF.
- A binary write path that never touches a JSON parser.
- A check that separates a ready file from one that is still being generated.
Prerequisites
- An access token — see Authentication.
- A Label identifier —
data.postageLabel.idfrom Buy a Label from a Selected Rate, ordata.labelIdfrom Recover a Label Purchase After 202. They are the same value. - Python examples use the
requestspackage.
Step 1 — Download the bytes
GET/api/v1/labels/{labelId}/download
format=1 asks for PDF. Omit format entirely to use the Account's configured
label printing technology, which falls back to PDF.
- cURL
- JavaScript
- Python
- Java
curl -s -o label.pdf -w '%{http_code} %{content_type}\n' \
"${MAILHUB_API_BASE_URL}/api/v1/labels/${LABEL_ID}/download?format=1" \
-H "Authorization: Bearer ${MAILHUB_ACCESS_TOKEN}"
import {writeFile} from 'node:fs/promises';
const response = await fetch(
`${process.env.MAILHUB_API_BASE_URL}/api/v1/labels/${labelId}/download?format=1`,
{headers: {Authorization: `Bearer ${process.env.MAILHUB_ACCESS_TOKEN}`}},
);
if (response.status !== 200) {
// 202 means the file is still being generated. Anything else is an error
// envelope — this is the one branch that may be read as JSON.
throw new Error(`Label not ready: ${response.status}`);
}
const contentType = response.headers.get('content-type')?.split(';')[0];
if (!['application/pdf', 'application/zpl'].includes(contentType)) {
throw new Error(`Unexpected Label content type: ${contentType}`);
}
// Your application chooses the filename.
await writeFile('label.pdf', new Uint8Array(await response.arrayBuffer()));
import os
import requests
response = requests.get(
f"{os.environ['MAILHUB_API_BASE_URL']}/api/v1/labels/{label_id}/download",
params={"format": 1},
headers={"Authorization": f"Bearer {os.environ['MAILHUB_ACCESS_TOKEN']}"},
)
# 202 means the file is still being generated. Anything else is an error
# envelope — this is the one branch that may be read as JSON.
if response.status_code != 200:
raise RuntimeError(f"Label not ready: {response.status_code}")
content_type = response.headers.get("content-type", "").split(";")[0]
if content_type not in ("application/pdf", "application/zpl"):
raise RuntimeError(f"Unexpected Label content type: {content_type}")
# Your application chooses the filename.
with open("label.pdf", "wb") as file:
file.write(response.content)
// Java 11+ java.net.http — no MailHub package to install and no third-party client.
// ofByteArray keeps the body as bytes; it is never handed to a JSON reader.
var request = HttpRequest.newBuilder()
.uri(URI.create(System.getenv("MAILHUB_API_BASE_URL")
+ "/api/v1/labels/" + labelId + "/download?format=1"))
.header("Authorization", "Bearer " + System.getenv("MAILHUB_ACCESS_TOKEN"))
.GET()
.build();
HttpResponse<byte[]> response = HttpClient.newHttpClient()
.send(request, HttpResponse.BodyHandlers.ofByteArray());
// 202 means the file is still being generated. Anything else is an error
// envelope — this is the one branch that may be read as JSON.
if (response.statusCode() != 200) {
throw new IllegalStateException("Label not ready: " + response.statusCode());
}
String contentType = response.headers().firstValue("content-type").orElse("").split(";")[0];
if (!Set.of("application/pdf", "application/zpl").contains(contentType)) {
throw new IllegalStateException("Unexpected Label content type: " + contentType);
}
// Your application chooses the filename.
Files.write(Path.of("label.pdf"), response.body());
Response
A 200 has no JSON envelope. The body is the file itself, and Content-Type
is application/pdf or application/zpl:
GET /api/v1/labels/f6c7d8e9-0a1b-4c2d-8e3f-4a5b6c7d8e9f/download?format=1
HTTP/1.1 200 OK
Content-Type: application/pdf
%PDF-1.4 ...binary...
Use this next
Nothing. The bytes are the end of the workflow: hand them to your printer, storage, or fulfilment step.
Expected result
label.pdf on disk, with the Label identifier still available for
Cancel a Label if you need it.
Common outcomes
| Status | What it means | What to do |
|---|---|---|
200 | The Label file was returned. | Write the bytes. Do not parse them as JSON. |
202 | The requested Label file is pending or still being generated. | Keep the Label identifier and ask again later, at a cadence your application chooses. |
404 | The Label was not found, or the requested format has not been generated. | Confirm the Label identifier, and whether you asked for a format that exists. |
409 | Label generation conflicts with the current state. | Inspect the response — see Label Errors. |
400, 401, 403, and 500 follow the standard public error envelope — see
Error Handling.
Other formats
1 is PDF. 2, 3, and 4 are ZPL at 300, 203, and 600 DPI, and all three
share the one application/zpl media type — the format you asked for is what
identifies the resolution, not the response. See
Download a Label for the full treatment.
Next steps
- Download shipping label in the API Reference — the complete parameter and response detail.
- Download a Label — formats, file handling, and every documented failure.
- Binary Labels — handling the bytes in your own client.
- Recipes — back to the section.