Good practices in an API Wrapper Class
There is no problem modelling the request with classes representing each part of the request and a class that aggregates them.

One thing to note here, those classes adhere to builder pattern - builder of JSON.
Maybe you dont know that there is an interface \JsonSerializable which would comminucate the intent of the classes much better then a toArray() method. Although many arrays can be deemd json serializable, its not always true. Where as json serializable object is always serializable to json and it makes it clear that the json serializability is its purpose...

Then i quite dont understand this piece:

        $product
        -&gt;setSkus($price);
        -&gt;setSkus($stock);


You set skus to a Price object, then overwrite with Stock object?
Given this piece of data:

"skus": [
        {
          "price": {
            "offer": "offer",
            "default": "default"
          },
          "stock": {
            "available": "available",
            "amount": "amount"
          },
          "gtin": "gtin",
          "images": [
            "image",
            "image"
          ],
          "idSku": "idSku",
        }
      ]


I would expect that there is one more object between Product and Stock/Price object. Maybe a Sku object:

$product-&gt;addSku((new Sku())-&gt;setPrice($price)-&gt;setStock($stock));


And I wouldnt also see problem adding methods for more convenient work (that would instantiate the parts classes):

$sku = new Sku();
$sku-&gt;setPrice('offer', 'default');
$sku-&gt;setStock('available', 'amount')


instead of:

$sku = new Sku();
$sku-&gt;setPrice(new Price('offer', 'default'));
$sku-&gt;setStock(new Stock('available', 'amount'));


After all, those classes are not meant to represent the request, they represent a builder of a json request. And builder should make it as easy to build the target as possible....

EDIT: you were worried about coupling. I dont think this brings in any more coupling then necesary. The API uses specific keys in the request and these will never change, unless the API introduces BC break. But then maybe it was not a very good API structure... Anyway it wouldnt hurt to have those keys defined as constants of the bulder classes, so you dont have to repeat string literals all over the place... if nothing it makes it easier to find all occurences of a key.

Chances are that there are multiple ways the api could have been designed, yet retaining the same capabilities. And this means that there are also multiple ways to model the request with php objects. But you should prefer to have this 1:1. The api designer was probably aware of the multiple ways and chosen the one he chosen for a reason. And you should follow that reasoning...

Well this statement might have seem quite abstract, so let me complete it with an example. Lets say we have api structure:

{
  "scopeA": {
    "configA1": "valueA1"
  },
  "scopeB": {
    "configB1": "valueB1"
  }
}


but we can also model it as this structure:

{
  "scopeAconfigA1": "valueA1",
  "scopeBconfigB1": "valueB1"
}


but the first structure is the API structure, and so the PHP model should also have the first structure. Simply following the same reasoning why the api designers chose the first structure. Whatever reasoning it may have been...