How to Create Shipping Labels Automatically with SmartFreight
Use SmartFreight to automatically generate shipping labels and compare carrier rates.
What This Integration Does
SmartFreight is a freight management layer that sits in front of many carriers, so it's a natural fit when you want to compare quotes and pick the cheapest (or fastest) option per order instead of hardcoding a single carrier. Manually rating every parcel in the SmartFreight UI is exactly the kind of work automation eats well: every order has the same shape, the cheapest carrier is a deterministic calculation, and the consignment payload is just a remapping of order fields.
This workflow runs on each new order from your store. It pulls the order's destination and parcel data, asks SmartFreight to rate the shipment, picks the carrier that meets your service-level constraint at the lowest cost, imports the consignment into SmartFreight, and writes the resulting tracking number back to the order. The store remains the system of record; SmartFreight is the execution layer.
Prerequisites
- A store connection (Shopify, BigCommerce, or WooCommerce) with order read access and the ability to update orders.
- A SmartFreight connection with API credentials for your account.
- SmartFreight already configured with at least two carrier services so rate comparison is meaningful.
- Default parcel dimensions and weight on your products, or a way to fetch them per SKU.
Step 1: Webhook Trigger on New Order
Drop a Trigger node onto the canvas and set its type to Webhook. Point your store's order-created (or order-paid) webhook at it. Triggering on paid orders avoids rating orders that get abandoned at checkout.
Step 2: Transform - Build the Shipment Payload
Add a Transform node that flattens the order into the structure SmartFreight expects:
{
"receiver": {
"name": "{{ trigger.body.shipping_address.name }}",
"address1": "{{ trigger.body.shipping_address.address1 }}",
"suburb": "{{ trigger.body.shipping_address.city }}",
"state": "{{ trigger.body.shipping_address.province_code }}",
"postcode": "{{ trigger.body.shipping_address.zip }}",
"country": "{{ trigger.body.shipping_address.country_code }}"
},
"items": [
{ "weight_kg": "{{ item.grams / 1000 }}", "qty": "{{ item.quantity }}" }
]
}
If product dimensions live in a separate system, fan out with a Loop over trigger.body.line_items and look them up before assembling the items array.
Step 3: Rate the Shipment
Add a Connector node pointing at the smartfreight connector and pick the calculate-rate tool. Pass the transformed payload. The response contains rated services from every configured carrier with cost and ETA.
Step 4: Pick the Best Carrier
Add a second Connector node on smartfreight using cost-comparison to apply your service-level rules (for example: "two-day or faster, then cheapest"). Alternatively, use an array sort on the rates by cost and a Condition to pick the first result meeting your ETA constraint.
Step 5: Import the Consignment
Add a Connector node on smartfreight and pick import-consignment. Pass the same shipment payload along with the selected carrier and service code from the previous step. SmartFreight returns a consignment number and label URL.
Step 6: Update the Order and Notify
Add a Connector node on your store (Shopify update-order, WooCommerce update-order, BigCommerce via raw-api-request if needed) and write the consignment number and tracking link back to the order. Optionally follow with a Send Email step to email the label PDF to your warehouse, or a slack send-message step into #fulfillment.
Tips
- Cache rates briefly for orders going to the same suburb on the same day - SmartFreight rate APIs can be slow, and parallel rate calls compound the wait.
- For heavy items, split the order into multiple consignments before
calculate-rateso per-carrier weight limits don't disqualify good options. - Log every
calculate-rateresponse to a mongodb collection - this becomes a goldmine for shipping cost analysis later. - Use the
get-delivery-optionstool when you want to expose carrier choices to customers at checkout instead of picking automatically.
Common Pitfalls
- Missing dimensions: SmartFreight rates are weight + dimension based. Orders that ship at default dimensions will be priced wrong and possibly surcharged by the carrier at the depot.
- State vs province codes: stores often send full names; SmartFreight wants ISO 3166-2 short codes. Normalize in the Transform step.
- Duplicate consignments: if the workflow retries after a partial failure, you can end up importing the same consignment twice. Use
find-consignmentby order ID first and skip if it already exists. - SOAP quirks: SmartFreight's API is SOAP-backed. Some fields are case-sensitive in ways that don't match modern REST APIs. Test with
raw-soap-requestwhen something looks off.
Testing
Trigger the workflow manually with a single test order destined for a domestic suburb you frequently ship to. Inspect the calculate-rate output, confirm the carrier selection logic picks the option you expect, and verify the consignment shows up in the SmartFreight UI. Only then enable the production webhook.