Zum Inhalt springen

Webhooks

Fügen Sie im Dashboard einen Endpunkt hinzu, und wir senden jedes Ereignis, das Ihre Schlüssel auslösen, per POST dorthin, signiert mit dem eigenen Secret des Endpunkts. Webhooks gibt es in jedem Plan.

Ereignisse

Webhook-Ereignisse
TypWanndata enthält
mark.completedEine über POST /v1/mark markierte Datei (ein Clip, sobald sein Auftrag abgeschlossen ist) oder ein über POST /v1/sign signiertes Manifest (lokaler Modus).mark_id, mode (cloud oder local), project_id, kind (picture, song oder clip), format, bytes, sha256, watermark_id, manifest, log_index, safety; bei Songs und Clips außerdem seconds und marks
mark.failedEin Clip, dessen Auftrag fehlgeschlagen ist: von der Sicherheitsprüfung blockiert, mehr Markierungen als noch verfügbar, eine Datei, die wir nicht lesen können, oder ein Fehler bei uns. Es wurde nichts markiert.mark_id, project_id, kind, error (code und message) sowie safety eines blockierten Einzelbilds
check.blockedEin Bild oder Einzelbild eines Clips, das die Sicherheitsprüfung blockiert hat, über POST /v1/check oder mit check bei POST /v1/mark.request_id, endpoint, project_id, policy, reason, picture (file oder input) sowie frame bei einem Clip. Nie das Bild oder sein Hash: Wir bewahren keines von beiden auf
pingEin Test, aus dem Dashboard an einen Endpunkt gesendet.message

Ein Endpunkt erhält die Ereignisse entweder von Live- oder von Testschlüsseln, nie von beiden, genau wie Schlüssel selbst (Umgebungen). Der 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 einer Zustellung
HeaderWert
Kennmarq-Signaturet=<Unix-Sekunden>,v1=<HMAC-SHA256 in Hex>: was Sie verifizieren, bevor Sie dem Body vertrauen.
Kennmarq-Event-IdDie ID des Ereignisses (evt_…), bei jedem erneuten Versuch dieselbe: Damit verarbeiten Sie jedes Ereignis nur einmal.
Kennmarq-Event-TypeDer Typ des Ereignisses.
Content-Typeapplication/json
User-AgentKennmarq-Webhooks/1

Jede Zustellung verifizieren

Die Signatur ist ein HMAC-SHA256 über den Zeitpunkt, einen Punkt und den unveränderten Body, mit dem Secret, das das Dashboard beim Hinzufügen des Endpunkts angezeigt hat (whsec_…). Sie folgt dem Signaturschema der Webhooks von Stripe, sodass derselbe Prüfcode für beide funktioniert. Vergleichen Sie in konstanter Zeit, und lehnen Sie einen Zeitpunkt ab, der mehr als fünf Minuten abweicht, damit sich eine alte Zustellung nicht erneut einspielen lässt.

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", ""))
Verifizieren Sie den Body so, wie er angekommen ist, bevor ein JSON-Parser ihn anfasst: Ein neu serialisierter Body passt nicht.

Zustellung und erneute Versuche

  • Eine Zustellung gilt als erfolgreich, wenn Ihr Endpunkt innerhalb von 10 Sekunden mit 2xx antwortet. Antworten Sie zuerst, und erledigen Sie dann die Arbeit.
  • Andernfalls versuchen wir es nach 1 und 5 Minuten, nach einer halben Stunde, dann nach 2, 6, 12 und 24 Stunden erneut und geben danach auf. Ereignisse können mehrfach und in falscher Reihenfolge ankommen: Verarbeiten Sie jede Kennmarq-Event-Id nur einmal.
  • Endpunkte nutzen HTTPS auf dem Standardport, im öffentlichen Internet: Wir folgen nie einer Weiterleitung und senden nie an eine private, Loopback- oder Link-Local-Adresse, egal, worauf ein Name aufgelöst wird.
  • Das Dashboard zeigt die letzten Zustellungen jeder Organisation; wir bewahren sie 30 Tage auf.