Authentification
Créez une clé API dans le tableau de bord, sous Paramètres, API et webhooks. Les clés commencent par ss_live_, appartiennent à un espace de travail et peuvent être limitées à certains projets. Envoyez la clé comme jeton bearer dans chaque requête :
curl https://www.amaposta.com/api/v1/me \
-H "Authorization: Bearer ss_live_…"
La réponse indique le nom de la clé, ses permissions et l’espace de travail. Chaque clé possède une ou plusieurs permissions :
| Permission | Autorise |
|---|---|
content:read | Lire les projets, canaux, publications et médias. |
content:write | Importer des médias et créer ou modifier des publications. |
posts:publish | Programmer et publier sans vérification. Sans cette permission, les publications passent dans la boîte de vérification des projets avec validation et restent des brouillons partout ailleurs. |
Chaque clé peut effectuer 120 requêtes par minute. Au-delà, vous recevez un statut 429 avec le code rate_limited ; attendez un instant et réessayez.
Projets et canaux
Les publications appartiennent à un projet. Listez les projets visibles par votre clé, puis les canaux de l’un d’eux. L’identifiant d’un canal vous permet de le cibler ou de remplacer son texte.
curl https://www.amaposta.com/api/v1/projects \
-H "Authorization: Bearer $AMAPOSTA_KEY"
curl https://www.amaposta.com/api/v1/projects/$PROJECT_ID/channels \
-H "Authorization: Bearer $AMAPOSTA_KEY"
Un canal possède un provider (youtube, instagram, tiktok, x, facebook, custom ou sandbox), un status (active, expiring, needs_reconnect, error ou disabled) et les types de publications qu’il prend en charge dans supports.
Importer des médias
Les images et vidéos sont importées une seule fois par projet et peuvent être utilisées dans autant de publications que vous le souhaitez. Il existe trois méthodes d’import.
Import direct
Envoyez le fichier en données de formulaire multipart dans un champ nommé file. Idéal pour les fichiers jusqu’à quelques centaines de Mo.
curl https://www.amaposta.com/api/v1/projects/$PROJECT_ID/media \
-H "Authorization: Bearer $AMAPOSTA_KEY" \
-F "[email protected]"
Import présigné pour les fichiers volumineux
Demandez une URL d’import, envoyez directement les octets au stockage par PUT, puis indiquez à Amaposta que l’envoi est terminé.
# 1. Ask for an upload URL. The response is {"media": { … }, "upload_url": "…"}
curl https://www.amaposta.com/api/v1/projects/$PROJECT_ID/media/uploads \
-H "Authorization: Bearer $AMAPOSTA_KEY" \
-H "Content-Type: application/json" \
-d '{"filename": "batch-142.mp4", "content_type": "video/mp4", "size_bytes": 48213844}'
# 2. Upload the bytes to upload_url
curl -X PUT "$UPLOAD_URL" \
-H "Content-Type: video/mp4" \
--upload-file batch-142.mp4
# 3. Finish the upload
curl -X POST https://www.amaposta.com/api/v1/media/$MEDIA_ID/complete \
-H "Authorization: Bearer $AMAPOSTA_KEY"
Importer depuis une URL
Fournissez une URL publique à Amaposta pour qu’il télécharge le fichier en arrière-plan. Vous pouvez aussi sauter cette étape et transmettre media_url lors de la création de la publication.
curl https://www.amaposta.com/api/v1/projects/$PROJECT_ID/media/import \
-H "Authorization: Bearer $AMAPOSTA_KEY" \
-H "Content-Type: application/json" \
-d '{"url": "https://cdn.example.com/batch-142.mp4"}'
Chaque import renvoie un objet média. Son status passe de pending à processing, puis à ready (ou failed, avec une error). Après traitement, il contient width, height, duration_ms et une miniature. Interrogez GET /api/v1/media/{id} ou écoutez le webhook media.ready. L’url renvoyée est signée et valable 12 heures.
Créer une publication
POST /api/v1/projects/{project_id}/posts crée une publication avec une diffusion pour chaque canal. Amaposta l’adapte à chaque plateforme : les titres ne sont envoyés que là où un champ titre existe, les hashtags deviennent des tags sur YouTube et sont intégrés au texte ailleurs.
curl https://www.amaposta.com/api/v1/projects/$PROJECT_ID/posts \
-H "Authorization: Bearer $AMAPOSTA_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: episode-142" \
-d @- <<'JSON'
{
"kind": "video",
"title": "How we roast a batch in 12 minutes",
"description": "From green beans to first crack. We filmed one batch start to finish.",
"hashtags": ["coffee", "behindthescenes"],
"media_url": "https://cdn.example.com/batch-142.mp4",
"cover_url": "https://cdn.example.com/batch-142-cover.jpg",
"overrides": {
"<x-channel-id>": {
"description": "Batch 142 is out: green beans to first crack in 12 minutes."
},
"<youtube-channel-id>": {
"options": { "privacy": "unlisted" }
}
},
"schedule": { "mode": "queue" },
"external_ref": "episode-142",
"metadata": {
"pipeline": { "name": "nightly-cut", "run": "2026-10-17" }
}
}
JSON
Champs
| Champ | Son fonctionnement |
|---|---|
kind | text, image ou video. Obligatoire. |
title | Utilisé par les plateformes disposant d’un champ titre : YouTube, publications photo TikTok, vidéos Facebook. |
description | La légende, la description ou le texte de la publication. Également accepté sous les noms body, caption ou text. |
hashtags | Une liste, avec ou sans #. |
media_id, media_url | L’identifiant d’un média importé ou une URL publique qu’Amaposta télécharge pour vous. Nécessaire pour les publications d’images et de vidéos. |
cover_media_id, cover_url | Une image de couverture pour les vidéos, lorsque la plateforme le permet. |
channels | Identifiants des canaux sur lesquels publier. Omettez ce champ pour utiliser tous les canaux actifs du projet qui prennent en charge ce type de publication. |
overrides | Modifications par canal, indexées par identifiant de canal : title, description, hashtags et options de plateforme, comme privacy sur YouTube. |
schedule | mode vaut at (avec un champ at au format ISO 8601), now ou queue pour le prochain créneau de publication libre. Omettez-le pour créer un brouillon. |
external_ref | Votre propre référence, renvoyée dans la publication et dans les diffusions Custom API. |
metadata | JSON libre conservé avec la publication. Incluez "pipeline" pour identifier le contenu généré ; le tableau de bord l’affiche et les webhooks indiquent pipeline comme origine. |
La réponse contient la publication, avec une entrée dans deliveries par canal.
Des nouvelles tentatives sans doublons
Les réseaux peuvent perdre des requêtes. Envoyez un en-tête Idempotency-Key lors de la création d’une publication : une nouvelle tentative avec la même clé renverra la publication de la première tentative sans en créer une seconde. Utilisez une valeur stable de votre côté, comme un identifiant de tâche ou d’épisode. Les clés sont tronquées à 200 caractères.
Programmer et publier
Programmez un brouillon, publiez-le immédiatement, ajoutez-le à la file d’attente ou retirez-le du calendrier avec POST /api/v1/posts/{post_id}/schedule.
curl https://www.amaposta.com/api/v1/posts/$POST_ID/schedule \
-H "Authorization: Bearer $AMAPOSTA_KEY" \
-H "Content-Type: application/json" \
-d '{"mode": "at", "at": "2026-10-20T07:00:00Z"}'
atPublie à l’heure indiquée, jusqu’à deux ans à l’avance.nowPublie immédiatement.queueUtilise le prochain créneau de publication libre pour les canaux de la publication dans les 12 prochaines semaines.unscheduleReplace la publication dans les brouillons.
Avant toute programmation, les mêmes contrôles que dans l’éditeur sont exécutés. Si l’un d’eux échoue, la requête renvoie 400 avec un message tel que Corrigez ceci avant de programmer : YouTube exige un titre.
La programmation nécessite la permission posts:publish ou un projet avec validation activée, auquel cas la publication attend dans la boîte de vérification.
Lire les publications et les diffusions
Listez les publications d’un projet, filtrées par status (statuts séparés par des virgules, ou inbox, queue ou history), une plage from/to, limit et offset. La réponse a la forme {"items": […], "total": n}.
curl "https://www.amaposta.com/api/v1/projects/$PROJECT_ID/posts?status=queue" \
-H "Authorization: Bearer $AMAPOSTA_KEY"
curl https://www.amaposta.com/api/v1/posts/$POST_ID \
-H "Authorization: Bearer $AMAPOSTA_KEY"
Une publication possède un status global (draft, in_review, changes_requested, ready, scheduled, publishing, published, partial ou failed) et une diffusion par canal :
"deliveries": [
{
"id": "0192b7d4-…",
"channel_id": "0192b7a1-…",
"status": "published",
"url": "https://www.youtube.com/watch?v=…",
"error": null,
"published_at": "2026-10-20T07:00:41Z"
},
{
"id": "0192b7d4-…",
"channel_id": "0192b7a9-…",
"status": "failed",
"url": null,
"error": {
"code": "endpoint_unavailable",
"message": "Your endpoint returned 503 Service Unavailable",
"hint": "Amaposta will retry with backoff."
},
"published_at": null
}
]
Les statuts de diffusion sont pending, scheduled, publishing, processing, published, failed et cancelled. DELETE /api/v1/posts/{post_id} supprime une publication.
Erreurs
Toutes les erreurs ont la même structure : un objet error avec un code stable, un message que vous pouvez afficher aux utilisateurs et, parfois, fields (messages par champ) et un hint.
{
"error": {
"code": "validation",
"message": "Please fix the highlighted fields.",
"fields": {
"kind": "Use text, image or video."
}
}
}
| Statut | Code | Signification |
|---|---|---|
| 400 | bad_request | La requête ne peut pas être exécutée en l’état, par exemple la programmation d’une publication qui échoue aux contrôles. |
| 401 | unauthorized | La clé API est absente, incorrecte ou révoquée. |
| 402 | plan_limit | L’offre de l’espace de travail n’autorise pas cette action ; limit indique la limite concernée. |
| 403 | forbidden | Il manque une permission ou l’accès au projet à la clé. |
| 404 | not_found | Ce projet, cette publication, ce média ou ce point de terminaison n’existe pas. |
| 409 | conflict | La modification entre en conflit avec l’état actuel, par exemple la modification d’un contenu déjà en cours de publication. |
| 422 | validation | Un ou plusieurs champs doivent être corrigés ; consultez fields. |
| 429 | rate_limited | Plus de 120 requêtes par minute avec cette clé. |
| 502 | provider_error | Une plateforme a refusé la requête ou rencontré une erreur ; hint indique la marche à suivre. |
Webhooks
Ajoutez un point de terminaison dans Paramètres, API et webhooks, choisissez les événements souhaités et copiez son secret de signature. Amaposta envoie une requête POST avec du JSON à votre URL pour chaque événement. Toute réponse autre qu’un code 2xx, ou toute absence de réponse sous 15 secondes, entraîne une nouvelle tentative avec un délai croissant. Les points de terminaison qui continuent d’échouer sont désactivés et les administrateurs en sont informés.
| Événement | Envoyé lorsque |
|---|---|
post.created | Une publication a été créée (tableau de bord ou API) |
post.scheduled | Une publication a été programmée |
post.approved | Une publication a été validée |
post.published | Une publication a été mise en ligne sur un canal |
post.failed | Une publication n’a pas pu être publiée sur un canal |
channel.connected | Un canal a été connecté ou reconnecté |
channel.disconnected | Un canal a perdu sa connexion |
media.ready | Le traitement d’un fichier importé est terminé |
media.failed | Un fichier importé n’a pas pu être traité |
POST /your/webhook HTTP/1.1
Content-Type: application/json
User-Agent: Amaposta-Webhooks/1.0
X-Amaposta-Event: post.published
X-Amaposta-Event-Id: 0192b7e0-…
X-Amaposta-Signature: t=1792479641,v1=5f2b0c…
{
"id": "0192b7e0-…",
"type": "post.published",
"created_at": "2026-10-20T07:00:41Z",
"project_id": "0192a3f1-…",
"data": {
"post_id": "0192b7c8-…",
"delivery_id": "0192b7d4-…",
"channel_id": "0192b7a1-…",
"provider": "youtube",
"external_id": "…",
"url": "https://www.youtube.com/watch?v=…"
}
}
Vérifier la signature
X-Amaposta-Signature a la forme t=<unix seconds>,v1=<hex>, où v1 est HMAC_SHA256(secret, t + "." + body), calculé sur le corps brut de la requête. Calculez-la de votre côté, comparez en temps constant et rejetez les horodatages anciens pour empêcher les attaques par rejeu.
import crypto from "node:crypto";
// rawBody: the request body exactly as received (string or Buffer).
export function verifySignature(rawBody, header, secret, toleranceSeconds = 300) {
const parts = Object.fromEntries(header.split(",").map((p) => p.split("=", 2)));
const t = Number(parts.t);
if (!t || Math.abs(Date.now() / 1000 - t) > toleranceSeconds) return false;
const expected = crypto
.createHmac("sha256", secret)
.update(`${t}.${rawBody}`)
.digest();
const given = Buffer.from(parts.v1 ?? "", "hex");
return given.length === expected.length && crypto.timingSafeEqual(given, expected);
}
import hashlib
import hmac
import time
def verify_signature(raw_body: bytes, header: str, secret: str, tolerance: int = 300) -> bool:
parts = dict(p.split("=", 1) for p in header.split(","))
t = int(parts.get("t", "0"))
if abs(time.time() - t) > tolerance:
return False
expected = hmac.new(secret.encode(), f"{t}.".encode() + raw_body, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, parts.get("v1", ""))
Canaux Custom API
Un canal Custom API publie vers un point de terminaison HTTPS que vous gérez : votre CMS, un outil de newsletter, une plateforme qu’Amaposta ne prend pas encore en charge. Il figure dans le calendrier et bénéficie des mêmes contrôles, validations et nouvelles tentatives que les autres canaux. Lorsqu’une publication est diffusée, Amaposta envoie une requête POST par diffusion :
POST /amaposta/publish HTTP/1.1
Authorization: Bearer <your API key>
Content-Type: application/json
Idempotency-Key: 0192b7d4-…
X-Amaposta-Delivery: 0192b7d4-…
X-Amaposta-Signature: t=1792479600,v1=9ac41e…
{
"id": "0192b7d4-…",
"type": "post.publish",
"created_at": "2026-10-20T07:00:00Z",
"content": {
"kind": "video",
"title": "How we roast a batch in 12 minutes",
"text": "From green beans to first crack. We filmed one batch start to finish.",
"hashtags": ["coffee", "behindthescenes"],
"media": {
"url": "https://…",
"content_type": "video/mp4",
"size_bytes": 48213844,
"width": 1080,
"height": 1920,
"duration_ms": 58000,
"filename": "batch-142.mp4"
},
"cover": null,
"options": {}
},
"post": {
"id": "0192b7c8-…",
"external_ref": "episode-142",
"scheduled_at": "2026-10-20T07:00:00Z",
"metadata": {
"pipeline": { "name": "nightly-cut" }
}
},
"project": { "id": "0192a3f1-…", "name": "Spring launch" },
"channel": { "id": "0192b7a9-…", "name": "api.example.com" }
}
Authorization- Votre clé API. Le nom de l’en-tête et le préfixe (
Bearerpar défaut) sont définis sur le canal. Idempotency-Key- L’identifiant de diffusion. Une nouvelle tentative de la même diffusion envoie la même clé, pour vous permettre d’ignorer le travail déjà effectué.
X-Amaposta-Delivery- À nouveau l’identifiant de diffusion, pour vos journaux.
X-Amaposta-Signature- Signé comme les webhooks, avec le secret de signature propre au canal.
Comment répondre
- 2xxPublié. Vous pouvez renvoyer
{"id": "…", "url": "…"}pour afficher le lien sur la publication. - 401, 403La clé a été rejetée. Le canal est signalé comme nécessitant une reconnexion et les administrateurs sont informés. N’utilisez pas ces codes pour une signature incorrecte.
- 5xx, 408, 429Temporaire. Amaposta réessaie avec un délai croissant.
- Autres 4xxLa publication est marquée comme échouée avec votre message ; une personne peut la corriger et appuyer sur Réessayer.
app.post("/amaposta/publish", express.raw({ type: "application/json" }), async (req, res) => {
const signature = req.get("X-Amaposta-Signature") ?? "";
if (!verifySignature(req.body, signature, process.env.AMAPOSTA_SIGNING_SECRET)) {
return res.status(400).json({ message: "Bad signature" });
}
const delivery = JSON.parse(req.body);
const item = await publishToYourSystem(delivery.content, req.get("Idempotency-Key"));
res.json({ id: item.id, url: item.url });
});
Votre point de terminaison doit être accessible depuis Internet ; les redirections ne sont pas suivies. Lors de la connexion du canal, Amaposta le vérifie avec une requête GET vers votre URL de disponibilité si vous en avez défini une, sinon avec une requête OPTIONS vers le point de terminaison.
Canaux Sandbox
Un canal sandbox se comporte comme un vrai canal, mais rien ne quitte Amaposta. Utilisez-le pour créer et tester votre intégration de bout en bout : les publications sont programmées, passent à l’antenne, sont publiées ou échouent et déclenchent les mêmes webhooks. Les canaux sandbox sont gratuits avec toutes les offres et ne comptent pas dans les limites de canaux.
Choisissez son comportement lors de l’ajout :
- Toujours réussirToutes les publications sont diffusées.
- Échouer de temps en tempsDécouvrez les échecs et les nouvelles tentatives sans attendre une vraie panne.
- Toujours échouerTestez votre traitement de
post.failed. - Connexion expiréeDécouvrez les alertes et liens de reconnexion lorsque l’accès expire.
Règles des plateformes
Ce que chaque type de canal accepte. Les contrôles utilisent les mêmes limites : la plupart des problèmes sont donc détectés avant la programmation, plutôt qu’au moment de la diffusion.
| Plateforme | Publication | Titre | Texte | Hashtags | Médias |
|---|---|---|---|---|---|
| YouTube | Vidéo | TitreObligatoire, jusqu’à 100 caractères | DescriptionJusqu’à 5 000 caractères | Envoyés comme tags, jusqu’à 60 | MP4, MOV, WebM, AVI, MKV; jusqu’à 256 GB; 1 s à 12 h |
| Les comptes sans numéro de téléphone vérifié peuvent importer des vidéos de 15 minutes maximum et ne peuvent pas définir de miniatures personnalisées. Chaque import consomme du quota API ; le quota Google par défaut permet environ six imports par jour et par application. | |||||
| Image | Aucun titre | LégendeJusqu’à 2 200 caractères | Ajoutés au texte, jusqu’à 30 | JPEG; jusqu’à 8 MB | |
| Vidéo | Aucun titre | LégendeJusqu’à 2 200 caractères | Ajoutés au texte, jusqu’à 30 | MP4, MOV; jusqu’à 300 MB; 3 s à 15 min | |
| Nécessite un compte Instagram Business ou Creator. Instagram autorise 50 publications via l’API par compte sur une période glissante de 24 heures. Les publications composées uniquement de texte ne sont pas possibles sur Instagram. | |||||
| TikTok | Image | TitreJusqu’à 90 caractères | DescriptionJusqu’à 4 000 caractères | Ajoutés au texte | JPEG, WebP; jusqu’à 20 MB |
| Vidéo | Aucun titre | LégendeJusqu’à 2 200 caractères | Ajoutés au texte | MP4, MOV, WebM; jusqu’à 4 GB; 3 s à 10 min | |
| Les publications des applications n’ayant pas passé l’audit de TikTok sont visibles uniquement par leur créateur. TikTok choisit la couverture parmi les images de la vidéo ; les images de couverture personnalisées ne sont pas prises en charge. Les publications composées uniquement de texte ne sont pas possibles sur TikTok. | |||||
| X | Texte | Aucun titre | PublicationObligatoire, jusqu’à 280 (23 pour un lien, 2 pour un emoji) | Ajoutés au texte | Aucun |
| Image | Aucun titre | PublicationJusqu’à 280 (23 pour un lien, 2 pour un emoji) | Ajoutés au texte | JPEG, PNG, WebP, GIF; jusqu’à 5 MB | |
| Vidéo | Aucun titre | PublicationJusqu’à 280 (23 pour un lien, 2 pour un emoji) | Ajoutés au texte | MP4, MOV; jusqu’à 512 MB; 0,5 s à 2:20 min | |
| Avec votre propre application de développement X, les publications consomment ses crédits API facturés à l’usage. Les hashtags comptent dans la limite de caractères. | |||||
| Texte | Aucun titre | PublicationObligatoire, jusqu’à 63 206 caractères | Ajoutés au texte | Aucun | |
| Image | Aucun titre | LégendeJusqu’à 63 206 caractères | Ajoutés au texte | JPEG, PNG, GIF, WebP; jusqu’à 10 MB | |
| Vidéo | TitreJusqu’à 255 caractères | DescriptionJusqu’à 63 206 caractères | Ajoutés au texte | MP4, MOV; jusqu’à 1 GB; 1 s à 20 min | |
| Publie uniquement sur les Pages ; l’API ne permet pas de publier sur les profils personnels. | |||||
| Custom API | Texte | TitreAucune limite de longueur | DescriptionAucune limite de longueur | Envoyés comme tags | Aucun |
| Image | TitreAucune limite de longueur | DescriptionAucune limite de longueur | Envoyés comme tags | JPEG, PNG, WebP, GIF | |
| Vidéo | TitreAucune limite de longueur | DescriptionAucune limite de longueur | Envoyés comme tags | MP4, MOV, WebM | |
| Chaque requête est signée avec un en-tête HMAC-SHA256 pour vous permettre de vérifier qu’elle provient d’Amaposta. Répondez avec un statut 2xx et éventuellement le JSON {"id": "…", "url": "…"}. Les réponses 408, 429 et 5xx entraînent de nouvelles tentatives avec un délai croissant ; les réponses 401/403 signalent un canal à reconnecter ; les autres 4xx font échouer la diffusion pour vous permettre de corriger le problème et de réessayer. | |||||
| Sandbox | Texte | TitreJusqu’à 200 caractères | DescriptionJusqu’à 5 000 caractères | Ajoutés au texte, jusqu’à 30 | Aucun |
| Image | TitreJusqu’à 200 caractères | DescriptionJusqu’à 5 000 caractères | Ajoutés au texte, jusqu’à 30 | JPEG, PNG, WebP, GIF | |
| Vidéo | TitreJusqu’à 200 caractères | DescriptionJusqu’à 5 000 caractères | Ajoutés au texte, jusqu’à 30 | MP4, MOV, WebM | |
| La publication prend un instant pour vous permettre de suivre les changements de statut en direct. | |||||