लॉग इनमुफ़्त ट्रायल शुरू करें
Meta Tech Provider

Supabase Edge Function में WhatsApp वेबहुक पाएँ

Supabase Edge Function सीधे नंबर का वेबहुक डेस्टिनेशन बन सकता है। यह Meta के पुष्टि वाले GET का जवाब hub.challenge वैल्यू से देता है, POST हुए हर मैसेज को Postgres टेबल में डालता है, और Cloud API से जवाब भेजता है। इसे JWT जाँच बंद करके डिप्लॉय करें, क्योंकि Supabase डिफ़ॉल्ट रूप से वैध JWT माँगता है और Meta वह नहीं भेज सकता।

verify_jwt = true

Edge Functions के लिए Supabase का डिफ़ॉल्ट: आपका हैंडलर चलने से पहले ही वैध JWT के बिना आया हर अनुरोध अस्वीकार हो जाता है।

--no-verify-jwt

supabase functions deploy का वह फ़्लैग जो किसी फ़ंक्शन के लिए JWT जाँच बंद करता है।

150 s

Edge Function के लिए अनुरोध का आइडल टाइमआउट; तब तक जवाब न मिले तो 504 लौटता है।

Edge Function को क्या करना होता है?

दो काम हैं, दो मेथड पर।

GET पर यह Meta की पुष्टि का जवाब देता है। क्वेरी स्ट्रिंग से hub.mode, hub.verify_token और hub.challenge पढ़ें, टोकन को उस टोकन से मिलाएँ जो आपने डेस्टिनेशन के पुष्टि टोकन के रूप में डाला था, और challenge को प्लेन टेक्स्ट बॉडी में स्टेटस 200 के साथ लौटाएँ। टोकन न मिले तो 403 लौटाएँ।

POST पर यह इवेंट लेता है। बॉडी पार्स करें, entry, changes और value में से मैसेज निकालें, उन्हें टेबल में डालें और 200 लौटाएँ। जवाब तेज़ रखें: Meta धीमे या असफल जवाब को डिलीवरी की विफलता मानकर दोबारा भेजता है, यानी वही मैसेज दो बार आता है।

EasyCoexistence में फ़ंक्शन का यूआरएल नंबर के वेबहुक डेस्टिनेशन के रूप में उसी पुष्टि टोकन के साथ सेट करें, और Meta डिलीवरी शुरू कर देता है।

supabase/functions/whatsapp/index.ts
import { createClient } from "npm:@supabase/supabase-js@2";

const db = createClient(Deno.env.get("SUPABASE_URL")!, Deno.env.get("SUPABASE_SERVICE_ROLE_KEY")!);

Deno.serve(async (req) => {
  const url = new URL(req.url);
  if (req.method === "GET") {
    const ok = url.searchParams.get("hub.verify_token") === Deno.env.get("VERIFY_TOKEN");
    return new Response(ok ? url.searchParams.get("hub.challenge") : "forbidden", { status: ok ? 200 : 403 });
  }
  if (url.searchParams.get("key") !== Deno.env.get("URL_SECRET")) return new Response("no", { status: 401 });
  const body = await req.json();
  const rows = (body.entry ?? []).flatMap((e: any) => e.changes ?? [])
    .flatMap((c: any) => (c.value?.messages ?? []).map((m: any) => ({
      wamid: m.id, sender: m.from, kind: m.type, text: m.text?.body ?? null,
      phone_number_id: c.value.metadata?.phone_number_id, raw: m,
    })));
  if (rows.length) await db.from("whatsapp_messages").upsert(rows, { onConflict: "wamid" });
  return new Response("ok");
});

फ़ंक्शन Meta को 401 क्यों लौटाता है?

क्योंकि JWT जाँच चालू है। Supabase, Edge Function का हैंडलर चलने से पहले Authorization हेडर में JWT को जाँचता है, और यही हर फ़ंक्शन का डिफ़ॉल्ट है। Meta ऐसा कोई हेडर नहीं भेजता, इसलिए प्लेटफ़ॉर्म पुष्टि वाले GET और हर डिलीवरी, दोनों को ठुकरा देता है, और आपका कोड उन्हें कभी देखता ही नहीं।

इसे केवल इसी फ़ंक्शन के लिए बंद करें। या तो supabase functions deploy whatsapp --no-verify-jwt से डिप्लॉय करें, या supabase/config.toml में फ़ंक्शन के सेक्शन के नीचे verify_jwt = false सेट करें। Supabase के डॉक्स ठीक इसी स्थिति का वर्णन करते हैं: बाहरी वेबहुक प्रदाता द्वारा बुलाया जाने वाला सार्वजनिक एंडपॉइंट।

प्लेटफ़ॉर्म की जाँच बंद होने पर फ़ंक्शन को अपनी जाँच चाहिए। सिग्नेचर हेडर आपके काम का नहीं है, क्योंकि Meta उस ऐप के ऐप सीक्रेट से साइन करता है जिसके पास सब्सक्रिप्शन है। डेस्टिनेशन यूआरएल में क्वेरी पैरामीटर के रूप में एक लंबा रैंडम सीक्रेट रखें और उसके बिना आए अनुरोध ठुकरा दें, जैसा उदाहरण POST पर करता है।

फ़ंक्शन को स्टोर और जवाब कैसे करना चाहिए?

पहले स्टोर करें, जवाब बाद में। WhatsApp मैसेज आईडी पर यूनिक कंस्ट्रेंट के साथ upsert करें, ताकि Meta के दोबारा भेजे मैसेज डुप्लिकेट बनाने के बजाय उसी रो पर पहुँचें। एक से ज़्यादा नंबर फ़ंक्शन की ओर इशारा करते हों तो हर रो में मैसेज पाने वाला phone_number_id रखें।

जो काम धीमा हो, जैसे जवाब देने से पहले किसी मॉडल या दूसरे एपीआई को बुलाना, उसे EdgeRuntime.waitUntil को सौंपें और जवाब तुरंत लौटा दें। वह प्रॉमिस पूरा होने तक फ़ंक्शन चलता रहता है, जबकि Meta को अपना 200 पहले ही मिल चुका होता है। Supabase 150 सेकंड के आइडल समय पर इंतज़ार छोड़कर 504 लौटाता है, इसलिए जो हैंडलर जवाब देने से पहले सारा काम करता है, वही सबसे ज़्यादा बार दोबारा भेजे जाने की वजह बनता है।

जवाब Cloud API के मैसेज एंडपॉइंट पर जाते हैं, नंबर के phone number id और टोकन के साथ, जो फ़ंक्शन सीक्रेट के रूप में रखे हैं। ग्राहक के आख़िरी मैसेज के 24 घंटे के भीतर फ़्री टेक्स्ट डिलीवर होता है; उसके बाद केवल मंज़ूर टेम्पलेट।

फ़ोन से भेजे मैसेज क्या फ़ंक्शन तक पहुँचते हैं?

हाँ। Coexistence नंबर पर WhatsApp Business ऐप चलता रहता है, और जब कोई उससे जवाब देता है तो Meta उस भेजे गए मैसेज का इको उसी डेस्टिनेशन पर पहुँचाता है, messages की जगह smb_message_echoes फ़ील्ड और message_echoes ऐरे के तहत।

पार्सर को दोनों पढ़ने लायक बढ़ाएँ और direction कॉलम स्टोर करें। तब टेबल में पूरी बातचीत रहती है, ग्राहक की पंक्तियाँ और कारोबार के जवाब, जिन पर लोग आगे अक्सर क्वेरी चलाना चाहते हैं: जवाब देने का समय, बिना जवाब की बातचीत, हर संपर्क का आख़िरी इनबाउंड समय।

यही आख़िरी मान हर भेजने वाले रास्ते का इनपुट भी है, क्योंकि वही तय करता है कि जवाब फ़्री टेक्स्ट हो सकता है या टेम्पलेट ज़रूरी है। टेबल पर बना व्यू इसे हर संपर्क के लिए आपके बाकी ऐप को दे सकता है।

आम गड़बड़ियाँ

  • JWT जाँच चालू छोड़कर डिप्लॉय करना। Supabase हैंडलर चलने से पहले ही Meta के अनुरोध 401 के साथ ठुकरा देता है, और कोई मैसेज नहीं पहुँचता।
  • challenge को JSON में लपेटकर लौटाना। Meta को बॉडी में कच्चा मान चाहिए, वरना पुष्टि चुपचाप विफल हो जाती है।
  • जवाब देने से पहले धीमा काम करना। Meta जिसे विफलता मानता है उसे दोबारा भेजता है, और वही मैसेज दो बार प्रोसेस होता है।
  • अपनी कोई जाँच लगाए बिना JWT जाँच बंद करना। यूआरएल पाने वाला कोई भी टेबल में नकली मैसेज भेज सकता है।
EasyCoexistence के साथ ऐसा करना

easycoexistence.com पर नंबर कनेक्ट करें, उसका वेबहुक डेस्टिनेशन Edge Function के यूआरएल पर अपने पुष्टि टोकन के साथ सेट करें, और phone number id व टोकन को फ़ंक्शन सीक्रेट के रूप में रखें। US$ 9 प्रति नंबर प्रति माह से शुरू, नंबर बढ़ने के साथ घटकर US$ 1, और पहले 3 दिन मुफ़्त।

अक्सर पूछे जाने वाले सवाल

क्या यह Supabase के फ़्री प्लान पर चलता है?

Edge Functions फ़्री प्लान पर चलते हैं, जहाँ वॉल क्लॉक सीमा 150 सेकंड है, जबकि पेड प्लान पर 400 सेकंड। जल्दी जवाब देने वाला वेबहुक हैंडलर दोनों सीमाओं से बहुत भीतर रहता है।

क्या फ़ंक्शन में service role key इस्तेमाल करनी चाहिए?

केवल सर्वर साइड पर, जैसा यहाँ है, फ़ंक्शन के एनवायरनमेंट से पढ़कर। यह row level security को बायपास करती है, इसलिए यह ब्राउज़र तक कभी नहीं पहुँचनी चाहिए।

क्या एक फ़ंक्शन कई नंबर संभाल सकता है?

हाँ। हर नंबर का वेबहुक डेस्टिनेशन उसी पर रखें और हर पेलोड के phone_number_id के आधार पर ब्रांच करें।

क्या EasyCoexistence मैसेज देखता है?

नहीं। Meta हर वेबहुक सीधे आपके फ़ंक्शन तक पहुँचाता है, और EasyCoexistence बातचीत की सामग्री कभी स्टोर नहीं करता।

पढ़ना जारी रखें

शुरू करने के लिए तैयार हैं?

WhatsApp Coexistence को महीनों में नहीं, मिनटों में कॉन्फ़िगर करें। ऐप्लिकेशन मोबाइल पर काम करता रहता है।

मुफ़्त ट्रायल शुरू करें

इस तारीख को सत्यापित

Supabase Edge Functions में WhatsApp वेबहुक