Create a shipping label (draft)
Purchase a shipping label
Creates a shipping label in `draft` status. This call does NOT buy the label, does not charge your balance, and does not return a label file — the response comes back with `status: "draft"`, `rate: null` and `label_url: null`.
To actually buy it, call `POST /v1/labels/{id}/purchase` with the id returned here. That second call is what charges your balance and produces the printable label.
Recommended workflow:
1. `POST /v1/rates` to get available rates
2. `POST /v1/labels` with the chosen `rate_id` — creates the draft
3. `POST /v1/labels/{id}/purchase` — buys it
Alternative: specify `carrier` and `service` instead of `rate_id`; the cheapest matching rate is used at purchase time. `carrier` may be omitted, in which case it defaults to USPS.
Parameters
Request Body
rate_id
string
Rate ID from
POST /v1/rates (recommended). Carrier and service are derived from it — but an explicitly supplied carrier, service or service_code overrides the rate. Send rate_id alone unless you intend that. An expired or unknown rate_id returns 400 SERVICE_REQUIRED, not 404.from_address
object
Required
Sender address. Same fields as
name, street1, city, zip are required.
state is required only for
phone is required on international shipments (see
country defaults to
to_address.name, street1, city, zip are required.
state is required only for
US, CA and AU addresses.phone is required on international shipments (see
to_address.phone).country defaults to
US.to_address
object
Required
Recipient address.
name (string, required)
street1 (string, required) · street2 (string, optional)
city (string, required)
state (string) — required only for
zip (string, required)
country (string, optional, default
phone (string) — optional for domestic, required on international shipments: carriers strand a cross-border parcel without a reachable recipient number, so a missing, too-short or placeholder value (
email (string, optional)
delivery_instructions (string, optional) — note for the recipient (gate code, “Back door”). Truncated at 35 characters; anything longer is reported in the response
residential (boolean, optional) — override. Omit and the server classifies the address itself.
name (string, required)
street1 (string, required) · street2 (string, optional)
city (string, required)
state (string) — required only for
US, CA and AU addresses. Most countries have no province system; omit it or send null.zip (string, required)
country (string, optional, default
US) — two-letter ISO codephone (string) — optional for domestic, required on international shipments: carriers strand a cross-border parcel without a reachable recipient number, so a missing, too-short or placeholder value (
0000000000, 1234567890) is rejected with VALIDATION_FAILED. The same rule applies to from_address.phone.email (string, optional)
delivery_instructions (string, optional) — note for the recipient (gate code, “Back door”). Truncated at 35 characters; anything longer is reported in the response
warnings.residential (boolean, optional) — override. Omit and the server classifies the address itself.
parcel
object
Required
Package dimensions and weight.
weight (number, required): Package weight
length (number, required): Package length
width (number, required): Package width
height (number, required): Package height
weight_unit (string, optional, default
dimension_unit (string, optional, default
Imperial example:
Metric example:
weight (number, required): Package weight
length (number, required): Package length
width (number, required): Package width
height (number, required): Package height
weight_unit (string, optional, default
oz): oz | lb | g | kgdimension_unit (string, optional, default
in): in | cmImperial example:
{ "weight": 16, "length": 10, "width": 8, "height": 4, "weight_unit": "oz", "dimension_unit": "in" }Metric example:
{ "weight": 0.5, "length": 25, "width": 20, "height": 10, "weight_unit": "kg", "dimension_unit": "cm" }
carrier
string (USPS | FEDEX | UPS | DHL)
Carrier code. Optional — when omitted and no
rate_id is given, it defaults to USPS. You must still supply service or service_code.
service
string
Service name (human-readable). Required if `rate_id` and `service_code` not provided.
Use either `service` OR `service_code`, not both.
service_code
string
Service code (machine-readable). Alternative to `service`.
Get this from the `service_code` field in `/v1/rates` response.
carrier_account_id
string
Your BYOCA carrier account ID (for negotiated rates)
label_format
string (pdf | png | zpl)
Label file format
label_size
string (4x6 | 4x8)
Label dimensions
reference
string
Your internal reference (e.g., order ID)
label_custom_fields
object
Custom fields to print on the shipping label. What reaches the printed label depends on the carrier and service. Most carriers print the reference fields and show the SKU/UPC in the content description; where a field is not supported it is stored with the label and returned by the API, but does not appear on the label itself. Keep each value within its documented maxLength - carriers that do print these fields truncate silently past their own limit.
options
object
Shipping options including insurance, signature, and hazmat
customs
object
Required for international
Customs declaration. Required whenever the sender and recipient countries differ — a request without it is rejected with
description (string, required) — must be specific. “Cotton t-shirts, 100% cotton” clears; “clothing”, “goods” or “gift” are rejected and, if they get through, cause customs holds.
value (number, required) — declared value, greater than 0
contents_type (string, optional, default
quantity (integer, optional, default
hs_code (string, optional) — HS tariff number
country_of_origin (string, optional, default
tax_id (string, optional) — recipient tax ID. Mandatory for Brazil (CPF/CNPJ) and Italy (Codice Fiscale / Partita IVA): the rate returns fine and the carrier rejects the purchase without it (
tax_id_type (string, optional) — override, e.g.
eel_pfc (string, optional) — US export declaration. Only needed once the declared value clears
Duties and taxes are billed to the recipient (incoterm DAP) on every international label. This is applied automatically and is not a parameter you set.
CUSTOMS_REQUIRED. Rates quote without it; only the purchase enforces it.description (string, required) — must be specific. “Cotton t-shirts, 100% cotton” clears; “clothing”, “goods” or “gift” are rejected and, if they get through, cause customs holds.
value (number, required) — declared value, greater than 0
contents_type (string, optional, default
merchandise): merchandise | documents | gift | returned_goods | samplequantity (integer, optional, default
1)hs_code (string, optional) — HS tariff number
country_of_origin (string, optional, default
US)tax_id (string, optional) — recipient tax ID. Mandatory for Brazil (CPF/CNPJ) and Italy (Codice Fiscale / Partita IVA): the rate returns fine and the carrier rejects the purchase without it (
TAX_ID_REQUIRED).tax_id_type (string, optional) — override, e.g.
vat, eori, tineel_pfc (string, optional) — US export declaration. Only needed once the declared value clears
$2,500; supply an AES ITN (AES X20260818123456). Below that threshold the 15 CFR 30.37(a) exemption is cited for you. USPS refuses the purchase without it on high-value shipments.Duties and taxes are billed to the recipient (incoterm DAP) on every international label. This is applied automatically and is not a parameter you set.
ship_date
string
Ship date, accepted at the top level as well as inside
options so a caller can mirror the shape of their POST /v1/rates request. It must match the date the quote was priced on — a different one re-prices the label and the charge stops matching the rate you accepted.billing
object
Billing party for BYOCA carrier accounts (e.g. your own UPS account). Requires
payer (required):
accountNumber: Required for
countryCode: 2-letter ISO. Required for
postalCode: Required for
carrier_account_id to be set.payer (required):
shipper (default — your BYOCA account is billed) | recipient | third_partyaccountNumber: Required for
recipient and third_partycountryCode: 2-letter ISO. Required for
third_partypostalCode: Required for
third_party
Request Body — Order Linking (optional)
platform
string
E-commerce platform the order came from (e.g.
SHOPIFY). Pair with platform_order_id to link this label to that order.platform_order_id
string
The order's id on that platform.
order_id
string
An atoship Order ID. Links directly and skips the platform lookup — use this when you already know it.
channel
string
Accepted alias for
platform, kept for plugins that already send this name.external_order_id
string
Accepted alias for
platform_order_id.Returns
201
Draft label created. Not purchased —
status is draft, rate and label_url are null. Call POST /v1/labels/{id}/purchase next.
400
VALIDATION_FAILED — invalid body, or an international shipment missing a usable sender/recipient phone or a specific customs description.CUSTOMS_REQUIRED — international shipment with no customs object.TAX_ID_REQUIRED — Brazil or Italy destination without customs.tax_id.SERVICE_REQUIRED — no service could be resolved; also what an expired or unknown rate_id returns.ADDRESS_BLOCKED — destination is on the block list.CARRIER_ACCOUNT_NOT_FOUND — carrier_account_id is not one of yours.NO_ORGANIZATION — the API key is not attached to an organization.
401
Authentication required
403
PLAN_LIMIT_REACHED — the plan's label allowance is exhausted.
Related
Labels
POST/api/v1/labels