Documentationde la clé au premier clip
Tout ce qu’il faut pour une première génération : une clé, une requête, la tâche et le webhook.
L’accès à l’API développeur se fait sur demande.
Présentation
REST sur HTTPS, JSON en entrée et en sortie. Chaque génération est asynchrone.
- URL de base
https://api.pershot.app/v1- Authentification
- Authorization: Bearer suivi de votre clé. Les clés commencent par sk_test_ ou sk_live_ et ne sont affichées qu’une fois ; nous n’en stockons qu’un hachage.
- Permissions des clés
- Chaque clé a des permissions et, si vous en définissez une dans le studio, une liste autorisée de modèles et d’outils. Une clé avec une liste autorisée ne peut utiliser que ce qui y figure, outils compris : agrandissement d’image, suppression d’arrière-plan, Améliorer, synchronisation labiale, extension d’image et retouche d’image. Tout le reste répond 403 forbidden_model. Le 1080p ou la 4K avec Améliorer nécessite à la fois le modèle vidéo et Améliorer.
- Format des erreurs
{ "error": { "code", "message", "param", "request_id" } }- Identifiants
- Préfixés par type : job_, qt_, key_, up_.
- OpenAPI
- /api/v1/openapi.json
- Pour les agents IA
- Texte brut pour les agents IA : entrées, valeurs admises, chaque prix et un exemple de requête
seedance-2.0-fastseedance-2.0-miniqwen-image-2512-lightningqwen-image-2512qwen-image-edit-2511-lightningqwen-image-edit-2511
Les vraies générations ne sont pas encore ouvertes. Laissez votre e-mail sur la page d’un modèle et nous vous écrirons une seule fois, à leur ouverture.
Démarrage rapide
Quatre étapes, chacune avec la réponse que vous devriez voir.
- 01
Obtenez une clé
L’accès à l’API développeur se fait sur demande : demandez-le dans le studio, sous Clés API. Une fois l’accès ouvert, créez-y une clé et copiez-la tout de suite : la clé complète n’est affichée qu’une fois.
export API_KEY="sk_test_…" - 02
Envoyez une requête
Envoyez le plan en POST avec un Idempotency-Key et un plafond max_credits. Vous recevez aussitôt un 202 et une tâche en file, et les crédits sont réservés.
curl https://api.pershot.app/v1/videos/generations \ -H "Authorization: Bearer $API_KEY" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "model": "seedance-2.0-fast", "prompt": "Perfume mist in hard side light. Slow push-in, black background, grain.", "duration": 5, "resolution": "720p", "aspect_ratio": "16:9", "generate_audio": true, "max_credits": 34 }'{ "id": "job_01J9ZK4T8W", "object": "job", "kind": "video", "status": "queued", "money_status": "reserved", "queue_position": 2, "requested_model": "seedance-2.0-fast", "credits_quoted": 34, "credits_charged": null } - 03
Vérifiez la tâche
Faites un GET sur la tâche jusqu’à ce que son statut soit succeeded. L’URL de sortie est signée et expire : téléchargez ce que vous gardez.
curl https://api.pershot.app/v1/jobs/job_01J9ZK4T8W \ -H "Authorization: Bearer $API_KEY"{ "id": "job_01J9ZK4T8W", "object": "job", "kind": "video", "status": "succeeded", "money_status": "settled", "requested_model": "seedance-2.0-fast", "resolved_model": "seedance-2.0-fast", "credits_quoted": 34, "credits_charged": 34, "outputs": [ { "kind": "video", "url": "https://…/job_01J9ZK4T8W.mp4?sig=…", "width": 1280, "height": 720, "duration_s": 5 } ], "error": null } - 04
Recevez le webhook
Passez webhook_url et nous y envoyons en POST chaque changement d’état, signé avec un horodatage. Répondez 2xx ; les livraisons échouées sont relancées avec un délai croissant.
{ "id": "evt_01J9ZKB1QX", "type": "job.succeeded", "created_at": "2026-09-29T14:02:31Z", "data": { "job": { "id": "job_01J9ZK4T8W", "object": "job", "status": "succeeded", "money_status": "settled", "credits_charged": 34, "outputs": [ { "kind": "video", "url": "https://…/job_01J9ZK4T8W.mp4?sig=…", "width": 1280, "height": 720, "duration_s": 5 } ] } } }
Points d’accès
Tous les chemins sont relatifs à l’URL de base.
| Méthode | Chemin | Ce qu’il fait |
|---|---|---|
| GET | /v1/models | Modèles, capacités et état disponibles pour votre compte |
| GET | /v1/pricing | Prix publics ; une fois connecté, les prix de votre compte |
| POST | /v1/quotes | Planification, lignes, facturation maximale et expiration (10 minutes) |
| POST | /v1/videos/generations | Générer une vidéo ; 202 et une tâche |
| POST | /v1/images/generations | Générer ou retoucher une image ; 202 et une tâche |
| GET | /v1/jobs/{id} | Statut, sorties sous forme de liens signés, coût réel |
| GET | /v1/jobs | Vos tâches, les plus récentes d’abord |
| POST | /v1/jobs/{id}/cancel | Demander l’annulation ; les crédits réservés sont remboursés sauf si le modèle a déjà accepté la tâche |
| GET | /v1/balance | Crédits disponibles et réservés, par catégorie |
| GET | /v1/usage | Utilisation par jour ou par modèle, en JSON ou en CSV |
| POST | /v1/uploads | Importer un JPEG, PNG ou WebP jusqu’à 10 Mo |
Devis et plafonds
Chaque génération exige soit un quote_id, soit un plafond max_credits, jamais les deux. Avec un quote_id, la tâche s’exécute au prix du devis ; avec max_credits, elle ne s’exécute que si le prix est inférieur ou égal au plafond.
model: "auto" exige toujours max_credits. Un devis est valable 10 minutes ; ensuite, vous recevez quote_expired.
Idempotence
Envoyez un en-tête Idempotency-Key (1 à 255 caractères ASCII visibles) sur chaque requête de génération.
La même clé dans les 24 heures renvoie la même tâche avec HTTP 200 au lieu de 202 : une nouvelle tentative après un délai dépassé ne crée ni ne facture jamais une seconde tâche.
Webhooks
Passez webhook_url sur une génération (ou sur un lot) pour recevoir ses changements d’état. Chaque événement est un POST dont le corps JSON contient id, type, created_at et data : data.job pour les événements de tâche, data.batch pour batch.completed.
Événements
job.queuedjob.processingjob.succeededjob.failedjob.cancelledbatch.completed
- Chaque livraison a un identifiant d’événement, un horodatage et une signature. Vérifiez-la avant de faire confiance au corps.
- Une livraison compte quand votre point d’accès répond 2xx en moins de 10 secondes. Sinon, elle est relancée après 1 min, 5 min, 30 min, 2 h et 6 h, puis marquée échouée ; le support peut la relancer. Les redirections ne sont pas suivies.
- Les URL de webhook doivent être en https. Les hôtes à adresse privée, de bouclage ou réservée sont refusés, à l’envoi comme à la connexion.
En-têtes
X-Signaturet=<unix>,v1=<hex HMAC-SHA256(secret, "<t>.<raw body>")>X-Event-Id- L’identifiant de l’événement, aussi présent dans le corps. Les nouvelles tentatives et les relances le conservent : stockez-le et ignorez un identifiant déjà traité.
- Secret de signature
- Un secret whsec_… par compte, dans le studio sous Clés API. La clé HMAC est le secret entier, préfixe compris.
- Renouvellement
- Après un renouvellement, l’ancien secret continue de signer pendant 24 heures, sous forme d’une seconde entrée v1. Acceptez une livraison si l’une des entrées v1 correspond.
Calculez le HMAC sur le corps brut, pas sur une copie resérialisée, comparez en temps constant, et refusez les horodatages de plus de cinq minutes.
import { createHmac, timingSafeEqual } from "node:crypto";
// rawBody: the request body exactly as received, before any JSON parsing.
export function verifyWebhook(header, rawBody, secret, toleranceSec = 300) {
let t = null;
const signatures = [];
for (const item of (header ?? "").split(",")) {
const [key, value] = item.split("=", 2);
if (key === "t") t = Number(value);
if (key === "v1") signatures.push(Buffer.from(value, "hex"));
}
if (!t || Math.abs(Date.now() / 1000 - t) > toleranceSec) return false;
const expected = createHmac("sha256", secret).update(`${t}.${rawBody}`).digest();
return signatures.some((s) => s.length === expected.length && timingSafeEqual(s, expected));
}
// verifyWebhook(req.headers["x-signature"], rawBody, process.env.WEBHOOK_SECRET)
// Answer 2xx quickly, and skip an X-Event-Id you have already handled.Erreurs
Les codes et les statuts HTTP sont fixes ; le message s’adresse aux humains.
| Code | HTTP | Quand |
|---|---|---|
invalid_request | 400 | Un champ est manquant ou hors limites |
unauthorized | 401 | Pas de clé, une clé révoquée ou une signature invalide |
insufficient_credits | 402 | Le solde ne couvre pas la réservation |
forbidden_model | 403 | La liste autorisée de la clé n’inclut pas ce modèle ou cet outil |
region_not_supported | 403 | Le modèle n’est pas proposé dans votre région |
developer_api_closed | 403 | Une clé développeur alors que l’API développeur est fermée ; l’accès se fait sur demande |
member_connections_paused | 403 | Une connexion de membre (MCP, code de connexion ou ligne de commande) alors que la connexion de votre propre agent IA est en pause |
not_found | 404 | Aucune tâche, aucun devis ni aucun import de ce nom dans votre compte |
quote_expired | 409 | Le devis a plus de 10 minutes |
price_changed | 409 | Le prix a dépassé votre plafond |
content_rejected | 422 | Le contenu a été refusé ; rien n’est facturé |
rate_limited | 429 | Trop de requêtes pour cette clé |
concurrency_limited | 429 | Trop de tâches en cours pour ce compte |
internal_error | 500 | Un problème est survenu de notre côté |
upstream_unavailable | 503 | Le modèle est indisponible ; réessayez plus tard |
Un résultat incertain du modèle n’est pas une erreur : la tâche indique le statut unknown et est vérifiée avant toute nouvelle soumission.
Limites
- Requêtes
- 60 par minute et par clé par défaut.
- Simultanéité
- 3 tâches à la fois par compte par défaut ; demandez à l’augmenter.
- Plafond
- La capacité du modèle est un plafond strict. Plus de clés n’ajoutent pas de simultanéité.
Images
POST /v1/images/generations prend les mêmes en-têtes. Choisissez un identifiant de modèle selon le niveau et l’opération ; les modèles de retouche exigent aussi image_url, que les modèles de génération refusent.
| Niveau | génération | retouche |
|---|---|---|
| Image MiniÉconomique · brouillon | qwen-image-2512-lightning | qwen-image-edit-2511-lightning |
| Image FastRecommandé | qwen-image-2512 | qwen-image-edit-2511 |
Un résumé en texte brut pour les agents se trouve sur /llms.txt.
Limites par modèle
La page API de chaque modèle contient la table complète : la valeur, l’unité, qui la vérifie et ce qui se passe au-delà. GET /v1/models renvoie les mêmes limites en JSON.
- AppliquéeNous la vérifions et répondons 400 avant tout devis ou toute réservation.
- FournisseurLe fournisseur la vérifie. Une tâche qu’il refuse échoue, et rien n’est facturé.
- RecommandéePersonne ne la vérifie. La respecter donne de meilleurs résultats.
| Modèle | Limites principales | Table complète |
|---|---|---|
seedance-2.0-fastSeedance 2.0 Fast | Prompt de 2 à 2 000 caractères · 4 à 15 s · jusqu’à 9 images de référence · images de 300 à 6 000 px par côté | Ouvrir la table |
seedance-2.0-miniSeedance 2.0 Mini | Prompt de 2 à 2 000 caractères · 4 à 15 s · jusqu’à 9 images de référence · images de 300 à 6 000 px par côté | Ouvrir la table |
qwen-image-2512Qwen-Image-2512 | Prompt de 2 à 2 000 caractères · 1K ou 2K · sans image source | Ouvrir la table |
qwen-image-2512-lightningQwen-Image-2512 · Lightning 4-step | Prompt de 2 à 2 000 caractères · 1K ou 2K · sans image source | Ouvrir la table |
qwen-image-edit-2511Qwen-Image-Edit-2511 | Prompt de 2 à 2 000 caractères · 1K ou 2K · une image source, JPEG, PNG ou WebP jusqu’à 10 Mo | Ouvrir la table |
qwen-image-edit-2511-lightningQwen-Image-Edit-2511 · Lightning | Prompt de 2 à 2 000 caractères · 1K ou 2K · une image source, JPEG, PNG ou WebP jusqu’à 10 Mo | Ouvrir la table |
Imports
POST /v1/uploads lit le type dans le fichier lui-même. Les liens d’import durent 7 jours.
| Fichier | Formats | Taille maximale | Durée maximale |
|---|---|---|---|
| Image : première image, référence ou source de retouche | JPEG, PNG, WebP | 10 Mo | – |
| Vidéo : synchronisation labiale | MP4 | 50 Mo | 60 s |
| Audio : synchronisation labiale | MP3, WAV, M4A | 10 Mo | 60 s |
Nous ne récupérons jamais d’images sur d’autres hôtes : pour ces liens, c’est le fournisseur qui vérifie la taille, et une tâche qu’il refuse n’est pas facturée. Les mêmes limites existent en JSON : GET /v1/models renvoie un objet limits pour chaque modèle.
Vous venez de fal, Replicate ou WaveSpeed
Changer l’URL de base et la clé ne suffit pas : chaque requête a aussi besoin de l’identifiant du modèle dans le corps, d’un en-tête Idempotency-Key et d’un plafond de prix (max_credits ou un quote_id). Le guide de migration fait correspondre chaque champ pour Seedance 2.0 et Qwen-Image et liste ce qui ne se transpose pas.