Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

stesvis's avatar

POST failing using Guzzle but works on Postman

I am trying to consume a POST api with Guzzle, after testing that it works on Postman: https://snipboard.io/Bqwd5y.jpg As you can see, there is a body which is an array of objects.

With Guzzle I tried this. First I converted that payload to a php array:

    $body = [
        [
            "Url" => "StorageMgmt",
            "Method" => "PATCH",
            "Payload" => [
                "Identities" => [
                    "userId" => "userid",
                    "companyId" => "company",
                    "ownerId" => "ownerId",
                ],
            ],
        ],
        [
            "Url" => "Reports/List",
            "Method" => "GET",
        ],
    ];

Then I set it as the POST body, I tried different ways:

$promise = $this->httpClient->postAsync($url, [
	'json' => $body, // did not work, server responded with 500 error
	//'body' => $body // did not work
	//'body' => json_encode($body),  // did not work, server responded with 500 error
])
	->then(
		function (ResponseInterface $resp) {
			$jsonBody = json_decode($resp->getBody(), true);

			return $jsonBody;
		},
		function (RequestException $ex) {
			parent::handleHttpException($ex);
		}
	);

return $promise->wait();

After a lot of testing, the only way that it works is quite weird to me, because it is to pass the array as plain text, such as:

        $promise = $this->httpClient->postAsync($url, [
            'body' => '[
 {
 "Url": "StorageMgmt",
 "Method": "PATCH",
 "Payload": {
 "Identities": {
 "userId": "userid",
 "companyId": "company",
 "ownerId": "ownerId"
 }
 }
 },
 {
 "Url": "Reports/List",
 "Method": "GET"
 }
]',
        ])
            ->then(
                function (ResponseInterface $resp) {
                    $jsonBody = json_decode($resp->getBody(), true);

                    return $jsonBody; // returned by $promise->wait()
                },
                function (RequestException $ex) {
                    parent::handleHttpException($ex);
                }
            );

        return $promise->wait();
    }

And the trick is to avoid IDE auto-formatting, which means no extra spaces, not tabs etc in the body string.

Can someone help me understand why it works this way? Shouldn't I be able to just pass the array or the json_encode of it?

How can I replicate with Guzzle what I have working in Postman? Thanks.

PS: I do set the Accept and Content-Type to application/json. I just omitted them from the code snippet to keep it more readable.

0 likes
9 replies
ajithlal's avatar

Not sure. But can you try this?

$body  =json_encode('
        [
            "Url" => "StorageMgmt",
            "Method" => "PATCH",
            "Payload" => [
                "Identities" => [
                    "userId" => "userid",
                    "companyId" => "company",
                    "ownerId" => "ownerId",
                ],
            ],
        ],
        [
            "Url" => "Reports/List",
            "Method" => "GET",
        ]');

And in guzzle

$this->httpClient->postAsync($url, [
	'body' =>[ $body]
])
stesvis's avatar

@ajithlal Thanks, but it still doesn't allow me to do that:

Passing in the "body" request option as an array to send a request is not supported. Please use the "form_params" request option to send a application/x-www-form-urlencoded request, or the "multipart" request option to send a multipart/form-data request.

ajithlal's avatar

@stesvis can you try this

$this->httpClient->postAsync($url, [
	'body' =>$body
])
stesvis's avatar

@ajithlal Already tried, see my original post. I commented out the options that I tried:

$promise = $this->httpClient->postAsync($url, [
	'json' => $body, // did not work, server responded with 500 error
	//'body' => $body // did not work
	//'body' => json_encode($body),  // did not work, server responded with 500 error
])
ajithlal's avatar

@stesvis Yes. That I understood. But the structure of the payload is different. by json_encode() the array we have to get the same payload as in postman.

stesvis's avatar
stesvis
OP
Best Answer
Level 1

@ajithlal i think I found the problem. The json data has one field that looks like this:

{
    ...
    "Payload": {},
    ...
}

But the equivalent as PHP array is:

[
    ...
    "Payload": [],
    ...
]

Which becomes like this after the json_encode:

{
    ...
    "Payload": [],
    ...
}

So basically the result is "Payload": [] instead of "Payload": {}. Those square brackets make the difference. So, unless there is a better way, I have to do this:

'body' => str_replace('[]', '{}', json_encode($body))

Please or to participate in this conversation.