Update Magento product using curl and the REST API

I just spent all afternoon teaching myself how to update a product in Magento using the REST API and curl. I started by building on the tutorial by Ashley Schroder which got me part of the way there, and then figured the rest out the hard way. There are many little gotchas that I encountered while I worked through this and I am pretty disappointed with the lack of information about using the Magento REST API – hope this helps you!

First I set up my REST API roles and attributes in the Magento admin. I had to enable the Admin role and then specifically set which actions I wanted to be available. There are other tutorials that cover this part thoroughly, so in a nutshell you just need to make sure that you:

  1. Configure roles (what can the REST API do?)
  2. Configure attributes (which model attributes can be read/written by the REST API?)
  3. Create a REST API consumer and record the consumer_key and consumer_secret
  4. Associate your admin user to a REST API role
  5. Allow the REST API Guest role to view products (this will help greatly when debugging)

Then you will need to generate an OAuth token. You can try doing it the way Ashley describes by using the oauth Ruby gem, or you can do it the way I did by following the instructions for retrieving a product using the Admin REST API role found on Magento’s site.

It took me quite a while to actually get my token. I ended up having to modify Zend_Controller_Request_Http::getHeader to correct for the fact that my host does not have the function apache_request_headers enabled (for those of us using php-fpm this will always be the case. This StackOverflow answer was what finally pointed me in the right direction.

Once you have your access token and the accompanying secret you can use the oauth Ruby gem to get the nonce, timestamp, and signature that you will need to perform your PUT request and update a product using curl. Here is what that looks like:

You can see the response from oauth beginning on line 10. This is what I used to substitute into the following curl request. You will need to replace the nonce, timestamp, and signature values with your own. Note the use of the –method parameter in the OAuth request to indicate that we want to perform a PUT request. This tripped me up for a while. The default is GET and if you don’t include method you’ll get a signature mismatch. Note also that I’m passing the OAuth authorization details using a header instead of in the querystring like other examples on the web. The querystring method did not work for me.

You might also note the duplicate Content-Type and Content_Type headers. This little gotcha stopped me in my tracks for a while until I found this post on the Magento boards.

Finally, you can issue a curl request using the values from the OAuth request dance that will – if your roles and attributes are configured correctly – update a product in Magento. The product data that you want to update is passed using curl’s -d parameter as a JSON string containing as many attribute name and value pairs as you want to update. Note that you cannot pass the text values for dropdown attributes – you need to use their option ID values. This seems like a disappointing half-implementation of a very useful feature to me, but then again, I’ve come to expect this sort of stuff when working with Magento!

During my research I also successfully created a product using the PHP OAuth library and the examples provided by Magento. The file I created to do that is in the gist below. Remember to update your consumer_key, consumer_secret, and URLs to your own. There are a few weird behaviours I noticed:

  1. When you create a product using the REST API, you can not actually retrieve it using the REST API until you save the product. This is explained further in a Magento StackExchange post.
  2. I received a 401 error every time a product was created successfully that indicated the same nonce had been used before. I tracked this down to /app/code/core/Mage/Api2/Model/Resource.php on line 227, where after creating a product the default response is to return a Location header which sends the client to the REST response with details of the newly-created product. I am unsure of the resolution but know that it has something to do with the way the PHP OAuth library negotiates the Location header it receives. I did not pursue this further – the product was being created fine and that was ok by me!

That concludes my exploration of Magento’s REST API and I hope this synthesis helps you in your own research.

Drew Gillson


VP, Technology at LiveOutThere.com. We provide the clothing, footwear, and gear that Canadians need to stay comfortable and looking great, from the city to the mountains. Since 2001, I have applied my expertise to clients in the advertising, retail, philanthropic, travel/tourism, real estate, and healthcare industries.

Comments ( 8 )

  1. ReplyDylan
    Thank you so much for this insight, it really helped me out with creating products using oAuth!
  2. ReplyJames Munsch
    There is an easier solution here: http://www.magentocommerce.com/api/soap/catalog/catalogProduct/catalogProduct.html Be sure to create the SOAP user and assign the roles accordingly. Also create the api_key.
  3. ReplyJames Munsch
  4. ReplyJames Munsch
    This seems to be a simpler solution and works in magento1.9: Where _s is the sku string: login('YOURSOAPUSER', 'YOURSOAPPASS'); $_s = '123%'; $filters = array( 'sku' => array('like'=> "$_s" ) ); $products = $proxy->call($sessionId, 'product.list', array($filters)); var_dump($products); } catch (Exception $e) { echo "" . print_r($e,true) . ""; }
    • James Munsch
      This seems to be a simpler solution and works in magento1.9: Where _s is the sku string: array(‘like’=> “$_s” ) ); $products = $proxy->call($sessionId, ‘product.list’, array($filters)); var_dump($products); } catch (Exception $e) { echo “” . print_r($e,true) . “”; }
  5. ReplyJames Munsch
    Hey thanks for the write up. Just for anyone who grumbles onto this post: oauth --verbose --query-string --consumer-key YOURKEY --consumer-secret YOURSECRET --access-token-url http://localhost/oauth/token --authorize-url http://localhost/index.php/admin/oauth_authorize --request-token-url http://localhost/index.php/oauth/initiate authorize Using Magento 1.9 ... although I may or may not have the rewirtes set correctly, in order to get closer I had to use `index.php` as above. And as of php5.4 I think the headers bit has been resolved? E.g.: $headers = apache_request_headers(); foreach ($headers as $header => $value) { echo "$header: $value \n"; } Returns without error. But still getting the below, so I am thinking it might be the rewrites or something, but I am probably totally wrong. Still new here. [message:protected] => Invalid auth/bad request (got a 404, expected HTTP/1.1 20X or a redirect) Anyways. Thanks Drew.
  6. ReplyMyrna Smit
    Question: How did you modify Zend_Controller_Request_Http::getHeader - in which document/path. I'm using Magento 1.9 but the public function getHeader seems to be protected now? Can you please help? Thank you in advance.
  7. ReplyDan M
    That was the stack overflow answer that pointed you in the right direction and you didn't even upvote it?!