Il n’existe pas de SDK PHP, donc ceci utilise directement l’API REST. C’est moins une limite qu’il n’y paraît : l’API n’est que du JSON en HTTPS avec un jeton bearer, et PHP dispose de tout le nécessaire dans sa bibliothèque standard.
Si vous publiez spécifiquement depuis WordPress, il existe un plugin et une route RSS qui demandent probablement moins de travail que d’écrire tout cela vous-même.
Authentification
Chaque requête porte votre clé API comme jeton bearer :
$apiKey = getenv('BULKPUBLISH_API_KEY');
$baseUrl = 'https://app.bulkpublish.com';
Gardez la clé dans l’environnement plutôt que dans le code source ou un fichier de configuration versionné.
Créer un brouillon
$payload = [
'content' => 'Check out our latest update!',
'channels' => [
['channelId' => 1, 'platform' => 'x'],
['channelId' => 2, 'platform' => 'linkedin'],
],
'status' => 'draft',
];
$ch = curl_init("$baseUrl/api/posts");
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Content-Type: application/json',
"Authorization: Bearer $apiKey",
],
CURLOPT_POSTFIELDS => json_encode($payload),
]);
$response = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($status >= 400) {
error_log("BulkPublish error $status: $response");
} else {
$post = json_decode($response, true);
}
Commencez par draft. Il apparaît dans l’application, ce qui vous permet de voir ce que votre code a produit avant que quoi que ce soit ne soit publié.
La même chose avec Guzzle
Si vous avez déjà Guzzle, c’est plus soigné :
use GuzzleHttp\Client;
$client = new Client([
'base_uri' => 'https://app.bulkpublish.com',
'headers' => [
'Authorization' => 'Bearer ' . getenv('BULKPUBLISH_API_KEY'),
'Content-Type' => 'application/json',
],
]);
$response = $client->post('/api/posts', [
'json' => [
'content' => 'Check out our new feature!',
'channels' => [['channelId' => 1, 'platform' => 'instagram']],
'status' => 'scheduled',
'scheduledAt' => '2026-04-10T14:00:00Z',
'timezone' => 'America/New_York',
],
]);
$post = json_decode((string) $response->getBody(), true);
Trouver les identifiants de canaux
$response = $client->get('/api/channels');
$channels = json_decode((string) $response->getBody(), true);
Récupérez-les ou conservez-les dans la configuration. Coder en dur un identifiant issu d’un script ponctuel dans quelque chose de durable, c’est ainsi qu’un déploiement se met à publier sur le mauvais compte.
Les champs de planification
scheduledAt est un horodatage ISO-8601 et timezone est un nom IANA. Passez le fuseau horaire explicitement pour tout ce qui est récurrent, sinon votre heure de publication se décale d’une heure au changement d’heure d’été.
Bien gérer les erreurs
Le mode d’échec propre à la publication côté serveur, c’est que personne ne surveille. Un post qui échoue à la validation à 3 h du matin passe inaperçu, sauf si vous l’avez rendu visible.
- Vérifiez les codes de statut, ne supposez pas qu’une réponse signifie un succès
- Journalisez le corps de la réponse en cas d’échec, car il indique ce qui n’allait pas
- Respectez les limites de débit et patientez plutôt que de réessayer immédiatement
| Free | Pro | Business | |
|---|---|---|---|
| Requêtes API/jour | 30 | 5 000 | 50 000 |
| Clés API | 1 | 5 | 10 |
| Les 30 par jour du plan Free servent à l’évaluation. Tout ce qui tourne selon un planning a besoin d’un plan payant. |
En résumé
Aucun SDK nécessaire. Envoyez du JSON en POST à /api/posts avec un jeton bearer, content, channels et un status. Commencez par des brouillons, récupérez les identifiants de canaux, passez un fuseau horaire avec les posts planifiés, et journalisez correctement les échecs, car la publication côté serveur échoue silencieusement par défaut.