Discord में दो चीज़ें हैं जिन्हें लोग "वेबहुक" कहते हैं और वे बिल्कुल अलग व्यवहार करती हैं। एक है मैसेज पोस्ट करने के लिए फ़ायर-एंड-फ़ॉरगेट URL। दूसरी है एक इंटरैक्शन एंडपॉइंट जो हर बार किसी यूज़र के slash कमांड चलाने पर साइन किए गए POST प्राप्त करता है। पहली localhost पर काम करती है। दूसरी कभी नहीं। यह गाइड दूसरी के बारे में है — क्योंकि टनल उसी को चाहिए।
Discord वेबहुक के दो प्रकार
आउटगोइंग वेबहुक वे URL हैं जिन पर आप POST करते हैं। आप एक JSON मैसेज भेजते हैं, वह एक चैनल में दिखता है। टनल की ज़रूरत नहीं क्योंकि ट्रैफ़िक आपकी मशीन से बाहर की ओर बहता है।
इंटरैक्शन एंडपॉइंट उल्टी दिशा में होते हैं। आप Discord में एक URL रजिस्टर करते हैं; जब कोई यूज़र /yourcommand चलाता है तो Discord उस पर POST करता है। एंडपॉइंट HTTPS होना चाहिए, तीन सेकंड के भीतर जवाब देना चाहिए, और हर रिक्वेस्ट पर एक Ed25519 सिग्नेचर सत्यापित करना चाहिए। localhost अकेले इनमें से कुछ नहीं कर सकता।
इंटरैक्शन एंडपॉइंट ज़्यादातर से सख़्त क्यों हैं
Discord सिर्फ़ HTTPS नहीं चाहता — वह URL स्वीकार करने से पहले यह साबित करवाता है कि आप एंडपॉइंट को नियंत्रित करते हैं। सत्यापन रजिस्ट्रेशन पर होता है: Discord एक PING इंटरैक्शन भेजता है, आपके सर्वर को एक साइन किए गए PONG से जवाब देना होता है। अगर Ed25519 सत्यापन एक बार भी फ़ेल हो, Discord URL सेव करने से इनकार कर देता है।
आप पहली ही कोशिश में Ed25519 वाला हिस्सा ठीक नहीं कर पाएँगे। लगभग कोई नहीं कर पाता।
Ed25519 सत्यापन, वह हिस्सा जो काटता है
Discord Ed25519 इस्तेमाल करता है (HMAC SHA-256 नहीं) और हर इंटरैक्शन पर दो हेडर देता है:
X-Signature-Ed25519— hex में सिग्नेचरX-Signature-Timestamp— सेकंड में timestamp
आप उस public key से timestamp + rawBody को साइन करते हैं जो Discord डेवलपर पोर्टल में दिखाता है। ज़्यादातर भाषाओं में इसके लिए एक लाइब्रेरी होती है। Node में:
import nacl from 'tweetnacl';
const valid = nacl.sign.detached.verify(
Buffer.from(timestamp + rawBody),
Buffer.from(signature, 'hex'),
Buffer.from(PUBLIC_KEY, 'hex'),
);
सत्यापन फ़ेल होने का नंबर-एक कारण है — फिर से — वह middleware जो इस कोड के चलने से पहले बॉडी पार्स कर देता है। आपको वह कच्ची स्ट्रिंग चाहिए जो Discord ने भेजी, पार्स किए ऑब्जेक्ट का दोबारा-स्ट्रिंग किया संस्करण नहीं।
चरण-दर-चरण: localhost पर इंटरैक्शन एंडपॉइंट
- अपने बॉट का HTTP सर्वर लोकल शुरू करें (कोई भी पोर्ट)।
- पब्लिक HTTPS URL पाने के लिए
npx portpreview 3000चलाएँ। - Discord डेवलपर पोर्टल में अपनी ऐप्लिकेशन खोलें और टनल URL के साथ अपना interactions पथ Interactions Endpoint URL में पेस्ट करें।
- Save दबाएँ। Discord तुरंत एक
PINGभेजेगा। अगर आपका Ed25519 सत्यापन काम करता है, URL सेव हो जाता है। नहीं तो फ़ील्ड में एरर दिखता है। - सेव होने के बाद, किसी भी सर्वर में जहाँ आपका बॉट है, एक slash कमांड चलाएँ। रिक्वेस्ट आपके handler में आती है।
अगर सेव बार-बार फ़ेल हो, कैप्चर की गई रिक्वेस्ट जाँचें — हेडर, बॉडी और आपके सर्वर का रिस्पॉन्स। दस में से नौ बार बॉडी सत्यापन से पहले एक JSON middleware ने चुपचाप बदल दी होती है।
तीन सेकंड की समय-सीमा
Discord तीन सेकंड से कम में जवाब माँगता है, वरना इंटरैक्शन को फ़ेल मान लेता है। उससे ज़्यादा समय लेने वाली किसी भी चीज़ के लिए, पहले एक type-5 रिस्पॉन्स (deferred) भेजें और बाद में असली जवाब के साथ मूल इंटरैक्शन को PATCH करें। लोकल टेस्टिंग स्पष्ट कर देती है कि कौन-से handler बहुत धीमे हैं — रिक्वेस्ट कैप्चर आपको सटीक latency दिखाता है।
आउटगोइंग वेबहुक टेस्ट के लिए अब भी उपयोगी हैं
अगर आप सिर्फ़ लोकल कोड से किसी चैनल में मैसेज भेजना चाहते हैं, तो आउटगोइंग वेबहुक URL बिना टनल के काम करता है। JSON POST करें, मैसेज दिखता है। हम इसका उपयोग लोकल dev रन से लॉग अलर्ट भेजने के लिए करते हैं।
यह सेटअप कब छोटा पड़ जाता है
मुट्ठी भर कमांड वाले एक बॉट के लिए, टनल के साथ लोकल टेस्टिंग पर्याप्त से ज़्यादा है। अगर आप लाखों यूज़र को सेवा देने वाला एक पब्लिक बॉट चला रहे हैं, तो आख़िरकार आपको एक स्थिर URL वाला staging डिप्लॉयमेंट चाहिए होगा ताकि टनल सेशन घूमने पर Discord को हर बार दोबारा सत्यापित न करना पड़े।
Discord का तीन-सेकंड timeout GitHub के दस-सेकंड विंडो जैसी ही समस्या के परिवार से है। विस्तृत संस्करण के लिए वेबहुक रिट्राई और idempotency पर हमारा नज़रिया पढ़ें। एक ही CLI में टनल + कैप्चर पाने के लिए PortPreview वेटलिस्ट में शामिल हों।