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
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énement | Quand | data |
|---|---|---|
video.uploaded | Fichier vérifié | { video } |
video.processing | Encodage démarré (à nouveau après une relance) | { video } |
video.ready | Vidéo lisible | { video } |
video.failed | Échec de l’encodage | { video } |
video.deleted | Suppression terminée | { video } |
organization.quota_warning | Stockage utilisé à 80 % ou plus (une fois par jour au plus) | { organizationId, reservedBytes, maxStorageBytes, percent } |
playback.completed | Une session de lecture a atteint 90 % de la vidéo (une fois par session) | { session } |
webhook.test | Envoi 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
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 :
attendu = hex(HMAC-SHA256(secret, "<t>.<corps brut>"))
accepter si une valeur v1 est égale à attendu (comparaison à temps constant)
et si |maintenant − t| ≤ 300 secondesimport { 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 });
}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
idet considérezstatuscomme 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.