API REST v1 · Référence

Documentation de l’API

Tout ce qu’il faut pour générer des vidéos motion design par HTTP : une clé, un brief, un devis, une génération, un MP4.
Créer une clé d’APISpec OpenAPI 3.1https://motiongist.com/api/v1

Introduction

Vue d’ensemble

L’API REST de Motiongist génère des vidéos motion design narrées (format vertical 1080×1920, 45 à 180 s) par HTTP : tu envoies un brief, tu reçois un devis, tu lances une génération et tu récupères le MP4, les sous-titres et le storyboard. C’est le même moteur que le studio web, avec les mêmes règles de prix.

Toutes les requêtes se font sur https://motiongist.com/api/v1. L’API est incluse dans les plans Studio, Équipe.

Les vidéos sont narrées en anglais (par défaut) ou en français : passe "language": "en" ou "language": "fr" dans le brief. Toutes les voix parlent les deux langues. L’API elle-même (erreurs, descriptions) est en anglais.

  • GET /api/v1 est un index public, sans clé, qui décrit l’authentification et tous les endpoints.
  • La spécification OpenAPI 3.1 est publiée sur /openapi.json (générateurs de clients, Postman, agents).
  • Pour piloter Motiongist depuis Claude, ChatGPT ou Cursor, utilise plutôt le serveur MCP.

Accès

Authentification

Crée une clé REST dans API & agents IA. La clé complète (préfixe mg_live_) n’est affichée qu’une fois : range-la dans un gestionnaire de secrets, jamais dans du code côté navigateur. Envoie-la dans l’en-tête X-API-Key (ou Authorization: Bearer) à chaque requête.

Requête authentifiée
curl https://motiongist.com/api/v1/me \
  -H "X-API-Key: $MOTIONGIST_API_KEY"

Chaque clé porte des portées : jobs:read, jobs:write, videos:read, videos:write, assets:write, webhooks:write. Une clé en lecture seule peut suivre les générations sans pouvoir dépenser de crédits. Les clés MCP (mg_mcp_) sont refusées sur l’API REST. Chaque clé est liée à un espace de travail : elle ne voit que ses projets, générations et vidéos.

En 4 appels

Démarrage rapide

1. Estimer le prix. Rien n’est débité ; la réponse contient le total en crédits et un devis signé valable 1 heure.

1 · Estimer
curl -X POST https://motiongist.com/api/v1/jobs/estimate \
  -H "X-API-Key: $MOTIONGIST_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "brief": {
    "subject": "How a CDN works",
    "length": "short",
    "language": "en",
    "voice": "George",
    "look": { "mode": "preset", "preset": "night" }
  }
}'
# → data.total (credits), data.quote (signed quote), data.allowed

2. Lancer la génération avec le même brief et le devis : le prix est garanti. Réponse 202 avec l’identifiant du job.

2 · Générer
curl -X POST https://motiongist.com/api/v1/jobs \
  -H "X-API-Key: $MOTIONGIST_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: cdn-short-001" \
  -d '{
  "brief": {
    "subject": "How a CDN works",
    "length": "short",
    "language": "en",
    "voice": "George",
    "look": { "mode": "preset", "preset": "night" }
  },
  "quote": "<data.quote from step 1>"
}'
# → data.job.id, data.queuePosition

3. Suivre toutes les 5 à 10 secondes jusqu’à status = succeeded (ou abonne-toi aux webhooks). Une vidéo prend quelques minutes.

3 · Suivre
curl https://motiongist.com/api/v1/jobs/$JOB_ID \
  -H "X-API-Key: $MOTIONGIST_API_KEY"
# → data.status: queued → running → succeeded, data.stage, data.progress, data.videoId

4. Télécharger. Les liens sont signés et valables 15 minutes ; redemande la vidéo pour en obtenir de nouveaux.

4 · Télécharger
URL=$(curl -s https://motiongist.com/api/v1/videos/$VIDEO_ID \
  -H "X-API-Key: $MOTIONGIST_API_KEY" | jq -r '.data.files.mp4.url')
curl -L -o video.mp4 "$URL"
Node.js (18+) · tout le parcours
const base = 'https://motiongist.com/api/v1';
const headers = { 'X-API-Key': process.env.MOTIONGIST_API_KEY, 'Content-Type': 'application/json' };
const call = async (path, init = {}) => {
  const res = await fetch(base + path, { headers, ...init });
  const json = await res.json();
  if (!res.ok) throw new Error(`${json.error.code}: ${json.error.message}`);
  return json.data;
};

const brief = { subject: 'How a CDN works', length: 'short', language: 'en', voice: 'George' };
const est = await call('/jobs/estimate', { method: 'POST', body: JSON.stringify({ brief }) });
console.log(`Price: ${est.total} credits`);
const { job } = await call('/jobs', { method: 'POST', body: JSON.stringify({ brief, quote: est.quote }) });

let j = job;
while (!['succeeded', 'failed', 'cancelled'].includes(j.status)) {
  await new Promise((r) => setTimeout(r, 8000));
  j = await call(`/jobs/${job.id}`);
}
if (j.status !== 'succeeded') throw new Error(j.error?.message ?? j.status);
const video = await call(`/videos/${j.videoId}`);
console.log(video.files.mp4.url);

Pour une narration en français, passe "language": "fr" dans le brief ; l’anglais ("en") est la valeur par défaut.

Conventions

Format des réponses

Tout est en JSON (UTF-8). Une réponse réussie enveloppe la charge utile dans data ; une erreur renvoie un objet error. Les deux contiennent toujours requestId.

Succès
{
  "data": { /* endpoint payload */ },
  "requestId": "req_3f9a1c2e7b8d4a60"
}
Erreur
{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Invalid request.",
    "details": [
      { "path": "brief.subject", "code": "too_small", "message": "…" }
    ]
  },
  "requestId": "req_3f9a1c2e7b8d4a60"
}

Les dates sont en ISO 8601 (UTC), les identifiants sont des UUID, les durées en secondes, les prix en crédits. Les messages d’erreur sont en anglais ; programme sur error.code, qui est stable.

En-tête de réponseRôle
X-Request-IdIdentifiant unique de la requête (aussi dans le corps). Cite-le au support.
X-RateLimit-LimitRequêtes autorisées par fenêtre (60 par 60 s et par clé).
X-RateLimit-RemainingRequêtes restantes dans la fenêtre en cours.
X-RateLimit-ResetDate ISO 8601 de remise à zéro de la fenêtre.
X-API-TierPlan résolu pour la clé (Studio, Équipe).
X-Idempotent-ReplayPrésent et à true quand la réponse est rejouée depuis une Idempotency-Key.
Retry-AfterSur un 429 (ou IDEMPOTENCY_IN_PROGRESS) : secondes à attendre avant de réessayer.

Les listes sont paginées par curseur : passe limit (1 à 100) et, pour la page suivante, le nextCursor reçu dans cursor. nextCursor: null signale la dernière page. L’API accepte les appels depuis un navigateur (CORS ouvert), mais ne mets jamais ta clé dans du code public.

Échecs

Erreurs

Chaque erreur renvoie le statut HTTP adapté et un error.code stable.

CodeStatutSignification
MISSING_API_KEY401Aucune clé envoyée (en-tête X-API-Key ou Authorization: Bearer).
INVALID_API_KEY401Clé inconnue ou révoquée, ou clé MCP (mg_mcp_) utilisée sur l’API REST.
UNAUTHENTICATED401Jeton OAuth absent ou expiré.
FORBIDDEN403La clé n’a pas la portée requise, ou l’action est momentanément désactivée.
PLAN_REQUIRED403Le plan de l’espace n’inclut pas l’API ou l’option demandée (voix finale, look sur mesure, qualité Studio…).
INSUFFICIENT_CREDITS402Pas assez de crédits pour lancer la génération. details.required et details.balance indiquent l’écart.
VALIDATION_ERROR400Corps JSON illisible ou champs invalides. details[] liste chaque champ fautif (path, message).
QUOTE_INVALID400Le devis a expiré (1 h), a été signé pour un autre espace, ou le brief / projet a changé depuis. Ré-estime.
NOT_FOUND404Ressource inexistante, supprimée, ou appartenant à un autre espace.
CONFLICT409Action impossible dans l’état actuel (ex. supprimer un projet dont la génération tourne).
NOT_CANCELLABLE409La génération est terminée ou son rendu a commencé.
CONCURRENCY_LIMIT429Trop de générations simultanées pour le plan.
RATE_LIMITED429Trop de requêtes : attends Retry-After secondes.
IDEMPOTENCY_CONFLICT409Idempotency-Key déjà utilisée avec un autre corps de requête.
IDEMPOTENCY_IN_PROGRESS409La première requête avec cette Idempotency-Key est encore en cours : réessaie après Retry-After.
PAYLOAD_TOO_LARGE413Fichier trop volumineux (logo 2 Mo, document 20 Mo).
UNSUPPORTED_MEDIA_TYPE415Format de fichier ou Content-Type non pris en charge.
INTERNAL_ERROR500Erreur inattendue de notre côté. Sûr à réessayer avec une Idempotency-Key ; cite le requestId au support.

Une génération qui échoue côté moteur n’est pas une erreur HTTP : le job passe en failed avec error.code (ex. render-failed) et ses crédits sont remboursés automatiquement.

Quotas

Limites de débit

  • 60 requêtes par minute et par clé, fenêtre fixe. Au-delà : 429 RATE_LIMITED avec Retry-After.
  • 10 lancements de génération par minute et par espace.
  • 60 appels IA par heure (écriture de script, idées, écoute de narration) et 30 envois de fichiers par heure, par espace.
  • Générations simultanées : 2 en Studio, 4 en Équipe. Les suivantes attendent dans la file.

Les appels de suivi comptent dans le quota : interroge GET /jobs/{id} toutes les 5 à 10 secondes au plus, ou utilise les webhooks. Les générations consomment des crédits, comme dans le studio.

Réessais sûrs

Idempotence

Tous les POST acceptent un en-tête facultatif Idempotency-Key (200 caractères max). Rejouer la même clé avec le même corps dans les 24 heures renvoie la réponse d’origine (marquée X-Idempotent-Replay: true) au lieu de créer un doublon : aucune génération n’est lancée, aucun crédit n’est débité deux fois. Réutiliser une clé avec un autre corps renvoie IDEMPOTENCY_CONFLICT ; réessayer pendant que la première requête tourne renvoie IDEMPOTENCY_IN_PROGRESS avec Retry-After. Les erreurs ne sont pas mémorisées : tu peux réessayer avec la même clé.

Création idempotente
curl -X POST https://motiongist.com/api/v1/jobs \
  -H "X-API-Key: $MOTIONGIST_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: order-4512" \
  -d '{ "brief": { "subject": "How a CDN works", "language": "en" } }'

Événements

Webhooks

Plutôt que d’interroger GET /jobs/{id}, enregistre une URL HTTPS (POST /webhooks) : Motiongist y envoie un POST JSON à chaque événement souscrit. Réponds 2xx en moins de 10 secondes ; sinon la livraison est retentée après 30 s, 5 min puis 30 min, avant d’être abandonnée. Un même événement peut arriver deux fois : dédoublonne avec id.

ÉvénementQuand
job.startedUn worker a pris la génération en charge (data.attempt indique la tentative).
job.progressChangement d’étape : data.stage (script, narration, storyboard, check, render, upload) et data.progress en %.
job.succeededLa vidéo est prête : data.videoId et data.durationS. Appelle GET /videos/{id} pour les liens.
job.failedÉchec définitif après les relances automatiques : data.error.code et message. Crédits remboursés.
job.cancelledGénération annulée (par toi ou par le système). Crédits remboursés.
video.deletedUne vidéo a été supprimée (API, studio).
post.publishedUne publication sociale est en ligne : data.postId, data.provider, data.externalUrl.
post.failedUne publication sociale a échoué après les nouvelles tentatives automatiques : data.error (data.reconnectRequired quand le compte doit être reconnecté).
Corps envoyé
{
  "id": "evt_Q2x8fK1mZpL0",
  "type": "job.succeeded",
  "created": "2026-10-23T09:19:41.000Z",
  "data": {
    "jobId": "7f3c2a10-5b1e-4c8a-9d2f-0e6b4a1c9d55",
    "projectId": "2b9e4d71-8c0a-4f3e-a6b5-1d2c3e4f5a6b",
    "videoId": "c4d5e6f7-1a2b-4c3d-8e9f-0a1b2c3d4e5f",
    "durationS": 104.2
  }
}

Vérifier la signature

Chaque requête porte l’en-tête X-Motiongist-Signature: t=<unix timestamp>,v1=<signature>, où la signature est le HMAC-SHA256 hexadécimal de la chaîne "<t>.<raw body>" avec le secret du webhook (whsec_…, montré une seule fois à la création). Compare en temps constant et refuse les horodatages de plus de 5 minutes pour bloquer les rejeux.

Node.js (Express)
import crypto from 'node:crypto';
import express from 'express';

const app = express();
const SECRET = process.env.MOTIONGIST_WEBHOOK_SECRET; // whsec_…

// Keep the raw body: the signature covers the exact bytes received.
app.post('/hooks/motiongist', express.raw({ type: 'application/json' }), (req, res) => {
  const header = req.get('X-Motiongist-Signature') ?? '';
  const parts = Object.fromEntries(header.split(',').map((p) => p.split('=')));
  const expected = crypto.createHmac('sha256', SECRET).update(`${parts.t}.${req.body}`).digest('hex');
  const fresh = Math.abs(Date.now() / 1000 - Number(parts.t)) < 300; // 5 min
  const valid = parts.v1 && parts.v1.length === expected.length
    && crypto.timingSafeEqual(Buffer.from(parts.v1), Buffer.from(expected));
  if (!valid || !fresh) return res.status(400).send('invalid signature');

  const event = JSON.parse(req.body);
  if (event.type === 'job.succeeded') {
    // event.data.videoId → GET /api/v1/videos/{id}
  }
  res.sendStatus(200); // answer fast (under 10 s), process in the background
});
Python (Flask)
import hashlib, hmac, json, os, time
from flask import Flask, request, abort

app = Flask(__name__)
SECRET = os.environ["MOTIONGIST_WEBHOOK_SECRET"].encode()  # whsec_…

@app.post("/hooks/motiongist")
def motiongist_hook():
    header = request.headers.get("X-Motiongist-Signature", "")
    parts = dict(p.split("=", 1) for p in header.split(",") if "=" in p)
    body = request.get_data()  # raw bytes
    expected = hmac.new(SECRET, f"{parts.get('t', '')}.".encode() + body, hashlib.sha256).hexdigest()
    if not hmac.compare_digest(parts.get("v1", ""), expected):
        abort(400)
    if abs(time.time() - int(parts.get("t", "0"))) > 300:
        abort(400)
    event = json.loads(body)
    if event["type"] == "job.succeeded":
        video_id = event["data"]["videoId"]  # → GET /api/v1/videos/{id}
    return "", 200

Modèle

Concepts

Brief

La description complète d’une vidéo : sujet, source (idea, script ou document), public, durée, langue de narration (en ou fr), voix, look, marque, consignes, mascotte, qualité. C’est l’unique entrée du moteur ; le studio, l’API et le MCP valident le même schéma (voir Estimer un brief pour tous les champs).

Projet

Un brouillon, comme dans le studio : réglages, script éditable, écoute de la voix, puis générations successives (versions). Les projets créés par l’API apparaissent dans le studio web. POST /jobs avec un brief crée un projet automatiquement ; les endpoints /projects servent quand on veut itérer (écrire le script, l’écouter, l’ajuster) avant de payer.

Devis (quote)

Un jeton signé renvoyé par les endpoints d’estimation. Il fige le prix pour ce brief exact, dans cet espace, pendant 1 heure. Une génération lancée avec un devis ne coûte jamais plus que le prix annoncé ; si le brief ou le projet change, le devis est refusé (QUOTE_INVALID) et il faut ré-estimer. POST /projects/{id}/generate l’exige ; POST /jobs l’accepte (sans devis, le prix est recalculé au lancement).

Génération (job)

Une exécution du moteur : queued → running → succeeded | failed | cancelled. Pendant running, stage passe par script, narration, storyboard, check, render, upload. L’annulation est possible jusqu’au début du rendu. Les échecs transitoires sont relancés automatiquement.

Vidéo

Le résultat d’une génération réussie : MP4 1080×1920, sous-titres SRT, planche-contact, affiche, storyboard JSON et rapport. Les fichiers sont privés : l’API renvoie des liens signés valables 15 minutes. Les MP4 contiennent des métadonnées indiquant un contenu généré par IA.

Crédits

Chaque génération consomme des crédits pris sur le solde de l’espace (GET /me) : 400 (courte), 700 (standard) ou 1 000 (longue), plus 1 crédit pour 10 caractères narrés en voix finale, +300 en qualité Studio, +300 pour un look sur mesure. Une nouvelle version d’un projet coûte 50 % du prix de base. Les échecs et annulations sont remboursés. Les plans Studio et Équipe peuvent dépasser leur solde mensuel (file plus lente) jusqu’à −15 000 et −50 000 crédits.

Référence

Endpoints

Base : https://motiongist.com/api/v1. Tous les endpoints exigent une clé, sauf l’index. Les exemples utilisent la variable $MOTIONGIST_API_KEY.

Compte et catalogue

Index public

GET/api/v1sans clé

Décrit l’API sans clé : version, liens vers cette documentation et la spec OpenAPI, authentification et liste des endpoints.

Requête
curl https://motiongist.com/api/v1
Réponse 200
{
  "data": {
    "name": "Motiongist API",
    "version": "1.0.0",
    "docs": "https://motiongist.com/docs/api",
    "openapi": "https://motiongist.com/openapi.json",
    "endpoints": [
      "…"
    ]
  },
  "requestId": "req_3f9a1c2e7b8d4a60"
}

Mon compte

GET/api/v1/me

Espace de travail lié à la clé, plan, solde de crédits, limites (débit, générations en parallèle) et portées de la clé.

Requête
curl https://motiongist.com/api/v1/me \
  -H "X-API-Key: $MOTIONGIST_API_KEY"
Réponse 200
{
  "data": {
    "workspace": {
      "id": "0d1e2f3a-4b5c-4d6e-8f70-81a2b3c4d5e6",
      "name": "Acme’s workspace",
      "plan": "studio",
      "subscriptionStatus": "active"
    },
    "plan": {
      "id": "studio",
      "name": "Studio",
      "monthlyCredits": 30000,
      "softOverdraft": 15000,
      "maxConcurrentJobs": 2
    },
    "credits": {
      "balance": 29153
    },
    "limits": {
      "requestsPerMinute": 60,
      "maxConcurrentJobs": 2,
      "activeJobs": {
        "running": 1,
        "queued": 0
      }
    },
    "key": {
      "id": "b1c2d3e4-…",
      "kind": "rest",
      "scopes": [
        "jobs:write",
        "jobs:read",
        "videos:read",
        "videos:write",
        "assets:write",
        "webhooks:write"
      ]
    }
  },
  "requestId": "req_3f9a1c2e7b8d4a60"
}

Catalogue

GET/api/v1/catalog

Tout ce qu’on peut mettre dans un brief : voix (avec extraits audio), looks, durées, langues de narration (en, fr), publics, coûts en crédits et plans.

Requête
curl https://motiongist.com/api/v1/catalog \
  -H "X-API-Key: $MOTIONGIST_API_KEY"
Réponse 200
{
  "data": {
    "voices": [
      {
        "id": "George",
        "name": "George",
        "gender": "m",
        "description": "Warm and steady, made for explaining",
        "tags": [
          "narration",
          "calm"
        ]
      }
    ],
    "looks": [
      {
        "id": "clean",
        "label": "Light, product"
      },
      {
        "id": "night",
        "label": "Dark, tech"
      },
      {
        "id": "toon",
        "label": "Illustrated"
      }
    ],
    "lengths": [
      {
        "id": "short",
        "secondsMin": 45,
        "secondsMax": 60,
        "baseCredits": 400
      }
    ],
    "languages": [
      "en",
      "fr"
    ],
    "defaultLanguage": "en",
    "audiences": [
      "beginner",
      "dev",
      "ops",
      "decision-maker"
    ],
    "creditCosts": {
      "base": {
        "short": 400,
        "standard": 700,
        "full": 1000
      },
      "finalVoicePerChars": 10,
      "studioTier": 300,
      "customLook": 300,
      "threeD": 100,
      "revisionFactor": 0.5
    }
  },
  "requestId": "req_3f9a1c2e7b8d4a60"
}

Générations (jobs)

Estimer un brief

POST/api/v1/jobs/estimateportée jobs:read

Calcule le prix exact en crédits, la durée de génération et renvoie un devis signé (quote) valable 1 heure. Rien n’est débité. Repasse le quote à POST /jobs pour garantir le prix.

Corps JSON

ChampTypeDescription
briefobjectLe brief complet de la vidéo (sur POST /jobs : un projet est créé pour lui ; ou bien projectId).requis
brief.subjectstringSujet de la vidéo, en une phrase (3 à 200 caractères).requis
brief.inputobjet (variantes)Source du contenu : { kind: "idea" } (le script est écrit pour toi), { kind: "script", text } (ton texte exact, 4 000 car. max) ou { kind: "document", text, sourceName } (faits à respecter, 40 000 car. max).Défaut : {"kind":"idea"}
brief.audience"beginner" | "dev" | "ops" | "decision-maker"Public visé : beginner, dev, ops ou decision-maker.Défaut : "dev"
brief.length"short" | "standard" | "full"Durée : short (45–60 s), standard (90–120 s) ou full (150–180 s).Défaut : "standard"
brief.language"fr" | "en"Langue de la narration : en (anglais, par défaut) ou fr (français).Défaut : "en"
brief.voicestringVoix du narrateur (voir GET /catalog) : George, Sarah, Daniel, Brian, Lily, Alice, Will, Matilda. Toutes les voix parlent les deux langues.Défaut : "George"
brief.lookobjet (variantes)Style visuel : { mode: "preset", preset: "clean" | "night" | "toon" }, { mode: "brand" } (couleurs de la marque, champ brand requis) ou { mode: "custom", description } (plan Studio).Défaut : {"mode":"preset"}
brief.brandobjectMarque affichée : name (24 car.), site, colors (1 à 3 couleurs #RRGGBB), logo (« asset:<id> » renvoyé par POST /assets).
brief.brand.namestringNom de la marque (24 caractères max).requis
brief.brand.sitestringSite affiché en fin de vidéo (40 caractères max).
brief.brand.colorsstring[]1 à 3 couleurs hexadécimales #RRGGBB.requis
brief.brand.logostringLogo : « asset:<id> » renvoyé par POST /assets.
brief.notesobjectConsignes : mustShow (10 éléments à montrer max), avoid (à éviter), keyMoment, free (texte libre).Défaut : {"mustShow":[],"avoid":[]}
brief.notes.mustShowstring[]Éléments à montrer absolument (10 max, 80 car. chacun).Défaut : []
brief.notes.avoidstring[]Éléments à éviter (10 max).Défaut : []
brief.notes.keyMomentstringLe moment clé à mettre en valeur.
brief.notes.freestringConsignes libres (1 000 caractères max).
brief.mascotbooleanAjoute un présentateur animé.Défaut : false
brief.tier"standard" | "studio"standard, ou studio (qualité supérieure, +300 crédits, plan Studio).Défaut : "standard"
brief.dimension"2d" | "3d"2d (motion design à plat, par défaut) ou 3d (perspective, volume, profondeur et mouvements de caméra).Défaut : "2d"
brief.threeD"none" | "signature"Ancien champ, ignoré : utilise dimension.Défaut : "none"
voiceMode"draft" | "final"final = voix sous licence (plans payants), draft = voix de brouillon gratuite. Par défaut : final sur les plans payants.
Requête
curl -X POST https://motiongist.com/api/v1/jobs/estimate \
  -H "X-API-Key: $MOTIONGIST_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
  "brief": {
    "subject": "How a CDN works",
    "input": {
      "kind": "idea"
    },
    "audience": "dev",
    "length": "standard",
    "language": "en",
    "voice": "George",
    "look": {
      "mode": "preset",
      "preset": "night"
    },
    "notes": {
      "mustShow": [
        "edge cache",
        "latency"
      ],
      "avoid": []
    }
  }
}'
Réponse 200
{
  "data": {
    "total": 847,
    "lines": [
      {
        "label": "Standard video (90–120 s)",
        "credits": 700
      },
      {
        "label": "Final voice (1,470 characters)",
        "credits": 147
      }
    ],
    "quote": "eyJ3cyI6IjQ…(signed quote, pass it back unchanged)…",
    "quoteExpiresAt": "2026-10-23T10:12:00.000Z",
    "voiceMode": "final",
    "isRevision": false,
    "balance": 29153,
    "allowed": true,
    "blockers": [],
    "overdraft": false,
    "eta": {
      "minutesMin": 4,
      "minutesMax": 8
    }
  },
  "requestId": "req_3f9a1c2e7b8d4a60"
}

Erreurs possibles : VALIDATION_ERROR (400)

Lancer une génération

POST/api/v1/jobsportée jobs:write

Débite les crédits et met la génération en file. Avec un quote, le prix est garanti (et refusé si le brief a changé) ; sans quote, le serveur recalcule le prix. Réponse 202 : interroge ensuite GET /jobs/{id} ou abonne-toi aux webhooks.

Corps JSON

ChampTypeDescription
briefobjectLe brief complet de la vidéo (sur POST /jobs : un projet est créé pour lui ; ou bien projectId).
brief.subjectstringSujet de la vidéo, en une phrase (3 à 200 caractères).requis
brief.inputobjet (variantes)Source du contenu : { kind: "idea" } (le script est écrit pour toi), { kind: "script", text } (ton texte exact, 4 000 car. max) ou { kind: "document", text, sourceName } (faits à respecter, 40 000 car. max).Défaut : {"kind":"idea"}
brief.audience"beginner" | "dev" | "ops" | "decision-maker"Public visé : beginner, dev, ops ou decision-maker.Défaut : "dev"
brief.length"short" | "standard" | "full"Durée : short (45–60 s), standard (90–120 s) ou full (150–180 s).Défaut : "standard"
brief.language"fr" | "en"Langue de la narration : en (anglais, par défaut) ou fr (français).Défaut : "en"
brief.voicestringVoix du narrateur (voir GET /catalog) : George, Sarah, Daniel, Brian, Lily, Alice, Will, Matilda. Toutes les voix parlent les deux langues.Défaut : "George"
brief.lookobjet (variantes)Style visuel : { mode: "preset", preset: "clean" | "night" | "toon" }, { mode: "brand" } (couleurs de la marque, champ brand requis) ou { mode: "custom", description } (plan Studio).Défaut : {"mode":"preset"}
brief.brandobjectMarque affichée : name (24 car.), site, colors (1 à 3 couleurs #RRGGBB), logo (« asset:<id> » renvoyé par POST /assets).
brief.brand.namestringNom de la marque (24 caractères max).requis
brief.brand.sitestringSite affiché en fin de vidéo (40 caractères max).
brief.brand.colorsstring[]1 à 3 couleurs hexadécimales #RRGGBB.requis
brief.brand.logostringLogo : « asset:<id> » renvoyé par POST /assets.
brief.notesobjectConsignes : mustShow (10 éléments à montrer max), avoid (à éviter), keyMoment, free (texte libre).Défaut : {"mustShow":[],"avoid":[]}
brief.notes.mustShowstring[]Éléments à montrer absolument (10 max, 80 car. chacun).Défaut : []
brief.notes.avoidstring[]Éléments à éviter (10 max).Défaut : []
brief.notes.keyMomentstringLe moment clé à mettre en valeur.
brief.notes.freestringConsignes libres (1 000 caractères max).
brief.mascotbooleanAjoute un présentateur animé.Défaut : false
brief.tier"standard" | "studio"standard, ou studio (qualité supérieure, +300 crédits, plan Studio).Défaut : "standard"
brief.dimension"2d" | "3d"2d (motion design à plat, par défaut) ou 3d (perspective, volume, profondeur et mouvements de caméra).Défaut : "2d"
brief.threeD"none" | "signature"Ancien champ, ignoré : utilise dimension.Défaut : "none"
projectIduuidProjet existant à générer (alternative à brief).
quotestringDevis signé renvoyé par l’endpoint d’estimation (valable 1 h). Garantit le prix ; sans devis sur POST /jobs, le serveur recalcule le prix.
titlestringTitre (120 caractères max). Par défaut : le sujet.
voiceMode"draft" | "final"final = voix sous licence (plans payants), draft = voix de brouillon gratuite. Par défaut : final sur les plans payants.
Requête
curl -X POST https://motiongist.com/api/v1/jobs \
  -H "X-API-Key: $MOTIONGIST_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
  "brief": {
    "subject": "How a CDN works",
    "input": {
      "kind": "idea"
    },
    "audience": "dev",
    "length": "standard",
    "language": "en",
    "voice": "George",
    "look": {
      "mode": "preset",
      "preset": "night"
    },
    "notes": {
      "mustShow": [
        "edge cache",
        "latency"
      ],
      "avoid": []
    }
  },
  "quote": "eyJ3cyI6IjQ…(signed quote, pass it back unchanged)…"
}'
Réponse 202
{
  "data": {
    "job": {
      "id": "7f3c2a10-5b1e-4c8a-9d2f-0e6b4a1c9d55",
      "projectId": "2b9e4d71-8c0a-4f3e-a6b5-1d2c3e4f5a6b",
      "status": "queued",
      "stage": "script",
      "stageLabel": "Script",
      "progress": 0,
      "detail": null,
      "stages": {},
      "voiceMode": "final",
      "isRevision": false,
      "credits": 847,
      "queuePosition": 1,
      "cancellable": true,
      "error": null,
      "videoId": null,
      "attempt": 1,
      "source": "api",
      "queuedAt": "2026-10-23T09:12:04.000Z",
      "startedAt": null,
      "finishedAt": null
    },
    "projectId": "2b9e4d71-8c0a-4f3e-a6b5-1d2c3e4f5a6b",
    "queuePosition": 1
  },
  "requestId": "req_3f9a1c2e7b8d4a60"
}

Erreurs possibles : VALIDATION_ERROR (400), QUOTE_INVALID (400), INSUFFICIENT_CREDITS (402), PLAN_REQUIRED (403), RATE_LIMITED (429)

Lister les générations

GET/api/v1/jobsportée jobs:read

Générations de l’espace, de la plus récente à la plus ancienne, paginées par curseur.

Paramètres

NomOùTypeDescription
limitqueryintegerNombre d’éléments (1 à 100, 20 par défaut)
cursorquerystringCurseur renvoyé par nextCursor pour la page suivante
statusquerystringFiltre, une ou plusieurs valeurs séparées par des virgules : queued, running, succeeded, failed, cancelled
sincequerydate-timeSeulement les générations créées après cette date (ISO 8601)
Requête
curl https://motiongist.com/api/v1/jobs \
  -H "X-API-Key: $MOTIONGIST_API_KEY"
Réponse 200
{
  "data": {
    "items": [
      {
        "id": "7f3c2a10-5b1e-4c8a-9d2f-0e6b4a1c9d55",
        "projectId": "2b9e4d71-8c0a-4f3e-a6b5-1d2c3e4f5a6b",
        "status": "running",
        "stage": "storyboard",
        "stageLabel": "Storyboard",
        "progress": 46,
        "detail": "Scene 4/9",
        "stages": {},
        "voiceMode": "final",
        "isRevision": false,
        "credits": 847,
        "queuePosition": 0,
        "cancellable": true,
        "error": null,
        "videoId": null,
        "attempt": 1,
        "source": "api",
        "queuedAt": "2026-10-23T09:12:04.000Z",
        "startedAt": "2026-10-23T09:12:09.000Z",
        "finishedAt": null
      }
    ],
    "nextCursor": "2026-10-23T09:12:04.000Z"
  },
  "requestId": "req_3f9a1c2e7b8d4a60"
}

Suivre une génération

GET/api/v1/jobs/{id}portée jobs:read

Statut, étape (script, voix, storyboard, vérification, rendu), progression en %, position dans la file, erreur éventuelle et videoId une fois terminée. Interroge toutes les 5 à 10 secondes au plus.

Paramètres

NomOùTypeDescription
idcheminuuidIdentifiant de la générationrequis
Requête
curl https://motiongist.com/api/v1/jobs/7f3c2a10-5b1e-4c8a-9d2f-0e6b4a1c9d55 \
  -H "X-API-Key: $MOTIONGIST_API_KEY"
Réponse 200
{
  "data": {
    "id": "7f3c2a10-5b1e-4c8a-9d2f-0e6b4a1c9d55",
    "projectId": "2b9e4d71-8c0a-4f3e-a6b5-1d2c3e4f5a6b",
    "status": "succeeded",
    "stage": "done",
    "stageLabel": "Ready",
    "progress": 100,
    "detail": null,
    "stages": {},
    "voiceMode": "final",
    "isRevision": false,
    "credits": 847,
    "queuePosition": 0,
    "cancellable": false,
    "error": null,
    "videoId": "c4d5e6f7-1a2b-4c3d-8e9f-0a1b2c3d4e5f",
    "attempt": 1,
    "source": "api",
    "queuedAt": "2026-10-23T09:12:04.000Z",
    "startedAt": "2026-10-23T09:12:09.000Z",
    "finishedAt": "2026-10-23T09:19:41.000Z"
  },
  "requestId": "req_3f9a1c2e7b8d4a60"
}

Erreurs possibles : NOT_FOUND (404)

Annuler une génération

POST/api/v1/jobs/{id}/cancelportée jobs:write

Annule une génération tant que le rendu n’a pas commencé. En file : annulation immédiate et crédits remboursés. En cours : l’annulation est demandée au moteur, le remboursement suit.

Paramètres

NomOùTypeDescription
idcheminuuidIdentifiant de la générationrequis
Requête
curl -X POST https://motiongist.com/api/v1/jobs/7f3c2a10-5b1e-4c8a-9d2f-0e6b4a1c9d55/cancel \
  -H "X-API-Key: $MOTIONGIST_API_KEY"
Réponse 200
{
  "data": {
    "id": "7f3c2a10-5b1e-4c8a-9d2f-0e6b4a1c9d55",
    "projectId": "2b9e4d71-8c0a-4f3e-a6b5-1d2c3e4f5a6b",
    "status": "cancelled",
    "stage": "storyboard",
    "stageLabel": "Storyboard",
    "progress": 46,
    "detail": "Scene 4/9",
    "stages": {},
    "voiceMode": "final",
    "isRevision": false,
    "credits": 847,
    "queuePosition": 0,
    "cancellable": false,
    "error": null,
    "videoId": null,
    "attempt": 1,
    "source": "api",
    "queuedAt": "2026-10-23T09:12:04.000Z",
    "startedAt": "2026-10-23T09:12:09.000Z",
    "finishedAt": null
  },
  "requestId": "req_3f9a1c2e7b8d4a60"
}

Erreurs possibles : NOT_FOUND (404), NOT_CANCELLABLE (409)

Vidéos

Lister les vidéos

GET/api/v1/videosportée videos:read

Vidéos terminées de l’espace, de la plus récente à la plus ancienne. Utilise GET /videos/{id} pour obtenir les liens de téléchargement.

Paramètres

NomOùTypeDescription
limitqueryintegerNombre d’éléments (1 à 100, 20 par défaut)
cursorquerystringCurseur renvoyé par nextCursor pour la page suivante
projectIdqueryuuidSeulement les versions de ce projet
Requête
curl https://motiongist.com/api/v1/videos \
  -H "X-API-Key: $MOTIONGIST_API_KEY"
Réponse 200
{
  "data": {
    "items": [
      {
        "id": "c4d5e6f7-1a2b-4c3d-8e9f-0a1b2c3d4e5f",
        "projectId": "2b9e4d71-8c0a-4f3e-a6b5-1d2c3e4f5a6b",
        "jobId": "7f3c2a10-5b1e-4c8a-9d2f-0e6b4a1c9d55",
        "title": "How a CDN works",
        "durationS": 104.2,
        "width": 1080,
        "height": 1920,
        "draftVoice": false,
        "watermarked": false,
        "createdAt": "2026-10-23T09:19:41.000Z"
      }
    ],
    "nextCursor": "2026-10-23T09:12:04.000Z"
  },
  "requestId": "req_3f9a1c2e7b8d4a60"
}

Récupérer une vidéo

GET/api/v1/videos/{id}portée videos:read

Métadonnées et liens signés valables 15 minutes : MP4 (1080×1920, lecture partielle Range supportée), sous-titres SRT, planche-contact, affiche, storyboard. Redemande la vidéo pour obtenir des liens frais.

Paramètres

NomOùTypeDescription
idcheminuuidIdentifiant de la vidéorequis
Requête
curl https://motiongist.com/api/v1/videos/c4d5e6f7-1a2b-4c3d-8e9f-0a1b2c3d4e5f \
  -H "X-API-Key: $MOTIONGIST_API_KEY"
Réponse 200
{
  "data": {
    "id": "c4d5e6f7-1a2b-4c3d-8e9f-0a1b2c3d4e5f",
    "projectId": "2b9e4d71-8c0a-4f3e-a6b5-1d2c3e4f5a6b",
    "jobId": "7f3c2a10-5b1e-4c8a-9d2f-0e6b4a1c9d55",
    "title": "How a CDN works",
    "durationS": 104.2,
    "width": 1080,
    "height": 1920,
    "voice": "George",
    "voiceProvider": "elevenlabs",
    "draftVoice": false,
    "watermarked": false,
    "look": "night",
    "scenes": 11,
    "qaScore": 0.93,
    "createdAt": "2026-10-23T09:19:41.000Z",
    "aiGenerated": true,
    "files": {
      "mp4": {
        "url": "https://motiongist.com/api/files/videos/…/video.mp4?e=1761211161&s=…",
        "download": "https://motiongist.com/api/files/videos/…/video.mp4?e=1761211161&s=…&d=how-a-cdn-works.mp4"
      },
      "srt": {
        "url": "https://motiongist.com/api/files/videos/…/captions.srt?e=1761211161&s=…",
        "download": "https://motiongist.com/api/files/videos/…/captions.srt?e=1761211161&s=…&d=how-a-cdn-works-captions.srt"
      },
      "contact": {
        "url": "https://motiongist.com/api/files/videos/…/contact.jpg?e=1761211161&s=…",
        "download": "https://motiongist.com/api/files/videos/…/contact.jpg?e=1761211161&s=…&d=…"
      },
      "poster": {
        "url": "https://motiongist.com/api/files/videos/…/poster.jpg?e=1761211161&s=…",
        "download": "https://motiongist.com/api/files/videos/…/poster.jpg?e=1761211161&s=…&d=…"
      }
    }
  },
  "requestId": "req_3f9a1c2e7b8d4a60"
}

Erreurs possibles : NOT_FOUND (404)

Supprimer une vidéo

DELETE/api/v1/videos/{id}portée videos:write

Supprime la vidéo (fichiers effacés définitivement après 30 jours). Émet l’événement video.deleted.

Paramètres

NomOùTypeDescription
idcheminuuidIdentifiant de la vidéorequis
Requête
curl -X DELETE https://motiongist.com/api/v1/videos/c4d5e6f7-1a2b-4c3d-8e9f-0a1b2c3d4e5f \
  -H "X-API-Key: $MOTIONGIST_API_KEY"
Réponse 200
{
  "data": {
    "id": "c4d5e6f7-1a2b-4c3d-8e9f-0a1b2c3d4e5f",
    "deleted": true
  },
  "requestId": "req_3f9a1c2e7b8d4a60"
}

Erreurs possibles : NOT_FOUND (404)

Textes, partage et publication

Lire les textes de post

GET/api/v1/videos/{id}/post-copyportée videos:read

Titre, description et hashtags pour YouTube, TikTok, Instagram et LinkedIn, dans la langue de la vidéo et dans les limites de chaque plateforme (renvoyées). Générés au premier appel puis conservés. caption est le texte réellement publié (description + hashtags).

Paramètres

NomOùTypeDescription
idcheminuuidIdentifiant de la vidéorequis
Requête
curl https://motiongist.com/api/v1/videos/c4d5e6f7-1a2b-4c3d-8e9f-0a1b2c3d4e5f/post-copy \
  -H "X-API-Key: $MOTIONGIST_API_KEY"
Réponse 200
{
  "data": {
    "language": "en",
    "generatedAt": "2026-10-23T09:20:00.000Z",
    "platforms": {
      "youtube": {
        "title": "How a CDN works in 60 seconds #shorts",
        "description": "Your files, next to your visitors.\n\nFollow for more explainers.",
        "hashtags": [
          "cdn",
          "webdev",
          "shorts"
        ],
        "caption": "Your files, next to your visitors.\n\nFollow for more explainers.\n\n#cdn #webdev #shorts",
        "limits": {
          "title": 100,
          "caption": 5000,
          "hashtags": 15
        }
      }
    }
  },
  "requestId": "req_3f9a1c2e7b8d4a60"
}

Erreurs possibles : NOT_FOUND (404)

Réécrire les textes de post

POST/api/v1/videos/{id}/post-copyportée videos:write

Réécrit les textes (toutes les plateformes ou certaines), éventuellement dans une autre langue. Gratuit, limité à 60 appels IA par heure et par espace.

Paramètres

NomOùTypeDescription
idcheminuuidIdentifiant de la vidéorequis

Corps JSON

ChampTypeDescription
language"en" | "fr"Langue de la narration : en (anglais, par défaut) ou fr (français).
platformsenum[]Only these platforms (the others are kept)
Requête
curl -X POST https://motiongist.com/api/v1/videos/c4d5e6f7-1a2b-4c3d-8e9f-0a1b2c3d4e5f/post-copy \
  -H "X-API-Key: $MOTIONGIST_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
  "language": "en",
  "platforms": [
    "tiktok"
  ]
}'
Réponse 200
{
  "data": {
    "language": "en",
    "generatedAt": "2026-10-23T09:20:00.000Z",
    "platforms": {
      "youtube": {
        "title": "How a CDN works in 60 seconds #shorts",
        "description": "Your files, next to your visitors.\n\nFollow for more explainers.",
        "hashtags": [
          "cdn",
          "webdev",
          "shorts"
        ],
        "caption": "Your files, next to your visitors.\n\nFollow for more explainers.\n\n#cdn #webdev #shorts",
        "limits": {
          "title": 100,
          "caption": 5000,
          "hashtags": 15
        }
      }
    }
  },
  "requestId": "req_3f9a1c2e7b8d4a60"
}

Erreurs possibles : NOT_FOUND (404), RATE_LIMITED (429)

Modifier les textes de post

PATCH/api/v1/videos/{id}/post-copyportée videos:write

Remplace les plateformes fournies. Un texte au-delà de la limite d’une plateforme est refusé (VALIDATION_ERROR), jamais tronqué. Les hashtags sont donnés sans #.

Paramètres

NomOùTypeDescription
idcheminuuidIdentifiant de la vidéorequis

Corps JSON

ChampTypeDescription
language"en" | "fr"Langue de la narration : en (anglais, par défaut) ou fr (français).
platformsobjectrequis
platforms.youtubeobject
platforms.youtube.titlestringrequis
platforms.youtube.descriptionstringrequis
platforms.youtube.hashtagsstring[]requis
platforms.tiktokobject
platforms.tiktok.titlestringrequis
platforms.tiktok.descriptionstringrequis
platforms.tiktok.hashtagsstring[]requis
platforms.instagramobject
platforms.instagram.titlestringrequis
platforms.instagram.descriptionstringrequis
platforms.instagram.hashtagsstring[]requis
platforms.linkedinobject
platforms.linkedin.titlestringrequis
platforms.linkedin.descriptionstringrequis
platforms.linkedin.hashtagsstring[]requis
Requête
curl -X PATCH https://motiongist.com/api/v1/videos/c4d5e6f7-1a2b-4c3d-8e9f-0a1b2c3d4e5f/post-copy \
  -H "X-API-Key: $MOTIONGIST_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "platforms": {
    "tiktok": {
      "title": "How a CDN works",
      "description": "Your files, next to your visitors.",
      "hashtags": [
        "webdev",
        "cdn"
      ]
    }
  }
}'
Réponse 200
{
  "data": {
    "language": "en",
    "generatedAt": "2026-10-23T09:20:00.000Z",
    "platforms": {
      "youtube": {
        "title": "How a CDN works in 60 seconds #shorts",
        "description": "Your files, next to your visitors.\n\nFollow for more explainers.",
        "hashtags": [
          "cdn",
          "webdev",
          "shorts"
        ],
        "caption": "Your files, next to your visitors.\n\nFollow for more explainers.\n\n#cdn #webdev #shorts",
        "limits": {
          "title": 100,
          "caption": 5000,
          "hashtags": 15
        }
      }
    }
  },
  "requestId": "req_3f9a1c2e7b8d4a60"
}

Erreurs possibles : NOT_FOUND (404), VALIDATION_ERROR (400)

Lire la page de partage

GET/api/v1/videos/{id}/shareportée videos:read

Page de partage publique de la vidéo : lien (non répertorié, noindex), code d’intégration, bouton, téléchargement, badge et nombre de vues. enabled=false signifie pas de lien public.

Paramètres

NomOùTypeDescription
idcheminuuidIdentifiant de la vidéorequis
Requête
curl https://motiongist.com/api/v1/videos/c4d5e6f7-1a2b-4c3d-8e9f-0a1b2c3d4e5f/share \
  -H "X-API-Key: $MOTIONGIST_API_KEY"
Réponse 200
{
  "data": {
    "enabled": true,
    "token": "Xq3vR8kP2mWz7tLa",
    "url": "https://motiongist.com/v/Xq3vR8kP2mWz7tLa",
    "embedUrl": "https://motiongist.com/embed/Xq3vR8kP2mWz7tLa",
    "embedCode": "<iframe src=\"https://motiongist.com/embed/Xq3vR8kP2mWz7tLa\" …></iframe>",
    "cta": {
      "label": "Book a demo",
      "url": "https://example.com/demo"
    },
    "allowDownload": false,
    "showBranding": true,
    "brandingForced": false,
    "views": 128,
    "createdAt": "2026-10-23T09:25:00.000Z"
  },
  "requestId": "req_3f9a1c2e7b8d4a60"
}

Erreurs possibles : NOT_FOUND (404)

Modifier la page de partage

PATCH/api/v1/videos/{id}/shareportée videos:write

enabled=true crée le lien (conservé ensuite) ; enabled=false le révoque définitivement (le réactiver crée un nouveau lien). cta ajoute un bouton (URL http/https). Le plan gratuit affiche toujours le badge « Fait avec Motiongist ».

Paramètres

NomOùTypeDescription
idcheminuuidIdentifiant de la vidéorequis

Corps JSON

ChampTypeDescription
enabledbooleanrequis
ctaobjet (variantes)
allowDownloadboolean
showBrandingboolean
Requête
curl -X PATCH https://motiongist.com/api/v1/videos/c4d5e6f7-1a2b-4c3d-8e9f-0a1b2c3d4e5f/share \
  -H "X-API-Key: $MOTIONGIST_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "enabled": true,
  "cta": {
    "label": "Book a demo",
    "url": "https://example.com/demo"
  },
  "allowDownload": false
}'
Réponse 200
{
  "data": {
    "enabled": true,
    "token": "Xq3vR8kP2mWz7tLa",
    "url": "https://motiongist.com/v/Xq3vR8kP2mWz7tLa",
    "embedUrl": "https://motiongist.com/embed/Xq3vR8kP2mWz7tLa",
    "embedCode": "<iframe src=\"https://motiongist.com/embed/Xq3vR8kP2mWz7tLa\" …></iframe>",
    "cta": {
      "label": "Book a demo",
      "url": "https://example.com/demo"
    },
    "allowDownload": false,
    "showBranding": true,
    "brandingForced": false,
    "views": 128,
    "createdAt": "2026-10-23T09:25:00.000Z"
  },
  "requestId": "req_3f9a1c2e7b8d4a60"
}

Erreurs possibles : NOT_FOUND (404), VALIDATION_ERROR (400)

Lister les comptes connectés

GET/api/v1/social-accountsportée videos:read

Comptes YouTube, TikTok, Instagram et LinkedIn connectés par les membres dans l’app web (/app/publishing ; la connexion se fait dans un navigateur). platforms indique les plateformes disponibles sur ce serveur.

Requête
curl https://motiongist.com/api/v1/social-accounts \
  -H "X-API-Key: $MOTIONGIST_API_KEY"
Réponse 200
{
  "data": {
    "items": [
      {
        "id": "01970d2c-55aa-7c1e-9d0b-3e4f5a6b7c8d",
        "provider": "youtube",
        "name": "Motiongist Demo",
        "avatarUrl": null,
        "status": "active",
        "simulated": false,
        "connectedAt": "2026-10-20T14:02:00.000Z",
        "updatedAt": "2026-10-20T14:02:00.000Z"
      }
    ],
    "platforms": [
      {
        "id": "youtube",
        "available": true,
        "mode": "live"
      }
    ]
  },
  "requestId": "req_3f9a1c2e7b8d4a60"
}

Lister les publications

GET/api/v1/postsportée videos:read

Publications de l’espace, filtrées par date programmée (from, to), statut ou vidéo.

Paramètres

NomOùTypeDescription
fromquerydate-timeProgrammées à partir de (ISO 8601 avec fuseau)
toquerydate-timeProgrammées jusqu’à
statusquerystringscheduled, publishing, published, failed ou cancelled
videoIdqueryuuidSeulement les publications de cette vidéo
limitqueryintegerNombre d’éléments (1 à 500, 100 par défaut)
Requête
curl https://motiongist.com/api/v1/posts \
  -H "X-API-Key: $MOTIONGIST_API_KEY"
Réponse 200
{
  "data": {
    "items": [
      {
        "id": "01970d2c-77cc-7e3a-8f1b-5a6b7c8d9e0f",
        "videoId": "c4d5e6f7-1a2b-4c3d-8e9f-0a1b2c3d4e5f",
        "videoTitle": "How a CDN works",
        "projectId": "2b9e4d71-8c0a-4f3e-a6b5-1d2c3e4f5a6b",
        "accountId": "01970d2c-55aa-7c1e-9d0b-3e4f5a6b7c8d",
        "accountName": "Motiongist Demo",
        "provider": "youtube",
        "status": "scheduled",
        "scheduledAt": "2026-10-30T16:30:00.000Z",
        "publishedAt": null,
        "copy": {
          "title": "How a CDN works in 60 seconds #shorts",
          "description": "Your files, next to your visitors.\n\nFollow for more explainers.",
          "hashtags": [
            "cdn",
            "webdev",
            "shorts"
          ]
        },
        "caption": "Your files, next to your visitors.\n\nFollow for more explainers.\n\n#cdn #webdev #shorts",
        "options": {},
        "externalId": null,
        "externalUrl": null,
        "error": null,
        "attempts": 0,
        "createdAt": "2026-10-23T09:30:00.000Z"
      }
    ]
  },
  "requestId": "req_3f9a1c2e7b8d4a60"
}

Publier ou programmer

POST/api/v1/postsportée videos:write

Met une vidéo en file pour un compte connecté, maintenant (sans scheduledAt) ou à scheduledAt (jusqu’à 1 an à l’avance). Utilise les textes de post de la vidéo pour la plateforme, sauf si copy est fourni. Aucun crédit consommé. Le worker publie dans les secondes qui suivent, réessaie les erreurs temporaires (après 1 min, 5 min, 30 min) et émet post.published ou post.failed.

Corps JSON

ChampTypeDescription
videoIduuidrequis
accountIduuidrequis
scheduledAtobjet (variantes)
copyobject
copy.titlestringrequis
copy.descriptionstringrequis
copy.hashtagsstring[]requis
optionsobject
options.privacy"public" | "unlisted" | "private"
options.simulate"transient" | "permanent" | "auth"
Requête
curl -X POST https://motiongist.com/api/v1/posts \
  -H "X-API-Key: $MOTIONGIST_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
  "videoId": "c4d5e6f7-1a2b-4c3d-8e9f-0a1b2c3d4e5f",
  "accountId": "01970d2c-55aa-7c1e-9d0b-3e4f5a6b7c8d",
  "scheduledAt": "2026-10-30T17:30:00+01:00"
}'
Réponse 201
{
  "data": {
    "id": "01970d2c-77cc-7e3a-8f1b-5a6b7c8d9e0f",
    "videoId": "c4d5e6f7-1a2b-4c3d-8e9f-0a1b2c3d4e5f",
    "videoTitle": "How a CDN works",
    "projectId": "2b9e4d71-8c0a-4f3e-a6b5-1d2c3e4f5a6b",
    "accountId": "01970d2c-55aa-7c1e-9d0b-3e4f5a6b7c8d",
    "accountName": "Motiongist Demo",
    "provider": "youtube",
    "status": "scheduled",
    "scheduledAt": "2026-10-30T16:30:00.000Z",
    "publishedAt": null,
    "copy": {
      "title": "How a CDN works in 60 seconds #shorts",
      "description": "Your files, next to your visitors.\n\nFollow for more explainers.",
      "hashtags": [
        "cdn",
        "webdev",
        "shorts"
      ]
    },
    "caption": "Your files, next to your visitors.\n\nFollow for more explainers.\n\n#cdn #webdev #shorts",
    "options": {},
    "externalId": null,
    "externalUrl": null,
    "error": null,
    "attempts": 0,
    "createdAt": "2026-10-23T09:30:00.000Z"
  },
  "requestId": "req_3f9a1c2e7b8d4a60"
}

Erreurs possibles : NOT_FOUND (404), VALIDATION_ERROR (400)

Lire une publication

GET/api/v1/posts/{id}portée videos:read

Statut d’une publication ; externalUrl une fois publiée, error en cas d’échec.

Paramètres

NomOùTypeDescription
idcheminuuidIdentifiant de la publicationrequis
Requête
curl https://motiongist.com/api/v1/posts/01970d2c-77cc-7e3a-8f1b-5a6b7c8d9e0f \
  -H "X-API-Key: $MOTIONGIST_API_KEY"
Réponse 200
{
  "data": {
    "id": "01970d2c-77cc-7e3a-8f1b-5a6b7c8d9e0f",
    "videoId": "c4d5e6f7-1a2b-4c3d-8e9f-0a1b2c3d4e5f",
    "videoTitle": "How a CDN works",
    "projectId": "2b9e4d71-8c0a-4f3e-a6b5-1d2c3e4f5a6b",
    "accountId": "01970d2c-55aa-7c1e-9d0b-3e4f5a6b7c8d",
    "accountName": "Motiongist Demo",
    "provider": "youtube",
    "status": "published",
    "scheduledAt": "2026-10-30T16:30:00.000Z",
    "publishedAt": "2026-10-30T16:30:08.000Z",
    "copy": {
      "title": "How a CDN works in 60 seconds #shorts",
      "description": "Your files, next to your visitors.\n\nFollow for more explainers.",
      "hashtags": [
        "cdn",
        "webdev",
        "shorts"
      ]
    },
    "caption": "Your files, next to your visitors.\n\nFollow for more explainers.\n\n#cdn #webdev #shorts",
    "options": {},
    "externalId": "dQw4w9WgXcQ",
    "externalUrl": "https://www.youtube.com/shorts/dQw4w9WgXcQ",
    "error": null,
    "attempts": 0,
    "createdAt": "2026-10-23T09:30:00.000Z"
  },
  "requestId": "req_3f9a1c2e7b8d4a60"
}

Erreurs possibles : NOT_FOUND (404)

Reprogrammer une publication

PATCH/api/v1/posts/{id}portée videos:write

Déplace une publication programmée, ou remet en file une publication en échec ou annulée (tentatives remises à zéro).

Paramètres

NomOùTypeDescription
idcheminuuidIdentifiant de la publicationrequis

Corps JSON

ChampTypeDescription
scheduledAtobjet (variantes)New time (ISO 8601 with offset); null = nowrequis
Requête
curl -X PATCH https://motiongist.com/api/v1/posts/01970d2c-77cc-7e3a-8f1b-5a6b7c8d9e0f \
  -H "X-API-Key: $MOTIONGIST_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "scheduledAt": "2026-10-31T09:00:00+01:00"
}'
Réponse 200
{
  "data": {
    "id": "01970d2c-77cc-7e3a-8f1b-5a6b7c8d9e0f",
    "videoId": "c4d5e6f7-1a2b-4c3d-8e9f-0a1b2c3d4e5f",
    "videoTitle": "How a CDN works",
    "projectId": "2b9e4d71-8c0a-4f3e-a6b5-1d2c3e4f5a6b",
    "accountId": "01970d2c-55aa-7c1e-9d0b-3e4f5a6b7c8d",
    "accountName": "Motiongist Demo",
    "provider": "youtube",
    "status": "scheduled",
    "scheduledAt": "2026-10-30T16:30:00.000Z",
    "publishedAt": null,
    "copy": {
      "title": "How a CDN works in 60 seconds #shorts",
      "description": "Your files, next to your visitors.\n\nFollow for more explainers.",
      "hashtags": [
        "cdn",
        "webdev",
        "shorts"
      ]
    },
    "caption": "Your files, next to your visitors.\n\nFollow for more explainers.\n\n#cdn #webdev #shorts",
    "options": {},
    "externalId": null,
    "externalUrl": null,
    "error": null,
    "attempts": 0,
    "createdAt": "2026-10-23T09:30:00.000Z"
  },
  "requestId": "req_3f9a1c2e7b8d4a60"
}

Erreurs possibles : NOT_FOUND (404), CONFLICT (409), VALIDATION_ERROR (400)

Annuler une publication

DELETE/api/v1/posts/{id}portée videos:write

Annule une publication qui n’a pas commencé (CONFLICT sinon).

Paramètres

NomOùTypeDescription
idcheminuuidIdentifiant de la publicationrequis
Requête
curl -X DELETE https://motiongist.com/api/v1/posts/01970d2c-77cc-7e3a-8f1b-5a6b7c8d9e0f \
  -H "X-API-Key: $MOTIONGIST_API_KEY"
Réponse 200
{
  "data": {
    "id": "01970d2c-77cc-7e3a-8f1b-5a6b7c8d9e0f",
    "videoId": "c4d5e6f7-1a2b-4c3d-8e9f-0a1b2c3d4e5f",
    "videoTitle": "How a CDN works",
    "projectId": "2b9e4d71-8c0a-4f3e-a6b5-1d2c3e4f5a6b",
    "accountId": "01970d2c-55aa-7c1e-9d0b-3e4f5a6b7c8d",
    "accountName": "Motiongist Demo",
    "provider": "youtube",
    "status": "cancelled",
    "scheduledAt": "2026-10-30T16:30:00.000Z",
    "publishedAt": null,
    "copy": {
      "title": "How a CDN works in 60 seconds #shorts",
      "description": "Your files, next to your visitors.\n\nFollow for more explainers.",
      "hashtags": [
        "cdn",
        "webdev",
        "shorts"
      ]
    },
    "caption": "Your files, next to your visitors.\n\nFollow for more explainers.\n\n#cdn #webdev #shorts",
    "options": {},
    "externalId": null,
    "externalUrl": null,
    "error": null,
    "attempts": 0,
    "createdAt": "2026-10-23T09:30:00.000Z"
  },
  "requestId": "req_3f9a1c2e7b8d4a60"
}

Erreurs possibles : NOT_FOUND (404), CONFLICT (409)

Projets

Lister les projets

GET/api/v1/projectsportée jobs:read

Projets (brouillons du studio) de l’espace, triés par dernière modification.

Paramètres

NomOùTypeDescription
limitqueryintegerNombre d’éléments (1 à 100, 20 par défaut)
cursorquerystringCurseur renvoyé par nextCursor pour la page suivante
statusquerystringdraft, queued, generating, ready ou failed
qquerystringRecherche dans le titre
Requête
curl https://motiongist.com/api/v1/projects \
  -H "X-API-Key: $MOTIONGIST_API_KEY"
Réponse 200
{
  "data": {
    "items": [
      {
        "id": "2b9e4d71-8c0a-4f3e-a6b5-1d2c3e4f5a6b",
        "title": "How a CDN works",
        "status": "draft",
        "draft": {
          "subject": "How a CDN works",
          "inputKind": "script",
          "audience": "dev",
          "length": "standard",
          "language": "en",
          "voice": "George",
          "look": {
            "mode": "preset",
            "preset": "night"
          },
          "notes": {
            "mustShow": [],
            "avoid": []
          },
          "mascot": false,
          "tier": "standard",
          "format": "9:16",
          "captions": true,
          "music": true
        },
        "script": "Your site takes 3 seconds to load in Tokyo? The problem isn’t your server. It’s the distance…",
        "narration": null,
        "latestJobId": null,
        "latestVideoId": null,
        "source": "api",
        "createdAt": "2026-10-23T09:02:11.000Z",
        "updatedAt": "2026-10-23T09:04:37.000Z",
        "url": "https://motiongist.com/app/projects/2b9e4d71-8c0a-4f3e-a6b5-1d2c3e4f5a6b"
      }
    ],
    "nextCursor": "2026-10-23T09:12:04.000Z"
  },
  "requestId": "req_3f9a1c2e7b8d4a60"
}

Créer un projet

POST/api/v1/projectsportée jobs:write

Crée un brouillon, comme dans le studio : réglages, script, écoute de la voix, puis estimation et génération. Pratique pour un agent qui itère avec l’utilisateur avant de payer. Le projet apparaît aussi dans le studio web.

Corps JSON

ChampTypeDescription
titlestringTitre (120 caractères max). Par défaut : le sujet.
scriptstringTexte exact à narrer. Sans script, POST /projects/{id}/script en écrit un.
draftobjectRéglages du projet : sujet, public, durée, langue (en ou fr), voix, look, marque, notes…
draft.subjectstringSujet de la vidéo.
draft.inputKind"idea" | "script" | "url" | "document"idea, script, url ou document.
draft.sourceTextstringTexte source (document, page web) dont les faits doivent être utilisés.
draft.sourceNamestring
draft.sourceUrlstring
draft.audience"beginner" | "dev" | "ops" | "decision-maker"Public visé : beginner, dev, ops ou decision-maker.
draft.length"short" | "standard" | "full"Durée : short (45–60 s), standard (90–120 s) ou full (150–180 s).
draft.language"fr" | "en"Langue de la narration : en (anglais, par défaut) ou fr (français).
draft.voicestringVoix du narrateur (voir GET /catalog) : George, Sarah, Daniel, Brian, Lily, Alice, Will, Matilda. Toutes les voix parlent les deux langues.
draft.lookobjet (variantes)Style visuel : { mode: "preset", preset: "clean" | "night" | "toon" }, { mode: "brand" } (couleurs de la marque, champ brand requis) ou { mode: "custom", description } (plan Studio).
draft.brandobjectMarque affichée : name (24 car.), site, colors (1 à 3 couleurs #RRGGBB), logo (« asset:<id> » renvoyé par POST /assets).
draft.brand.namestringNom de la marque (24 caractères max).requis
draft.brand.sitestringSite affiché en fin de vidéo (40 caractères max).
draft.brand.colorsstring[]1 à 3 couleurs hexadécimales #RRGGBB.requis
draft.brand.logostringLogo : « asset:<id> » renvoyé par POST /assets.
draft.notesobjectConsignes : mustShow (10 éléments à montrer max), avoid (à éviter), keyMoment, free (texte libre).
draft.notes.mustShowstring[]Éléments à montrer absolument (10 max, 80 car. chacun).
draft.notes.avoidstring[]Éléments à éviter (10 max).
draft.notes.keyMomentstringLe moment clé à mettre en valeur.
draft.notes.freestringConsignes libres (1 000 caractères max).
draft.mascotbooleanAjoute un présentateur animé.
draft.tier"standard" | "studio"standard, ou studio (qualité supérieure, +300 crédits, plan Studio).
draft.dimension"2d" | "3d"2d (motion design à plat, par défaut) ou 3d (perspective, volume, profondeur et mouvements de caméra).
draft.format"9:16" | "16:9"Format : 9:16 (vertical) ou 16:9.
draft.captionsbooleanSous-titres incrustés.
draft.musicbooleanMusique de fond.
Requête
curl -X POST https://motiongist.com/api/v1/projects \
  -H "X-API-Key: $MOTIONGIST_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
  "draft": {
    "subject": "How a CDN works",
    "length": "standard",
    "language": "en",
    "voice": "George",
    "look": {
      "mode": "preset",
      "preset": "night"
    }
  }
}'
Réponse 201
{
  "data": {
    "id": "2b9e4d71-8c0a-4f3e-a6b5-1d2c3e4f5a6b",
    "title": "How a CDN works",
    "status": "draft",
    "draft": {
      "subject": "How a CDN works",
      "inputKind": "script",
      "audience": "dev",
      "length": "standard",
      "language": "en",
      "voice": "George",
      "look": {
        "mode": "preset",
        "preset": "night"
      },
      "notes": {
        "mustShow": [],
        "avoid": []
      },
      "mascot": false,
      "tier": "standard",
      "format": "9:16",
      "captions": true,
      "music": true
    },
    "script": "Your site takes 3 seconds to load in Tokyo? The problem isn’t your server. It’s the distance…",
    "narration": null,
    "latestJobId": null,
    "latestVideoId": null,
    "source": "api",
    "createdAt": "2026-10-23T09:02:11.000Z",
    "updatedAt": "2026-10-23T09:04:37.000Z",
    "url": "https://motiongist.com/app/projects/2b9e4d71-8c0a-4f3e-a6b5-1d2c3e4f5a6b"
  },
  "requestId": "req_3f9a1c2e7b8d4a60"
}

Erreurs possibles : VALIDATION_ERROR (400)

Lire un projet

GET/api/v1/projects/{id}portée jobs:read

Réglages, script, aperçu de narration, dernière génération et dernière vidéo du projet.

Paramètres

NomOùTypeDescription
idcheminuuidIdentifiant du projetrequis
Requête
curl https://motiongist.com/api/v1/projects/2b9e4d71-8c0a-4f3e-a6b5-1d2c3e4f5a6b \
  -H "X-API-Key: $MOTIONGIST_API_KEY"
Réponse 200
{
  "data": {
    "id": "2b9e4d71-8c0a-4f3e-a6b5-1d2c3e4f5a6b",
    "title": "How a CDN works",
    "status": "draft",
    "draft": {
      "subject": "How a CDN works",
      "inputKind": "script",
      "audience": "dev",
      "length": "standard",
      "language": "en",
      "voice": "George",
      "look": {
        "mode": "preset",
        "preset": "night"
      },
      "notes": {
        "mustShow": [],
        "avoid": []
      },
      "mascot": false,
      "tier": "standard",
      "format": "9:16",
      "captions": true,
      "music": true
    },
    "script": "Your site takes 3 seconds to load in Tokyo? The problem isn’t your server. It’s the distance…",
    "narration": null,
    "latestJobId": null,
    "latestVideoId": null,
    "source": "api",
    "createdAt": "2026-10-23T09:02:11.000Z",
    "updatedAt": "2026-10-23T09:04:37.000Z",
    "url": "https://motiongist.com/app/projects/2b9e4d71-8c0a-4f3e-a6b5-1d2c3e4f5a6b"
  },
  "requestId": "req_3f9a1c2e7b8d4a60"
}

Erreurs possibles : NOT_FOUND (404)

Modifier un projet

PATCH/api/v1/projects/{id}portée jobs:write

Modifie le titre, le script (null pour l’effacer) ou une partie des réglages (fusionnés avec l’existant). Toute modification invalide le devis précédent.

Paramètres

NomOùTypeDescription
idcheminuuidIdentifiant du projetrequis

Corps JSON

ChampTypeDescription
titlestringTitre (120 caractères max). Par défaut : le sujet.
scriptobjet (variantes)Texte exact à narrer. Sans script, POST /projects/{id}/script en écrit un.
draftobjectRéglages du projet : sujet, public, durée, langue (en ou fr), voix, look, marque, notes…
draft.subjectstringSujet de la vidéo.
draft.inputKind"idea" | "script" | "url" | "document"idea, script, url ou document.
draft.sourceTextstringTexte source (document, page web) dont les faits doivent être utilisés.
draft.sourceNamestring
draft.sourceUrlstring
draft.audience"beginner" | "dev" | "ops" | "decision-maker"Public visé : beginner, dev, ops ou decision-maker.
draft.length"short" | "standard" | "full"Durée : short (45–60 s), standard (90–120 s) ou full (150–180 s).
draft.language"fr" | "en"Langue de la narration : en (anglais, par défaut) ou fr (français).
draft.voicestringVoix du narrateur (voir GET /catalog) : George, Sarah, Daniel, Brian, Lily, Alice, Will, Matilda. Toutes les voix parlent les deux langues.
draft.lookobjet (variantes)Style visuel : { mode: "preset", preset: "clean" | "night" | "toon" }, { mode: "brand" } (couleurs de la marque, champ brand requis) ou { mode: "custom", description } (plan Studio).
draft.brandobjectMarque affichée : name (24 car.), site, colors (1 à 3 couleurs #RRGGBB), logo (« asset:<id> » renvoyé par POST /assets).
draft.brand.namestringNom de la marque (24 caractères max).requis
draft.brand.sitestringSite affiché en fin de vidéo (40 caractères max).
draft.brand.colorsstring[]1 à 3 couleurs hexadécimales #RRGGBB.requis
draft.brand.logostringLogo : « asset:<id> » renvoyé par POST /assets.
draft.notesobjectConsignes : mustShow (10 éléments à montrer max), avoid (à éviter), keyMoment, free (texte libre).
draft.notes.mustShowstring[]Éléments à montrer absolument (10 max, 80 car. chacun).
draft.notes.avoidstring[]Éléments à éviter (10 max).
draft.notes.keyMomentstringLe moment clé à mettre en valeur.
draft.notes.freestringConsignes libres (1 000 caractères max).
draft.mascotbooleanAjoute un présentateur animé.
draft.tier"standard" | "studio"standard, ou studio (qualité supérieure, +300 crédits, plan Studio).
draft.dimension"2d" | "3d"2d (motion design à plat, par défaut) ou 3d (perspective, volume, profondeur et mouvements de caméra).
draft.format"9:16" | "16:9"Format : 9:16 (vertical) ou 16:9.
draft.captionsbooleanSous-titres incrustés.
draft.musicbooleanMusique de fond.
Requête
curl -X PATCH https://motiongist.com/api/v1/projects/2b9e4d71-8c0a-4f3e-a6b5-1d2c3e4f5a6b \
  -H "X-API-Key: $MOTIONGIST_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "draft": {
    "voice": "Sarah",
    "length": "short"
  }
}'
Réponse 200
{
  "data": {
    "id": "2b9e4d71-8c0a-4f3e-a6b5-1d2c3e4f5a6b",
    "title": "How a CDN works",
    "status": "draft",
    "draft": {
      "subject": "How a CDN works",
      "inputKind": "script",
      "audience": "dev",
      "length": "standard",
      "language": "en",
      "voice": "George",
      "look": {
        "mode": "preset",
        "preset": "night"
      },
      "notes": {
        "mustShow": [],
        "avoid": []
      },
      "mascot": false,
      "tier": "standard",
      "format": "9:16",
      "captions": true,
      "music": true
    },
    "script": "Your site takes 3 seconds to load in Tokyo? The problem isn’t your server. It’s the distance…",
    "narration": null,
    "latestJobId": null,
    "latestVideoId": null,
    "source": "api",
    "createdAt": "2026-10-23T09:02:11.000Z",
    "updatedAt": "2026-10-23T09:04:37.000Z",
    "url": "https://motiongist.com/app/projects/2b9e4d71-8c0a-4f3e-a6b5-1d2c3e4f5a6b"
  },
  "requestId": "req_3f9a1c2e7b8d4a60"
}

Erreurs possibles : NOT_FOUND (404), VALIDATION_ERROR (400)

Supprimer un projet

DELETE/api/v1/projects/{id}portée jobs:write

Supprime le projet et ses vidéos. Refusé (409) si une génération est en cours.

Paramètres

NomOùTypeDescription
idcheminuuidIdentifiant du projetrequis
Requête
curl -X DELETE https://motiongist.com/api/v1/projects/2b9e4d71-8c0a-4f3e-a6b5-1d2c3e4f5a6b \
  -H "X-API-Key: $MOTIONGIST_API_KEY"
Réponse 200
{
  "data": {
    "id": "2b9e4d71-8c0a-4f3e-a6b5-1d2c3e4f5a6b",
    "deleted": true
  },
  "requestId": "req_3f9a1c2e7b8d4a60"
}

Erreurs possibles : NOT_FOUND (404), CONFLICT (409)

Écrire le script

POST/api/v1/projects/{id}/scriptportée jobs:write

Écrit un script narré (accroche, une idée par phrase, récap) à partir du sujet du projet ou du document source, dans la langue du projet, et l’enregistre dans le projet. Gratuit, limité à 60 appels IA par heure et par espace.

Paramètres

NomOùTypeDescription
idcheminuuidIdentifiant du projetrequis

Corps JSON

ChampTypeDescription
topicstringSujet à traiter (3 à 500 caractères ; pour /projects/{id}/script, le sujet du projet par défaut).
tonestringTon souhaité, ex. « drôle et direct » (120 caractères max).
Requête
curl -X POST https://motiongist.com/api/v1/projects/2b9e4d71-8c0a-4f3e-a6b5-1d2c3e4f5a6b/script \
  -H "X-API-Key: $MOTIONGIST_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
  "tone": "direct, with a touch of humor"
}'
Réponse 200
{
  "data": {
    "title": "How a CDN works",
    "script": "Your site takes 3 seconds to load in Tokyo? The problem isn’t your server. It’s the distance…",
    "words": 246,
    "seconds": 100,
    "source": "llm",
    "project": {
      "id": "2b9e4d71-8c0a-4f3e-a6b5-1d2c3e4f5a6b",
      "title": "How a CDN works",
      "status": "draft",
      "draft": {
        "subject": "How a CDN works",
        "inputKind": "script",
        "audience": "dev",
        "length": "standard",
        "language": "en",
        "voice": "George",
        "look": {
          "mode": "preset",
          "preset": "night"
        },
        "notes": {
          "mustShow": [],
          "avoid": []
        },
        "mascot": false,
        "tier": "standard",
        "format": "9:16",
        "captions": true,
        "music": true
      },
      "script": "Your site takes 3 seconds to load in Tokyo? The problem isn’t your server. It’s the distance…",
      "narration": null,
      "latestJobId": null,
      "latestVideoId": null,
      "source": "api",
      "createdAt": "2026-10-23T09:02:11.000Z",
      "updatedAt": "2026-10-23T09:04:37.000Z",
      "url": "https://motiongist.com/app/projects/2b9e4d71-8c0a-4f3e-a6b5-1d2c3e4f5a6b"
    }
  },
  "requestId": "req_3f9a1c2e7b8d4a60"
}

Erreurs possibles : NOT_FOUND (404), VALIDATION_ERROR (400), RATE_LIMITED (429)

Écouter la narration

POST/api/v1/projects/{id}/narrationportée jobs:write

Synthétise le script avec la voix choisie pour l’écouter avant de générer. Gratuit, mis en cache tant que le texte et la voix ne changent pas. Renvoie une URL audio valable 15 minutes.

Paramètres

NomOùTypeDescription
idcheminuuidIdentifiant du projetrequis
Requête
curl -X POST https://motiongist.com/api/v1/projects/2b9e4d71-8c0a-4f3e-a6b5-1d2c3e4f5a6b/narration \
  -H "X-API-Key: $MOTIONGIST_API_KEY"
Réponse 200
{
  "data": {
    "narration": {
      "assetId": "5e6f7a8b-9c0d-4e1f-a2b3-c4d5e6f7a8b9",
      "voice": "George",
      "provider": "edge",
      "seconds": 98.4,
      "words": 246
    },
    "audioUrl": "https://motiongist.com/api/files/narrations/…"
  },
  "requestId": "req_3f9a1c2e7b8d4a60"
}

Erreurs possibles : NOT_FOUND (404), VALIDATION_ERROR (400), RATE_LIMITED (429)

Lire le storyboard

GET/api/v1/projects/{id}/storyboardportée jobs:read

Le plan scène par scène du projet : statut (none, planning, ready, failed) et scènes (id, stage, narration, intent). Après un rendu, c’est le storyboard de la dernière vidéo ; dirty liste les scènes que le prochain rendu reconstruit.

Paramètres

NomOùTypeDescription
idcheminuuidIdentifiant du projetrequis
Requête
curl https://motiongist.com/api/v1/projects/2b9e4d71-8c0a-4f3e-a6b5-1d2c3e4f5a6b/storyboard \
  -H "X-API-Key: $MOTIONGIST_API_KEY"
Réponse 200
{
  "data": {
    "supported": true,
    "status": "ready",
    "source": "engine",
    "basedOnVideoId": null,
    "dirty": [],
    "planJob": null,
    "error": null,
    "updatedAt": "2026-10-23T09:14:00.000Z",
    "plan": {
      "title": "How a CDN works",
      "look": "night",
      "presenter": false,
      "scenes": [
        {
          "id": "s1",
          "stage": "hero",
          "narration": "Your site lives on one server. Your visitors live everywhere.",
          "intent": "A single server in Virginia, dots of visitors light up around the globe."
        },
        {
          "id": "s2",
          "stage": "graph",
          "narration": "A CDN keeps copies of it close to every visitor.",
          "intent": "Edge servers pop up on each continent on “copies”, lines shorten on “close”."
        },
        {
          "id": "s3",
          "stage": "split",
          "narration": "Pages load faster, and your server breathes.",
          "intent": "Left: stopwatch 800 → 40 ms. Right: CPU gauge drops."
        }
      ]
    }
  },
  "requestId": "req_3f9a1c2e7b8d4a60"
}

Erreurs possibles : NOT_FOUND (404)

Écrire le storyboard

POST/api/v1/projects/{id}/storyboardportée jobs:write

Optionnel et gratuit : le moteur planifie la vidéo scène par scène en une minute environ, pour la relire avant de payer un rendu. Interroge GET jusqu’au statut ready. Le rendu suit ensuite le storyboard à la lettre.

Paramètres

NomOùTypeDescription
idcheminuuidIdentifiant du projetrequis
Requête
curl -X POST https://motiongist.com/api/v1/projects/2b9e4d71-8c0a-4f3e-a6b5-1d2c3e4f5a6b/storyboard \
  -H "X-API-Key: $MOTIONGIST_API_KEY"
Réponse 202
{
  "data": {
    "jobId": "7f3c2a10-5b1e-4c8a-9d2f-0e6b4a1c9d55",
    "reused": false,
    "storyboard": {
      "supported": true,
      "status": "planning",
      "source": "engine",
      "basedOnVideoId": null,
      "dirty": [],
      "planJob": null,
      "error": null,
      "updatedAt": "2026-10-23T09:14:00.000Z",
      "plan": null
    }
  },
  "requestId": "req_3f9a1c2e7b8d4a60"
}

Erreurs possibles : NOT_FOUND (404), CONFLICT (409), RATE_LIMITED (429)

Modifier le storyboard

PATCH/api/v1/projects/{id}/storyboardportée jobs:write

Remplace la liste ordonnée des scènes (3 à 24). Garde l’id des scènes existantes, omets-le pour les nouvelles. Les scènes modifiées sont reconstruites au prochain rendu ; les scènes intactes d’une vidéo rendue gardent leurs visuels. Refais une estimation ensuite.

Paramètres

NomOùTypeDescription
idcheminuuidIdentifiant du projetrequis

Corps JSON

ChampTypeDescription
titlestringTitre (120 caractères max). Par défaut : le sujet.
scenesobject[]requis
Requête
curl -X PATCH https://motiongist.com/api/v1/projects/2b9e4d71-8c0a-4f3e-a6b5-1d2c3e4f5a6b/storyboard \
  -H "X-API-Key: $MOTIONGIST_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "scenes": [
    {
      "id": "s1",
      "narration": "A CDN keeps copies of your site close to every visitor.",
      "intent": "World map, servers light up on “close”."
    },
    {
      "narration": "New scene without id.",
      "intent": "Stopwatch drops from 800 to 40 ms."
    },
    {
      "id": "s3",
      "narration": "Faster pages, lighter servers.",
      "intent": "Two gauges move in opposite directions."
    }
  ]
}'
Réponse 200
{
  "data": {
    "supported": true,
    "status": "ready",
    "source": "engine",
    "basedOnVideoId": null,
    "dirty": [],
    "planJob": null,
    "error": null,
    "updatedAt": "2026-10-23T09:14:00.000Z",
    "plan": {
      "title": "How a CDN works",
      "look": "night",
      "presenter": false,
      "scenes": [
        {
          "id": "s1",
          "stage": "hero",
          "narration": "Your site lives on one server. Your visitors live everywhere.",
          "intent": "A single server in Virginia, dots of visitors light up around the globe."
        },
        {
          "id": "s2",
          "stage": "graph",
          "narration": "A CDN keeps copies of it close to every visitor.",
          "intent": "Edge servers pop up on each continent on “copies”, lines shorten on “close”."
        },
        {
          "id": "s3",
          "stage": "split",
          "narration": "Pages load faster, and your server breathes.",
          "intent": "Left: stopwatch 800 → 40 ms. Right: CPU gauge drops."
        }
      ]
    }
  },
  "requestId": "req_3f9a1c2e7b8d4a60"
}

Erreurs possibles : NOT_FOUND (404), CONFLICT (409), VALIDATION_ERROR (400)

Reconstruire des scènes

POST/api/v1/projects/{id}/storyboard/regenerateportée jobs:write

Marque des scènes à reconstruire au prochain rendu même si leur texte n’a pas changé (nouvelle proposition de visuels). Les autres scènes sont réutilisées telles quelles.

Paramètres

NomOùTypeDescription
idcheminuuidIdentifiant du projetrequis

Corps JSON

ChampTypeDescription
sceneIdsstring[]requis
Requête
curl -X POST https://motiongist.com/api/v1/projects/2b9e4d71-8c0a-4f3e-a6b5-1d2c3e4f5a6b/storyboard/regenerate \
  -H "X-API-Key: $MOTIONGIST_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
  "sceneIds": [
    "s2"
  ]
}'
Réponse 200
{
  "data": {
    "supported": true,
    "status": "ready",
    "source": "engine",
    "basedOnVideoId": null,
    "dirty": [
      "s2"
    ],
    "planJob": null,
    "error": null,
    "updatedAt": "2026-10-23T09:14:00.000Z",
    "plan": {
      "title": "How a CDN works",
      "look": "night",
      "presenter": false,
      "scenes": [
        {
          "id": "s1",
          "stage": "hero",
          "narration": "Your site lives on one server. Your visitors live everywhere.",
          "intent": "A single server in Virginia, dots of visitors light up around the globe."
        },
        {
          "id": "s2",
          "stage": "graph",
          "narration": "A CDN keeps copies of it close to every visitor.",
          "intent": "Edge servers pop up on each continent on “copies”, lines shorten on “close”."
        },
        {
          "id": "s3",
          "stage": "split",
          "narration": "Pages load faster, and your server breathes.",
          "intent": "Left: stopwatch 800 → 40 ms. Right: CPU gauge drops."
        }
      ]
    }
  },
  "requestId": "req_3f9a1c2e7b8d4a60"
}

Erreurs possibles : NOT_FOUND (404), CONFLICT (409), VALIDATION_ERROR (400)

Retirer le storyboard

DELETE/api/v1/projects/{id}/storyboardportée jobs:write

Retire le storyboard : le moteur planifie lui-même les scènes pendant le prochain rendu.

Paramètres

NomOùTypeDescription
idcheminuuidIdentifiant du projetrequis
Requête
curl -X DELETE https://motiongist.com/api/v1/projects/2b9e4d71-8c0a-4f3e-a6b5-1d2c3e4f5a6b/storyboard \
  -H "X-API-Key: $MOTIONGIST_API_KEY"
Réponse 200
{
  "data": {
    "supported": true,
    "status": "none",
    "source": "engine",
    "basedOnVideoId": null,
    "dirty": [],
    "planJob": null,
    "error": null,
    "updatedAt": "2026-10-23T09:14:00.000Z",
    "plan": null
  },
  "requestId": "req_3f9a1c2e7b8d4a60"
}

Erreurs possibles : NOT_FOUND (404)

Estimer un projet

POST/api/v1/projects/{id}/estimateportée jobs:read

Prix exact en crédits pour l’état actuel du projet et devis signé valable 1 heure. Une nouvelle version d’un projet déjà généré est facturée comme une révision (50 % du prix de base).

Paramètres

NomOùTypeDescription
idcheminuuidIdentifiant du projetrequis

Corps JSON

ChampTypeDescription
voiceMode"draft" | "final"final = voix sous licence (plans payants), draft = voix de brouillon gratuite. Par défaut : final sur les plans payants.
Requête
curl -X POST https://motiongist.com/api/v1/projects/2b9e4d71-8c0a-4f3e-a6b5-1d2c3e4f5a6b/estimate \
  -H "X-API-Key: $MOTIONGIST_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
  "voiceMode": "final"
}'
Réponse 200
{
  "data": {
    "total": 847,
    "lines": [
      {
        "label": "Standard video (90–120 s)",
        "credits": 700
      },
      {
        "label": "Final voice (1,470 characters)",
        "credits": 147
      }
    ],
    "quote": "eyJ3cyI6IjQ…(signed quote, pass it back unchanged)…",
    "quoteExpiresAt": "2026-10-23T10:12:00.000Z",
    "voiceMode": "final",
    "isRevision": false,
    "balance": 29153,
    "allowed": true,
    "blockers": [],
    "overdraft": false,
    "eta": {
      "minutesMin": 4,
      "minutesMax": 8
    }
  },
  "requestId": "req_3f9a1c2e7b8d4a60"
}

Erreurs possibles : NOT_FOUND (404), VALIDATION_ERROR (400)

Générer un projet

POST/api/v1/projects/{id}/generateportée jobs:write

Lance la génération au prix du devis. Le devis est obligatoire : s’il a expiré ou si le projet a changé depuis l’estimation, la réponse est QUOTE_INVALID et il faut ré-estimer.

Paramètres

NomOùTypeDescription
idcheminuuidIdentifiant du projetrequis

Corps JSON

ChampTypeDescription
quotestringDevis signé renvoyé par l’endpoint d’estimation (valable 1 h). Garantit le prix ; sans devis sur POST /jobs, le serveur recalcule le prix.requis
Requête
curl -X POST https://motiongist.com/api/v1/projects/2b9e4d71-8c0a-4f3e-a6b5-1d2c3e4f5a6b/generate \
  -H "X-API-Key: $MOTIONGIST_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
  "quote": "eyJ3cyI6IjQ…(signed quote, pass it back unchanged)…"
}'
Réponse 202
{
  "data": {
    "job": {
      "id": "7f3c2a10-5b1e-4c8a-9d2f-0e6b4a1c9d55",
      "projectId": "2b9e4d71-8c0a-4f3e-a6b5-1d2c3e4f5a6b",
      "status": "queued",
      "stage": "storyboard",
      "stageLabel": "Storyboard",
      "progress": 0,
      "detail": "Scene 4/9",
      "stages": {},
      "voiceMode": "final",
      "isRevision": false,
      "credits": 847,
      "queuePosition": 0,
      "cancellable": true,
      "error": null,
      "videoId": null,
      "attempt": 1,
      "source": "api",
      "queuedAt": "2026-10-23T09:12:04.000Z",
      "startedAt": "2026-10-23T09:12:09.000Z",
      "finishedAt": null
    },
    "projectId": "2b9e4d71-8c0a-4f3e-a6b5-1d2c3e4f5a6b",
    "queuePosition": 1
  },
  "requestId": "req_3f9a1c2e7b8d4a60"
}

Erreurs possibles : NOT_FOUND (404), QUOTE_INVALID (400), INSUFFICIENT_CREDITS (402), PLAN_REQUIRED (403)

Fichiers

Envoyer un fichier

POST/api/v1/assetsportée assets:write

Envoi multipart/form-data (champ file). Logo PNG, SVG, JPEG ou WebP jusqu’à 2 Mo : utilise ref (« asset:<id> ») dans brand.logo. Document PDF, DOCX, TXT ou MD jusqu’à 20 Mo : le texte extrait (40 000 caractères max) est renvoyé, à passer dans brief.input (kind document) ou draft.sourceText. Le type est détecté sur le contenu, pas sur l’extension.

Corps (multipart/form-data)

ChampTypeDescription
filefichierLe fichier à envoyer. requis
kind"logo" | "document"Facultatif : refuse le fichier s’il ne correspond pas au type attendu.
Requête
curl -X POST https://motiongist.com/api/v1/assets \
  -H "X-API-Key: $MOTIONGIST_API_KEY" \
  -F "file=@whitepaper.pdf" \
  -F "kind=document"
Réponse 201
{
  "data": {
    "id": "5e6f7a8b-9c0d-4e1f-a2b3-c4d5e6f7a8b9",
    "ref": "asset:5e6f7a8b-9c0d-4e1f-a2b3-c4d5e6f7a8b9",
    "kind": "document",
    "name": "whitepaper.pdf",
    "mime": "application/pdf",
    "bytes": 482113,
    "sha256": "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08",
    "createdAt": "2026-10-23T09:00:00.000Z",
    "url": "https://motiongist.com/api/files/assets/…",
    "text": "Whitepaper — CDNs in 2026…",
    "textLength": 18342,
    "truncated": false,
    "title": "whitepaper"
  },
  "requestId": "req_3f9a1c2e7b8d4a60"
}

Erreurs possibles : VALIDATION_ERROR (400), PAYLOAD_TOO_LARGE (413), UNSUPPORTED_MEDIA_TYPE (415), RATE_LIMITED (429)

Webhooks

Lister les webhooks

GET/api/v1/webhooksportée webhooks:write

Webhooks de l’espace avec le statut de la dernière livraison. Le secret n’est montré qu’à la création.

Requête
curl https://motiongist.com/api/v1/webhooks \
  -H "X-API-Key: $MOTIONGIST_API_KEY"
Réponse 200
{
  "data": [
    {
      "id": "9a8b7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d",
      "url": "https://example.com/hooks/motiongist",
      "events": [
        "job.succeeded",
        "job.failed"
      ],
      "active": true,
      "lastStatus": null,
      "lastDeliveredAt": null,
      "createdAt": "2026-10-23T08:55:00.000Z",
      "secretPreview": "whsec_k3Jd…"
    }
  ],
  "requestId": "req_3f9a1c2e7b8d4a60"
}

Créer un webhook

POST/api/v1/webhooksportée webhooks:write

Enregistre une URL qui recevra les événements choisis. La réponse contient le secret de signature (whsec_…), affiché une seule fois.

Corps JSON

ChampTypeDescription
urlstringURL HTTPS publique qui recevra les événements (POST JSON signé).requis
eventsenum[]Événements souscrits : job.started, job.progress, job.succeeded, job.failed, job.cancelled, video.deleted, post.published, post.failed. Tous par défaut.
Requête
curl -X POST https://motiongist.com/api/v1/webhooks \
  -H "X-API-Key: $MOTIONGIST_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
  "url": "https://example.com/hooks/motiongist",
  "events": [
    "job.succeeded",
    "job.failed"
  ]
}'
Réponse 201
{
  "data": {
    "id": "9a8b7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d",
    "url": "https://example.com/hooks/motiongist",
    "events": [
      "job.succeeded",
      "job.failed"
    ],
    "active": true,
    "lastStatus": null,
    "lastDeliveredAt": null,
    "createdAt": "2026-10-23T08:55:00.000Z",
    "secret": "whsec_k3JdQ9…"
  },
  "requestId": "req_3f9a1c2e7b8d4a60"
}

Erreurs possibles : VALIDATION_ERROR (400)

Supprimer un webhook

DELETE/api/v1/webhooks/{id}portée webhooks:write

Supprime le webhook ; les livraisons en attente sont abandonnées.

Paramètres

NomOùTypeDescription
idcheminuuidIdentifiant du webhookrequis
Requête
curl -X DELETE https://motiongist.com/api/v1/webhooks/9a8b7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d \
  -H "X-API-Key: $MOTIONGIST_API_KEY"
Réponse 200
{
  "data": {
    "id": "9a8b7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d",
    "deleted": true
  },
  "requestId": "req_3f9a1c2e7b8d4a60"
}

Erreurs possibles : NOT_FOUND (404)

Scripts et idées

Écrire un script

POST/api/v1/scripts/generateportée jobs:write

Écrit un script narré pour une vidéo verticale, en anglais (par défaut) ou en français (language), sans créer de projet. Passe-le ensuite dans brief.input ({kind: "script", text}). Gratuit, limité à 60 appels IA par heure et par espace.

Corps JSON

ChampTypeDescription
topicstringSujet à traiter (3 à 500 caractères ; pour /projects/{id}/script, le sujet du projet par défaut).requis
audience"beginner" | "dev" | "ops" | "decision-maker"Public visé : beginner, dev, ops ou decision-maker.
length"short" | "standard" | "full"Durée : short (45–60 s), standard (90–120 s) ou full (150–180 s).
language"fr" | "en"Langue de la narration : en (anglais, par défaut) ou fr (français).
tonestringTon souhaité, ex. « drôle et direct » (120 caractères max).
sourcestringTexte source dont les faits doivent être respectés.
Requête
curl -X POST https://motiongist.com/api/v1/scripts/generate \
  -H "X-API-Key: $MOTIONGIST_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
  "topic": "How a CDN works",
  "audience": "dev",
  "length": "standard",
  "language": "en"
}'
Réponse 200
{
  "data": {
    "title": "How a CDN works",
    "script": "Your site takes 3 seconds to load in Tokyo? The problem isn’t your server. It’s the distance…",
    "words": 246,
    "seconds": 100,
    "source": "llm"
  },
  "requestId": "req_3f9a1c2e7b8d4a60"
}

Erreurs possibles : VALIDATION_ERROR (400), RATE_LIMITED (429)

Idées de vidéos

POST/api/v1/scripts/ideasportée jobs:write

Propose des idées de vidéos (titre accrocheur et angle visuel) pour une niche. Gratuit, limité à 60 appels IA par heure et par espace.

Corps JSON

ChampTypeDescription
nichestringThème ou niche (2 à 200 caractères).requis
language"fr" | "en"Langue de la narration : en (anglais, par défaut) ou fr (français).
countintegerNombre d’idées (1 à 12, 8 par défaut).
Requête
curl -X POST https://motiongist.com/api/v1/scripts/ideas \
  -H "X-API-Key: $MOTIONGIST_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
  "niche": "cybersecurity for small businesses",
  "language": "en",
  "count": 3
}'
Réponse 200
{
  "data": {
    "ideas": [
      {
        "title": "Your password lasts 3 seconds",
        "angle": "A stopwatch cracking longer and longer passwords"
      }
    ]
  },
  "requestId": "req_3f9a1c2e7b8d4a60"
}

Erreurs possibles : VALIDATION_ERROR (400), RATE_LIMITED (429)