Interaktionen über HTTP
Empfange Befehle, Schaltflächen und Formulare an deiner eigenen HTTPS-Adresse, ohne Gateway-Verbindung.
Das brauchst du
- Node 22 oder neuer und eine öffentliche HTTPS-Adresse.
- Dein Bot-Token (
YOUR_BOT_TOKEN) und sein Signier-Geheimnis (YOUR_SIGNING_SECRET). - Keine Intents: Interaktionen kommen unabhängig von den Gateway-Intents.
Schritte
- Öffne deinen Bot im Entwicklerportal und wähle HTTP-Interaktionen. Erzeuge ein Signier-Geheimnis und kopiere es. Es erscheint einmal.
- Starte das Beispiel unten auf deinem Server, mit dem Geheimnis in
ZRZUR_SIGNING_SECRET. - Trage deine Adresse im selben Dialog ein, speichere und bestätige dein Passwort. Zrzur schickt zuerst zwei Testanfragen in beliebiger Reihenfolge: eine mit falscher Signatur, die abgelehnt werden muss, und ein signiertes
Ping, das{"type":"Pong"}bekommen muss. Das SDK erledigt beides.
Ab jetzt bekommt das Gateway die Interaktionen dieses Bots nicht mehr. Entferne die Adresse, um zurückzugehen.
Vollständiges Beispiel
// A bot without a gateway connection: `/hello` answered over HTTP.
//
// ZRZUR_BOT_TOKEN=... ZRZUR_SIGNING_SECRET=... PORT=8787 node http-interactions.mjs
import { Client } from "@zrzur/sdk/bot";
const bot = new Client({ apiUrl: process.env.ZRZUR_API_URL });
bot.command("hello", (i) => i.reply(`Hello ${i.user.username}, over HTTP!`));
await bot.loginHttp(process.env.ZRZUR_BOT_TOKEN);
await bot.syncCommands([{ name: "hello", description: "Say hello" }]);
await bot.listen({
secret: process.env.ZRZUR_SIGNING_SECRET,
port: Number(process.env.PORT ?? 8787),
});
console.log(`ready as ${bot.user.username}`);
Was du sehen solltest
ready as <your bot> in der Konsole, dann Hello <name>, over HTTP! im Kanal, wenn jemand /hello nutzt.
So sieht eine Anfrage aus
Jede Anfrage ist ein POST mit demselben JSON wie interaction in InteractionCreate und drei Headern:
| Header | Bedeutung |
|---|---|
X-Zrzur-Timestamp | Sekunden seit der Epoche beim Signieren |
X-Zrzur-Signature | v1= und das hexadezimale HMAC-SHA256 des signierten Texts |
X-Zrzur-Delivery | ID dieser Zustellung, für deine Logs. Nicht signiert |
Der signierte Text ist v1:<timestamp>:<raw body>. Ohne SDK:
- Lehne die Anfrage mit
401ab, wenn der Zeitstempel mehr als 300 Sekunden von deiner Uhr abweicht. - Berechne das HMAC-SHA256 des signierten Texts mit deinem Geheimnis und vergleiche in konstanter Zeit (
crypto.timingSafeEqualin Node,hmac.compare_digestin Python). Vergleiche nie mit==. - Lehne eine
_idaus dem signierten Text ab, die du in den letzten zehn Minuten behandelt hast: Das ist eine erneut gesendete, abgefangene Anfrage. Nutze dafür nichtX-Zrzur-Delivery: Das ist nicht signiert, jeder kann es ändern. - Beantworte
{"type":"Ping"}mit{"type":"Pong"}.
Ein abgeschalteter Bot, oder einer mit gesperrtem Eigentümer, bekommt nichts, und seine Adresse lässt sich nicht ändern.
Prüfe an diesem Beispiel. Mit dem Geheimnis zrzur_sign_f27c5773e21ddeceaeb5e956dc45c16451f737addd5c0e4472f61060bca9b030, dem Zeitstempel 1700000000 und dem Text {"type":"Ping"} ist die Signatur v1=928e5ffdc88564103b59f5485a6bfa7e1a633dca64f397396606a314f572c4d3.
So antwortest du
Antworte innerhalb von 3 Sekunden, auf eine von zwei Arten:
202oder204ohne Text, dannPOST /interactions/{id}/{token}/callbackwie beim Gateway. Das SDK tut das.200mit dem Text, den du an diese Route senden würdest, zum Beispiel{"type":"Message","data":{"content":"Hello"}}.
Jeder andere Status, eine Zeitüberschreitung, eine Weiterleitung oder eine Antwort über 1 MiB lässt die Interaktion scheitern, und die Person sieht das. Weiterleitungen werden nicht verfolgt.
Häufige Fehler
Eine Adresse zu speichern scheitert mit SignedDeliveryRejected, und reason sagt, warum:
reason | Ursache | Lösung |
|---|---|---|
invalid_url | Nicht https, oder enthält ein Passwort | Nimm eine einfache https://-Adresse |
blocked_address | Die Adresse ist privat oder gesperrt | Nimm eine öffentliche Adresse |
not_reachable | Nichts hat geantwortet | Prüfe, ob der Server läuft und öffentlich ist |
timed_out | Keine Antwort in 3 Sekunden | Antworte schneller |
accepts_bad_signatures | Die Anfrage mit falscher Signatur kam durch | Prüfe Signaturen, antworte 401 |
bad_status | Das Ping bekam kein 200 | Beantworte Ping mit 200 |
bad_answer | Das Ping bekam kein {"type":"Pong"} | Sende genau dieses JSON |
answer_too_large | Die Antwort ist über 1 MiB | Sende eine kleinere Antwort |
FeatureDisabled heißt, dieser Server hat keinen Signierschlüssel oder einen unter 32 Bytes. InvalidOperation heißt, der Bot hat noch kein Signier-Geheimnis.