Rückkanal

Webhook

So erfährt dein Tool, welcher Knopf gedrückt wurde, und prüft, dass die Anfrage echt ist.

Als Markdown öffnen

Über den Webhook erfährt dein Tool, dass du in der App auf einen Aktions-Knopf getippt hast.

Einrichten

Die Webhook-URL trägst du beim Anlegen des Packlets oder später in seinen Einstellungen ein.

  • Sie muss mit https:// beginnen und öffentlich erreichbar sein.
  • Zugangsdaten in der Adresse (https://name:passwort@…) sind nicht erlaubt.

Die Anfrage

Bei einem Tipp schickt Samy einen POST mit diesem JSON-Body:

JSON
{
  "message_id": "5b0c1a52-…",
  "packlet_id": "9d2f7c10-…",
  "button_id": "label",
  "pressed_at": "2026-11-09T18:00:00Z"
}
FeldBedeutung
message_idDie Nachricht, zu der der Knopf gehört. Derselbe Wert wie in der Antwort beim Senden.
packlet_idDas Packlet.
button_idDie id, die du dem Knopf gegeben hast.
pressed_atZeitpunkt des Tipps, ISO 8601 in UTC.
HeaderWert
Content-Typeapplication/json
X-Samy-Eventbutton.pressed
X-Samy-Signaturesha256=<Signatur>
User-AgentSamy-Webhook/1.0

Antworten und Wiederholungen

  • Antworte innerhalb von 10 Sekunden mit einem Status 2xx. Der Inhalt der Antwort wird nicht gelesen.
  • Bei Zeitüberschreitung, Status 429 oder einem Status ab 500 versucht Samy es bis zu fünfmal erneut, mit wachsendem Abstand.
  • Andere Fehler (zum Beispiel 400 oder 404) werden nicht wiederholt.
  • Weiterleitungen folgt Samy nicht.

Wegen der Wiederholungen kann dieselbe Anfrage mehrfach ankommen. Merke dir message_id zusammen mit button_id, wenn eine Aktion nur einmal laufen darf.

Signatur prüfen

Mit der Signatur stellst du sicher, dass die Anfrage wirklich von Samy kommt.

  • Algorithmus: HMAC-SHA256 über den unveränderten Body (die rohen Bytes, nicht das neu erzeugte JSON).
  • Geheimnis: der SHA-256-Hash deines Schlüssels als Hex-Text in Kleinbuchstaben.
  • Format des Headers: sha256= gefolgt vom HMAC als Hex-Text.
Python
import hashlib, hmac, os

SAMY_KEY = os.environ["SAMY_KEY"]

def is_from_samy(raw_body: bytes, signature: str) -> bool:
    secret = hashlib.sha256(SAMY_KEY.encode()).hexdigest()
    expected = "sha256=" + hmac.new(secret.encode(), raw_body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, signature or "")
Node.js
import { createHash, createHmac, timingSafeEqual } from "node:crypto";

export function isFromSamy(rawBody, signature = "") {
  const secret = createHash("sha256").update(process.env.SAMY_KEY).digest("hex");
  const expected = "sha256=" + createHmac("sha256", secret).update(rawBody, "utf8").digest("hex");
  const a = Buffer.from(expected);
  const b = Buffer.from(signature);
  return a.length === b.length && timingSafeEqual(a, b);
}

Erzeugst du in der App einen neuen Schlüssel, ändert sich auch das Geheimnis für die Signatur.