I didn't think to use http_build_query() for this, indeed it works with.
Unlike you, I used (as it worked with the other APIs by IPS, I didn't ask myself any questions...)
curl_setopt($ch, CURLOPT_POSTFIELDS, $post);
Thank you @Nathan Explosion
Orignal code
$api = "https://domain.example/api/core/messages";
$key = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxx';
$post = [
'from' => 26583, // Bot Account
'to' => [
17997,
26105,
22505
], // Staff
'title' => 'title of private message',
'body' => 'send by api',
];
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $api);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
curl_setopt($ch, CURLOPT_USERPWD, $key);
curl_setopt($ch, CURLOPT_USERAGENT, 'Core X');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post);
$result = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$curl = json_decode($result);
curl_close($ch);
var_dump($result);