Exemples de webhooks
Cette page propose des exemples complets, prêts pour la production, pour recevoir et traiter les webhooks Ignite dans différents langages de programmation.
Exemples serveur complets
Next.js API Routes
// pages/api/webhook.ts
import { createHmac, timingSafeEqual } from "crypto";
import { NextApiRequest, NextApiResponse } from "next";
// Disable body parser to access raw body for signature verification
export const config = {
api: {
bodyParser: false,
},
};
interface ThumbnailFormat {
url: string;
fileSize: number;
}
interface ThumbnailVariant {
name: string;
width: number;
height: number;
formats: {
jpeg: ThumbnailFormat;
webp: ThumbnailFormat;
};
}
interface VideoWebhookData {
id: string;
status: "COMPLETE" | "PROCESSING" | "NO_FILE" | "FAILED";
title: string;
src?: {
thumbnails?: ThumbnailVariant[];
thumbnailUrl?: string; // deprecated — use src.thumbnails instead
mp4?: Array<{ name: string; url: string; width: number; height: number }>;
};
// ... other video properties
}
async function getRawBody(req: NextApiRequest): Promise<string> {
const chunks: Buffer[] = [];
for await (const chunk of req) {
chunks.push(typeof chunk === "string" ? Buffer.from(chunk) : chunk);
}
return Buffer.concat(chunks).toString("utf-8");
}
function isValidSignature(
rawBody: string,
signatureHeader: string | string[] | undefined,
secret: string
): boolean {
try {
if (typeof signatureHeader !== "string") {
return false;
}
const time = signatureHeader.match(/t=(\d+)/)?.[1];
const token = signatureHeader.match(/v1=(\w+)/)?.[1];
if (!time || !token) {
return false;
}
const signedPayload = `${time}.${rawBody}`;
const hmac = createHmac("sha256", secret);
const calculatedSignature = hmac.update(signedPayload).digest("hex");
return timingSafeEqual(
Buffer.from(token),
Buffer.from(calculatedSignature)
);
} catch {
return false;
}
}
export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
if (req.method !== "POST") {
return res.status(405).end();
}
const rawBody = await getRawBody(req);
if (
!isValidSignature(
rawBody,
req.headers["x-webhook-signature"],
process.env.WEBHOOK_SIGNING_SECRET!
)
) {
console.error("Invalid webhook signature");
return res.status(403).end();
}
const eventType = req.headers["x-webhook-event"];
const deliveryId = req.headers["x-webhook-delivery-id"];
const video = JSON.parse(rawBody) as VideoWebhookData;
// Process based on event type
switch (eventType) {
case "video.created":
console.log("New video created:", video.id, video.title);
// await handleVideoCreated(video);
break;
case "video.updated":
console.log("Video updated:", video.id, video.title);
if (video.status === "COMPLETE") {
// Video processing finished - update your database
// await db.updateVideo(video.id, {
// thumbnails: video.src?.thumbnails,
// thumbnail: video.src?.thumbnails?.[0]?.formats.jpeg.url,
// sizes: video.src?.mp4,
// });
}
break;
case "video.deleted":
console.log("Video deleted:", video.id);
// await handleVideoDeleted(video);
break;
}
return res.status(204).end();
}Livraisons webhook
Chaque tentative de livraison d’un webhook est journalisée. Si une livraison échoue, le système retente automatiquement.
Statut de livraison
| Statut | Description |
|---|---|
success | Événement livré avec succès (réponse HTTP 2xx) |
failed | Échec de la livraison (délai dépassé, HTTP 4xx/5xx, erreur réseau) |
Informations de livraison
Chaque enregistrement de livraison contient :
| Champ | Description |
|---|---|
responseCode | Code de statut HTTP renvoyé par ton endpoint |
responseBody | Corps de la réponse de ton endpoint (tronqué si trop volumineux) |
errorMessage | Message d’erreur en cas d’échec de livraison |
deliveredAt | Horodatage de la tentative de livraison |
attemptNumber | Numéro de la tentative (s’incrémente aux nouvelles tentatives) |
nextRetryAt | Date de la prochaine tentative (le cas échéant) |
Comportement des nouvelles tentatives
- Les livraisons en échec sont automatiquement retentées
- Si
nextRetryAtest défini, une nouvelle tentative est planifiée - Si
nextRetryAtn’est pas défini, aucune nouvelle tentative n’aura lieu
Bonnes pratiques
Suivre ces bonnes pratiques assure un traitement fiable des webhooks et facilite le débogage.
Temps de réponse
Ton endpoint doit répondre dans les 30 secondes. Pour des opérations longues, accuse réception immédiatement du webhook et traite en arrière-plan :
app.post('/webhook', async (req, res) => {
// Immediately acknowledge receipt
res.status(200).json({ received: true });
// Process asynchronously (don't await)
processWebhookAsync(req.body).catch(console.error);
});
async function processWebhookAsync(video) {
// Long-running operations here
}Sécurité
- Secrets — N’expose jamais ton secret de signature dans le code client ni dans le contrôle de version
- HTTPS — Utilise toujours des endpoints HTTPS en production
- Validation — Vérifie toujours les signatures avant traitement
- Limitation de débit — Envisage une limitation de débit sur ton endpoint
Fiabilité
- Idempotence — Stocke et vérifie
X-Webhook-Delivery-Idpour gérer les livraisons en double - Journaux — Journalise toutes les requêtes webhook pour le débogage
- Surveillance — Configure des alertes en cas d’échec du traitement
- Gestion d’erreurs — Renvoie des codes HTTP appropriés pour que les nouvelles tentatives fonctionnent
Codes de statut HTTP
| Code | Signification |
|---|---|
200-299 | Succès — événement traité |
4xx | Erreur client — nouvelle tentative prévue |
5xx | Erreur serveur — nouvelle tentative prévue |
Dépannage
Aucun événement reçu
- Vérifie que l’abonnement webhook est actif
- Vérifie que les bons types d’événements sont sélectionnés
- Assure-toi que les événements se produisent dans le bon espace de travail
- Consulte les journaux de ton serveur pour les requêtes entrantes
Échec de la vérification de signature
- Vérifie que tu utilises le bon secret de signature (pas un jeton d’API)
- Assure-toi que le corps de la requête n’est pas modifié avant la vérification
- Vérifie que la sérialisation JSON correspond (compacte, sans espace superflu)
- Vérifie que le format de l’en-tête de signature est correctement analysé :
t=timestamp,v1=signature
Erreurs de délai dépassé
- Réponds dans les 30 secondes
- Déplace les opérations longues vers un traitement en arrière-plan
- Renvoie
200immédiatement, traite de façon asynchrone
Événements en double
- Implémente l’idempotence avec
X-Webhook-Delivery-Id - Consulte
attemptNumberpour les nouvelles tentatives - Stocke les ID de livraison traités en base de données