Skip to content

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

  1. Tunnel Service - You need a service that exposes your local server to the internet. Choose one:
  2. ngrok (recommended): https://ngrok.com
  3. Tunnelmole: Simple alternative, install with npm install -g tunnelmole
  4. Cloudflare Tunnel: Free alternative with Cloudflare account
  5. localtunnel: Open source option npm install -g localtunnel

  6. 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

  1. Send a WhatsApp message to the business number from your registered phone
  2. Check your local app logs - you should see the webhook hit /api/sana/webhook
  3. The webhook router will:
  4. Receive the webhook at the router app
  5. Extract your phone number from the payload
  6. Look up your URL in the database
  7. Forward the request to {your-tunnel-url}/api/sana/webhook

Testing SendGrid Webhooks

  1. Send an email to your configured inbound email address
  2. Check your local app logs - you should see the webhook hit /api/email/inbound/webhook
  3. The webhook router will:
  4. Receive the webhook at the router app
  5. Extract the recipient email from the payload
  6. Look up your URL in the database
  7. 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

  1. Tunnel URLs Change - Most free tunnel services generate new URLs on restart. Remember to update your database entry when this happens.

  2. One Route Per Identifier - Each phone number and email can only have one active route. Coordinate with your team if sharing test numbers/emails.

  3. Security - The webhook router uses the Supabase service role to bypass RLS. Never expose your tunnel URL publicly.

  4. Local App Must Be Running - Ensure your local development server is running before testing webhooks.

  5. 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 = true for 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/webhook for WhatsApp
  • /api/email/inbound/webhook for 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:

  1. Temporarily modify the webhook URL in the external service (WhatsApp/SendGrid)
  2. Point it directly to your tunnel URL
  3. Remember to change it back! This affects all developers

However, the database routing approach is strongly recommended for team development.