Updated Deadline: Aug 1st -- [Deprecation] Important changes to ProductVariant, Refund and Fulfillment APIs

New Member
3 0 0

Hi Ryan,

According to the document https://help.shopify.com/api/getting-started/authentication/oauth/scopes the app needs read_locations scope to have access to the locations resource. 

But I have tested with several stores that the app can read location with these scopes: write_products, read_products, write_orders, read_orders, write_shipping, read_shipping but without read_locations scope.

{
    "access_scopes": [
        {
            "handle": "write_products"
        },
        {
            "handle": "write_orders"
        },
        {
            "handle": "write_shipping"
        },
        {
            "handle": "read_products"
        },
        {
            "handle": "read_orders"
        },
        {
            "handle": "read_shipping"
        }
    ]
}

Since we need to know the location id to create fulfillment we need to have access to location resource. 
Should we update the access scopes for the app by adding read_locations or not because the app has access to it already?

Thanks,

Yuriy
 

0 Likes
Shopify Staff
Shopify Staff
469 36 92

Hey all, I'll try to answer what I can.  We definitely know there is a need for some better error messaging as inventory can have a lot of edge cases so good error messaging is key.

 

When doing `POST /admin/inventory_levels/set.json` if the location_id belongs to a fulfillment_service the endpoint returns 422 without any error message even if you pass `disconnect_if_necessary: true`

I've asked the team to look into this. looks like a bug.

 

We created a new product with some inventory in the screen and inventory levels GET call shows the item is randomly assigned location_id = 1809842203 which doesn't exist when we lookup using GET location calls.

Is there any reason why the new product is assigned to a random location_id after creation ?

There is currently some older shops that have inventory items assigned to deleted locations, there is work ongoing to fix this bad data. 

 

Then when we tried to set the inventory qty using set.json it throws 403 forbidden even when disconnect_if_necessary to true.

403 is returned if the item is active at a location (not a fulfillment service location) and set or connect is called for a different (not a fulfillment service location) and the shop is not multi-location. This happens regardless of any disconnect_if_necessay or relocate_if_necessaryflags. You won't see a 403 if you are dealing with a fulfillment service location. 

 

I even tried with 200 inventory adjustment but it results the same error. Then I tried with only 14 inventory adjustment, it showed me the same.

But when I tried multiple times with 11 adjustment values, it showed me unreliable results, like, it results proper output while some time shows "TypeError: NetworkError when attempting to fetch resource." error again.

There may be a size limit for requests, not entirely sure.  The good news is that there is no call limit besides the complexity costs, so you can simply make multiple calls of 10 mutations.

 

I saw the fufillment service is just a name, so does that mean that i will need to search through the locations based on the name and find the location_id

I would probably store these locally instead of fetching each time as they are unlikely to change often.  But yes, you would need to find the location_id associated to the service.

 

So, if my shop has "multi_location_enabled" set to false, confirmed by querying the "shop" endpoint - is there any action I need to take? This seems unclear.

From what I understand, for my POST requests to create Fulfillments, I need to add a "location_id" - but the only locations my shop has (found by querying the "locations" endpoint) are Point-Of-Sale iPad locations. (I'm guessing these are meant to be "legacy" locations now, but their "legacy" properties are false).

What should I be setting "location_id" to on my requests..??

-EDIT-

I'm seeing a "primary_location_id" - is this what I should be using? Is this property even mentioned in the documentation anywhere?

Also, the migration guide URL at the top of this page is still broken:
https://help.shopify.com/api/reference/shipping_and_fulfillment/fulfillment#create

Even without multi-location enabled you still need to migrate to use the new APIs.  Currently the only additional locations that a shop can have are POS locations, and fulfillment service locations.  The "legacy" property applies to fulfillment services only, not POS locations.  Your fulfillment should include the "location_id" that corresponds to the physical location you are shipping the item from.  "Primary_location_id" on the shop.json is a property that will always return the "location_id" of the 'Shipping Origin' which is a setting in the Shopify admin under shipping.  This is the address used to calculate the default shipping rates.  URL has been fixed.

 

I am still unsure if my fulfillment service is set to manual, which location_id should i use. I can't seem to find the answer for this in any of the documentation. Not sure is it because i am missing something or am unable to understand.

If an app is creating a fulfillment, the "location_id" you provide in the fulfillment should be the physical location that the goods are being fulfilled from.  If it is being provided by a 3rd party service, you pass the "location_id" of that fulfillment service.

 

I've done the /admin/inventory_levels/set.json POST through php with json data, and I'm receiving an error message:

{"errors":{"inventory_item_id":"Required parameter missing or invalid"}}

I've sent inventory_item_id in the json string.  I got the inventory_item_id from the product api call in the variants section of the return.

As per the docs you need to pass all 3 of: inventory_item_id, location_id, available. Another developer posted a solution above as well!

 

First of all, I am sorry to come back to this forum again, you must be drowning in different questions the developper community is bring up every day. 

We have been in touch with a couple of Shopify developpers and they reported an issue on Shopify side which is causing the inventory level updates to either fail with 422 error or reset the product filfillement services to Manual. 

The Shopify developpers confirmed that you guys are looking into these issues. Can you please let us know if the July 1st deprecation deadline will still apply even if these issues aren't fixed? 

Thanks in advance and again, sorry for all the back and forth. 

No problem, we realize this is as big of a migration for app developers as it is for us.  We will have more information to share soon on these issues.  Thanks for the patience!

 

Since we need to know the location id to create fulfillment we need to have access to location resource. 
Should we update the access scopes for the app by adding read_location or not because the app has access to it already?

We are currently not enforcing the need to have "read_locations" in order to query the `locations.json` endpoint to ease in migration.  This will be required in the future, so yes you should add it.

 

Happy coding!

Developer Experience @ Shopify
0 Likes
Shopify Partner
2 0 0

Ryan,

I have some questions on edge cases:

1. If we're POSTing a fulfillment without any line items (in order to fulfill the entire order), do we need to fetch the individual line items from the order and create a different fulfillment for each item? During testing, we tried POSTing a fulfillment using mixed items with mutually exclusive locations, but only specifying a single location_id, and received this error: 

"{"errors":{"line_items":["must be stocked at the same location"]}}"

To me, this suggests we can no longer POST a fulfillment without line items if any items have mutually exclusive locations. Is this accurate?

2. Using an Order with a single item having quantity = 2, when we POST a partial fulfillment (quantity = 1) and specify a location A that has 0 quantity allocated, it appears that Shopify reallocates inventory levels at specified location A so that inventory level = -2. Further, the admin UI won't let us remove this item from location A because "Unfulfilled orders assigned to this location need inventory from this location." Is this the desired behavior? I was under the impression that going forwards items, not orders, are assigned to locations?

3. Right now we can POST fulfillments using location_ids with no stock, resulting in negative stock at that location. Will this functionality be in place after July 1st or are we currently in a grace period? Will we need to make sure that locations have stock available in order to POST fulfillments using that location_id?

Thanks, and appreciate all the hard work!

0 Likes
Shopify Partner
3 0 0

Hi Ngt500,

Thanks,

I actually did it as you described here, but it still doesn't work, I even used the curl statement directly:

curl -X POST -k -H -i 'https://apikey:apipassword@store.myshopify.com/admin/inventory_levels/set.json' --data '{"inventory_item_id":"<inventory item id>","location_id":"<location id>","available":"34"}'

It still puts out the error.  Do you have any suggestions I think I may be missing here?

0 Likes
New Member
2 0 1

To "ostalks Admin"

Here is a basic version of what my app does. It pulls data from a MySQL table and essentially creates the array and does the curl request all in the in the while loop. I have removed the sql code and while loop from the code below.  I would look in your code to make sure you are sending Content-Type and Content-Length header. Also are you rate limiting? From what i've seen above some error messages from the API are still buggy and might not be the right error.

$url           = "https://apikey:apipassword@store.myshopify.com/admin/inventory_levels/set.json";

$inventoryData = array("inventory_item_id" => $inventory_item_id, "location_id" => $location_id, "available" => $available);
$data          = json_encode($inventoryData);

$ch = curl_init();
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type:application/json', 'Content-Length: ' . strlen($data)));
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_POSTFIELDS,$data);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_URL,$url);
$result=curl_exec($ch);
if(curl_getinfo($ch, CURLINFO_HTTP_CODE)!='200')
{
    echo curl_getinfo($ch, CURLINFO_HTTP_CODE)."\n";
}


My API permission: (some permissions might not be required for your app)
Inventory
write_inventory, read_inventory

Locations
read_locations

Product information
read_product_listings, write_product_listings

Products, variants and collections
read_products, write_products

Also I subscribed on your demo store if you would like to email me instead.

0 Likes
Shopify Partner
3 0 0

ngt500,

Thanks, that helped.  I was missing Content-type.  Now works.

0 Likes
Tourist
36 0 2

Robert, I'm looking for an answer on this as well. Did you learn anything new? My store is also not multi location enabled, and I fulfill manually.

 

Could someone please answer Robert and Hari's questions about private apps that fulfill manually and don't have multi location enabled? Does this change coming up on 7/1 still apply in those cases? I did find a location ID on our only fulfillment location and I tested this by adding a location_id to my request to the fulfillment API and it came back as "NotFound", presumably because the location_id field on our orders is set to NULL.

1 Like
Tourist
9 0 1

Hi Ben,

No I haven't got an answer yet, though Ryan did reply - I still have no idea what I should be setting the location_id to of the requests that I make. I have no fulfillment locations, so I have no IDs...!

0 Likes
Shopify Partner
9 0 2

Ben & Robert - I'm also using a private app with no fulfillment services.  For my fulfillments, I'm using the Primary_Location_ID from the /admin/shop.json.  I can query the locations (/admin/locations.json) and confirm that the locations exists.

0 Likes
Shopify Partner
1 0 0

Hi Ryan,

My name is Bindu. I am new here. Trying to migrate to the new Inventory level API without any success. I use a private app to upload inventory. I  successfully retrieved the available quantity using the below endpoint.

"admin/inventory_levels.json?inventory_item_ids=1069369732&location_ids=19931407";

But POST is failing. It keep saying bad request. Couldn't figure out what am I doing wrong in here. Below are some details about my request.

Exception: {"The remote server returned an error: (400) Bad Request."}  

Endpoint:     "https://*****.myshopify.com/admin/inventory_levels/set.json"
Json : {{"location_id":19931407,"inventory_item_id":1069369732,"available":43,"disconnect_if_necessary":true}}    System.Text.StringBuilder
X-Request-ID:    "70d6c6e5-bad0-4290-a532-21890715fcc1" 

 

We have only few more days left to migrate to the new Inventory-level API and I am kind of stuck here. Any help would be greatly appreciated.   

0 Likes