Fulfillable location ID in Order API

PatrickWatzeels
Shopify Expert
14 0 13

Hi all,

 

I have a question regarding the REST API for Orders, or it is more a 'feature request' 😉

It came to my attention that the fulfillable location is not in the JSON output of the API for an order.

 

So when an order is placed the unfulfilled items are listed in the order detail page. You can change the fulfillable location if you want. It would be very nice if it is possible to put this fulfillable location id in the JSON of the order (in the line_items section since an order can be fulfilled from 2 locations).

 

So when we fulfil the order through the API that we know what the current value is and we can just use this value directly in the fulfillment API request.

 

Thanks!

 

fulfillable-location.png

Solutions Engineer / Sr. Developer at CODE - a Shopify Plus agency | Delft | The Netherlands
Replies 33 (33)

Jonathan-HA
Shopify Partner
317 24 99

+1 for this!

 

Just got a request for it recently from a customer of one of our apps.

Co-Founder / Developer at Highview Apps
Our Shopify Apps: EZ Exporter | EZ Inventory | EZ Importer | EZ Notify | EZ Fulfill

renan
Shopify Partner
7 0 3

+1 ! Any update on this ? 

In the graphql api there is the "DraftFulfillment" and we can get the location from "service.location" but the location name is different from the one shown on the order =/

Lasvad
Excursionist
14 0 5

Any update here?

Since its sortable and can be updated via UI, one would think it should be possible to access via API. Based on some research and checking the json payload, this doesn't seemed solved yet, hoping I'm wrong.

browntaped
Tourist
7 0 4

Is there a solution for this? Is this solved?

Gregarican
Shopify Partner
1033 86 285

There has been a solution to this for awhile now. Either through the REST API (https://shopify.dev/docs/admin-api/rest/reference/inventory/inventorylevel?api[version]=2020-07), or the GraphQL API. You can get all of the information in one shot a lot easier through the GraphQL API in my opinion at least. So here's an example where you can query the API for a product variant and see fulfillable quantities at up to 10 fulfillment locations.

{
  productVariant(id: "gid://shopify/ProductVariant/31512998182964") {
    title
    id
    product {
      title
    }
    inventoryItem {
      id
      inventoryLevels(first: 10) {
        edges {
          node {
            id
            available
            location {
              id
              name
              address {
                address1
                address2
                city
                province
                country
                phone

              }
            }
          }
        }
      }
    }
  }
}

 

Lasvad
Excursionist
14 0 5

Hmm I don't believe this actually solves the current issue @Gregarican. If the specific Item has inventory at 2 locations both of these locations will appear in the Inventory Levels response. There doesn't seem to be a way to get the location_id for what is selected from the dropdown. 


If I'm mistaken, please let me know. I ran through the endpoints quickly with Postman to confirm. Product_variant -> Inventory_item -> Inventory_levels

 

Lasvad_1-1595953258686.png

 

 

Gregarican
Shopify Partner
1033 86 285

So you actually tried the GraphQL example that I provided? It displays the id (i.e. - the location_id) and the name (i.e. - the display name, like in the Shopify web admin dropdown) in the results. I'll paste the raw data for the GraphQL API response that I received when I tried it. You can install the Shopify GraphiQL App as an app on a production store, test store, development store, etc. and test out API requests. It's pretty useful for learning how it works.

Specifically below, the  

...

"location": {
"id": "gid://shopify/Location/203128",
"name": "Sawmill",

...

is what you are looking for. In above, the 203128 is the location_id and Sawmill is the display name. Can't be much plainer than that?

 

 

{
  "data": {
    "productVariant": {
      "title": "Default Title",
      "id": "gid://shopify/ProductVariant/31512998182964",
      "product": {
        "title": "\"Be Own Kind of Beautiful\" Cuff"
      },
      "inventoryItem": {
        "id": "gid://shopify/InventoryItem/33055390433332",
        "inventoryLevels": {
          "edges": [
            {
              "node": {
                "id": "gid://shopify/InventoryLevel/4232978?inventory_item_id=33055390433332",
                "available": 2,
                "location": {
                  "id": "gid://shopify/Location/203128",
                  "name": "Sawmill",
                  "address": {
                    "address1": "6280 Sawmill Road",
                    "address2": "",
                    "city": "Dublin",
                    "province": "Ohio",
                    "country": "United States",
                    "phone": ""
                  }
                }
              }
            },
            {
              "node": {
                "id": "gid://shopify/InventoryLevel/17069604926?inventory_item_id=33055390433332",
                "available": 0,
                "location": {
                  "id": "gid://shopify/Location/17431658558",
                  "name": "Easton",
                  "address": {
                    "address1": "3960 New Bond Street",
                    "address2": "",
                    "city": "Columbus",
                    "province": "Ohio",
                    "country": "United States",
                    "phone": ""
                  }
                }
              }
            },
            {
              "node": {
                "id": "gid://shopify/InventoryLevel/17069637694?inventory_item_id=33055390433332",
                "available": 0,
                "location": {
                  "id": "gid://shopify/Location/17431691326",
                  "name": "Weber",
                  "address": {
                    "address1": "1523 East 15th Street",
                    "address2": "",
                    "city": "Tulsa",
                    "province": "Oklahoma",
                    "country": "United States",
                    "phone": ""
                  }
                }
              }
            }
          ]
        }
      }
    }
  },
  "extensions": {
    "cost": {
      "requestedQueryCost": 35,
      "actualQueryCost": 14,
      "throttleStatus": {
        "maximumAvailable": 1000,
        "currentlyAvailable": 986,
        "restoreRate": 50
      }
    }
  }
}

 

 

Lasvad
Excursionist
14 0 5

Appreciate the response @Gregarican, I used the rest endpoints for my test.

the solution you described returns all the locations that a specific product_variant has inventory at. 

What we are looking for is how to get the location_id for the selected dropdown location by only using the API.

Example using the data you provided

If in the Shopify UI we had selected `Sawmill` from the dropdown of an unfulfilled order, how would we be able to determine that from the response? The return has 3 different locations.

We need some way to get ether the name of the location, which can then be used to find the location_id from all the locations of the shop, or we need a `reference_location_id` that directly points to the location that is used for the dropdown on the unfulfilled order.

 

Please let me know if any piece is unclear. Happy to dive into more details.

 

Cheers

Gregarican
Shopify Partner
1033 86 285

I thought you were looking to retrieve all of the location ID's and display names for a variant that's stocked. If you are just looking to pull any/all locations with their ID's and display names, then this is also something possible using the Shopify GraphQL API.

Here's a query. First 10 locations with this information:

 

{
    locationsAvailableForDeliveryProfilesConnection (first: 10) {
        edges {
            node {
                id
                name
            }
        }
    }
}

 

 

And here was the response that I got back:

 

{
  "data": {
    "locationsAvailableForDeliveryProfilesConnection": {
      "edges": [
        {
          "node": {
            "id": "gid://shopify/Location/203128",
            "name": "Sawmill"
          }
        },
        {
          "node": {
            "id": "gid://shopify/Location/17431658558",
            "name": "Easton"
          }
        },
        {
          "node": {
            "id": "gid://shopify/Location/17431691326",
            "name": "Weber"
          }
        },
        {
          "node": {
            "id": "gid://shopify/Location/18763743294",
            "name": "Green Hills"
          }
        }
      ]
    }
  },
  "extensions": {
    "cost": {
      "requestedQueryCost": 12,
      "actualQueryCost": 6,
      "throttleStatus": {
        "maximumAvailable": 1000,
        "currentlyAvailable": 994,
        "restoreRate": 50
      }
    }
  }
}

 

So translating this to the Shopify web admin, if I were to pull down Sawmill in the location dropdown, this would map to location_id 203128 in the API. Does this make more sense?

 

browntaped
Tourist
7 0 4

@Gregarican In our case we have 2 locations. Whenever a new order arrives, shopify is automatically assigning the location to be used for fulfillment which is great. However, we want to get this information using REST or GraphQL, wow do we do that? Also unlike @PatrickWatzeels we are not getting the drop down to update the location, is there some setting we need to do for this?

browntaped_0-1595987056733.png

 

Lasvad
Excursionist
14 0 5

Hey @browntaped, Sounds like we are encountering the same issues regarding getting the specified location from the rest endpoint. Based on other forums, I don't believe this is possible yet. https://community.shopify.com/c/Shopify-APIs-SDKs/Get-Location-Id-of-the-item-on-the-order-that-shop...

In terms of the getting the dropdown to appear, you need to have multiple locations on your shop and you need to have more then 1 location on the item. 

Lasvad_1-1595990413537.png

 

Lasvad_0-1595990346320.png

 

browntaped
Tourist
7 0 4

@Lasvad Yes, you are right! multiple locations need to carry the inventory and for such products I am able to see the drop down. Thank you for the information.

With respect to getting the location, we have been spending lot of time in figuring out. Unfortunately shopify support has not been helpful and they keep referring us to the developer community and as you mentioned there seems to be no solution for this 😞

Gregarican
Shopify Partner
1033 86 285

From my end, I don't know what other assistance I can offer. I provided two specific functional examples --- one example listing all location ID's and display names that can stock a specified product variant, another example listing any/all location ID's defined for a shop along with their display names. These examples utilize the Shopify GraphQL API not the Shopify REST API. But nevertheless it's a means to an end. 

 

reyanshmishra
Tourist
3 0 1

+1 for this feature.

Mark_Stewart
Tourist
11 0 3

I posted about this myself here before finding this thread.

I think the original poster and others in this thread articulated it slightly better than myself. I really think this is quite a large hole in the fulfilment/inventory API implementations as it makes it very difficult or impossible to create or manage complex fulfillments from multiple locations from within an app.

It would be great if the community could get more clarity on how things like this can be achieved.

Gregarican
Shopify Partner
1033 86 285

I still don't understand what the gap is. Below is a GraphQL request example. I have an order that hasn't been fulfilled. But should be pulled from the Sawmill location based on what the order shows in the Shopify web admin. 

{
  order(id: "gid://shopify/Order/2645786329250") {
    lineItems(first: 10) {
      edges {
        node {
          fulfillmentService {
            location {
              id
              name
            }
          }
        }
      }
    }
  }
}
{
  "data": {
    "order": {
      "lineItems": {
        "edges": [
          {
            "node": {
              "fulfillmentService": {
                "location": {
                  "id": "gid://shopify/Location/203128",
                  "name": "Sawmill"
                }
              }
            }
          }
        ]
      }
    }
  },
  "extensions": {
    "cost": {
      "requestedQueryCost": 33,
      "actualQueryCost": 6,
      "throttleStatus": {
        "maximumAvailable": 1000,
        "currentlyAvailable": 994,
        "restoreRate": 50
      }
    }
  }
}

If I look up the order in the Shopify web admin, the UI shows that its origin location is Sawmill. And that's what the GraphQL response shows as well.

Mark_Stewart
Tourist
11 0 3

Okay so here's an example with two locations. In this example Order there's three line items, according to the page for this order the first two items are coming from Test Location 1 and the third item is coming from Test Location 2.

Screenshot 2020-08-31 at 15.34.49.png

Using a similar query to yours, here's the response:

 

{
  "id": "gid://shopify/Order/2672195043493",
  "lineItems": {
    "edges": [
      {
        "node": {
          "id": "gid://shopify/LineItem/5841433886885",
          "sku": "Tool - Ice 15mm Wrench",
          "quantity": 1,
          "fulfillmentService": {
            "location": {
              "id": "gid://shopify/Location/50193891493",
              "name": "Test Location 1"
            }
          }
        }
      },
      {
        "node": {
          "id": "gid://shopify/LineItem/5841433919653",
          "sku": "Tool - Park Balldriver 456",
          "quantity": 1,
          "fulfillmentService": {
            "location": {
              "id": "gid://shopify/Location/50193891493",
              "name": "Test Location 1"
            }
          }
        }
      },
      {
        "node": {
          "id": "gid://shopify/LineItem/5841433952421",
          "sku": "Aerospoke - Lime Green Front",
          "quantity": 1,
          "fulfillmentService": {
            "location": {
              "id": "gid://shopify/Location/50193891493",
              "name": "Test Location 1"
            }
          }
        }
      }
    ]
  }

The location in the response is always Test Location 1. What is the preferred method for getting the Location that Shopify is actually showing me in the admin?

This becomes even more challenging when a single line item has it's quantities split across two locations.

Gregarican
Shopify Partner
1033 86 285

I see what you mean now. My apologies for being dense, in that my examples included items which were only currently stocked at one particular location. Since our dummy data set is like our production set for the most part. Almost all serialized one-of-a-kind items. For a test I stocked that item at several locations and created an order in the Shopify web admin. As you can see it should be pulled from our Easton location per the UI.

Admin.jpg 

Yet when I query this order in GraphQL, it shows one of the other stock site locations as the fulfillment point.

GQL.jpg

Unless I'm missing something, this definitely appears to be a bug. Can anyone from Shopify chime in with some insight or feedback?

Mark_Stewart
Tourist
11 0 3

No need to apologise, it's counter intuitive. I think it's clear that this is either a bug or an oversight in the API.

Or maybe Shopify intends us to handle this in a different way that isn't well documented anywhere. Either way it would be nice to find out as myself and others have all had similar requests from clients that it appears (at least at this point) to be impossible to implement.

Gregarican
Shopify Partner
1033 86 285

The first place I was going to look other than the API was the webhook data sent for orders/create --> https://shopify.dev/docs/admin-api/rest/reference/events/webhook. But that request body doesn't indicate a fulfillment site at all. This really is odd. For those clients who are looking to act off this data. From everything I see, unless they directly hit the Shopify web admin they can't get the info.

Lasvad
Excursionist
14 0 5

Hey everyone.

I've made significant progress on this. What is needed is to use the Fulfillment Orders endpoint. https://shopify.dev/docs/admin-api/rest/reference/shipping-and-fulfillment/fulfillmentorder and be use `Merchant-managed fulfillment` orders to enable.

Screen Shot 2020-08-31 at 10.36.16 AM.png

as this will enable the Fulfillment Order endpoint to actually be populated with what is shown in the Shopify Admin.

Its not perfect, as it gives you the entire history of the all the order fulfillments that have been available in the past and there is not timestamp, but you can use the `

"status": "in_progress" or "open"` to see the current ones. If a split has been fulfilled, it will be marked as `Closed`
Lasvad
Excursionist
14 0 5

More details. Used in the Fulfillment Orders endpoint will return an array of this format.

I've combined 2 different examples here so the screenshots may not match perfectly.

For partial fulfillments at a specific location will move the FulfillmentOrder to be `In Progress` ( Location B has 2 items. 1x test Item A, 2x test item B. If 1 of the 2 test item B were fulfilled, it would show In progress). If nothing has been fulfilled yet, they will appear as `Open` for status

Image 2020-08-31 at 10.38.32 AM.png

 

Image 2020-08-31 at 10.40.38 AM.png

Gregarican
Shopify Partner
1033 86 285

If you look at my last post with the screen shots, you'll see that I called this FulfillmentOrder endpoint using the GraphQL API and it still showed the incorrect location. 

Lasvad
Excursionist
14 0 5

Hmmm let me take a look. I've successfully finished and delivered the feature I needed by using the Fulfillment order endpoint via REST.  

Lasvad
Excursionist
14 0 5

@Gregarican You do not want a Fulfillment Service, I initially thought the same thing. This is a completely different feature in Shopify which caused confusions for me. If you update the app permissions to have Merchant-managed fulfillment orders permissions and then add assigned_location_id on the node where you call line_items, I believe this should work.

Image 2020-08-31 at 10.53.30 AM.png

Gregarican
Shopify Partner
1033 86 285

Yes, I compared a REST API request to a GraphQL API request. Both for the same FulFillmentOrder endpoint. The assigned_location data in the REST API response contained the correct location that the line item was to be pulled from (per the Shopify web admin). Whereas the GraphQL API response contained the incorrect location. There isn't an assigned_location property that I can see in the GraphQL API endpoint. Like I said I could likely be missing something, but based on my observations it appears as if the REST API works as expected for this, whereas the GraphQL API doesn't provide.

.REST API.jpgGQL.jpg

 

Gregarican
Shopify Partner
1033 86 285

Disregard, as I answered my own question in terms of GraphQL. Here is the query that worked. Duh!

{
  order(id: "gid://shopify/Order/2684801679522") {
    fulfillmentOrders(first: 10) {
      edges {
        node {
          assignedLocation {
            name
          }
          id
          lineItems(first: 10) {
            edges {
              node {
                lineItem {
                  id
                  name
                }
              }
            }
          }
        }
      }
    }
  }
}
Mark_Stewart
Tourist
11 0 3

I actually did get that far with fulfilment orders too, which does give you the assigned locations.

The other piece of the puzzle (in my case at least) is getting the quantities available at other locations, to work out if another location could be used. It only seems possible to get the unreserved quantity available.

Lasvad
Excursionist
14 0 5

@Mark_Stewart 

Have you seen this endpoint. This will tell you all the locations that something can be moved too. https://shopify.dev/docs/admin-api/rest/reference/shipping-and-fulfillment/locationsformove

I haven't used it yet but looks promising.

Gregarican
Shopify Partner
1033 86 285

I think you can do it all in one shot, in terms of a single GraphQL API request. Here's an example, where I can pull an order to see it's assignedLocation, as well as the inventoryLevels where else it's currently available. Although this still doesn't resolve the "reserved" quantities that by default might have been linked to other orders. Therefore perhaps a second query would be required.

 

{
  order(id: "gid://shopify/Order/2684801679522") {
    name
    fulfillmentOrders(first: 5) {
      edges {
        node {
          id
          lineItems(first: 5) {
            edges {
              node {
                lineItem {
                  id
                  name
                  variant {
                    inventoryItem {
                      inventoryLevels(first: 5) {
                        edges {
                          node {
                            available                            
                            location {
                              name
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
          assignedLocation {
            name
          }
        }
      }
    }
  }
}

 

Gregarican
Shopify Partner
1033 86 285

Although if you also pull the deactivationAlert and canDeactivate fields in the single GraphQL API request it does inform you that a 0 available item is committed to an unfulfilled order. See below.

 

{
  order(id: "gid://shopify/Order/2684801679522") {
    name
    fulfillmentOrders(first: 5) {
      edges {
        node {
          id
          lineItems(first: 5) {
            edges {
              node {
                lineItem {
                  id
                  name
                  variant {
                    inventoryItem {
                      inventoryLevels(first: 5) {
                        edges {
                          node {
                            available   
                            deactivationAlert
                            canDeactivate
                            location {
                              name
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
          assignedLocation {
            name
          }
        }
      }
    }
  }
}

 

{
  "data": {
    "order": {
      "name": "#1320",
      "fulfillmentOrders": {
        "edges": [
          {
            "node": {
              "id": "gid://shopify/FulfillmentOrder/2420702347426",
              "lineItems": {
                "edges": [
                  {
                    "node": {
                      "lineItem": {
                        "id": "gid://shopify/LineItem/5814392357026",
                        "name": "STSLVR DAVID YURMAN PERIDOT AND DIAMOND CABLE CUFF",
                        "variant": {
                          "inventoryItem": {
                            "inventoryLevels": {
                              "edges": [
                                {
                                  "node": {
                                    "available": 0,
                                    "deactivationAlert": "Can’t unstock from this location because it has unfulfilled orders.",
                                    "canDeactivate": false,
                                    "location": {
                                      "name": "Sawmill"
                                    }
                                  }
                                },
                                {
                                  "node": {
                                    "available": 0,
                                    "deactivationAlert": "Can’t unstock from this location because it has unfulfilled orders.",
                                    "canDeactivate": false,
                                    "location": {
                                      "name": "Easton"
                                    }
                                  }
                                },
                                {
                                  "node": {
                                    "available": 1,
                                    "deactivationAlert": "1 unit of inventory at this location will be deleted.",
                                    "canDeactivate": true,
                                    "location": {
                                      "name": "Green Hills"
                                    }
                                  }
                                },
                                {
                                  "node": {
                                    "available": 0,
                                    "deactivationAlert": null,
                                    "canDeactivate": true,
                                    "location": {
                                      "name": "Weber"
                                    }
                                  }
                                }
                              ]
                            }
                          }
                        }
                      }
                    }
                  }
                ]
              },
              "assignedLocation": {
                "name": "Easton"
              }
            }
          }
        ]
      }
    }
  },
  "extensions": {
    "cost": {
      "requestedQueryCost": 423,
      "actualQueryCost": 21,
      "throttleStatus": {
        "maximumAvailable": 1000,
        "currentlyAvailable": 979,
        "restoreRate": 50
      }
    }
  }
}

 

JoesIdeas
Shopify Expert
2228 203 593

This is a good thread, I've seen this requested quite often (and a few times by me haha) to get the location ID that shows up in the order page, via the REST API + GraphQL so everyone wins.

It would be REALLY COOL if Shopify would just put a property in the line item of the Order data that says assigned_location_id (and maybe assigned_location_name too if you want to be double cool)... so that you could see the location from the API like you do on the order details page.

This would solve the issue and make a bunch of developers happy. 😃👍

• Creator of Order Automator (automate tagging, fulfillment, Amazon, notifications + more)
• Shopify developer for 10+ years, store owner for 7 years
• I also make guides like Shopify Automation Tips and How to Deal with Fraud / Chargebacks
policenauts
Shopify Partner
206 10 67

Thanks @Gregarican, your GraphQL solution works. Because the order webhook object doesn't contain location_id, I am immediately hitting GraphQL to grab this field once the webhook comes in. The maddening thing I just realized is, the node comes up empty when doing this in real-time - probably because the order doesn't yet exist?? Either way, I have to throw a sleep() to create some buffer and make sure the order data exists by the time I query GraphQL.

Like others have mentioned, it would be great if the location_id just showed up in the order webhook object itself without requiring a separate query with a clumsy built-in delay.