Rückkanal
Webhook
So erfährt dein Tool, welcher Knopf gedrückt wurde, und prüft, dass die Anfrage echt ist.
Ü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"
}| Feld | Bedeutung |
|---|---|
message_id | Die Nachricht, zu der der Knopf gehört. Derselbe Wert wie in der Antwort beim Senden. |
packlet_id | Das Packlet. |
button_id | Die id, die du dem Knopf gegeben hast. |
pressed_at | Zeitpunkt des Tipps, ISO 8601 in UTC. |
| Header | Wert |
|---|---|
Content-Type | application/json |
X-Samy-Event | button.pressed |
X-Samy-Signature | sha256=<Signatur> |
User-Agent | Samy-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
429oder 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.