Skip to main content

Source: ocean/docs/WEBHOOK_TESTING_BEST_PRACTICES.md | ✏️ Edit on GitHub

Webhook Testing Best Practices

1. Use Official CLI Tools

Stripe CLI for Local Testing

# Install Stripe CLI
brew install stripe/stripe-cli/stripe

# Login to Stripe
stripe login

# Forward webhooks to local endpoint
stripe listen --forward-to localhost:3000/api/webhooks/stripe

# Trigger test events
stripe trigger customer.created

Cloudflare Wrangler for Local Development

# Run worker locally
pnpm wrangler dev --env staging

# Tail production logs
pnpm wrangler tail --env production

2. Environment-Based Testing

Local Development

  • Use Stripe CLI to forward webhooks to local endpoints
  • Use wrangler dev to test Cloudflare Workers locally
  • Mock Supabase triggers with local test scripts

Staging Environment

  • Use real webhook endpoints (e.g., https://ocean-stripe-webhook.staging.goldfish.io)
  • Use test API keys (Stripe test mode, Supabase staging project)
  • Monitor with logging services

Production Environment

  • Use monitoring and alerting (Sentry, Datadog, etc.)
  • Implement webhook signature verification
  • Add retry logic and idempotency

3. Testing Strategies

Unit Tests

// Test webhook payload parsing
describe('parseStripeWebhook', () => {
it('should parse customer.created event', () => {
const payload = {
/* mock payload */
}
const result = parseStripeWebhook(payload)
expect(result.customerId).toBeDefined()
})
})

Integration Tests

// Test with real API calls but test keys
describe('Stripe Integration', () => {
it('should create customer in Stripe', async () => {
const customer = await stripe.customers.create({
email: 'test@example.com',
metadata: { supabase_user_id: 'test-123' },
})
expect(customer.id).toMatch(/^cus_/)
})
})

End-to-End Tests

// Test complete flow with test data
describe('Signup Flow E2E', () => {
it('should sync user from Supabase to Stripe', async () => {
// 1. Create user in Supabase
// 2. Wait for webhook
// 3. Verify customer in Stripe
})
})

4. Webhook Security

Always Verify Signatures

const sig = request.headers.get('stripe-signature')
const event = stripe.webhooks.constructEvent(rawBody, sig, process.env.STRIPE_WEBHOOK_SECRET)

Implement Idempotency

// Store processed event IDs
const processed = await kv.get(`webhook:${event.id}`)
if (processed) return { status: 200, body: 'Already processed' }

Add Rate Limiting

// Use Cloudflare rate limiting or implement custom logic
const rateLimiter = new RateLimiter({
windowMs: 60000, // 1 minute
max: 100, // limit each IP to 100 requests per minute
})

5. Monitoring and Debugging

Structured Logging

console.log(
JSON.stringify({
event: 'webhook_received',
type: event.type,
customer_id: event.data.object.id,
timestamp: new Date().toISOString(),
environment: process.env.ENVIRONMENT,
})
)

Use Webhook Dashboards

  • Stripe Dashboard → Developers → Webhooks → View logs
  • Cloudflare Dashboard → Workers → View logs
  • Supabase Dashboard → Logs → Edge logs

Implement Health Checks

// Add endpoint to verify webhook is responsive
if (request.url.includes('/health')) {
return new Response('OK', { status: 200 })
}

6. Testing Commands

Manual Testing with cURL

# Test webhook endpoint directly
curl -X POST https://ocean-stripe-webhook.staging.goldfish.io \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_SECRET" \
-d '{"type":"INSERT","table":"users","record":{"id":"test-123","email":"test@example.com"}}'

Stripe CLI Testing

# Listen and forward to staging
stripe listen --forward-to https://ocean-stripe-webhook.staging.goldfish.io

# Trigger specific events
stripe trigger customer.created
stripe trigger customer.updated

Database Testing

-- Manually trigger Supabase function
SELECT webhook_sync_user_to_stripe();

-- Check pg_net request logs
SELECT * FROM net._http_response ORDER BY created DESC LIMIT 10;

7. Common Pitfalls to Avoid

  1. Never hardcode secrets - Always use environment variables
  2. Don't skip signature verification - Security risk
  3. Avoid synchronous processing - Use queues for heavy operations
  4. Don't trust webhook data - Always validate and sanitize
  5. Never expose internal IDs - Map to external references
  • Stripe CLI: Official tool for webhook testing
  • ngrok: Expose local endpoints for testing
  • Postman/Insomnia: API testing with webhook simulation
  • Jest/Vitest: Unit and integration testing
  • Playwright: E2E testing including webhook flows