Jump to content

Mailchimp API Batch Request


jaybo
Go to solution Solved by jaybo,

Recommended Posts

Working with Mailchimp API, I'm trying to add contacts without success by sending in PHP Async Request batch call to their endpoint. I've gone trough their documentation may times but still without success, trying to replicate their example. https://mailchimp.com/developer/marketing/guides/run-async-requests-batch-endpoint/ I am using the php sdk.

Would be great if someone could point me in the right direction why the second example is not working.

#################START OF CODE #############################

<?php

    require_once('vendor/autoload.php');
    require_once('config.php');
    include 'dbh.php';
    include 'testDbh.php';

    $mailchimp = new MailchimpMarketing\ApiClient();

    $mailchimp->setConfig([
        'apiKey' => $key,
        'server' => $server
    ]);

        // build json array from mysql db

        $users = [];

        $conn = mysqli_connect("localhost","root","","mailchimpapi");

        //check connection
        if(!$conn){
            echo "Failed to connect to MySQL: " . mysqli_connect_error();
            exit();

          }else{
              echo 'Connection Successful! <br><br>';
          }

          $sql = "SELECT * FROM mailchimpbatch";

            //mysqli write query and get result
            $results = mysqli_query($conn, $sql);

            $users = mysqli_fetch_all($results, MYSQLI_ASSOC);


    $operations = [];

    foreach($users as $user) {
        $operation = [  
            'method' => 'POST',
            'path' => "/lists/$listId/members",
            'operation_id' => $user['id'],
            'body' => json_encode([
                'email_address' => $user['email'],
                'status' => $user['status'],
                'merge_fields' =>
                    'FNAME' => $user['fname'],
                    'LNAME' => $user['lname']
                ]
            ])
        ];

        array_push($operations, $operation);
    }

    try {
        $response = $mailchimp->batches->start($operations);
        echo $response;

    } catch (\MailchimpMarketing\ApiException $e) {
        echo $e->getMessage();
    }

############################END OF CODE ##########################

Here is the print_r of $users I pull from the database (made up people);

Array ( 
	[0] => Array 
		( 
			[id] => 1 
			[status] => subscribed 
			[email] => test1@example.com 
			[fname] => David 
			[lname] => Tester 
		) 
	[1] => Array 
		( 
			[id] => 2 
			[status] => subscribed 
			[email] => test2@example.com 
			[fname] => Kevin 
			[lname] => Ishere 
		) 
	[2] => Array 
		( 
			[id] => 3 
			[status] => subscribed 
			[email] => happy@example.com 
			[fname] => Gerald 
			[lname] => Happy 
		) 
	[3] => Array 
		(
			[id] => 4 
			[status] => subscribed 
			[email] => Tim@example.com 
			[fname] => Tim 
			[lname] => Toolman 
		) 
	[4] => Array 
		( 
			[id] => 5 
			[status] => subscribed 
			[email] => grealish@example.com 
			[fname] => Jack [lname] => Grealish 
		)
)

The error I receive is a 400 BAD REQUEST, INVALID RESOURCE (full error returned is at the bottom of this post).

*****Upon reaching out to Mailchimp they responded with the following:

While we are unable to assist with editing or making PHP calls, we can see the Request is being sent over as an array, and does not have any reference to the required "operations". For example, we would expect to see something like:

```

{
 "operations": [
{
    "method": "POST",
    "path": "\/lists\/$listID\/members",
    "operation_id": "1",
    "body": "{\"email_address\":\"test1@example.com\",\"status\":\"subscribed\",\"merge_fields\":{\"FNAME\":\"David\",\"LNAME\":\"Tester\"}}"
  }
 ]
}


```

The request must be an object, rather than an array.

So now I am working on that change, but i'm unsure how to implement that - any ideas?


###################################################################


*Full error returned =
**Fatal error**: Uncaught GuzzleHttp\Exception\ClientException: Client error: `POST https://us6.api.mailchimp.com/3.0/batches` resulted in a `400 Bad Request` response: {"type":"https://mailchimp.com/developer/marketing/docs/errors/","title":"Invalid Resource","status":400,"detail":"The r (truncated...) in C:\xampp\htdocs\dashboard\MailchimpAPI\vendor\guzzlehttp\guzzle\src\Exception\RequestException.php:113 Stack trace: #0 C:\xampp\htdocs\dashboard\MailchimpAPI\vendor\guzzlehttp\guzzle\src\Middleware.php(69): GuzzleHttp\Exception\RequestException::create(Object(GuzzleHttp\Psr7\Request), Object(GuzzleHttp\Psr7\Response), NULL, Array, NULL) #1 C:\xampp\htdocs\dashboard\MailchimpAPI\vendor\guzzlehttp\promises\src\Promise.php(204): GuzzleHttp\Middleware::GuzzleHttp\{closure}(Object(GuzzleHttp\Psr7\Response)) #2 C:\xampp\htdocs\dashboard\MailchimpAPI\vendor\guzzlehttp\promises\src\Promise.php(153): GuzzleHttp\Promise\Promise::callHandler(1, Object(GuzzleHttp\Psr7\Response), NULL) #3 C:\xampp\htdocs\dashboard\MailchimpAPI\vendor\guzzlehttp\promises\src\TaskQueue.php(48): GuzzleHttp\Promise\Promise::GuzzleHttp\Promise\{closure}() #4 C:\xampp\htdocs\dashboard\MailchimpAPI\vendor\guzzlehttp\promises\src\Promise.php(248): GuzzleHttp\Promise\TaskQueue->run(true) #5 C:\xampp\htdocs\dashboard\MailchimpAPI\vendor\guzzlehttp\promises\src\Promise.php(224): GuzzleHttp\Promise\Promise->invokeWaitFn() #6 C:\xampp\htdocs\dashboard\MailchimpAPI\vendor\guzzlehttp\promises\src\Promise.php(269): GuzzleHttp\Promise\Promise->waitIfPending() #7 C:\xampp\htdocs\dashboard\MailchimpAPI\vendor\guzzlehttp\promises\src\Promise.php(226): GuzzleHttp\Promise\Promise->invokeWaitList() #8 C:\xampp\htdocs\dashboard\MailchimpAPI\vendor\guzzlehttp\promises\src\Promise.php(62): GuzzleHttp\Promise\Promise->waitIfPending() #9 C:\xampp\htdocs\dashboard\MailchimpAPI\vendor\guzzlehttp\guzzle\src\Client.php(123): GuzzleHttp\Promise\Promise->wait() #10 C:\xampp\htdocs\dashboard\MailchimpAPI\vendor\mailchimp\marketing\lib\Api\BatchesApi.php(538): GuzzleHttp\Client->send(Object(GuzzleHttp\Psr7\Request), Array) #11 C:\xampp\htdocs\dashboard\MailchimpAPI\vendor\mailchimp\marketing\lib\Api\BatchesApi.php(527):

Link to comment
Share on other sites

Try to understand what the code is doing when it comes to sending API requests to MailChimp. It's sending a certain request body right now which is not entirely correct. You need to modify that body it's trying to send to be more correct.

So some questions for you to answer include "how am I sending API requests?" and "what and where is the request body?".

Link to comment
Share on other sites

  • 2 weeks later...
  • 4 months later...

The Mailchimp SDK isn't the smartest thing around. When you give it requests to execute, you have to match exactly what the API says you're supposed to use.

Here, the API wants the request body to be an object with an "operations" key that is the array of operations. You almost but not quite have that.

Link to comment
Share on other sites

...Why are you adding a json_decode?

Read the docs: the request body is an object containing an "operations" key whose value is an array of the operations to perform. You have the array of operations to perform already. What you don't have is them inside an object.

Link to comment
Share on other sites

Yes I don't quite get how I do that. I have been reading the docs, specifically noting "expects a JSON object with a single key: operations, which is an array of objects that describe the API calls you want to make". I see, as you mentioned, that I have the $operations array all set.

I have tried a couple of methods to create an object and then put the key:value pair inside, which is how I'm conceptualizing this part...

// create object to put $operations array inside

// $operationsObject = (object)['operations'=>$operations];

This brings about the same error.

 

I feel I'm missing something that is more straight forward than what I am trying.

Link to comment
Share on other sites

FYI it doesn't have to be a PHP object: PHP's arrays will serialize into a JSON object when they are associative (have keys). So you can remove the (object) typecast.

Having that array looks right to me. You're definitely passing $operationsObject to the API, right, and not $operations? What's your full code look like now?

Link to comment
Share on other sites

response now=

Fatal error: Uncaught Error: Object of class stdClass could not be converted to string in C:\xampp\htdocs\dashboard\MailchimpAPI\batchRequestAddMem.php:141 Stack trace: #0 {main} thrown in C:\xampp\htdocs\dashboard\MailchimpAPI\batchRequestAddMem.php on line 141

 

code now:
 

$operations = [];

 // create object to put $operations array inside

 $operationsObject = ['operations'=>$operations];

foreach($users as $user) {

$operation = [

        'method' => 'POST',

        'path' => "/lists/$listId/members",

        'operation_id' => $user['id'],

        'body' => json_encode([

            'email_address' => $user['email'],

            'status' => $user['status'], // Create sync/button to allow BFCMA back end to change this with the DB to then update with daily/weekly batch request

            //add additional fields to insert into MC

            'merge_fields' => [ //  8/10/21 Stackoverflow suggests to use merge-fields *not currently working with it included

                'FNAME' => $user['fname'],

                'LNAME' => $user['lname']

            ]

        ])

    ];

    array_push($operations, $operation);

}

try {

    $response = $mailchimp->batches->start($operationsObject);

    echo $response;

} catch (\MailchimpMarketing\ApiException $e) {

    echo $e->getMessage();

}

 

Link to comment
Share on other sites

And what line is 141? Is it the one where you try to echo $response? You can't just output objects like that. Try print_r.

But you've got a pretty big bug here: when you create $operationsObject, $operations is an empty array. You add to $operations later but that's too late because $operationsObject has already been created. Move that line until after the array is ready to be used.

Link to comment
Share on other sites

Thanks - yes I missed that one. After using print_r  for $response and moving the $operationsObject after the array has been populated I get the following response indicating that there are no operations passed in the request;

 stdClass Object
(
    [id] => snxzha6dug
    [status] => pending
    [total_operations] => 0
    [finished_operations] => 0
    [errored_operations] => 0
    [submitted_at] => 2022-01-11T00:42:23+00:00
    [completed_at] => 
    [response_body_url] => 
    [_links] => Array
        (
            [0] => stdClass Object
                (
                    [rel] => parent
                    [href] => https://us6.api.mailchimp.com/3.0/batches
                    [method] => GET
                    [targetSchema] => https://us6.api.mailchimp.com/schema/3.0/Definitions/Batches/CollectionResponse.json
                    [schema] => https://us6.api.mailchimp.com/schema/3.0/Paths/Batches/Collection.json
                )

            [1] => stdClass Object
                (
                    [rel] => self
                    [href] => https://us6.api.mailchimp.com/3.0/batches/snxzha6dug
                    [method] => GET
                    [targetSchema] => https://us6.api.mailchimp.com/schema/3.0/Definitions/Batches/Response.json
                )

            [2] => stdClass Object
                (
                    [rel] => delete
                    [href] => https://us6.api.mailchimp.com/3.0/batches/snxzha6dug
                    [method] => DELETE
                )

        )

)

 

If I also print_r $operationsObject then I get the following which again indicates an array, not an object;

Array
(
    [operations] => Array
        (
            [0] => Array
                (
                    [method] => POST
                    [path] => /lists/6ecc1e6884/members
                    [operation_id] => 1
                    [body] => {"email_address":"test1@example.com","status":"subscribed","merge_fields":{"FNAME":"David","LNAME":"Tester"}}
                )

            [1] => Array
                (
                    [method] => POST
                    [path] => /lists/6ecc1e6884/members
                    [operation_id] => 2
                    [body] => {"email_address":"test2@example.com","status":"subscribed","merge_fields":{"FNAME":"Kevin","LNAME":"Ishere"}}
                )

            [2] => Array
                (
                    [method] => POST
                    [path] => /lists/6ecc1e6884/members
                    [operation_id] => 3
                    [body] => {"email_address":"happy@example.com","status":"subscribed","merge_fields":{"FNAME":"Gerald","LNAME":"Happy"}}
                )

            [3] => Array
                (
                    [method] => POST
                    [path] => /lists/6ecc1e6884/members
                    [operation_id] => 4
                    [body] => {"email_address":"Tim@example.com","status":"subscribed","merge_fields":{"FNAME":"Tim","LNAME":"Toolman"}}
                )

            [4] => Array
                (
                    [method] => POST
                    [path] => /lists/6ecc1e6884/members
                    [operation_id] => 5
                    [body] => {"email_address":"grealish@example.com","status":"subscribed","merge_fields":{"FNAME":"Jack","LNAME":"Grealish"}}
                )

        )

)

 

I tried to json_encode $operationsObject and then pass that through with the request, which appears to pass through the correct object format, but it returns the same $response message.

 

 

 

Link to comment
Share on other sites

  • Solution

Code now;

$operations = [];

foreach($users as $user) {

$operation = [

        'method' => 'POST',

        'path' => "/lists/$listId/members",

        'operation_id' => $user['id'],

        'body' => json_encode([

            'email_address' => $user['email'],

            'status' => $user['status'], // Create sync/button to allow BFCMA back end to change this with the DB to then update with daily/weekly batch request

            //add additional fields to insert into MC

            'merge_fields' => [ //  8/10/21 Stackoverflow suggests to use merge-fields *not currently working with it included

                'FNAME' => $user['fname'],

                'LNAME' => $user['lname']

            ]

        ])

    ];

    array_push($operations, $operation);

}


 // create object to put $operations array inside

 $operationsObject = ['operations'=>$operations];
echo '<pre> ';
print_r($operationsObject);
echo '</pre>';

try {

       $response = $mailchimp->batches->start($operationsObject);
    // echo $response;
    echo '<pre> ';
    print_r($response);
    echo '</pre>';

} catch (\MailchimpMarketing\ApiException $e) {

    echo $e->getMessage();

}

 

In addition, here is the final part of the code if you were to include the json_encode;

// create object to put $operations array inside
$operationsObject = ['operations'=>$operations];
echo '<pre> ';
print_r($operationsObject);
echo '</pre>';

$json = json_encode($operationsObject, JSON_PRETTY_PRINT);
echo '<pre> ';
print_r($json);
echo '</pre>';


try {
    $response = $mailchimp->batches->start($json);
    // echo $response;
    echo '<pre> ';
    print_r($response);
    echo '</pre>';

} catch (\MailchimpMarketing\ApiException $e) {
    echo $e->getMessage();
}

 

 

Link to comment
Share on other sites

You did indeed, Mailchimp responded back to me yesterday:

Quote

Jumping right in, unfortunately, we are unable to view historic calls through our API monitoring tool. This means that we are unable to see calls that were made before the monitoring tool was turned on. However, I was able to turn on our monitoring tool (that will monitor calls for the next 48 hours). 

What I can do is let that run for 24-48 hours, then reach back out tomorrow with any errors that we see on our end. This way, you will be able to receive the proper error messages that are being transmitted.

So I sent through both requests (with and without the json_encode) for them to review and respond with error messages. It is unfortunate that they do not allow the api monitoring tool to be used on the client end.

 

Link to comment
Share on other sites

still to explore guzzle - but we have a resolution!

The final code that we got to was indeed correct! The issue at that point was with the mailchimp audience logic. The emails that I was passing (made up emails) were causing the errors as they were invalid emails. I then was able to pass through real email addresses and this allowed the API request to process correctly.

As previously discussed the Mailchimp API document for php is incomplete and using their API dashboard you cannot get more detailed error information. Contacting mailchimp and asking them to set up the API watcher for your account for 24-48hrs to check the API requests made during that period is one way of collecting that information.

Link to comment
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.