Search code examples
pythonpython-3.xauthenticationoauthetsy

etsy-api-oauth1 PUT Requests return invalid signature when made from python, but not from Postman


I've been troubleshooting an issue when sending a PUT Request to the ETSY REST API, when I make a PUT request, I get a signature invalid error. I have tried all the solutions found on google, but none seem to work.

Sending the same request through POSTMAN works, if I specify the auth parameters to go in the body. However when I try to replicate this using python's standard procedures I get the same invalid signature error.

Even if I export the python code for that exact request from postman, I get a signature invalid error when running said code in python.

This is the json data I need to send:

"products": [
      {
         "product_id":4262200422,
         "sku":"00100012",
         "property_values":[
            {
               "property_id":200,
               "property_name":"Primary color",
               "scale_id":null,
               "scale_name":null,
               "values":[
                  "Black"
               ],
               "value_ids":[
                  1
               ]
            }
         ],
         "offerings":[
            {
               "offering_id":4128359213,
               "price":{
                  "amount":200,
                  "divisor":100,
                  "currency_code":"GBP",
                  "currency_formatted_short":"\\u00a32.00",
                  "currency_formatted_long":"\\u00a32.00 GBP",
                  "currency_formatted_raw":"2.00"
               },
               "quantity":12,
               "is_enabled":1,
               "is_deleted":0
            }
         ],
         "is_deleted":0
      },
      {
         "product_id":4031391357,
         "sku":"00100013",
         "property_values":[
            {
               "property_id":200,
               "property_name":"Primary color",
               "scale_id":null,
               "scale_name":null,
               "values":[
                  "Bronze"
               ],
               "value_ids":[
                  1216
               ]
            }
         ],
         "offerings":[
            {
               "offering_id":4244423138,
               "price":{
                  "amount":300,
                  "divisor":100,
                  "currency_code":"GBP",
                  "currency_formatted_short":"\\u00a33.00",
                  "currency_formatted_long":"\\u00a33.00 GBP",
                  "currency_formatted_raw":"3.00"
               },
               "quantity":56,
               "is_enabled":1,
               "is_deleted":0
            }
         ],
         "is_deleted":0
      }
   ],
"price_on_property": [200],
"quantity_on_property": [200],
"sku_on_property": [200]

Etsy is using Oauth1, POST and GET requests work fine in Python, but don't work in POSTMAN, returning an invalid signature error.

Maybe they are doing something differently that causes this behaviour?

I need to build a request that simply takes product data, oauth1 details, and sends it to Etsy. Please let me know what I'm missing.


Solution

  • I managed to get it working... turns out you aren't supposed to include the actual oauth parameters in the signature calculations.

    This is the code I used to make a PUT request --- Class Definition.

    class etsyClient:
    def __init__(self, consumer_key, consumer_secret, resource_owner_key, 
                                                      resource_owner_secret):
        self.consumer_key = consumer_key
        self.consumer_secret = consumer_secret
        self.resource_owner_key = resource_owner_key
        self.resource_owner_secret = resource_owner_secret
    
        self.oauthclient = self.regen()
    
    def regen(self, sig=oauth1.SIGNATURE_HMAC_SHA1):
        client = oauth1.Client(self.consumer_key,
                               client_secret=self.consumer_secret,
                               resource_owner_key=self.resource_owner_key,
                               resource_owner_secret=self.resource_owner_secret,
                               signature_method=sig)
        return client
    

    Actual request code:

        uri, headers, body = self.client.regen(sig=oauth1.SIGNATURE_PLAINTEXT).sign(
            f"https://openapi.etsy.com/v2/listings/{self.product.listing.id}/inventory")
    
        r = requests.session()
        headers["Content-Type"] = "application/x-www-form-urlencoded"
        data = {
                "listing_id": self.product.listing.id,
                "products": json.dumps(products),
                'price_on_property': [200],
                'quantity_on_property': [200],
                'sku_on_property': [200]
        }
        a = r.put(uri, headers=headers, data=data)