Help CenterGitHub

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 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 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 code
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 (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 oz): oz | lb | g | kg
dimension_unit (string, optional, default in): in | cm

Imperial 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 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 | sample
quantity (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, tin
eel_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 carrier_account_id to be set.

payer (required): shipper (default — your BYOCA account is billed) | recipient | third_party
accountNumber: Required for recipient and third_party
countryCode: 2-letter ISO. Required for third_party
postalCode: 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 purchasedstatus 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_FOUNDcarrier_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