Aller au contenu

Automatise tes carrousels Instagram par API

Un carrousel, c’est une série d’images publiées ensemble. Avec l’API image, tu rends chaque slide depuis le même template, avec le texte de cette slide, et ton outil de planification publie la série. Il n’y a pas d’endpoint « carrousel », et il n’en faut pas : un appel par slide, une petite boucle, et les images arrivent dans un dossier, prêtes à être envoyées.

Ce guide te donne la boucle complète sous forme de script Python prêt à lancer (bibliothèque standard uniquement), puis la passation à l’étape de publication, quel que soit ton outil.

  • Une clé API TemplateFox (sk_…), à créer dans le tableau de bord. La référence de l’API image détaille chaque champ de la requête.

  • Un template image dont les blocs de texte sont des calques nommés. Le script ci-dessous suppose ces noms ; renomme-les pour coller à ton propre template :

    Nom du calqueCe qu’il contient
    kickerle petit libellé au-dessus du titre (par exemple 1 · Le loyer)
    titlele titre de la slide
    bodyune ou deux phrases
    counterla position de la slide, remplie par le script (2 / 6)
    brandton pseudo, rempli par le script (@maltaexpat)

    Dimensionne-le pour le fil : 1080×1350 (portrait, le format qu’Instagram affiche le plus grand) ou 1080×1080 (carré). L’image rendue garde le format du template ; le width de la requête ne fait que la mettre à l’échelle.

Tu peux construire le template dans l’éditeur (en nommant chaque calque dans le panneau Layers), ou laisser l’agent de création l’écrire à partir d’une description :

Créer un template de slide avec l'agent de création
curl -X POST https://api.templatefox.com/v1/agent/templates \
-H "x-api-key: sk_ta_cle_api" \
-H "Content-Type: application/json" \
-d '{
"name": "carousel-slide",
"width": 1080,
"height": 1350,
"instructions": "Une slide de carrousel Instagram. Calques texte nommés : kicker (petit libellé en majuscules), title (grand titre, 5 lignes maximum), body (paragraphe), counter (position de la slide, en bas à droite), brand (pseudo, en bas à gauche). Fond blanc cassé, texte bleu marine foncé, un seul accent indigo."
}'

La tâche est asynchrone : interroge GET /v1/agent/jobs/{job_id} jusqu’à ce qu’elle soit completed ; la réponse contient alors le template_id et une preview_url. Vérifie les noms des calques avec GET /v1/templates/{template_id}/layers. Une création par l’agent coûte 25 crédits, remboursés si la tâche échoue.

Un fichier par carrousel. Chaque entrée est une slide ; chaque clé est un nom de calque de ton template, et chaque valeur est le texte qui va dans ce calque.

slides.json
{
"template_id": "id-de-ton-template",
"brand": "@maltaexpat",
"format": "png",
"slides": [
{
"kicker": "S'installer à Malte",
"title": "5 trucs qu'on ne te dit pas avant de partir à Malte",
"body": "Le loyer, les papiers, le bus, la mer, et le truc que tous les expats auraient aimé savoir. Fais défiler."
},
{
"kicker": "1 · Le loyer",
"title": "Le loyer, c'est le premier choc",
"body": "Sliema et St Julian's sont les plus chers. Gzira, Msida et Birkirkara sont à dix minutes, pour beaucoup moins cher."
},
{
"kicker": "2 · Les papiers",
"title": "Déclare-toi avant trois mois",
"body": "Pas de visa pour les citoyens de l'UE, mais une carte de résident. Apporte ton bail, ta pièce d'identité et une preuve de revenus."
},
{
"kicker": "3 · Se déplacer",
"title": "Personne n'est à l'heure. Même pas le bus.",
"body": "Le bus ne coûte presque rien et va partout, en retard. Si ton trajet compte, habite près du boulot ou prends un scooter."
},
{
"kicker": "4 · La mer",
"title": "La mer, c'est le vrai salaire",
"body": "La saison des baignades va de mai à novembre, à dix minutes de n'importe quel bureau du pays. C'est ça, le deal."
},
{
"kicker": "5 · Le mot magique",
"title": "Apprends le mot « mela »",
"body": "Il veut tout dire et rien dire. Place-le au bon moment et tu passes pour un local."
}
]
}

D’où vient ce JSON, c’est toi qui vois : un article découpé en slides, une ligne de tableur, la réponse d’un assistant IA, une requête en base de données. Le script s’en moque.

Enregistre ce script sous render_carousel.py. Il lit le JSON, fait un appel POST /v1/image/create par slide avec le texte de la slide en modifications, et écrit slide-01.png, slide-02.png, … dans le dossier de sortie. export_type: "binary" renvoie directement les octets de l’image : pas de second téléchargement.

render_carousel.py
#!/usr/bin/env python3
"""Rend chaque slide d'un carrousel Instagram avec l'API image TemplateFox.
Utilisation :
TEMPLATEFOX_API_KEY=sk_... python3 render_carousel.py slides.json ./out
Chaque clé d'une slide est un nom de calque du template ; la valeur est le texte
à mettre dans ce calque. Le script ajoute lui-même les calques "counter"
("1 / 6") et "brand". Aucune dépendance hors bibliothèque standard.
"""
import json
import os
import sys
import urllib.request
from pathlib import Path
API_URL = "https://api.templatefox.com/v1/image/create"
API_KEY = os.environ["TEMPLATEFOX_API_KEY"]
def render_slide(template_id: str, modifications: list[dict], fmt: str) -> bytes:
"""Un appel d'API = une slide. export_type=binary renvoie directement les octets de l'image."""
payload = {
"template_id": template_id,
"modifications": modifications,
"format": fmt,
"export_type": "binary",
}
request = urllib.request.Request(
API_URL,
data=json.dumps(payload).encode("utf-8"),
headers={"x-api-key": API_KEY, "Content-Type": "application/json"},
method="POST",
)
with urllib.request.urlopen(request) as response:
return response.read()
def main(spec_path: str, out_dir: str) -> None:
spec = json.loads(Path(spec_path).read_text(encoding="utf-8"))
slides = spec["slides"]
total = len(slides)
fmt = spec.get("format", "png")
out = Path(out_dir)
out.mkdir(parents=True, exist_ok=True)
for index, slide in enumerate(slides, start=1):
modifications = [
{"name": "counter", "text": f"{index} / {total}"},
{"name": "brand", "text": spec["brand"]},
]
modifications += [{"name": layer, "text": text} for layer, text in slide.items()]
image = render_slide(spec["template_id"], modifications, fmt)
path = out / f"slide-{index:02d}.{fmt}"
path.write_bytes(image)
print(f"{path} {len(image) // 1024} Ko")
print(f"{total} slides rendues dans {out}/ — prêtes pour ton outil de planification.")
if __name__ == "__main__":
if len(sys.argv) != 3:
sys.exit("utilisation : render_carousel.py slides.json dossier_de_sortie")
main(sys.argv[1], sys.argv[2])

Lance-le :

Fenêtre de terminal
TEMPLATEFOX_API_KEY=sk_ta_cle_api python3 render_carousel.py slides.json ./out
Sortie
out/slide-01.png 39 Ko
out/slide-02.png 27 Ko
out/slide-03.png 32 Ko
out/slide-04.png 34 Ko
out/slide-05.png 29 Ko
out/slide-06.png 25 Ko
6 slides rendues dans out/ — prêtes pour ton outil de planification.

Chaque appel coûte un crédit : un carrousel de six slides coûte six crédits. Si un nom de calque de ton JSON n’existe pas dans le template, l’image est quand même rendue ; avec export_type: "url", la réponse JSON signale le nom inconnu dans warnings (en binary, comme dans le script, cette information n’est pas renvoyée). Corrige le nom dans le JSON ou dans le template.

Tu préfères un client typé ? Le même appel avec les SDK officiels :

Node.js — @templatefox/sdk
import { Configuration, ImageApi } from "@templatefox/sdk";
const api = new ImageApi(new Configuration({ apiKey: "sk_ta_cle_api" }));
const slide = await api.createImage({
templateId: "id-de-ton-template",
format: "png",
modifications: [
{ name: "kicker", text: "1 · Le loyer" },
{ name: "title", text: "Le loyer, c'est le premier choc" },
{ name: "counter", text: "2 / 6" },
],
});
console.log(slide.url);
Python — templatefox
from templatefox import ApiClient, Configuration, ImageApi, CreateImageRequest, Modification
config = Configuration()
config.api_key["ApiKeyAuth"] = "sk_ta_cle_api"
with ApiClient(config) as client:
slide = ImageApi(client).create_image(CreateImageRequest(
template_id="id-de-ton-template",
format="png",
modifications=[
Modification(name="kicker", text="1 · Le loyer"),
Modification(name="title", text="Le loyer, c'est le premier choc"),
Modification(name="counter", text="2 / 6"),
],
))
print(slide.url)

Ouvre le dossier. Sur un nouveau template, voici ce qui vaut le coup d’être vérifié avant d’automatiser le déclenchement :

  • Les titres longs. Par défaut, le texte est coupé au bord de son bloc : il ne rétrécit pas tout seul. Si un titre est coupé, raccourcis-le dans le JSON, agrandis le bloc dans le template, ou active l’option Autoscale down (section Typography de l’éditeur), qui réduit la taille du texte quand il déborde en largeur.
  • Le compteur et le pseudo sont sur chaque slide, et la dernière affiche bien 6 / 6.
  • Le format. png pour un texte bien net ; jpeg ou webp (fichiers plus légers) si ton outil de planification les préfère : change "format" dans le JSON.

TemplateFox s’arrête aux images. Publier un carrousel, c’est donner ces images, dans l’ordre, à un outil qui poste sur Instagram à une date donnée : n’importe quel outil de planification qui accepte plusieurs images par post fait l’affaire. Deux façons de faire la passation :

  • Envoyer le dossier dans la médiathèque de l’outil et composer le carrousel à partir de là : le plus simple pour démarrer, sans code.
  • Appeler l’API de l’outil : demande l’image avec export_type: "url" au lieu de binary (la réponse contient alors une url signée, valable expiration secondes, jusqu’à sept jours), puis passe les six URL à l’endpoint « créer un post » de ton outil, dans l’ordre des slides.

Par exemple, Nadia prend une liste d’URL d’images et une date, et publie le carrousel à l’heure dite : c’est comme ça que tournent nos propres comptes. Les autres outils de planification fonctionnent sur le même principe ; vérifie le nombre maximum de slides que chacun accepte avant d’envoyer un long carrousel.

Une fois que la boucle marche à la main, branche-la sur un déclencheur pour qu’elle tourne sans toi :

  • une tâche cron qui prend chaque matin la ligne suivante d’un tableur,
  • une automatisation n8n, Make ou Zapier qui se déclenche à la publication d’un nouvel article et en tire le JSON,
  • un webhook de ton CMS.

Le script prend le chemin du JSON en premier argument : chaque déclencheur n’a qu’à écrire un fichier et lancer une commande.