Aller au contenu

Webhooks

Ajoutez un endpoint dans le tableau de bord : nous lui envoyons en POST chaque événement que provoquent vos clés, signé avec le secret propre à cet endpoint. Toutes les offres en disposent.

Événements

Événements de webhook
TypeQuandContenu de data
mark.completedUn fichier marqué par POST /v1/mark (une vidéo, une fois sa tâche terminée), ou un manifeste signé par POST /v1/sign (mode local).mark_id, mode (cloud ou local), project_id, kind (picture, song ou clip), format, bytes, sha256, watermark_id, manifest, log_index, safety ; pour un morceau ou une vidéo, seconds et marks
mark.failedUne vidéo dont la tâche a échoué : bloquée par le contrôle de sécurité, au-delà des marquages restants, fichier illisible, ou défaillance de notre côté. Rien n’a été marqué.mark_id, project_id, kind, error (code et message) et, pour une image bloquée, safety
check.blockedUne image, ou une image d’une vidéo, bloquée par le contrôle de sécurité, sur POST /v1/check ou avec check sur POST /v1/mark.request_id, endpoint, project_id, policy, reason, picture (file ou input) et, pour une vidéo, frame. Jamais l’image ni son empreinte : nous n’en conservons aucune
pingUn test, envoyé depuis le tableau de bord à un endpoint.message

Un endpoint reçoit les événements des clés de production ou de celles de test, jamais des deux, comme les clés elles-mêmes (environnements). Le corps :

POST application/json
{
  "created": 1793182831,
  "data": {
    "bytes": 1208033, "format": "image/png", "log_index": 4127, "manifest": "urn:c2pa:…",
    "mark_id": "mk_4Q8oT1n6mWc2fLr0aZ9eYk", "mode": "cloud", "project_id": "prj_…",
    "kind": "picture", "safety": null, "sha256": "…", "watermark_id": "1cfc5f99ffce3db9"
  },
  "id": "evt_9w1KQ0p3aZ8xLm2Tn4Rb6c",
  "livemode": true,
  "object": "event",
  "type": "mark.completed"
}
En-têtes d’une livraison
En-têteValeur
Kennmarq-Signaturet=<secondes Unix>,v1=<HMAC-SHA256 en hexadécimal> : ce qu’il faut vérifier avant de se fier au corps.
Kennmarq-Event-IdL’ID de l’événement (evt_…), identique à chaque nouvelle tentative : utilisez-le pour traiter chaque événement une seule fois.
Kennmarq-Event-TypeLe type de l’événement.
Content-Typeapplication/json
User-AgentKennmarq-Webhooks/1

Vérifier chaque livraison

La signature est un HMAC-SHA256 de l’heure, d’un point et du corps brut, avec le secret que le tableau de bord a affiché quand vous avez ajouté l’endpoint (whsec_…). Elle suit le schéma de signature des webhooks de Stripe : le même code de vérification fonctionne donc pour les deux. Comparez en temps constant, et refusez une heure décalée de plus de cinq minutes, pour qu’une ancienne livraison ne puisse pas être rejouée.

Node.js
import { createHmac, timingSafeEqual } from "node:crypto";

export function verify(secret, rawBody, header, now = Date.now() / 1000) {
  const parts = Object.fromEntries(header.split(",").map((p) => p.trim().split("=")));
  const t = Number(parts.t);
  if (!Number.isFinite(t) || Math.abs(now - t) > 300) return false;
  const expected = createHmac("sha256", secret).update(`${t}.${rawBody}`).digest();
  const given = Buffer.from(parts.v1 ?? "", "hex");
  return given.length === expected.length && timingSafeEqual(given, expected);
}
Python
import hashlib, hmac, time

def verify(secret: str, raw_body: bytes, header: str) -> bool:
    parts = dict(p.strip().split("=", 1) for p in header.split(","))
    t = int(parts.get("t", "0"))
    if abs(time.time() - t) > 300:
        return False
    expected = hmac.new(secret.encode(), f"{t}.".encode() + raw_body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, parts.get("v1", ""))
Vérifiez le corps brut tel qu’il est arrivé, avant qu’un analyseur JSON n’y touche : un corps re-sérialisé ne correspondra pas.

Livraison et nouvelles tentatives

  • Une livraison est réussie quand votre endpoint répond 2xx en moins de 10 secondes. Répondez d’abord, puis faites le traitement.
  • Sinon, nous réessayons après 1 et 5 minutes, une demi-heure, puis 2, 6, 12 et 24 heures, avant d’abandonner. Les événements peuvent arriver plusieurs fois et dans le désordre : traitez chaque Kennmarq-Event-Id une seule fois.
  • Les endpoints sont en HTTPS sur le port standard, sur l’internet public : nous ne suivons jamais de redirection et n’envoyons jamais rien vers une adresse privée, de bouclage (loopback) ou link-local, quelle que soit la résolution d’un nom.
  • Le tableau de bord affiche les livraisons récentes de chaque organisation ; nous les conservons 30 jours.