Clerk Webhook Setup Guide

Overview

This guide explains how to set up and troubleshoot the Clerk webhook that automatically assigns the "waitlist" role to new users upon signup.

Webhook Configuration

1. Create Webhook in Clerk Dashboard

  1. Go to Clerk Dashboard
  2. Navigate to Webhooks in the left sidebar
  3. Click Add Endpoint
  4. Configure the webhook:
    • Endpoint URL: https://your-domain.com/api/webhooks/clerk
    • Events to listen:
      • user.created
      • user.updated
      • user.deleted
  5. Click Create
  6. Copy the Signing Secret (you'll need this for CLERK_WEBHOOK_SECRET)

2. Set Environment Variables

Add the following to your .env.local or Vercel environment variables:

CLERK_WEBHOOK_SECRET="whsec_xxxxxxxxxxxx"  # From Clerk webhook settings
CLERK_SECRET_KEY="sk_test_xxxxxxxxxxxx"    # From Clerk API Keys

3. Verify Webhook is Working

Option 1: Check Webhook Configuration (Admin Only)

curl https://your-domain.com/api/admin/check-webhook-config \
  -H "Cookie: your-auth-cookie"

This endpoint will check:

  • ✅ Environment variables are set
  • ✅ Recent users have waitlist role
  • ✅ Webhook URL configuration

Option 2: Check Clerk Dashboard Logs

  1. Go to Clerk Dashboard > Webhooks
  2. Click on your webhook endpoint
  3. Check the Logs tab for:
    • ✅ Successful deliveries (200 status)
    • ❌ Failed deliveries (check error messages)

Fix Existing Users Without Waitlist Role

1. Dry Run (Check How Many Users Need Fixing)

curl https://your-domain.com/api/admin/fix-missing-waitlist-roles \
  -H "Cookie: your-auth-cookie" \
  -H "Content-Type: application/json" \
  -d '{"dryRun": true, "limit": 10}'

2. Fix Users (Actually Apply the Waitlist Role)

curl https://your-domain.com/api/admin/fix-missing-waitlist-roles \
  -H "Cookie: your-auth-cookie" \
  -H "Content-Type: application/json" \
  -d '{"dryRun": false, "limit": 10}'

Parameters:

  • dryRun: (boolean) If true, only shows what would be changed
  • limit: (number) Maximum number of users to process (default: 10, for safety)

How It Works

  1. New User Signs Up → Clerk creates user account
  2. Clerk Webhook Fires → Sends user.created event to /api/webhooks/clerk
  3. Webhook Handler → Updates user with:
    {
      "publicMetadata": {
        "roles": ["waitlist"],
        "onboardingCompleted": false,
        "createdAt": 1234567890,
        "source": "organic"
      }
    }
  4. User Has Waitlist Role → Can access waitlist-only features

Troubleshooting

Webhook Not Firing

  1. Check Clerk Dashboard Logs: Look for failed deliveries
  2. Verify Environment Variables: Run the check-webhook-config endpoint
  3. Check Network: Ensure your app is publicly accessible
  4. Verify HTTPS: Clerk requires HTTPS for production webhooks

Users Not Getting Waitlist Role

  1. Check Webhook Secret: Must match exactly from Clerk dashboard
  2. Check Permissions: Ensure CLERK_SECRET_KEY has user update permissions
  3. Check Logs: Look for errors in your app logs
  4. Manual Fix: Use the fix-missing-waitlist-roles endpoint

Common Issues

  • 400 Error: Usually means webhook secret is wrong
  • 401 Error: CLERK_SECRET_KEY is invalid
  • No logs in Clerk: Webhook URL might be wrong or app not deployed

Testing Locally

For local development, use ngrok or similar to expose your local server:

# Install ngrok
brew install ngrok

# Start your dev server
pnpm dev

# In another terminal, expose it
ngrok http 3000

# Use the ngrok URL in Clerk webhook settings
# Example: https://abc123.ngrok.io/api/webhooks/clerk

Security Notes

  • Never commit CLERK_WEBHOOK_SECRET to version control
  • The webhook handler verifies signatures to prevent spoofing
  • Only admin users can run the fix-missing-waitlist-roles endpoint
  • Bulk operations are limited to 50 users at a time for safety

On this page