amro/gibbon

API Key Missing for a batch operation

guillaumewrobel opened this issue · 7 comments

Hello,

I'm using your awesome gem to deal with Mailchimp API.

For this batch operation:

  gibbon = Gibbon::Request.new(api_key: '12345', debug: true)
  nl_user_list_id = "12345"

  operations_array = []

  User.first(20).each do |user|

    operations_array << {
      method: "PUT",
      path: "lists/#{nl_user_list_id}/members",
      body: {
        email_address: user.email.downcase,
        status: "subscribed",
        status_if_new: "subscribed",
        merge_fields: {
          FIRSTNAME:    user.first_name,
          LASTNAME:    user.last_name,
        }
      }.to_s
    }
  end

  gibbon.batches.create(
    body: {
      operations: operations_array
    }
  )

I get the following error:

{
  "type":"http://developer.mailchimp.com/documentation/mailchimp/guides/error-glossary/",
  "title":"API Key Missing",
  "status":401,
  "detail":"Your request did not include an API key.",
  "instance":"7635352627-7272"
}

What's wrong with this request?

amro commented

Hi, I’m away from my machine — I’ll take a closer look a little later. At first glance, I wonder if Hash.to_s is really serializing to JSON as you expect when creating the body. That’s the first thing I would double check.

Thanks for your quick answer.

Here is what my_body_hash.to_s looks like:

"{:email_address=>\"test@email.com\", :status=>\"subscribed\", :status_if_new=>\"subscribed\", :merge_fields=>{:FIRSTNAME=>\"John\", :LASTNAME=>\"DOE\"}}"

The Mailchimp API v3 schema gives as an example:

          "body": {
            "type": "string",
            "title": "Body",
            "description": "A string containing the JSON body to be used with the request",
            "example": "{\"title\":\"Test\"}"
          }

So I had fun transforming my hash to look like the following, but it doesnt work either.

$ my_body_hash.to_s.gsub(":","\"").gsub("=>","\":")

"{\"email_address\":\"test@email.com\", \"status\":\"subscribed\", \"status_if_new\":\"subscribed\", \"merge_fields\":{\"FIRSTNAME\":\"John\", \"LASTNAME\":\"DOE\"}}"

If it helps, here is the gibbon debug print:

WARNING: Unexpected middleware set after the adapter. This won't be supported from Faraday 1.0.
I, [2017-09-28T14:04:05.708435 #28599]  INFO -- : post https://us8.api.mailchimp.com/3.0/batches
D, [2017-09-28T14:04:05.708729 #28599] DEBUG -- request: User-Agent: "Faraday v0.13.1"
Authorization: "Basic YXBpa2V5OjM4OGFlNDAzYWMyYjYxYzQ1OGEyNjcwNGZkNDA5OGJjLXVzOA=="
Content-Type: "application/json"
D, [2017-09-28T14:04:05.708865 #28599] DEBUG -- request: {"id":"8ec6cad48b","status":"pending","total_operations":0,"finished_operations":0,"errored_operations":0,"submitted_at":"2017-09-28T12:04:06+00:00","completed_at":"","response_body_url":"","_links":[{"rel":"parent","href":"https://us8.api.mailchimp.com/3.0/batches","method":"GET","targetSchema":"https://us8.api.mailchimp.com/schema/3.0/Definitions/Batches/CollectionResponse.json","schema":"https://us8.api.mailchimp.com/schema/3.0/CollectionLinks/Batches.json"},{"rel":"self","href":"https://us8.api.mailchimp.com/3.0/batches/8ec6cad48b","method":"GET","targetSchema":"https://us8.api.mailchimp.com/schema/3.0/Definitions/Batches/Response.json"},{"rel":"delete","href":"https://us8.api.mailchimp.com/3.0/batches/8ec6cad48b","method":"DELETE"}]}
I, [2017-09-28T14:04:05.709006 #28599]  INFO -- Status: 200
D, [2017-09-28T14:04:05.709127 #28599] DEBUG -- response: server: "openresty"
content-type: "application/json; charset=utf-8"
x-request-id: "c206ab22-8b2a-4663-ac19-d97b0836fb6e"
link: "<https://us8.api.mailchimp.com/schema/3.0/Batches/Instance.json>; rel=\"describedBy\""
vary: "Accept-Encoding"
date: "Thu, 28 Sep 2017 12:04:06 GMT"
content-length: "748"
connection: "close"
set-cookie: "_AVESTA_ENVIRONMENT=prod; path=/"
D, [2017-09-28T14:04:05.709220 #28599] DEBUG -- response: {"id":"8ec6cad48b","status":"pending","total_operations":0,"finished_operations":0,"errored_operations":0,"submitted_at":"2017-09-28T12:04:06+00:00","completed_at":"","response_body_url":"","_links":[{"rel":"parent","href":"https://us8.api.mailchimp.com/3.0/batches","method":"GET","targetSchema":"https://us8.api.mailchimp.com/schema/3.0/Definitions/Batches/CollectionResponse.json","schema":"https://us8.api.mailchimp.com/schema/3.0/CollectionLinks/Batches.json"},{"rel":"self","href":"https://us8.api.mailchimp.com/3.0/batches/8ec6cad48b","method":"GET","targetSchema":"https://us8.api.mailchimp.com/schema/3.0/Definitions/Batches/Response.json"},{"rel":"delete","href":"https://us8.api.mailchimp.com/3.0/batches/8ec6cad48b","method":"DELETE"}]}
amro commented

@guillaumewrobel You want to turn the hash into a JSON string. In the first case you posted, the hash is a string representation of a hash. The second looks correctish at first glance, but it's not the right way to do it. Replacing the => manually is probably error prone.

Yep, I see the log says HTTP 200 but 0 events processed. My guess is the events couldn't be parsed properly.

Try this:

gibbon = Gibbon::Request.new(api_key: '12345', debug: true)
  nl_user_list_id = "12345"

  operations_array = []

  User.first(20).each do |user|

    operations_array << {
      method: "PUT",
      path: "lists/#{nl_user_list_id}/members",
      body: MultiJson.dump({
        email_address: user.email.downcase,
        status: "subscribed",
        status_if_new: "subscribed",
        merge_fields: {
          FIRSTNAME:    user.first_name,
          LASTNAME:    user.last_name,
        }
      })
    }
  end

  gibbon.batches.create(
    body: {
      operations: operations_array
    }
  )

Thanks for the tip, but I got the same error.

I can't make batch operations work, even on the Mailchimp playground :(

amro commented

I noticed you're making a PUT here (upsert). That'll only work if you include the email hash in the path according to MC's docs.

This snippet worked for me, though the response still says 0 operations. You should contact MailChimp support about that as I believe it's a bug in the API.

api_key = "..."

list_id = "..."
emails = ["myemail+555@gmail.com", "myemail+5552@gmail.com"]

operations_array = []
emails.each do |email|
  email = email.downcase
  email_hash = Digest::MD5.hexdigest(email)

  body = {
    email_address: email,
    status: "subscribed",
    status_if_new: "subscribed",
    merge_fields: {
      FNAME: "My",
      LNAME:  "Email",
    }
  }

  operations_array << {
    method: "PUT",
    path: "/lists/#{list_id}/members/#{email_hash}",
    body: MultiJson.dump(body)
  }
end

gibbon = Gibbon::Request.new(api_key: api_key, debug: true)
gibbon.batches.create(
  body: {
    operations: operations_array
  }
)

You were right @amro.

I had to write the email hash in the path.
The reason I got the API key missing message was simple: I went on the web page https://usx.api.mailchimp.com/3.0/batches/1234 and since the request is not authenticated, MC raised that error.

Now it works well.

Thank you!