লগ ইনফ্রি ট্রায়াল শুরু করুন
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 Function-এর জন্য 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-এ ফাংশনের URL-টি নম্বরের ওয়েবহুক গন্তব্য হিসেবে একই ভেরিফাই টোকেন সহ বসান, তাহলেই 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 যাচাইকরণ চালু আছে। Edge Function-এর হ্যান্ডলার চলার আগে Supabase Authorization হেডারের JWT যাচাই করে, এবং এটি প্রতিটি ফাংশনের ডিফল্ট। Meta এমন কোনো হেডার পাঠায় না, তাই প্ল্যাটফর্ম যাচাইকরণ GET এবং প্রতিটি ডেলিভারি দুটোই প্রত্যাখ্যান করে, আর আপনার কোড সেগুলো কখনো দেখতেই পায় না।

শুধু এই ফাংশনের জন্য এটি বন্ধ করুন। হয় supabase functions deploy whatsapp --no-verify-jwt দিয়ে ডিপ্লয় করুন, অথবা supabase/config.toml-এ ফাংশনের সেকশনের নিচে verify_jwt = false দিন। Supabase-এর ডকুমেন্টেশনে ঠিক এই ক্ষেত্রটির কথাই আছে: বাইরের ওয়েবহুক প্রদানকারীর কল করা একটি পাবলিক এন্ডপয়েন্ট।

প্ল্যাটফর্মের যাচাই বন্ধ থাকলে ফাংশনের নিজস্ব একটি যাচাই দরকার। সিগনেচার হেডার এখানে আপনার কাজে আসে না, কারণ Meta সাবস্ক্রিপশনের মালিক অ্যাপের অ্যাপ সিক্রেট দিয়ে সাইন করে। গন্তব্যের URL-এ কোয়েরি প্যারামিটার হিসেবে একটি লম্বা র‍্যান্ডম সিক্রেট রাখুন এবং সেটি ছাড়া আসা রিকোয়েস্ট প্রত্যাখ্যান করুন, যেমন উদাহরণে POST-এ করা হয়েছে।

ফাংশন কীভাবে মেসেজ রাখবে ও উত্তর দেবে?

আগে সংরক্ষণ, পরে উত্তর। WhatsApp মেসেজ আইডির ওপর ইউনিক কনস্ট্রেইন্ট সহ upsert করুন, যাতে Meta-র পুনরায় পাঠানো মেসেজ নতুন সারি না বানিয়ে একই সারিতে বসে। একাধিক নম্বর যদি একই ফাংশনে আসে, প্রতিটি সারিতে গ্রহণকারী phone_number_id রাখুন।

ধীর কাজের জন্য, যেমন উত্তর দেওয়ার আগে কোনো মডেল বা অন্য API কল করা, কাজটি 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 যাচাইকরণ বন্ধ করা। URL যে-ই পাক, টেবিলে ভুয়া মেসেজ পোস্ট করতে পারবে।
EasyCoexistence দিয়ে এটি করা

easycoexistence.com-এ নম্বরটি সংযুক্ত করুন, ওয়েবহুক গন্তব্য হিসেবে Edge Function-এর URL ও আপনার ভেরিফাই টোকেন বসান, আর phone_number_id ও টোকেন ফাংশন সিক্রেট হিসেবে রাখুন। প্রতি নম্বরে মাসে US$ 9 থেকে শুরু, নম্বর বাড়ার সঙ্গে US$ 1 পর্যন্ত কমে, প্রথম 3 দিন ফ্রি।

প্রায়শই জিজ্ঞাসিত প্রশ্ন

এটি কি Supabase-এর ফ্রি প্ল্যানে চলে?

Edge Function ফ্রি প্ল্যানেও চলে, তবে ওয়াল ক্লক সীমা 150 সেকেন্ড, আর পেইড প্ল্যানে 400 সেকেন্ড। দ্রুত সাড়া দেওয়া ওয়েবহুক হ্যান্ডলার দুটো সীমার অনেক ভেতরেই থাকে।

ফাংশনে কি service role কী ব্যবহার করা উচিত?

শুধু সার্ভার-সাইডে, যেমন এখানে, ফাংশনের এনভায়রনমেন্ট থেকে পড়ে। এটি রো লেভেল সিকিউরিটি এড়িয়ে যায়, তাই কখনোই ব্রাউজারে পৌঁছানো চলবে না।

একটি ফাংশন কি একাধিক নম্বর সামলাতে পারে?

হ্যাঁ। প্রতিটি নম্বরের ওয়েবহুক গন্তব্য এতে দিন এবং প্রতিটি পেলোডের phone_number_id দেখে শাখা করুন।

EasyCoexistence কি মেসেজ দেখতে পায়?

না। Meta প্রতিটি ওয়েবহুক সরাসরি আপনার ফাংশনে পাঠায়, আর EasyCoexistence কথোপকথনের কোনো বিষয়বস্তু সংরক্ষণ করে না।

আরও পড়ুন

শুরু করতে প্রস্তুত?

মাস নয়, কয়েক মিনিটেই WhatsApp Coexistence সেট আপ করুন। ফোনে অ্যাপটি কাজ করতে থাকে।

ফ্রি ট্রায়াল শুরু করুন

যাচাই করা হয়েছে

Supabase Edge Function-এ WhatsApp ওয়েবহুক