Docs/Reference/Webhooks

Webhooks

Neofir consumes webhooks from four third parties. Each is signature-verified before processing, with explicit deduplication where the provider sends retries.

Meta (Instagram & Messenger)

Endpoint: POST /v1/webhooks/instagram, POST /v1/webhooks/messenger.

Verification: X-Hub-Signature-256 validated against META_APP_SECRET using HMAC-SHA256 on the raw body.

Setup challenge: GET /v1/webhooks/{ig|messenger}?hub.mode=subscribe&hub.verify_token=...&hub.challenge=... — the route returns the challenge string when the token matches IG_VERIFY_TOKEN.

Dedup: Each event carries an mid (message id); we store seen mids for 24 hours and drop duplicates.

Handler: Looks up the org by recipient page id, calls processInboundMessage(), sends the reply through the Send API.

Twilio (WhatsApp)

Endpoint: POST /v1/webhooks/whatsapp-twilio.

Verification: Twilio's X-Twilio-Signature; canonical URL + sorted form params hashed with the account auth token.

Handler: Looks up the org by To phone (the sender), parses From as the visitor, dispatches into the same pipeline.

Reply: Outbound via POST https://api.twilio.com/2010-04-01/Accounts/{SID}/Messages.json.

Stripe

Endpoint: POST /v1/webhooks/stripe.

Verification: Stripe-Signature header verified against STRIPE_WEBHOOK_SECRET.

Handled events:

Google Calendar

Push notifications via Google's Calendar push channel. Currently only outbound writes happen; inbound push is reserved for a future reverse-sync feature. The endpoint exists but is a no-op until reverse sync ships.

Supabase auth hooks

Neofir uses Supabase's Send Email Hook and Send SMS Hook to route Supabase Auth's transactional messages through Resend (email) and Twilio (SMS) so that they appear from noreply@neofir.com.

EndpointHookVerifies
POST /v1/auth/email-otp-hooksend_emailStandard Webhooks HMAC + SUPABASE_EMAIL_HOOK_SECRET.
POST /v1/auth/sms-hooksend_smsStandard Webhooks HMAC + SUPABASE_SMS_HOOK_SECRET.

Error handling

Every webhook handler responds 200 OK after the third party's expected acknowledgement (challenge response or empty body). Background processing failures are logged with the inbound payload id and the request id, but never fail the webhook handshake — that would trigger aggressive retries from the provider.