Webhook Routing Setup for Local Development¶
This guide explains how to set up webhook routing to receive SendGrid and WhatsApp webhooks on your local development environment.
Overview¶
When developing locally, you need to receive webhooks from external services (SendGrid for email, WhatsApp for messaging). Since these services can't directly reach your localhost, we use a webhook routing system that forwards requests to your local environment via a tunnel URL.
Prerequisites¶
- Tunnel Service - You need a service that exposes your local server to the internet. Choose one:
- ngrok (recommended): https://ngrok.com
- Tunnelmole: Simple alternative, install with
npm install -g tunnelmole - Cloudflare Tunnel: Free alternative with Cloudflare account
-
localtunnel: Open source option
npm install -g localtunnel -
Database Access - You need access to the staging database to add your routing entry
Step 1: Set Up Your Tunnel¶
Option A: Using ngrok¶
# Install ngrok (if not already installed)
# Download from https://ngrok.com/download
# Start ngrok tunnel for your local app (usually port 3000)
ngrok http 3000
# You'll see output like:
# Forwarding https://abc123.ngrok-free.app -> http://localhost:3000
Option B: Using Tunnelmole (tmole)¶
# Install tunnelmole
npm install -g tunnelmole
# Start tunnel for your local app
tmole 3000
# You'll see output like:
# https://xyz789.tunnelmole.net is forwarding to localhost:3000
Option C: Using Cloudflare Tunnel¶
# Install cloudflared
# See: https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/install-and-setup/
# Start tunnel
cloudflared tunnel --url http://localhost:3000
# You'll see output like:
# https://random-name.trycloudflare.com
Step 2: Add Your Route to the Database¶
Once you have your tunnel URL, add an entry to the dev_webhook_routes table in the staging database:
-- Connect to staging database via Supabase dashboard or your preferred SQL client
-- Complete insert example with all fields
INSERT INTO dev_webhook_routes (id, name, mobile_number, email, url, is_active, created_at, updated_at)
VALUES (
gen_random_uuid(), -- Auto-generate UUID
'Your Name', -- Your identifier
'+447700900123', -- Your WhatsApp test number (optional)
'yourname@example.com', -- Your SendGrid test email (optional)
'https://abc123.ngrok-free.app', -- Your tunnel URL (without trailing slash)
true, -- Active by default
NOW(), -- Current timestamp
NOW() -- Current timestamp
);
-- Simplified insert (recommended - uses defaults)
INSERT INTO dev_webhook_routes (name, mobile_number, email, url)
VALUES (
'Your Name', -- Your identifier
'+447700900123', -- Your WhatsApp test number (optional)
'yourname@example.com', -- Your SendGrid test email (optional)
'https://abc123.ngrok-free.app' -- Your tunnel URL (without trailing slash)
);
-- You can specify either mobile_number, email, or both depending on which webhooks you need
Examples:¶
For WhatsApp webhooks only:
INSERT INTO dev_webhook_routes (name, mobile_number, url)
VALUES ('John Dev', '+447700900123', 'https://abc123.ngrok-free.app');
For SendGrid webhooks only:
INSERT INTO dev_webhook_routes (name, email, url)
VALUES ('Jane Dev', 'jane@example.com', 'https://xyz789.tunnelmole.net');
For both webhooks:
INSERT INTO dev_webhook_routes (name, mobile_number, email, url)
VALUES ('Bob Dev', '+447700900456', 'bob@example.com', 'https://def456.trycloudflare.com');
Step 3: Test Your Setup¶
Testing WhatsApp Webhooks¶
- Send a WhatsApp message to the business number from your registered phone
- Check your local app logs - you should see the webhook hit
/api/sana/webhook - The webhook router will:
- Receive the webhook at the router app
- Extract your phone number from the payload
- Look up your URL in the database
- Forward the request to
{your-tunnel-url}/api/sana/webhook
Testing SendGrid Webhooks¶
- Send an email to your configured inbound email address
- Check your local app logs - you should see the webhook hit
/api/email/inbound/webhook - The webhook router will:
- Receive the webhook at the router app
- Extract the recipient email from the payload
- Look up your URL in the database
- Forward the request to
{your-tunnel-url}/api/email/inbound/webhook
Managing Your Routes¶
View your active routes:¶
SELECT * FROM dev_webhook_routes WHERE name = 'Your Name';
Update your tunnel URL (when ngrok restarts):¶
UPDATE dev_webhook_routes
SET url = 'https://new-url.ngrok-free.app', updated_at = NOW()
WHERE name = 'Your Name';
Temporarily disable your route:¶
UPDATE dev_webhook_routes
SET is_active = false, updated_at = NOW()
WHERE name = 'Your Name';
Delete your route:¶
DELETE FROM dev_webhook_routes WHERE name = 'Your Name';
Important Notes¶
-
Tunnel URLs Change - Most free tunnel services generate new URLs on restart. Remember to update your database entry when this happens.
-
One Route Per Identifier - Each phone number and email can only have one active route. Coordinate with your team if sharing test numbers/emails.
-
Security - The webhook router uses the Supabase service role to bypass RLS. Never expose your tunnel URL publicly.
-
Local App Must Be Running - Ensure your local development server is running before testing webhooks.
-
Validation Happens Locally - The router doesn't validate webhooks. All signature verification and validation happens in your local app, just like in production.
Troubleshooting¶
Webhook not reaching local app:¶
- Check tunnel is running and URL is correct in database
- Verify
is_active = truefor your route - Check phone number/email matches exactly (including country code for phones)
- Look at router app logs (if accessible) for forwarding errors
Getting 404 errors:¶
- Ensure your local app is running on the expected port
- Verify the webhook endpoints exist in your local app:
/api/sana/webhookfor WhatsApp/api/email/inbound/webhookfor SendGrid
Tunnel keeps disconnecting:¶
- Consider using a paid ngrok account for stable URLs
- Try alternative tunnel services if one is unreliable
- Some corporate networks block tunnel services - try a different network
Alternative Setup (Without Database)¶
If you need a quick test without database setup, you can:
- Temporarily modify the webhook URL in the external service (WhatsApp/SendGrid)
- Point it directly to your tunnel URL
- Remember to change it back! This affects all developers
However, the database routing approach is strongly recommended for team development.