USPS
Priority Mail Intl
10–15 days$7.40
$1.90 of duties & taxes prepaid on the rows that carry customs columns
all-in · no surprises
Upload a CSV, map your columns to shipping fields once and save the mapping, then validate every row before any money moves. Rows with a bad address are flagged, the rest are quoted across four carriers, and the file is purchased row by row from one prepaid wallet.
USPS, UPS, FedEx, and DHL quote each row's own parcel, so a heavy row and a light row in the same upload can land on different carriers.
Rows are bought one at a time against a single balance, so a half-finished file leaves you with exactly the labels you paid for and nothing in between.
Less than most people assume, and in a stricter form than most people expect. Eight fields have to resolve before a row can be bought: recipient name, address line 1, city, a two-letter ISO country code, weight, length, width, and height. That is the whole required set. Everything else in the catalog is optional — order number, company, email, phone, address line 2, state or province, postal code, package type, a pinned carrier, a pinned service, and the three customs columns of declared value, item description, and HS code.
Two of those deserve calling out because they are where clean-looking files break. Country has to be ISO-2 — US, GB, HK — not "United States" and not "USA", because that code is what selects which carrier services are even eligible for the row. And the three dimensions are required, not the nice-to-have they are on a single manual shipment, because a file is quoted without a human looking at each box. The one exception is a USPS flat-rate container: map the package type column instead and the dimensions stop mattering, since the container defines them.
Your file almost certainly does not use those names, and it does not have to. Headers are matched after lower-casing and stripping punctuation, so "Ship To Postal Code", "shipping_zip" and "Zip Code" all land on the same field, and the usual Shopify, Etsy, Amazon and eBay export headers are recognised on sight. One deliberate exception: any column starting with "From" is never auto-mapped, because bulk import always ships from your account's saved sender address and marketplace exports habitually put junk in their From columns.
Auto-detection gets most of the way and then stops, because no heuristic knows whether your "Total" column is the order total or the declared customs value. The mapping step is one dropdown per field, grouped by recipient, address, package, customs, and service, with the required ones marked — you finish what auto-detection started, set whether weights are pounds or kilos and dimensions inches or centimetres, and you are done.
Then save it under a name. "Etsy export", "backer survey", "wholesale PO". The next file of the same shape applies that preset in one click, and the presets list is yours to manage — apply, rename by saving again, delete. This is the difference between a one-off import and a repeatable process: the first file costs you ten minutes of mapping, and every file after it costs you the upload. If you are fulfilling a crowdfunding campaign, the late-pledge file and the replacement-parts file are the same shape as the original survey export, which is exactly the case presets are for — shipping labels for Kickstarter covers the rest of that job. Wholesale sellers get the same benefit from the opposite direction: a Faire purchase order has the same columns every month, and shipping labels for Faire explains why each carton in a multi-carton order needs its own row.
The validate step is the reason to do this in a wizard rather than a script that buys as it reads. Every row is checked before any money moves: required fields present, address accepted by the carrier network, country code valid, weights and dimensions in range, phone and email well-formed where they are supplied, and a restricted-goods keyword scan that mirrors the one a single shipment gets — so a row that would be refused at purchase is refused now, at the point where fixing it is free.
Rows come back with their problems named on the row rather than as a count at the top. A missing secondary unit, a postal code that does not match the city, an ISO code that is actually a country name — you edit, re-check, and move on. Good rows do not wait for bad ones; they proceed to quoting while you repair the rest. This is the single highest-value step in the whole flow, because the alternative version of catching these is a pallet of returns three weeks later, and what happens to a parcel that comes back costs the label twice plus the packaging.
Once rows are valid they are quoted in batch against USPS, UPS, FedEx, and DHL, and each row takes the cheapest all-in option for its own parcel — not one carrier chosen for the whole file. Rows that have to go a specific way keep their pinned carrier or service from the mapped columns. International rows use the customs columns you mapped; duties default to the recipient unless you explicitly choose to prepay them, and what to write on the form is on customs forms for small parcels.
Purchasing runs sequentially, one row at a time, and that is a deliberate design decision rather than a performance limitation. A parallel fan-out would let two rows clear the same wallet-balance check against the same starting balance and over-debit you; serialising the purchases makes the balance arithmetic exact. It also means a failure is contained to its own row instead of poisoning the batch.
So when a row fails — the carrier declines it, the address turns out to be undeliverable at purchase time, the balance will not stretch — that row reports its own error and the file carries on or stops with the reason visible. You get a summary of how many purchased, how many were skipped, and how many failed, and you can retry a single failed row without touching the ones that worked. Re-running a file you have already partly bought is safe: rows with a label already attached are recognised and skipped rather than purchased a second time.
One thing to know before a very large run: on the Free plan the monthly shipment allowance is enforced per row as the batch executes, so a file that starts under the cap stops exactly at it rather than silently overshooting, and the remaining rows report why. A single file is capped at 500 rows, so larger exports get split — which is a reasonable review checkpoint anyway. The plan detail is on pricing.
The order matters more than the steps do. Mapping happens before validation so the checker knows which column is the postal code; validation happens before quoting so a broken row never reaches a carrier; quoting happens before purchase so you approve the price. Money moves last, one row at a time.
Ship To Name, Ship To Address 1, Ship To City, Ship To Zip, Weight (lbs) — whatever your platform decided to call them.
Marketplace exports, warehouse extracts, backer surveys, wholesale POs — anything that saves as a .csv.
Purchased, skipped, and failed are counted separately — and re-running a file never buys a row twice.
Shopify, Etsy, WooCommerce, and TikTok Shop can sync orders straight into the To Ship queue with no file at all — but their CSV exports import just as happily, and their header names are recognised on sight. Anything that saves as a .csv works: a warehouse extract, a backer survey, a wholesale PO, a spreadsheet somebody keeps by hand.
Anyone can loop over a file and call an API. What decides whether a 400-row import is a good afternoon or a bad month is what happens to the rows that are wrong, and whether the money moved before or after you found out.
Rows are purchased sequentially against a single prepaid balance, so two rows can never clear the same balance check and over-debit you. Fund it with a card, Apple Pay, Google Pay, ACH, or crypto. Stop halfway and you own exactly the labels you paid for.
Headers are auto-detected from the common marketplace exports, you finish the mapping by hand, and then you save it. Apply it to the next file in one click. The first import costs ten minutes; every import after it costs the upload.
Required fields, carrier address validation, ISO-2 country codes, weight and dimension ranges, phone and email format, and a restricted-goods scan — all at the validate step, all with the failure reason on the offending row. Fixing is free; printing a bad row is not.
USPS, UPS, FedEx, and DHL price each row's own parcel and the cheapest all-in option wins per row, so the file does not get flattened onto one carrier. Rows that must go a specific way keep a pinned carrier or service from their mapped columns.
If the file is really a database query, the REST API does the same job programmatically with signed webhooks, real idempotency keys so a retried row never buys two labels, and unlimited calls on every plan.


Label ready
CL-1038 · Seattle, US
Every batch has a tail: the late pledge, the address correction that arrived by DM, the one carton nobody counted. Re-exporting and re-mapping a file for three rows is absurd, so those go the other way — straight from the phone, into the same queue, against the same four carriers and the same wallet.
A 400-row import turns into 400 questions later, and the answers are not in the spreadsheet you uploaded. Ask out loud — "where's Maya's package?" — and Billy pulls the tracking history and reads it back. The same assistant drafts and validates the one-off rows the batch missed, on every plan, at no extra cost. This is the real product, not a render.

Listening
"Where's Maya's package?"
Out for delivery
CL-1039 · Austin, TX · by 6 PM
Speaks plain English · answers for labels bought in a batch or one at a time · remembers customers and saved boxes · included on every plan.
A file is not one shipment, and flattening it onto one carrier is how a batch quietly overpays. Every valid row is priced by USPS, UPS, FedEx, and DHL against its own parcel, each column a single all-in number locked at quote time — so a heavy row and a light row in the same upload can end up on different carriers.
Priority Mail Intl
10–15 days$7.40
$1.90 of duties & taxes prepaid on the rows that carry customs columns
all-in · no surprises
Intl Connect Plus
3–5 days$8.90
$2.20 of duties & taxes prepaid on the rows that carry customs columns
all-in · no surprises
Express Worldwide
1–2 days$9.80
$2.50 of duties & taxes prepaid on the rows that carry customs columns
all-in · no surprises
Plenty of batches start life as a SELECT and only become a CSV because something downstream wanted one. Skip the export: REST, JSON, one Bearer header, and real idempotency keys so a retried row never buys two labels — with unlimited calls on every plan, which is what makes looping over ten thousand rows a non-event.
POST /api/v1/shipments
Authorization: Bearer sk_live_…
Idempotency-Key: ord_8421
{
"to": { "name": "Joyce", "city": "Berlin", "country": "DE" },
"parcel": { "weight": 2.6, "weight_unit": "lb" },
"service": "fedex_intl_priority"
}
Importing is not a paid feature and neither is the wizard. Free covers 50 shipments a month — and because the plan allowance is enforced per row as the batch executes, a file that starts under the cap stops exactly at it rather than silently overshooting. Pro lifts the cap entirely and lowers the label rates the rows are bought at.
Volume pricing
illustrativemore volume → lower per-label rates on every row
$0 / forever
Import, map, validate, and save presets on the free plan — the labels are the only cost.
The assistant that turns a pasted order or a screenshot into a validated draft runs unlimited in the web app on Free. It is what you use for the late pledge and the corrected address — the rows that were never going to be worth a second file. Pro adds Billy on Telegram.
GET /api/v1/shipments
200 OK · plan: free
Unlimited calls on Free — still unlimited on Pro, which is what makes a scripted import cheaper than a metered one.
On Pro we will work with you to beat the label rates you are already getting from
ShippoPirate ShipShipStationEvery row's price is quoted live from USPS, UPS, FedEx, and DHL as one all-in number, and that exact amount leaves your prepaid wallet as the row is bought — nothing is added at checkout and nothing is billed per file. Full pricing details
These are the shapes where orders never arrive one at a time: they arrive as an export, a survey, a purchase order, or a migration — and the label work is a batch from the moment it starts.
One survey export, hundreds of identical boxes
A backer survey is the purest bulk case there is: one file, one parcel spec, and addresses that have been sitting in a form for a year. Map it once, validate every row before you print, and the late-pledge file reuses the same preset.

Purchase orders, not shopping carts
Wholesale orders arrive as a PO or a buyer's spreadsheet, often with several cartons per account and a column layout that never changes from month to month. That stability is exactly what a saved mapping preset is for.
Pinned where it matters
Map the carrier column to hold one account's rows to one carrier
Moving off another platform mid-queue
Warehouse extracts and internal systems
8
required columns — the rest of the catalog is optional
A video took off and I had 80 TikTok Shop orders by morning. I printed every label from my phone on the bus to the post office.
Early customer · TikTok
TikTok Shop seller
I run my Etsy shop from the kitchen. The AI reads the order, picks the carrier, the label prints. That's the whole workflow now.
Early customer · Etsy
Etsy maker
The API is what every shipping API pretends to be. Idempotency that actually works.
Sasha R.
Staff engineer, marketplace
Upload the export, map the columns once, let every row be validated before a cent moves, then buy the file against USPS, UPS, FedEx, and DHL from one prepaid wallet.
Sign up in seconds. No card required. Save the mapping and the next file is a one-click job.