Vai al contenuto

Webhook

Aggiungi un endpoint nella dashboard e gli invieremo in POST ogni evento generato dalle tue chiavi, firmato con il segreto proprio dell’endpoint. I webhook sono inclusi in ogni piano.

Eventi

Eventi dei webhook
TipoQuandodata contiene
mark.completedUn file marcato da POST /v1/mark (una clip quando il suo job è terminato) o un manifest firmato da POST /v1/sign (modalità locale).mark_id, mode (cloud o local), project_id, kind (picture, song o clip), format, bytes, sha256, watermark_id, manifest, log_index, safety; per un brano e una clip, seconds e marks
mark.failedUna clip il cui job non è riuscito: bloccata dal controllo di sicurezza, oltre le marcature rimanenti, un file che non riusciamo a leggere o un errore da parte nostra. Non è stato marcato nulla.mark_id, project_id, kind, error (code e message) e, per un fotogramma bloccato, safety
check.blockedUn’immagine o un fotogramma di una clip bloccato dal controllo di sicurezza, su POST /v1/check o con check su POST /v1/mark.request_id, endpoint, project_id, policy, reason, picture (file o input) e, per una clip, il fotogramma. Mai l’immagine né il suo hash: non conserviamo nessuno dei due
pingUn test, inviato dalla dashboard a un endpoint.message

Un endpoint riceve gli eventi delle chiavi di produzione oppure di quelle di test, mai di entrambe, come avviene per le chiavi (ambienti). Il body:

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"
}
Header di una consegna
HeaderValore
Kennmarq-Signaturet=<secondi Unix>,v1=<HMAC-SHA256 esadecimale>: ciò che devi verificare prima di fidarti del body.
Kennmarq-Event-IdL’ID dell’evento (evt_…), lo stesso a ogni nuovo tentativo: usalo per gestire ogni evento una sola volta.
Kennmarq-Event-TypeIl tipo dell’evento.
Content-Typeapplication/json
User-AgentKennmarq-Webhooks/1

Verifica ogni consegna

La firma è un HMAC-SHA256 dell’orario, di un punto e del body grezzo, con il segreto che la dashboard ti ha mostrato quando hai aggiunto l’endpoint (whsec_…). Segue lo schema di firma dei webhook di Stripe, quindi lo stesso codice di verifica funziona per entrambi. Confronta in tempo costante e rifiuta un orario che si discosti di più di cinque minuti, così una vecchia consegna non può essere riutilizzata.

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", ""))
Verifica il body grezzo così come è arrivato, prima che lo tocchi qualsiasi parser JSON: un body riserializzato non corrisponderà.

Consegna e nuovi tentativi

  • Una consegna è riuscita quando il tuo endpoint risponde 2xx entro 10 secondi. Prima rispondi, poi esegui il lavoro.
  • Altrimenti riproviamo dopo 1 e 5 minuti, mezz’ora, poi 2, 6, 12 e 24 ore, e poi rinunciamo. Gli eventi possono arrivare più di una volta e fuori ordine: gestisci ogni Kennmarq-Event-Id una sola volta.
  • Gli endpoint sono HTTPS sulla porta standard, su internet pubblico: non seguiamo mai un redirect e non inviamo mai a un indirizzo privato, di loopback o link-local, qualunque sia l’indirizzo a cui si risolve un nome.
  • La dashboard mostra le consegne recenti di ogni organizzazione; le conserviamo per 30 giorni.