Kirjaudu sisäänAloita ilmainen kokeilu
Meta Tech Provider

WhatsApp-webhookien vastaanotto Supabase Edge Functionissa

Supabase Edge Function voi toimia numeron webhook-kohteena suoraan. Se vastaa Metan vahvistus-GET-pyyntöön hub.challenge-arvolla, lisää jokaisen POST-pyynnöllä tulleen viestin Postgres-tauluun ja vastaa Cloud API:n kautta. Julkaise funktio JWT-vahvistus pois päältä, koska Supabase vaatii oletuksena voimassa olevan JWT:n, eikä Meta voi lähettää sellaista.

verify_jwt = true

Supabasen oletus Edge Functioneille: se hylkää jokaisen pyynnön, jolla ei ole voimassa olevaa JWT:tä, ennen kuin käsittelijäsi ajetaan.

--no-verify-jwt

supabase functions deploy -komennon lippu, joka poistaa funktiolta JWT-vahvistuksen.

150 s

Edge Functionin pyynnön joutoaikaraja; jos vastausta ei ole tähän mennessä, palautuu 504.

Mitä Edge Functionin täytyy tehdä?

Kaksi asiaa, kahdella metodilla.

GET-pyynnössä funktio vastaa Metan vahvistukseen. Lue hub.mode, hub.verify_token ja hub.challenge kyselymerkkijonosta, vertaa tokenia siihen, jonka annoit kohteen vahvistustokeniksi, ja palauta challenge pelkkänä tekstinä tilakoodilla 200. Palauta 403, jos token ei täsmää.

POST-pyynnössä funktio vastaanottaa tapahtumat. Jäsennä runko, poimi viestit kentistä entry, changes ja value, lisää ne tauluun ja palauta 200. Pidä vastaus nopeana: Meta pitää hidasta tai epäonnistunutta vastausta epäonnistuneena toimituksena ja yrittää uudelleen, jolloin sama viesti tulee kahdesti.

Aseta funktion URL-osoite numeron webhook-kohteeksi EasyCoexistencessä samalla vahvistustokenilla, niin Meta alkaa toimittaa viestejä.

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");
});

Miksi funktio palauttaa Metalle 401?

Koska JWT-vahvistus on päällä. Supabase tarkistaa Authorization-otsakkeessa olevan JWT:n ennen kuin Edge Functionin käsittelijä ajetaan, ja tämä on oletus jokaiselle funktiolle. Meta ei lähetä tällaista otsaketta, joten alusta hylkää sekä vahvistus-GET-pyynnön että jokaisen toimituksen, eikä koodisi näe niitä koskaan.

Poista vahvistus käytöstä vain tältä funktiolta. Julkaise komennolla supabase functions deploy whatsapp --no-verify-jwt tai aseta verify_jwt = false funktion osioon tiedostossa supabase/config.toml. Supabasen dokumentaatio kuvaa juuri tämän tapauksen: julkinen endpoint, jota kutsuu ulkopuolinen webhook-palveluntarjoaja.

Kun alustan tarkistus on pois, funktiolla on oltava oma tarkistus. Allekirjoitusotsake ei ole käytettävissäsi, koska Meta allekirjoittaa tilauksen omistavan sovelluksen salaisella avaimella. Laita pitkä satunnainen salaisuus kohteen URL-osoitteeseen kyselyparametriksi ja hylkää pyynnöt ilman sitä, kuten esimerkki tekee POST-pyynnössä.

Miten funktion kannattaa tallentaa ja vastata?

Tallenna ensin, vastaa myöhemmin. Käytä upsertia WhatsAppin viestin id:llä ja yksilöllisyysrajoitetta, jolloin Metan uudelleenyritykset osuvat samalle riville eivätkä luo kaksoiskappaletta. Säilytä vastaanottavan numeron phone_number_id jokaisella rivillä, jos useampi numero osoittaa samaan funktioon.

Jos työ on hidasta, esimerkiksi mallin tai toisen API:n kutsuminen ennen vastaamista, anna se EdgeRuntime.waitUntil-kutsulle ja palauta vastaus heti. Funktio jatkaa ajoa, kunnes lupaus ratkeaa, ja Meta on jo saanut 200-vastauksensa. Supabase lopettaa odottamisen 150 sekunnin joutoajan jälkeen ja palauttaa 504:n, joten käsittelijä, joka tekee kaiken työnsä ennen vastaamista, aiheuttaa todennäköisimmin uudelleenyrityksiä.

Vastaukset lähtevät Cloud API:n messages-endpointiin numeron phone number id:llä ja tokenilla, jotka on tallennettu funktion salaisuuksina. Asiakkaan viimeisestä viestistä 24 tunnin sisällä voi lähettää vapaata tekstiä; sen jälkeen vain hyväksytty viestipohja menee perille.

Päätyvätkö puhelimesta lähetetyt viestit funktiolle?

Kyllä. Coexistence-numerolla WhatsApp Business -sovellus toimii edelleen, ja kun joku vastaa siitä, Meta toimittaa kaiun lähteneestä viestistä samaan kohteeseen kentän smb_message_echoes alla ja message_echoes-taulukossa, ei messages-taulukossa.

Laajenna jäsennin lukemaan molemmat ja tallenna direction-sarake. Taulu sisältää silloin koko keskustelun, sekä asiakkaan rivit että yrityksen vastaukset, mitä useimmat haluavat kysellä jälkikäteen: vastausajat, vastaamattomat keskustelut ja kunkin kontaktin viimeisen saapuneen viestin aika.

Tämä viimeinen arvo on myös syöte jokaiselle lähetyspolulle, koska se ratkaisee, voiko vastaus olla vapaata tekstiä vai onko pakko käyttää viestipohjaa. Taulun päälle tehty näkymä voi tarjota sen kontaktikohtaisesti muulle sovellukselle.

Yleiset virheet

  • Julkaisu JWT-vahvistus päällä. Supabase hylkää Metan pyynnöt 401-vastauksella ennen käsittelijää, eikä yhtään viestiä saavu perille.
  • Challengen palauttaminen JSONiin käärittynä. Meta tarvitsee raa'an arvon vastauksen runkona, muuten vahvistus epäonnistuu äänettömästi.
  • Hitaan työn tekeminen ennen vastaamista. Meta yrittää uudelleen sen, minkä se näkee epäonnistumisena, ja sama viesti käsitellään kahdesti.
  • JWT-vahvistuksen poistaminen ilman omaa tarkistusta. Kuka tahansa, joka löytää URL-osoitteen, voi lähettää tauluun väärennettyjä viestejä.
Näin teet tämän EasyCoexistencen avulla

Yhdistä numero osoitteessa easycoexistence.com, aseta sen webhook-kohteeksi Edge Functionin URL-osoite vahvistustokenillasi ja tallenna phone number id ja token funktion salaisuuksiksi. Hinta alkaen US$ 9 per numero kuukaudessa, laskien US$ 1:een numeroiden määrän kasvaessa, ensimmäiset 3 päivää ilmaiseksi.

Usein kysytyt kysymykset

Toimiiko tämä Supabasen ilmaisella paketilla?

Edge Functionit toimivat ilmaisella paketilla, jossa seinäkellon aikaraja on 150 sekuntia, kun maksullisilla paketeilla se on 400 sekuntia. Nopeasti vastaava webhook-käsittelijä pysyy reilusti kummankin rajan sisällä.

Pitäisikö funktiossa käyttää service role -avainta?

Vain palvelinpuolella, kuten tässä, luettuna funktion ympäristöstä. Se ohittaa rivitason suojauksen, joten se ei saa koskaan päätyä selaimeen.

Voiko yksi funktio palvella useita numeroita?

Kyllä. Osoita jokaisen numeron webhook-kohde siihen ja haaraudu kunkin payloadin phone_number_id:n mukaan.

Näkeekö EasyCoexistence viestit?

Ei. Meta toimittaa jokaisen webhookin suoraan funktioosi, eikä EasyCoexistence tallenna keskustelun sisältöä.

Lue lisää

Valmis aloittamaan?

Ota WhatsApp Coexistence käyttöön minuuteissa, ei kuukausissa. Sovellus toimii edelleen puhelimessa.

Aloita ilmainen kokeilu

Vahvistettu

WhatsApp-webhookit Supabase Edge Functionissa