Shopify Multi-Carrier Shipments: Why Your Tracking Links Go Missing (And How to Fix It!)
Hey store owners!
Ever found yourself scratching your head, wondering why only one of your carefully entered tracking numbers shows up in your Shopify admin, even when you know you've shipped items via different carriers for the same order? You're not alone. This is a common head-scratcher, and it recently came up in a really helpful community discussion that I wanted to share insights from.
Our friend ctevan ran into this exact issue, trying to update fulfillment tracking for multiple shipments. It's a classic example of what some of us seasoned Shopify folks affectionately call a "Shopify quirk." Let's dive into what's happening and, more importantly, how to fix it!
The Core of the Problem: Shopify's "One Shipment, One Carrier" Philosophy
The main takeaway from the community discussion, brilliantly articulated by ShopIntegrations, is this: a single fulfillment in Shopify is fundamentally designed to represent one shipment, which in turn expects a single carrier.
Think about it like this: when you manually create a fulfillment in the Shopify admin, you pick one shipping service (e.g., USPS, UPS, FedEx) and enter its tracking number. You don't usually see options to mix and match carriers within that single fulfillment record. While the API might technically allow you to pass multiple tracking numbers and URLs for different carriers into a single fulfillmentTrackingInfoUpdate call, the Shopify admin UI often struggles to display this correctly. It typically defaults to showing only the first one, or attempts to force the second carrier's number into the first carrier's tracking link, leading to confusion for both you and your customers.
What ctevan Experienced: Tracking Links Gone AWOL
ctevan's experience perfectly illustrates this. They were trying to update an existing fulfillment with two tracking numbers and URLs, one for USPS and one for UPS, using the fulfillmentTrackingInfoUpdate API call:
{
"fulfillmentId": "gid://shopify/Fulfillment/6566266765597",
"trackingInfoInput": {
"numbers": [
"1111111111111111111",
"55555555555555"
],
"urls": [
"https://tools.usps.com/go/TrackConfirmAction_input?qtc_tLabels1=1111111111111111111",
"https://www.ups.com/track?loc=en_US&requester=ST&trackNums=55555555555555"
]
},
"notifyCustomer": false
}
The API call itself ran successfully, which is often the most frustrating part because it looks like it worked! But when ctevan checked the order in the Shopify admin, only the first tracking link (the USPS one in this case) was visible. The second one, for UPS, was nowhere to be found, as shown in their screenshot:

This is exactly what ShopIntegrations was talking about – the UI just can't handle multiple carriers within a single fulfillment.
The Solution: Split Your Fulfillments!
The clear consensus and the correct approach, if you're shipping items from a single order using different carriers (or even just different packages with different tracking numbers), is to split them into separate fulfillments.
This means that instead of trying to cram all tracking info into one fulfillment record, you'll create a distinct fulfillment for each package or group of items being shipped together via a specific carrier. Shopify's system is built around the concept of "fulfillment orders" – which represent a group of line items to be fulfilled together – and then creating individual "fulfillments" from those fulfillment orders.
How to Implement Separate Fulfillments via API
Here's a simplified, step-by-step approach based on the insights from the thread:
- Identify Fulfillment Orders: For any given order, you'll first need to query its
FulfillmentOrders. An order can have one or more fulfillment orders, each containing specific line items that need to be shipped. - Group Line Items by Shipment: Determine which line items from a
FulfillmentOrderare going out in a single package with a single carrier. If you have items going via USPS and others via UPS, these need to be in separate groups. - Create a
fulfillmentCreateCall for Each Shipment: For each distinct shipment group, you'll make a separatefulfillmentCreateAPI call. Each call should specify:- The
fulfillmentOrderIdfor the relevant fulfillment order. - Only the
fulfillmentOrderLineItemsthat belong to that specific shipment. - The
trackingInfofor that single shipment (one carrier, one tracking number, one URL).
- The
- Repeat as Needed: If the same order has another set of items going out with a different carrier, repeat step 3 with the remaining line items.
When ctevan initially tried to use fulfillmentCreate and got those "Invalid id" errors, it highlighted another common API pitfall. The call they shared:
{
"fulfillment": {
"trackingInfo": {
// ...
},
"notifyCustomer": false,
"lineItemsByFulfillmentOrder": [
{
"fulfillmentOrderId": "{{fulfillment.order.id}}",
"fulfillmentOrderLineItems": [
{% for item in fulfillment.fulfillmentLineItems %}
{
"id": "{{ item.id }}",
"quantity": {{ item.quantity }}
}{% unless forloop.last %},{% endunless %}
{% endfor %}
]
}]
}
}
}
The key issue here is likely using "{{fulfillment.order.id}}" for fulfillmentOrderId. This looks like it's trying to pass an Order GID where a FulfillmentOrder GID is expected. Shopify's API is very strict about GID types. An Order GID (e.g., gid://shopify/Order/7570290966813) is different from a FulfillmentOrder GID (e.g., gid://shopify/FulfillmentOrder/1234567890) and a FulfillmentLineItem GID. Always double-check that you're using the correct GID type for the specific field you're populating!
The Mysterious Tag
One small side mystery ctevan mentioned was an odd tag appearing in one of their tracking URLs. As ShopIntegrations rightly pointed out, Shopify isn't adding that. This kind of artifact almost certainly comes from an upstream system – perhaps an ERP, a shipping app, or a custom script – that's generating the tracking URLs before they ever hit your Shopify API call. If you see something like this, trace back to your payload's source to clean up your data before it reaches Shopify.
Wrapping It Up: Clean Data, Clear Fulfillments
So, the big takeaway here is to align your fulfillment logic with Shopify's inherent structure. If you're sending out different parts of an order with different carriers, or even just multiple packages, treat them as separate fulfillments from the start. This not only ensures all your tracking links appear correctly in the admin and for your customers, but it also makes your integration with Shopify's API much smoother and less prone to those "classic quirks." And always, always validate your GIDs and sanitize your data before sending it over – it'll save you a lot of debugging headaches down the line!