API docs
JSON over HTTPS. Every amount is an integer number of US cents. Send your key as a bearer token; make one on the Developers page.
Base URL https://shipyesterday-side-projects-7607c0e9.vercel.app/api/v1
Authorization Bearer sy_test_... (sandbox keys start sy_test_, live keys sy_live_)This deployment runs in sandbox. Sandbox keys buy carrier test labels marked SAMPLE (or simulated ones in a bare preview) and spend sandbox credit. Live keys cannot be made until live labels are switched on.
Get rates
/api/v1/ratesCreates a shipment and returns one quote per available service, cheapest first. Each quote shows the postage, our fee and the total. Weights default to ounces and dimensions to inches. International shipments need customs and a recipient phone. Optional address_return sets the return address (see What prints on the label), and the first 30 characters of reference print on USPS labels. Optional options: signature ("STANDARD"), insurance_cents (up to 500000; the cost is included in the quoted price) and label_format ("PDF_4x6" or "ZPLII"). Only USPS rates are returned today. Quotes expire after 15 minutes.
curl https://shipyesterday-side-projects-7607c0e9.vercel.app/api/v1/rates \
-H "Authorization: Bearer $SHIPYESTERDAY_KEY" \
-H "Content-Type: application/json" \
-d '{
"address_from": { "name": "Dock Four Goods", "street1": "2121 Alton Pkwy",
"city": "Irvine", "state": "CA", "zip": "92614", "country": "US" },
"address_to": { "name": "Maya Ortega", "street1": "48 Livingston St",
"city": "Brooklyn", "state": "NY", "zip": "11201", "country": "US" },
"parcel": { "length": 12, "width": 9, "height": 4, "weight": 32, "mass_unit": "oz" },
"address_return": { "name": "Returns Dept", "company": "Juniper Candle Co", "street1": "965 Mission St",
"city": "San Francisco", "state": "CA", "zip": "94103", "country": "US" },
"reference": "order-4480",
"options": { "signature": "STANDARD", "label_format": "PDF_4x6" }
}'201 Created
{
"shipment_id": "2b0f...",
"mode": "test",
"simulated": false,
"quotes": [
{ "id": "7c1e9d2a-...", "carrier": "USPS", "service": "Ground Advantage",
"estimated_days": 4, "carrier_cost_cents": 942, "markup_cents": 82,
"price_cents": 1024, "expires_at": "2026-11-05T18:15:00Z" }
],
"messages": []
}Buy a label
/api/v1/labelsBuys the quote and charges the quote's price_cents to your wallet. The Idempotency-Key header is required: retrying with the same key returns the first label (replayed: true) and never charges twice. Responses: 201 bought, 202 still waiting on the carrier (money held, check back with GET), 422 the carrier refused (money returned).
curl https://shipyesterday-side-projects-7607c0e9.vercel.app/api/v1/labels \
-H "Authorization: Bearer $SHIPYESTERDAY_KEY" \
-H "Idempotency-Key: order-4480" \
-H "Content-Type: application/json" \
-d '{ "quote_id": "7c1e9d2a-..." }'201 Created
{
"label": {
"id": "f3a4...", "status": "purchased", "mode": "test",
"carrier": "USPS", "service": "Ground Advantage",
"tracking_number": "9400111899223456781234",
"reference": "order-4480",
"label_url": "https://...",
"amount": { "postage_cents": 942, "fee_cents": 82, "total_cents": 1024, "currency": "USD" },
"created_at": "2026-11-05T18:01:12Z"
},
"replayed": false
}Get a label
/api/v1/labels/{id}Returns one label. Use it to poll a label that answered 202.
200 OK
{ "label": { "id": "f3a4...", "status": "purchased", ... } }Download the label file
/api/v1/labels/{id}/fileStreams the PDF or ZPL from our domain. This is the address in every label's label_url; send your API key with it.
200 OK
Content-Type: application/pdf
Content-Disposition: inline; filename="label-9400111899223456781234.pdf"Track a label
/api/v1/labels/{id}/trackingThe carrier's current status and scan history, newest first. Test labels have no scans.
200 OK
{ "tracking": { "status": "TRANSIT", "eta": "2026-11-08T00:00:00Z", "tracking_number": "9400...",
"events": [ { "status": "TRANSIT", "details": "Arrived at USPS facility", "at": "...", "location": "Jersey City, NJ" } ] } }List labels
/api/v1/labels?limit=25&before=<created_at>Newest first, up to 100 per page. Pass the last created_at as before for the next page.
200 OK
{ "data": [ { "id": "...", "status": "purchased", ... } ], "has_more": true }Void a label
/api/v1/labels/{id}/refundAsks the carrier to void an unused label. The wallet is credited when the carrier confirms: 200 if it already did, 202 while it is pending.
202 Accepted
{ "label": { "id": "f3a4...", "status": "refund_pending", ... } }Wallet balance
/api/v1/walletAvailable balance and anything held for a withdrawal, in cents.
200 OK
{ "mode": "test", "currency": "USD", "available_cents": 48976, "pending_withdrawal_cents": 0 }Wallet history
/api/v1/wallet/transactions?limit=25Ledger lines for your wallet. Positive amounts add money, negative amounts spend it. Lines never change after they are written.
200 OK
{ "data": [ { "id": "...", "kind": "label_purchase", "amount_cents": -1024,
"memo": "USPS Ground Advantage", "reference": { "type": "label", "id": "f3a4..." },
"created_at": "..." } ] }Check an address
/api/v1/addresses/validateChecks whether an address is deliverable. Same address shape as in rates.
200 OK
{ "valid": true, "messages": [], "simulated": false }What prints on the label
Checked on USPS Ground Advantage test labels (Nov 5, 2026). Only USPS labels can be bought today.
- Without
address_return, the sender block printsaddress_from: name, company, street, city line. - With
address_return, the sender block prints the return address instead, andaddress_fromdoes not appear on the label.address_fromis still sent with the shipment data and the carrier can receive it. - The return address must be a real US address that can receive undeliverable parcels; USPS requires a legible domestic return address.
referenceis sent asreference_1; its first 30 characters print bottom right.- Phone and email are not printed. The label carries the postage company's name in the postage mark and its logo in the footer. USPS allows this mark and it can't be removed.
Errors
Errors look like { "error": { "code": "...", "message": "..." } }.
| HTTP | Code | Meaning |
|---|---|---|
| 401 | unauthorized | Missing, unknown or revoked key |
| 402 | insufficient_funds | Wallet balance is below the quote total |
| 403 | mode_mismatch | A test key against live, or the reverse |
| 404 | quote_not_found / label_not_found | Not on this account |
| 409 | idempotency_key_reused | Same key, different quote |
| 409 | quote_already_purchased | Quote bought under another key |
| 410 | quote_expired | Quotes last 15 minutes; ask for rates again |
| 422 | invalid_request | Validation failed; see issues[] |
| 422 | carrier_rejected | The carrier refused; nothing was charged |
| 503 | carrier_unavailable | The carrier network did not answer; safe to retry |
Label statuses
purchased- Bought. Print it from label_url.
needs_review- We did not hear back from the carrier in time. Money is held, never doubled; it settles to purchased or failed.
failed- The carrier refused. The full total is back in your wallet.
refund_pending- Void requested; waiting for the carrier.
refunded- Voided. The full total is back in your wallet.