Webhooks

Vidoum appelle votre serveur quand une vidéo change d’état. Vous publiez la leçon dès que la vidéo est prête, sans interroger l’API en boucle.

Créer un webhook

Terminal
curl -X POST https://api.vidoum.com/v1/webhooks \
  -H "Authorization: Bearer $VIDOUM_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "url": "https://exemple.ma/webhooks/vidoum", "events": ["video.ready", "video.failed"] }'

La réponse contient le secret de signature (whsec_…) une seule fois : rangez-le avec vos autres secrets. Dix webhooks au plus par organisation. L’URL doit être publique, en https:// (port 443 ou 8443) ; les adresses privées ou internes sont refusées. Vos développeurs peuvent aussi gérer les webhooks dans l’espace client.

Événements

ÉvénementQuanddata
video.uploadedFichier vérifié{ video }
video.processingEncodage démarré (à nouveau après une relance){ video }
video.readyVidéo lisible{ video }
video.failedÉchec de l’encodage{ video }
video.deletedSuppression terminée{ video }
organization.quota_warningStockage utilisé à 80 % ou plus (une fois par jour au plus){ organizationId, reservedBytes, maxStorageBytes, percent }
playback.completedUne session de lecture a atteint 90 % de la vidéo (une fois par session){ session }
webhook.testEnvoi de test demandé{ webhookId }

video vaut { id, title, status, externalRef, version, durationSeconds, error }. session vaut { id, videoId, externalRef, viewerRef, createdAt, expiresAt, revokedAt, progress } (voir Suivre la progression).

La requête reçue

HTTP
POST /webhooks/vidoum HTTP/1.1
Content-Type: application/json
User-Agent: Vidoum-Webhooks/1
Vidoum-Signature: t=1794312000,v1=5f2b…
Vidoum-Event-Id: …
Vidoum-Event-Type: video.ready
Vidoum-Delivery-Id: …
Vidoum-Delivery-Attempt: 1

{ "id": "…", "type": "video.ready", "createdAt": "…", "data": { "video": { … } } }

Vérifier la signature

Vérifiez chaque requête sur le corps brut, avant de le décoder et avant toute action :

Algorithme
attendu = hex(HMAC-SHA256(secret, "<t>.<corps brut>"))
accepter si une valeur v1 est égale à attendu (comparaison à temps constant)
         et si |maintenant − t| ≤ 300 secondes
Node.js · avec le SDK
import { Vidoum } from "@vidoum/node";

export async function POST(request) {
  const rawBody = await request.text(); // le corps brut, pas du JSON re-sérialisé
  const event = await Vidoum.verifyWebhook(
    rawBody,
    request.headers.get("Vidoum-Signature"),
    process.env.VIDOUM_WEBHOOK_SECRET,
  ); // lève une erreur si la signature est invalide
  if (event.type === "video.ready") await publishLesson(event.data.video.externalRef);
  return new Response(null, { status: 204 });
}
PHP
function vidoum_verify(string $raw, string $header, string $secret): bool {
    $t = null; $sigs = [];
    foreach (explode(',', $header) as $part) {
        [$k, $v] = array_pad(explode('=', $part, 2), 2, '');
        if ($k === 't') $t = (int) $v;
        if ($k === 'v1') $sigs[] = $v;
    }
    if ($t === null || abs(time() - $t) > 300) return false;
    $expected = hash_hmac('sha256', $t . '.' . $raw, $secret);
    foreach ($sigs as $sig) if (hash_equals($expected, $sig)) return true;
    return false;
}

Livraison et nouvelles tentatives

  • Répondez par un code 2xx en moins de 10 secondes ; faites les traitements longs après avoir répondu. Les redirections ne sont pas suivies.
  • En cas d’échec, Vidoum réessaie après 1 min, 5 min, 30 min, 2 h, 6 h, 12 h et 24 h. Au-delà, l’envoi est abandonné (dead).
  • Un webhook en échec 50 fois de suite est désactivé ; réactivez-le avec PATCH { "enabled": true }.
  • Un événement peut arriver plusieurs fois ou dans le désordre : dédoublonnez avec id et considérez status comme la référence.
  • Le journal des envois (30 jours), le renvoi d’un événement et le remplacement du secret (les deux secrets signent pendant 24 h) sont disponibles dans l’API et dans l’espace client.