API
The same label maker the site runs, over REST. Send one label and the file comes back in the response, or send a CSV of orders and read the batch until its file is ready. The API is on the Pro plan at $12 a month or $120 a year and the Business plan at $29 a month or $290 a year. Keys are created in the dashboard, and a key is shown once.
The API makes label files. It does not buy postage, connect to a carrier account or claim that a carrier will accept a label.
Authentication
Send the key as a Bearer token on every request. x-api-key works too. A missing, unknown or revoked key is a 401 and nothing else runs.
export SLG_API_KEY=the_key_from_your_dashboard
curl -X POST https://shippinglabelgenerator.com/api/v1/labels \
-H "Authorization: Bearer $SLG_API_KEY" \
-H "Content-Type: application/json" \
-d '{"input":{"from":{"name":"Ada Lovelace","line1":"12 Marylebone Road","city":"London","postal":"NW1 5LR","country":"GB"},"to":{"name":"Grace Hopper","line1":"1 Navy Yard","city":"Arlington","state":"VA","postal":"22202","country":"US"}},"layoutId":"thermal-4x6","format":"pdf"}' \
-o label.pdfOne label
POST /api/v1/labels takes a JSON body with the label under input, a layoutId and a format. A 200 is the finished file itself, not JSON: the response carries Content-Type: application/pdf or text/plain; charset=utf-8 and a Content-Disposition filename of label.pdf or label.zpl. The file is not stored, and the one rendered label counts once against the month.
{
"input": {
"from": {
"name": "Ada Lovelace",
"line1": "12 Marylebone Road",
"city": "London",
"postal": "NW1 5LR",
"country": "GB"
},
"to": {
"name": "Grace Hopper",
"line1": "1 Navy Yard",
"city": "Arlington",
"state": "VA",
"postal": "22202",
"country": "US"
},
"reference": "ORDER-1001",
"barcode": { "kind": "code128", "value": "ORDER-1001" }
},
"layoutId": "thermal-4x6",
"format": "pdf"
}from and to take name, line1, city, postal and country, plus optional company, line2, state and phone. reference is an optional line printed on the label, and barcode is an optional { kind, value } with kind of code128 or qr and a value of 1 to 40 characters from A-Z, a-z, 0-9 and -.
A required address field that is blank, a US address without a two letter state or a five or nine digit ZIP, a country that is not a two letter code, and a text field over 60 characters are all a 400 with the field named in details. A layout that is not one of thermal-4x6, letter-2up, avery-5163 or avery-5164 is also a 400.
A batch of orders
POST /api/v1/bulk takes a JSON body with either csv, the whole file as one string, or rows, an array of order objects, plus layoutId and format. A multipart upload works too: a file part or a csv field, with layoutId, format and an optional sender as form fields. A 201 means the batch is queued, not that its file exists yet.
curl -X POST https://shippinglabelgenerator.com/api/v1/bulk \
-H "Authorization: Bearer $SLG_API_KEY" \
-H "Content-Type: application/json" \
-d '{"csv":"name,company,address1,address2,city,state,postal,country,phone,reference\nGrace Hopper,US Navy,1 Navy Yard,,Arlington,VA,22202,US,,ORDER-1001\n","layoutId":"thermal-4x6","format":"pdf","sender":{"name":"Ada Lovelace","line1":"12 Marylebone Road","city":"London","postal":"NW1 5LR","country":"GB"}}'{
"batchId": "cm2q7v0e80000x9k4bq1hn3zt",
"statusUrl": "/api/v1/bulk/cm2q7v0e80000x9k4bq1hn3zt"
}The CSV columns, in this order, are name,company,address1,address2,city,state,postal,country,phone,reference. line1 and line2 are accepted in place of address1 and address2 in a JSON row. sender is the FROM block printed on every label: an address object with the same fields as from above. It may be left out, in which case the batch uses the account's first saved sender, and a batch on an account with no saved sender fails with batch has no sender address.
{
"rows": [
{
"name": "Grace Hopper",
"company": "US Navy",
"address1": "1 Navy Yard",
"city": "Arlington",
"state": "VA",
"postal": "22202",
"country": "US",
"reference": "ORDER-1001"
}
],
"layoutId": "thermal-4x6",
"format": "pdf"
}A file is refused whole, never half queued. A row problem comes back as a 400 with one details entry per bad field, carrying row (the sheet row, counting the header as row 1), field and message. A file over 5 MB, a file over the plan's batch cap, or an unknown layout or format is a 400 with no batch created.
Read a batch
GET /api/v1/bulk/{id} returns the batch and, once the file exists, its download link. Poll it until status is done or failed. rowCount is the rows in the upload and labelCount the labels rendered. A key reads only its own account batches, and anything else is the same 404 as an id that does not exist.
curl https://shippinglabelgenerator.com/api/v1/bulk/cm2q7v0e80000x9k4bq1hn3zt \ -H "Authorization: Bearer $SLG_API_KEY"
{
"id": "cm2q7v0e80000x9k4bq1hn3zt",
"status": "done",
"layoutId": "thermal-4x6",
"format": "pdf",
"rowCount": 1,
"labelCount": 1,
"error": null,
"createdAt": "2026-10-19T09:12:04.512Z",
"expiresAt": "2026-10-26T09:12:04.512Z",
"downloadUrl": "/api/bulk/cm2q7v0e80000x9k4bq1hn3zt/download?t=<token>"
}status is queued, running, done or failed. error is the reason a failed batch did not render, or null. downloadUrl is null until the batch is done and its file exists. The link is signed and stops working at the same instant the file is deleted, 7 days after the batch was created.
Limits
- 60 requests a minute per key, in fixed one minute windows. A 429 carries
x-ratelimit-limit,x-ratelimit-remainingandRetry-After. - Batches of up to 500 labels on Pro and 2,000 on Business. A larger file is a 400 and nothing is queued.
- Pro covers 3,000 labels a month and Business 15,000, shared with the labels you make in the web app. A single label past the month is a 403, and a batch the month cannot cover is a 402; neither renders anything.
- A bulk batch takes its labels from the month when it is queued and a failed batch gives them back. A refused request and an invalid label are never charged. Up to 2 batches can be queued or rendering at once per account; a third upload is a 429 until one finishes.
pdfandzplare both on Pro and Business. A format the plan does not list is a 403.- Anonymous files are kept 24 hours and files filed on an account 7 days. An API batch is filed on your account.
Errors
Every error is JSON with one sentence under error and an array under details, empty when no single field is to blame. A 429 also carries the rate headers and a Retry-After.
{
"error": "Label is invalid.",
"details": [
{ "field": "to.postal", "message": "postal code is required" }
]
}400the body is not JSON or not an object,inputis missing, the layout or format is unknown, a label or row is invalid, or the CSV is over 5 MB or the batch cap.401missing, unknown or revoked key. Nothing else runs.402the plan's month cannot cover the rows in a bulk upload. Nothing is queued.403the plan does not include the API, the account is suspended, the month has no labels left on a single label, or the plan does not list the requested format.404no batch with that id belongs to this key.429the per-key rate limit. Nothing was rendered, queued or charged.
What the API never does
It makes the label file and nothing else. It does not buy postage, connect to a carrier account, quote a rate, invent a tracking number or claim that a carrier will accept a label. It does not check that an address exists. The duties that stay with you are in the terms.