Tous les articles
Discordwebhook debugginglocal testingbots

Webhooks Discord vs interactions, testés en local

Discord appelle deux choses différentes des "webhooks". L'une est une URL où poster des messages. L'autre est un endpoint d'interaction qui reçoit des POSTs signés à chaque commande slash. La première fonctionne sur localhost. La seconde non — c'est elle qui a besoin d'un tunnel.

Les deux variantes

Webhooks sortants : URLs vers lesquelles vous postez. Le trafic part de votre machine, aucun tunnel nécessaire.

Endpoints d'interaction : direction inverse. Vous enregistrez une URL ; Discord POST dessus à chaque /votrecommande. HTTPS obligatoire, réponse en moins de trois secondes, vérification Ed25519 sur chaque requête.

Pourquoi c'est plus strict que la moyenne

Discord ne demande pas seulement HTTPS — il prouve que vous contrôlez l'endpoint à l'enregistrement. Une interaction PING est envoyée, votre serveur doit répondre par un PONG signé. Une seule erreur Ed25519 et Discord refuse d'enregistrer l'URL.

Vous n'aurez pas la vérification Ed25519 du premier coup. Presque personne ne l'a.

Ed25519, le piège principal

Discord utilise Ed25519 (pas HMAC SHA-256) et fournit deux en-têtes :

  • X-Signature-Ed25519 — signature en hex
  • X-Signature-Timestamp — timestamp en secondes

Vous signez timestamp + rawBody avec la clé publique du dev portal.

import nacl from 'tweetnacl';

const valid = nacl.sign.detached.verify(
  Buffer.from(timestamp + rawBody),
  Buffer.from(signature, 'hex'),
  Buffer.from(PUBLIC_KEY, 'hex'),
);

Encore une fois, la cause numéro un d'échec est un middleware qui parse le corps avant la vérification.

Étapes

  1. Démarrez le serveur HTTP de votre bot localement.
  2. Exécutez npx portpreview 3000 et copiez l'URL HTTPS.
  3. Dans le portail développeur Discord, collez l'URL dans Interactions Endpoint URL.
  4. Sauvegardez. Discord envoie immédiatement un PING. Si Ed25519 passe, l'URL est enregistrée.
  5. Lancez une commande slash dans un serveur où votre bot est présent.

Trois secondes pour répondre

Discord exige une réponse en moins de trois secondes. Pour du traitement plus long, envoyez une réponse de type 5 (différée) puis PATCH l'interaction avec la vraie réponse plus tard.

Les webhooks sortants restent utiles

Pour envoyer des messages depuis du code local, l'URL webhook sortant suffit, sans tunnel. Nous l'utilisons pour des alertes de logs depuis nos runs locaux.

Quand passer à autre chose

Pour un bot avec quelques commandes, le tunnel suffit. Pour un bot public à des millions d'utilisateurs, un staging avec URL stable évite les re-vérifications à chaque rotation de session.

La fenêtre de trois secondes ressemble à celle de GitHub (dix secondes). Voir notre article retries et idempotence. Rejoignez la waitlist PortPreview.

Questions fréquentes

Peut-on tester les slash commands Discord en local ?
Pas directement. Discord exige HTTPS, vérification Ed25519 et réponse en trois secondes. Un tunnel expose votre serveur local en HTTPS et permet de l'enregistrer comme endpoint d'interaction.
Pourquoi Discord refuse mon URL d'endpoint ?
Au moment de sauvegarder, Discord envoie un PING. Si la vérification Ed25519 échoue ou si le handler ne renvoie pas un PONG valide, la sauvegarde est rejetée. La cause la plus fréquente est un middleware qui parse le corps avant vérification.
Les webhooks sortants Discord ont-ils besoin d'un tunnel ?
Non. Les webhooks sortants sont des URLs où vous postez depuis votre code. Seuls les endpoints d'interaction (qui reçoivent des POSTs de Discord) nécessitent un tunnel.