Documentation

Webhooks

Notifications signées quand une vidéo est prête, en échec ou annulée.

Renseignez une URL dans API et webhooks (offres Growth et Scale). Pixamake envoie une requête POST avec un corps JSON pour ces événements :

Événement Quand
job.succeeded La vidéo propre est prête
job.failed Le traitement a échoué (crédits rendus)
job.canceled La tâche a été annulée
webhook.test Envoyé avec le bouton Envoyer un événement de test

Contenu

{
  "id": "evt_9sKq2mT4nVb7Lx3Rp8Wc",
  "object": "event",
  "type": "job.succeeded",
  "created_at": "2026-10-04T13:09:58.012Z",
  "data": { "object": { "id": "job_3kT9xQ2vLm8RfZp1Wq7a", "object": "job", "status": "succeeded", "result": { "url": "https://..." } } }
}

data.object est l'objet tâche complet. Son result.url expire au bout d'une heure : téléchargez tout de suite, ou relisez la tâche plus tard pour un nouveau lien.

Vérifier la signature

Chaque requête porte un en-tête Pixamake-Signature :

Pixamake-Signature: t=1791119398,v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd

v1 est le HMAC SHA-256 (hexadécimal) de "{t}.{corps brut}" avec votre secret de signature (whsec_...). Comparez en temps constant et refusez les horodatages de plus de 5 minutes.

import { createHmac, timingSafeEqual } from "node:crypto";
 
export function verify(rawBody: string, header: string, secret: string) {
  const parts = Object.fromEntries(header.split(",").map((p) => p.split("=")));
  const expected = createHmac("sha256", secret).update(`${parts.t}.${rawBody}`).digest("hex");
  const fresh = Math.abs(Date.now() / 1000 - Number(parts.t)) < 300;
  return fresh && expected.length === parts.v1?.length && timingSafeEqual(Buffer.from(expected), Buffer.from(parts.v1));
}
import hashlib, hmac, time
 
def verify(raw_body: bytes, header: str, secret: str) -> bool:
    parts = dict(p.split("=", 1) for p in header.split(","))
    expected = hmac.new(secret.encode(), f"{parts['t']}.".encode() + raw_body, hashlib.sha256).hexdigest()
    return abs(time.time() - int(parts["t"])) < 300 and hmac.compare_digest(expected, parts.get("v1", ""))

Vérifiez toujours sur le corps brut de la requête, avant de lire le JSON.

Livraison et nouveaux essais

  • Répondez avec un statut 2xx en moins de 15 secondes. Faites le travail lourd après avoir répondu.
  • Une livraison en échec est retentée après 1 minute, 5 minutes, 30 minutes, 2 heures, 6 heures et 12 heures.
  • Une livraison peut arriver plusieurs fois ou dans le désordre : utilisez l'id de l'événement et le status de la tâche pour traiter chaque changement une seule fois.
  • Les redirections ne sont pas suivies et l'URL doit être publique (https en production).
  • Vous pouvez renouveler le secret de signature à tout moment depuis le tableau de bord.