Publication multi-réseaux
POST /v1/posts publie le même contenu sur plusieurs réseaux en un seul appel — immédiatement ou à une date programmée. L'appel rend la main tout de suite (202) : la publication se fait en tâche de fond, chaque réseau vous est notifié par webhook et consultable via GET /v1/posts/:id.
Principe
/v1/postsCréer une publication (immédiate ou programmée)
/v1/postsLister les publications récentes
/v1/posts/:idÉtat détaillé, réseau par réseau
/v1/posts/:idModifier une publication programmée
/v1/posts/:idAnnuler une publication programmée
Scope requis : publish:posts (présent sur toute clé créée depuis le 19 juillet 2026 — les clés antérieures reçoivent 403 insufficient_scope, créez-en une nouvelle). Réseaux : facebook, instagram, linkedin, tiktok et youtube ; le compte correspondant doit être relié à votre espace de travail.
Si vous avez connecté plusieurs comptes d'un même réseau (deux pages Facebook, deux comptes TikTok…), une cible peut désigner le compte exact : { "platform": "facebook", "channelId": "…" }. Voir Comptes connectés pour obtenir ces identifiants.
Créer une publication
curl -X POST https://api.kreatoai.com/v1/posts \
-H "x-api-key: sk-kre-v1-votre_cle" \
-H "Content-Type: application/json" \
-d '{
"targets": ["facebook", "linkedin"],
"content": "Notre nouvelle offre est en ligne !",
"mediaUrls": ["https://media.kreatoai.com/abc.jpg"],
"idempotencyKey": "post-lancement-2026-07-19"
}'Champs : targets (1 à 20 cibles, sans doublon — un nom de réseau ou un objet { platform, channelId }), content (texte, jusqu'à 63 206 caractères — les bornes plus strictes de chaque réseau sont vérifiées par cible), mediaUrls (0 à 10 URLs https publiques — hébergez vos fichiers via /v1/media), scheduledAt (ISO 8601, optionnel — absent = publication immédiate), idempotencyKey (optionnel, voir plus bas). Un PDF part sur LinkedIn en carrousel document, tel quel : seul dans mediaUrls, avec LinkedIn pour seule cible. Hébergez-le avec /v1/media (25 Mo au plus), ou donnez l'adresse https publique où il est déjà en ligne (100 Mo au plus, la limite de LinkedIn).
// 202 Accepted
{
"id": "9f1c8b2e-…",
"status": "processing", // ou "scheduled" si scheduledAt est fourni
"scheduledAt": null,
"createdAt": "2026-07-19T14:30:00.000Z",
"targets": [
{ "platform": "facebook", "accountId": "a3f27c9e-…", "accountName": "Campus Plus",
"status": "pending", "externalPostId": null,
"postUrl": null, "failReason": null, "failType": null, "completedAt": null },
{ "platform": "linkedin", "accountId": "c04e91a7-…", "accountName": "Nafiou Tino",
"status": "pending", "externalPostId": null,
"postUrl": null, "failReason": null, "failType": null, "completedAt": null }
]
}accountId identifie le compte exact atteint par chaque cible — décisif quand plusieurs comptes du même réseau sont connectés. Il vaut null sur les publications antérieures au multi-comptes.
Fichier déposé plus tard (awaitMedia)
Quand le fichier est sur le téléphone ou l'ordinateur d'une personne, hors de portée de votre programme : créez la publication avec "awaitMedia": true et sans mediaUrls. Elle est enregistrée en attente, et la réponse porte un lien de dépôt à donner à la personne. Dès qu'elle y dépose son fichier (vidéo jusqu'à 512 Mo), la publication part seule, tout de suite ou à scheduledAt.
// POST /v1/posts
{ "targets": ["tiktok"], "content": "Ma vidéo du jour", "awaitMedia": true }
// 202 Accepted
{
"id": "e499086e-…",
"status": "awaiting_media",
"mediaUploadUrl": "https://kreatoai.com/envoyer/…",
"mediaUploadExpiresAt": "2026-10-09T11:13:37.157Z", // le lien vaut 7 jours
…
}awaitMedia avec des mediaUrls renvoie 400 await_media_with_media_urls. Si votre programme a lui-même accès au fichier, préférez l'envoi direct : POST /v1/media/upload-url.
Même fichier sur d'autres comptes, à d'autres heures : créez la première publication avec awaitMedia, puis chacune des suivantes avec "sameMediaAs": "<id de la première>", sans awaitMedia ni mediaUrls. Elles renvoient le même lien de dépôt : la personne dépose son fichier une seule fois, et chaque publication part à son heure. Pour plusieurs comptes à la même heure, une seule publication avec plusieurs targets suffit.
// 1. YouTube à midi
{ "targets": ["youtube"], "content": "Ma vidéo du jour", "awaitMedia": true,
"scheduledAt": "2026-10-07T12:00:00+02:00" }
// → { "id": "e499086e-…", "mediaUploadUrl": "https://kreatoai.com/envoyer/…", … }
// 2. TikTok à 13 h, le même fichier
{ "targets": ["tiktok"], "content": "Ma vidéo du jour", "sameMediaAs": "e499086e-…",
"scheduledAt": "2026-10-07T13:00:00+02:00" }
// → le même mediaUploadUrl, et "sameMediaAs": "e499086e-…"sameMediaAs qui ne désigne pas une publication de l'espace encore en attente de son fichier renvoie 400 same_media_post_not_waiting.
Statuts
| Statut global | Signification |
|---|---|
scheduled | Programmée, pas encore partie |
processing | Au moins un réseau en cours de publication |
completed | Tous les réseaux ont réussi |
partial | Au moins un succès ET au moins un échec |
failed | Tous les réseaux ont échoué |
cancelled | Annulée avant publication |
Par réseau : pending → publishing → succeeded ou failed (+ inbox_delivered pour un brouillon TikTok, cancelled quand la publication a été annulée avant son départ). TikTok est résolu en différé : la cible reste publishing jusqu'à confirmation réelle par TikTok (suivi automatique côté serveur), là où beaucoup d'outils annoncent « publié » dès l'acceptation de la demande.
Consulter et annuler
curl https://api.kreatoai.com/v1/posts/9f1c8b2e-... \
-H "x-api-key: sk-kre-v1-votre_cle"La réponse inclut, pour chaque réseau, l'identifiant du post publié (externalPostId), son lien (postUrl, quand le réseau l'expose) et en cas d'échec failReason + failType. DELETE /v1/posts/:id annule une publication programmée non partie (204) ; déjà partie → 409 post_not_cancellable. Si vous avez configuré un webhook, inutile de poller : un événement par réseau vous est envoyé.
Modifier une programmation
PATCH /v1/posts/:id change une publication programmée qui n'est pas encore partie. Envoyez seulement les champs à changer : scheduledAt pour la décaler, content, mediaUrls ou options. La publication garde son identifiant, et un nouveau texte ou de nouveaux médias sont vérifiés réseau par réseau comme à la création. Les comptes visés ne se modifient pas : pour en changer, annulez puis créez une nouvelle publication.
curl -X PATCH https://api.kreatoai.com/v1/posts/9f1c8b2e-... \
-H "x-api-key: sk-kre-v1-votre_cle" \
-H "Content-Type: application/json" \
-d '{ "scheduledAt": "2026-09-18T08:23:00+01:00" }'
// 200 OK : la publication à jour, contenu et médias comprisDéjà partie, en cours d'envoi ou annulée → 409 post_not_editable. Date passée → 400 scheduled_at_in_past.
Réglages TikTok — brouillon ou publication directe
Par défaut, TikTok publie immédiatement et publiquement. Si vous préférez déposer le contenu dans les brouillons du créateur — qui relira puis publiera lui-même depuis l'app — passez options.tiktok.postMode à MEDIA_UPLOAD.
{
"targets": ["tiktok"],
"content": "Ma légende",
"mediaUrls": ["https://media.kreatoai.com/1.jpg", "https://media.kreatoai.com/2.jpg"],
"options": {
"tiktok": {
"postMode": "MEDIA_UPLOAD", // brouillon ; défaut : DIRECT_POST
"title": "Mon titre", // photos : 90 caractères ; défaut : première ligne du texte
"privacyLevel": "PUBLIC_TO_EVERYONE", // DIRECT_POST uniquement
"disableComment": false, // DIRECT_POST uniquement
"disableDuet": false, // DIRECT_POST uniquement, vidéo
"disableStitch": false, // DIRECT_POST uniquement, vidéo
"isAigc": false, // DIRECT_POST uniquement, vidéo générée par l'IA
"autoAddMusic": true // DIRECT_POST uniquement, carrousel
}
}
}En MEDIA_UPLOAD, confidentialité et interactions ne sont pas transmises : TikTok les fait choisir au créateur au moment où il publie. Les envoyer quand même n'a aucun effet.
| En brouillon | Carrousel d’images | Vidéo |
|---|---|---|
| Texte de la publication | Titre et description conservés | Non transmis — saisi dans l’app |
| Limite TikTok | — | 5 brouillons en attente / 24 h |
Cette asymétrie vient de TikTok : un carrousel en brouillon passe par content/init, qui accepte un titre, tandis qu'une vidéo passe par inbox/video/init, qui n'accepte aucune métadonnée. Prévoyez donc de communiquer la légende autrement si vous déposez des vidéos en brouillon.
Le suivi ne change pas : la cible reste publishing jusqu'à confirmation réelle, puis passe à inbox_delivered pour un brouillon livré, ou succeeded pour une publication en ligne.
Story Facebook et Instagram
options.format à "story" publie une story au lieu d'une publication, sur une Page Facebook ou sur Instagram. Une story porte une seule image ou vidéo et aucun texte : content devient facultatif et n'est pas transmis. Elle reste visible 24 heures, puis la plateforme la retire.
{
"targets": ["facebook", "instagram"],
"mediaUrls": ["https://media.kreatoai.com/story.mp4"],
"options": { "format": "story" }
}Image en JPEG ou PNG ; vidéo en MP4, de 3 à 60 secondes, verticale (9:16) de préférence. Programmer une story fonctionne comme pour une publication, avec scheduledAt.
Idempotence — évitez les doubles publications
Si votre workflow réessaie après un timeout réseau, le même appel peut partir deux fois — et sans protection, publier deux fois. Fournissez un idempotencyKey stable (par exemple l'identifiant de votre tâche interne) : si une publication existe déjà avec cette clé, l'API renvoie la publication existante (200) au lieu d'en créer une seconde. Recommandé pour toute intégration automatisée.
Validation et erreurs
Tout est vérifié avant d'accepter la requête — échec rapide avec le détail par réseau, plutôt qu'un échec silencieux trente secondes plus tard :
// 400 Bad Request
{
"error": "invalid_targets",
"message": "Certains réseaux ne peuvent pas recevoir cette publication.",
"details": [
{ "platform": "instagram", "error": "media_required_for_target" },
{ "platform": "tiktok", "error": "channel_not_connected" }
]
}| Code | Cause |
|---|---|
invalid_target | Réseau inconnu (valides : facebook, instagram, linkedin, tiktok, youtube, bluesky, google_business) |
video_required_for_target | YouTube ne publie que des vidéos (Shorts) : ni texte seul, ni image. Première ligne du texte = titre (100 car.), texte entier = description ; options.youtube.privacyStatus (public par défaut), madeForKids, title, tags (500 car. cumulés), containsSyntheticMedia (déclaration de contenu IA réaliste) |
duplicate_target | Le même compte est visé deux fois (deux comptes distincts d’un même réseau sont valides) |
channel_not_connected | Aucun canal actif pour ce réseau, ou channelId inconnu de votre espace |
content_too_long_for_target | Texte au-delà de la limite du réseau (LinkedIn 3 000, Instagram/TikTok 2 200, Google Business 1 500, Bluesky 300) |
media_required_for_target | Instagram et TikTok exigent au moins un média |
document_linkedin_only | Un PDF ne part que sur LinkedIn, en carrousel document |
video_unsupported_target | Google Business ne publie pas de vidéo |
too_many_media_for_target | Bluesky accepte 4 images ou une vidéo seule, Google Business une image |
document_alone | Un PDF part seul : aucun autre média dans mediaUrls |
story_unsupported_target | Une story ne part que sur facebook ou instagram |
story_single_media | Une story porte une seule image ou vidéo |
content_required | Texte vide : il est obligatoire, sauf pour une story |
scheduled_at_in_past | Date de programmation déjà passée |
media_unreadable | Média inaccessible ou type indéterminable |
En cas d'échec de publication, failType distingue retriable (indisponibilité passagère, limite de débit — réessayer plus tard peut réussir) et permanent (média refusé, canal à reconnecter — réessayer est inutile). Ne bouclez jamais sur un échec permanent.
Limites actuelles
Facebook publie plusieurs photos en une seule publication, Bluesky jusqu'à quatre (ou une vidéo MP4 seule), Google Business une seule (jamais de vidéo, et un bouton facultatif dans options.google_business.callToAction). Instagram, TikTok et LinkedIn publient toutes les images en carrousel, de 2 à 10 ; sur LinkedIn le carrousel est un document PDF assemblé côté serveur, une page carrée par image. Une vidéo part en Reel sur Instagram, ou en story avec options.format. La visibilité d'une publication LinkedIn n'est pas encore réglable.