Shopify Fulfillment Orders and multi-location routing: the API is a nightmare, but InfiPlex still puts orders where you want them
Ask anyone who has built against Shopify's fulfillment API and you'll get the same reaction: it's a genuine nightmare. Two related objects, Fulfillment and FulfillmentOrder, look similar and are not the same thing. Orders route to locations automatically through Shopify's own black-box logic, and a 2024 platform change means an app that isn't careful about which location an order is assigned to can end up reporting zero fulfillable inventory on stock that is sitting right there. InfiPlex doesn't just read whatever Shopify's routing decided, though: it actively moves fulfillment orders to the location a client defines, both when pushing orders into Shopify from another channel and when pulling Shopify orders out to fulfill and track elsewhere.
Two Objects, Not OneFulfillmentOrder is the routing assignment; Fulfillment is the actual shipment record
Location Ownership Is EnforcedAn app can only create fulfillments for orders assigned to its own location
InfiPlex Moves Orders For YouPush or pull, fulfillment orders land at the location your rules define, not wherever Shopify's routing sends them
Why this part of the API is hard
Two objects, similar names, different jobs
A Fulfillment Order is not a Fulfillment, even though the names invite you to assume they are interchangeable. A FulfillmentOrder represents an item or group of items from an order that are expected to be fulfilled from the same location, it is the assignment and the intent. A Fulfillment is created once work actually starts on some or all of those line items, and represents the real, physical shipment: carrier, tracking number, what was sent. One FulfillmentOrder can end up with zero, one, or several associated Fulfillments over its life, since a partial shipment creates a Fulfillment for the portion that shipped while the rest of the FulfillmentOrder remains open, gets split, or moves to another location. Confusing the two, treating a FulfillmentOrder's status as if it described a shipment, or trying to update a Fulfillment's carrier info on a FulfillmentOrder, is one of the most common sources of integration bugs against this API.
Order routing
Automatic, not something you configure per order
After an order is created, a background process Shopify calls order routing determines which location or locations are responsible for fulfilling each line item, and creates one or more FulfillmentOrders assigned to those locations. This happens automatically and cannot be done manually; there is no API call to create a FulfillmentOrder directly. What you configure ahead of time, in Settings, Shipping and delivery, Order routing, is the priority and rules that process uses, not the individual routing decision for a given order.
The field that matters is assigned_location on each FulfillmentOrder. It is the authoritative answer to who is responsible for that group of line items. The older, per-variant fulfillment_service field on a product variant is not reliable for this anymore, since Shopify allows the same variant to be stocked at both merchant-managed and third-party locations simultaneously; an app that still checks the variant field instead of assigned_location will get the wrong answer as soon as multi-location inventory is in play.
Status fields
Two status fields that look alike and are not
Field
Scope
Values
FulfillmentOrder.status
Per fulfillment order (one location's piece of the order)
Notice IN_PROGRESS, ON_HOLD, and SCHEDULED appear in both lists, describing something different at each level: a single FulfillmentOrder can be IN_PROGRESS while the order as a whole shows PARTIALLY_FULFILLED because another location's FulfillmentOrder for the same order already closed. Shopify's own documentation is explicit that the order-level field is for display summary purposes only and does not capture the full fulfillment state, the FulfillmentOrder object is the source of truth. Building logic against the order-level status when you actually need to know what a specific location has to do is a reliable way to get the wrong answer some of the time.
The rule that trips up most integrations
You can only touch what is assigned to you
Since a platform change effective in the 2024-10 API version, an app can only create a fulfillment for a FulfillmentOrder that is assigned to a location it owns. If an app tries to fulfill an order assigned to merchant-managed inventory, or to a different app's fulfillment service location, the create call fails outright. This is the practical explanation behind a support pattern every multi-location Shopify merchant eventually hits: a warehouse or 3PL app reports zero fulfillable quantity on a SKU the merchant knows is in stock, because the order was never routed to that app's location in the first place, it was routed somewhere else, and the app has no visibility or authority over inventory it was not assigned.
The fix lives in the order routing configuration, not in the integration's code: the rules under Settings, Shipping and delivery, Order routing decide which location an order is assigned to, and if those rules do not rank the intended fulfillment location correctly, the API will faithfully assign orders elsewhere no matter how the integration is built. The same principle shows up in the multi-warehouse order routing guide and, on the CastleGate side, the 1:1 vs pooled inventory sync guide: the platform can only route intelligently to a location it can actually see and identify separately.
Splitting
Splitting a fulfillment order
A single FulfillmentOrder can be split, dividing its line items or quantities into a remaining piece and a new, separate FulfillmentOrder, most often used to ship part of an order now and hold or reroute the rest. The API returns both the remaining and the newly created FulfillmentOrder from that call, and each then follows its own status lifecycle independently from that point on. A merchant-managed FulfillmentOrder can also be moved between merchant-managed locations directly; moving does not change the shipping rate the customer already paid, since that was fixed at checkout.
Closing out
Closing out a fulfillment request
When a fulfillment service cannot ship any remaining items on a request it accepted, it closes the fulfillment order, which marks it incomplete and hands control back to the merchant to move the remaining items to another location, remove and refund them, or re-request fulfillment from the same service. That close action has narrow preconditions: it only works on a FulfillmentOrder assigned to a fulfillment-service location, only after that service has accepted the request, only while its status is exactly IN_PROGRESS, and only the specific app that accepted the request can call it. Any one of those conditions being off is a silent failure waiting to happen if it is not checked explicitly.
At the order level
Why Shopify's own routing isn't always the right answer
Shopify's order routing decides a location based on its own priority rules, which is fine when every order genuinely belongs wherever Shopify sends it. Multichannel sellers rarely have that luxury: an order that reaches Shopify from Amazon, Walmart, or any other connected channel often needs to land at a specific warehouse or 3PL, not wherever Shopify's routing settings happen to rank first, and an order pulled out of Shopify for fulfillment somewhere else usually needs to go to one particular place every time, not wherever it was originally assigned.
Automation
How InfiPlex actively moves fulfillment orders
When InfiPlex is used to send orders into Shopify, whether an order originated on Amazon, Walmart, or any other connected channel, and a client wants those orders fulfilled from a specific location, InfiPlex moves the resulting fulfillment order to that location rather than leaving it wherever Shopify's own order routing assigned it.
When InfiPlex is used to pull orders out of Shopify for fulfillment and push tracking information back once they ship, clients can have every order pulled from Shopify moved to one specific location for fulfillment, so warehouse and 3PL workflows built around that location handle Shopify orders the same way they handle every other channel, with no per-order manual reassignment.
Both directions rely on the same location-assignment mechanics covered above: InfiPlex reads assigned_location and FulfillmentOrder.status to know what Shopify has already decided, then moves the fulfillment order to the location the client's rules call for, the same way a merchant can move a fulfillment order between merchant-managed locations directly. Program page: Shopify integration.
Frequently asked
Questions, answered
The questions that come up once you're actually building against this part of Shopify's API.
A FulfillmentOrder represents the assignment: which location is expected to fulfill a group of line items, and its current state. A Fulfillment represents the actual shipment created once work begins, carrier, tracking, and what was sent. One FulfillmentOrder can produce multiple Fulfillments over time.
No. FulfillmentOrders are created automatically by Shopify's order routing process immediately after an order is placed. What you control ahead of time is the routing rules under Settings, Shipping and delivery, Order routing, not individual FulfillmentOrder creation.
Almost always because the order was routed, by Shopify's order routing rules, to a location your app does not own. Since the 2024-10 API change, an app can only fulfill orders assigned to its own location; it has no visibility or authority over stock assigned elsewhere, regardless of how the integration is built.
assigned_location on the FulfillmentOrder. The per-variant fulfillment_service field is unreliable once a variant is stocked at more than one location type, which Shopify explicitly allows.
FulfillmentOrder.status describes one location's piece of the order (OPEN, IN_PROGRESS, INCOMPLETE, ON_HOLD, SCHEDULED, CANCELLED, CLOSED). displayFulfillmentStatus is an aggregate across the whole order for display only, and Shopify's own docs say it does not capture full fulfillment detail. They can show different, non-contradictory states at the same time.
Yes. Order routing can assign different line items to different locations from the start, and an existing FulfillmentOrder can also be split afterward into a remaining piece and a new one, each following its own status from that point.
It marks the order incomplete and returns control to the merchant, who can then move the remaining items to another location, refund them, or re-request fulfillment from the same service. It only works under narrow conditions: assigned to a fulfillment-service location, request already accepted, status exactly IN_PROGRESS, and only callable by the app that accepted the request.
Yes. Whether InfiPlex is pushing an order into Shopify from another channel or pulling an order out of Shopify to fulfill and track elsewhere, it can move the resulting fulfillment order to whichever location the client has defined, rather than leaving it wherever Shopify's own automatic routing assigned it.
Both directions are supported. On the push side, orders sent into Shopify from another channel can be moved to a specific location as they are created. On the pull side, InfiPlex can move every order pulled out of Shopify to one specific location for fulfillment before tracking is set.
Because the objects, status fields, and ownership rules all exist specifically to handle more than one location correctly, and most of the confusing edge cases, wrong status field, wrong location field, ownership restrictions, only appear once more than one location is genuinely in play.
Fulfillment orders, routed to wherever you tell InfiPlex to put them
assigned_location read correctly, the right status field used for the right decision, and orders moved to the location your rules call for on push or pull. Live in 1–3 business days.
Fighting Shopify's fulfillment API across multiple locations or 3PLs?
We've built against every part of this API covered on this page, including moving fulfillment orders to the location a client defines on push or pull. Tell us where it's breaking and we'll help you find the actual cause. Contact us, email info@infiplex.com, or call 888‑770‑0857.
Our website uses cookies to help provide the best user experience. By continuing to use this site, you consent to the use of cookies as described in our Privacy Policy. OK