Skip to content
Last updated

Common Workflows

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.


Courier shipment lifecycle

Create, rate, label, and ship a single courier package. The most common V5 flow — covers ~80% of carrier integrations.

#StepEndpointWhat you do
1Create the shipmentPOST /shipments with type: courierSend to_address + packages. Returns data.id (the V5 shipment_id).
2List ratesGET /rates/{shipment_id}Pick a carrier.service_code (e.g. canada_post.expedited).
3Buy the labelPOST /labels/{shipment_id} with the chosen serviceCharges credits. Returns data.label_url (PDF) + data.tracking_code.
4Schedule 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.


LTL shipment booking

Less-than-truckload freight follows the same shape, just with type: ltl and a different cancel endpoint.

#StepEndpointWhat you do
1Create the LTL shipmentPOST /shipments with type: ltlReturns data.id.
2Get LTL quotesGET /rates/{shipment_id}LTL carriers (Freightcom).
3Book with the carrierPOST /labels/{shipment_id} with the chosen rateReturns data.confirmation_number.
4Cancel a booked LTL (optional)POST /ltl/{shipment_id}/cancelVoids the booking with the carrier. Use instead of DELETE /shipments/{id} for LTL.

Batch processing

Group many shipments into a single batch, generate labels for all of them, and drain per-shipment failures.

#StepEndpointWhat you do
1Create the batchPOST /batchesSend { name, shipment_ids }. Returns data.id.
2Trigger processingPOST /batches/{batch_id}/processReturns 202. Label generation runs async.
3Poll statusGET /batches/{batch_id}Repeat until data.status != "processing". Realistic clients back off (1s → 2s → 4s).
4Drain errorsGET /batches/{batch_id}/errorsPer-shipment failures with the validation problem.

Top up credits, then buy a label

Labels are paid from the account's credit balance. If the balance is low, top up first.

#StepEndpointWhat you do
1Charge the payment methodPOST /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).
2Confirm the new balanceGET /credits/balanceSanity-check that the top-up landed and covers the upcoming label cost.
3Buy the labelPOST /labels/{shipment_id} with the chosen serviceDebits the credit balance.

Always send an Idempotency-Key header on step 1. Top-up retries without a key double-charge.


Classify and approve a product

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.

#StepEndpointWhat you do
1Suggest an HS codePOST /products/classify with { title, description }Returns data.hs_code.
2Verify the manufacturer (optional)POST /products/verify-manufacturer with { manufacturer, country_of_origin }CUSMA / country-of-origin compliance check.
3Create the productPOST /products with the verified hs_code and source fieldsPersists 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.


Other endpoint-level flows

These don't need a multi-step description — they're single calls or small glue logic.

  • Quote rates without creating a shipmentPOST /rates with shipment details. Returns rates. No shipment row is created.
  • Validate addressesPOST /addresses/validate before POST /shipments to surface bad zip/postal codes early.
  • Manage imported ordersPOST /orders, GET /orders, PUT /orders/{order_id}. Delete only before linking to a non-voided shipment.
  • Find drop-off locationsGET /locations. Render the returned branch and partner-site addresses; refresh periodically because the catalog changes.

Idempotency & retry rules

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.