Primanje WhatsApp webhookova u Supabase Edge funkciji
Supabase Edge funkcija može direktno biti webhook odredište broja. Na verifikacioni GET od Mete odgovara vrednošću hub.challenge, svaku poruku primljenu preko POST-a upisuje u Postgres tabelu i odgovara preko Cloud API-ja. Postavite je sa isključenom JWT verifikacijom, jer Supabase podrazumevano zahteva važeći JWT, a Meta ne može da ga pošalje.
Podrazumevano podešavanje Supabasea za Edge funkcije: odbija svaki zahtev bez važećeg JWT-a pre nego što se izvrši vaš handler.
Zastavica komande supabase functions deploy koja isključuje JWT verifikaciju za funkciju.
Ograničenje neaktivnosti zahteva za Edge funkciju; ako odgovora nema do tada, vraća se 504.
Šta Edge funkcija mora da radi?
Dve stvari, na dve metode.
Na GET-u odgovara na Metinu verifikaciju. Pročitajte hub.mode, hub.verify_token i hub.challenge iz query stringa, uporedite token sa onim koji ste uneli kao verify token odredišta i vratite challenge kao običan tekst sa statusom 200. Ako se token ne poklapa, vratite 403.
Na POST-u prima događaje. Parsirajte telo, izvucite poruke iz entry, changes i value, upišite ih u tabelu i vratite 200. Odgovor držite brzim: Meta sporu ili neuspelu isporuku smatra neuspehom i ponavlja je, što znači da ista poruka stiže dvaput.
URL funkcije podesite kao webhook odredište broja u EasyCoexistence, sa istim verify tokenom, i Meta počinje da isporučuje.
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");
});Zašto funkcija vraća 401 Meti?
Zato što je JWT verifikacija uključena. Supabase proverava JWT u zaglavlju Authorization pre nego što se izvrši handler Edge funkcije, i to je podrazumevano za svaku funkciju. Meta ne šalje takvo zaglavlje, pa platforma odbija i verifikacioni GET i svaku isporuku, a vaš kod ih nikad ne vidi.
Isključite je samo za ovu funkciju. Postavite je sa supabase functions deploy whatsapp --no-verify-jwt ili podesite verify_jwt = false u odeljku funkcije u supabase/config.toml. Supabase dokumentacija opisuje upravo ovaj slučaj: javni endpoint koji poziva spoljni webhook provajder.
Kad je provera platforme isključena, funkciji treba sopstvena. Zaglavlje sa potpisom vam nije dostupno, jer Meta potpisuje tajnom aplikacije koja poseduje pretplatu. Stavite dugačku nasumičnu tajnu u URL odredišta kao query parametar i odbijte zahteve bez nje, kao što primer radi na POST-u.
Kako funkcija treba da čuva poruke i odgovara?
Prvo sačuvajte, odgovorite posle. Radite upsert po id-ju WhatsApp poruke sa unique ograničenjem, tako da se Metina ponovna slanja upisuju u isti red umesto da prave duplikat. Čuvajte phone_number_id primaoca u svakom redu ako na funkciju pokazuje više brojeva.
Za sve što je sporo, na primer poziv modela ili drugog API-ja pre odgovora, prepustite posao funkciji EdgeRuntime.waitUntil i odmah vratite odgovor. Funkcija nastavlja da radi dok se taj promise ne završi, a Meta je već dobila svoj 200. Supabase prestaje da čeka posle 150 sekundi neaktivnosti i vraća 504, pa je handler koji sav posao obavi pre odgovora najverovatniji uzrok ponovnih slanja.
Odgovori idu na messages endpoint Cloud API-ja sa phone number id-jem i tokenom broja, sačuvanim kao tajne funkcije. U roku od 24 sata od poslednje poruke kupca isporučuje se slobodan tekst; van tog roka samo odobren šablon.
Stižu li poruke poslate sa telefona do funkcije?
Da. Na Coexistence broju aplikacija WhatsApp Business nastavlja da radi, a kad neko odgovori iz nje, Meta isporučuje odjek te odlazne poruke na isto odredište, u polju smb_message_echoes i nizu message_echoes umesto messages.
Proširite parser da čita oba i čuvajte kolonu direction. Tabela tada sadrži celu konverzaciju, kupčeve poruke i odgovore firme, a to je ono što većina ljudi posle želi da upita: vreme odgovora, neodgovorene razgovore, vreme poslednje dolazne poruke po kontaktu.
Ta poslednja vrednost je ujedno ulaz za svaki put slanja, jer odlučuje da li odgovor može biti slobodan tekst ili mora biti šablon. View nad tabelom može da je izloži po kontaktu ostatku vaše aplikacije.
Česte greške
- Postavljanje sa uključenom JWT verifikacijom. Supabase odbija Metine zahteve sa 401 pre nego što se izvrši handler i nijedna poruka ne stiže.
- Vraćanje challengea umotanog u JSON. Meta traži sirovu vrednost kao telo odgovora, inače verifikacija tiho propada.
- Spor posao pre odgovora. Meta ponavlja ono što vidi kao neuspeh i ista poruka se obrađuje dvaput.
- Isključivanje JWT verifikacije bez ikakve sopstvene provere. Svako ko pronađe URL može da upiše lažne poruke u tabelu.
Povežite broj na easycoexistence.com, podesite njegovo webhook odredište na URL Edge funkcije uz vaš verify token, a phone number id i token sačuvajte kao tajne funkcije. Od US$ 9 po broju mesečno, do US$ 1 kako dodajete brojeve, uz prva 3 dana besplatno.
Često postavljana pitanja
Radi li ovo na besplatnom Supabase planu?
Edge funkcije rade na besplatnom planu, sa ograničenjem od 150 sekundi u odnosu na 400 sekundi na plaćenim planovima. Webhook handler koji brzo odgovara ostaje daleko ispod oba.
Treba li u funkciji da koristim service role key?
Samo na serverskoj strani, kao ovde, čitan iz okruženja funkcije. On zaobilazi row level security, pa nikad ne sme da dospe u pregledač.
Može li jedna funkcija da opslužuje više brojeva?
Da. Usmerite webhook odredište svakog broja na nju i grananje radite po phone_number_id u svakom payloadu.
Vidi li EasyCoexistence poruke?
Ne. Meta isporučuje svaki webhook direktno vašoj funkciji, a EasyCoexistence nikad ne čuva sadržaj konverzacija.
Nastavite sa čitanjem
Spremni da počnete?
Podesite WhatsApp Coexistence za nekoliko minuta, a ne meseci. Aplikacija nastavlja da radi na telefonu.
Započnite besplatni probni periodProvereno na