End-to-end flows that chain V5 endpoints together. Each workflow lists the exact endpoint sequence and what to do with the response between steps.
Create, rate, label, and ship a single courier package. The most common V5 flow — covers ~80% of carrier integrations.
| # | Step | Endpoint | What you do |
|---|---|---|---|
| 1 | Create the shipment | POST /shipments with type: courier | Send to_address + packages. Returns data.id (the V5 shipment_id). |
| 2 | List rates | GET /rates/{shipment_id} | Pick a carrier.service_code (e.g. canada_post.expedited). |
| 3 | Buy the label | POST /labels/{shipment_id} with the chosen service | Charges credits. Returns data.label_url (PDF) + data.tracking_code. |
| 4 | Schedule a pickup (optional) | POST /pickups with { shipment_ids: [...] } | Only valid for courier shipments (FedEx/UPS/Purolator via Freightcom). |
Use an Idempotency-Key header on steps 1, 3, and 4 so network retries can't double-charge or double-book.
Less-than-truckload freight follows the same shape, just with type: ltl and a different cancel endpoint.
| # | Step | Endpoint | What you do |
|---|---|---|---|
| 1 | Create the LTL shipment | POST /shipments with type: ltl | Returns data.id. |
| 2 | Get LTL quotes | GET /rates/{shipment_id} | LTL carriers (Freightcom). |
| 3 | Book with the carrier | POST /labels/{shipment_id} with the chosen rate | Returns data.confirmation_number. |
| 4 | Cancel a booked LTL (optional) | POST /ltl/{shipment_id}/cancel | Voids the booking with the carrier. Use instead of DELETE /shipments/{id} for LTL. |
Group many shipments into a single batch, generate labels for all of them, and drain per-shipment failures.
| # | Step | Endpoint | What you do |
|---|---|---|---|
| 1 | Create the batch | POST /batches | Send { name, shipment_ids }. Returns data.id. |
| 2 | Trigger processing | POST /batches/{batch_id}/process | Returns 202. Label generation runs async. |
| 3 | Poll status | GET /batches/{batch_id} | Repeat until data.status != "processing". Realistic clients back off (1s → 2s → 4s). |
| 4 | Drain errors | GET /batches/{batch_id}/errors | Per-shipment failures with the validation problem. |
Labels are paid from the account's credit balance. If the balance is low, top up first.
| # | Step | Endpoint | What you do |
|---|---|---|---|
| 1 | Charge the payment method | POST /credits/top-up with { amount, payment_method_id? } | payment_method_id is optional — defaults to the account's default card. Returns data.id (the new transaction). |
| 2 | Confirm the new balance | GET /credits/balance | Sanity-check that the top-up landed and covers the upcoming label cost. |
| 3 | Buy the label | POST /labels/{shipment_id} with the chosen service | Debits the credit balance. |
Always send an Idempotency-Key header on step 1. Top-up retries without a key double-charge.
Customs declarations need a per-product HS code. V5 wraps the TRU classification API so you can ask for a suggested code, optionally verify the manufacturer, then persist the product.
| # | Step | Endpoint | What you do |
|---|---|---|---|
| 1 | Suggest an HS code | POST /products/classify with { title, description } | Returns data.hs_code. |
| 2 | Verify the manufacturer (optional) | POST /products/verify-manufacturer with { manufacturer, country_of_origin } | CUSMA / country-of-origin compliance check. |
| 3 | Create the product | POST /products with the verified hs_code and source fields | Persists the row that store imports and later shipment-creation calls reference. |
If an existing product enters Manufacturer Failed after import, you can run just step 2 on it and re-call POST /products/{sku}/approve-classification.
These don't need a multi-step description — they're single calls or small glue logic.
- Quote rates without creating a shipment —
POST /rateswith shipment details. Returns rates. No shipment row is created. - Validate addresses —
POST /addresses/validatebeforePOST /shipmentsto surface bad zip/postal codes early. - Manage imported orders —
POST /orders,GET /orders,PUT /orders/{order_id}. Delete only before linking to a non-voided shipment. - Find drop-off locations —
GET /locations. Render the returned branch and partner-site addresses; refresh periodically because the catalog changes.
All mutating endpoints (POST, PUT, DELETE) accept an Idempotency-Key header. A retried request with the same key inside 24h returns the original response byte-for-byte. Reusing a key with a different body yields 409 idempotency_conflict. See Errors & Idempotency.