Webhooks Configuration
Set up inbound webhooks from Twilio, Stripe, and HubSpot to power real-time lead capture, billing, and CRM sync.
🔔 Required Webhook Endpoints
Twilio SMS Webhook
Receives inbound SMS replies and delivery status updates
/api/webhooks/twilio/sms- Inbound SMS (lead replies)
- Delivery receipts (sent/delivered/failed)
▶Example Payload
{
"MessageSid": "SMxxxxxxxxxxxx",
"From": "+12145550132",
"To": "+12145550199",
"Body": "Yes, I need service tomorrow",
"MessageStatus": "received",
"ApiVersion": "2010-04-01"
}Twilio Voice Webhook
Receives missed call notifications and AI voice callback events
/api/webhooks/twilio/voice- Incoming call (no-answer, busy, failed)
- Call completed (for AI voice callbacks)
- Recording/transcription ready
▶Example Payload
{
"CallSid": "CAxxxxxxxxxxxx",
"From": "+12145550132",
"To": "+12145550199",
"CallStatus": "no-answer",
"Direction": "inbound",
"CallerName": "Marcus T.",
"ForwardedFrom": "+12145550199"
}Stripe Webhook
Handles subscription lifecycle, payments, and billing events
/api/webhooks/stripe- customer.subscription.created/updated/deleted
- invoice.payment_succeeded/failed
- checkout.session.completed
- customer.updated
▶Example Payload
{
"id": "evt_xxxxxxxxxxxx",
"type": "customer.subscription.updated",
"data": {
"object": {
"id": "sub_xxxxxxxxxxxx",
"customer": "cus_xxxxxxxxxxxx",
"status": "past_due",
"current_period_end": 1704931200
}
}
}HubSpot Webhook
Receives contact/deal updates from HubSpot for two-way sync
/api/webhooks/hubspot- Contact property changes
- Deal stage changes
- New contact/deal created
▶Example Payload
{
"subscriptionType": "contact.propertyChange",
"objectId": 12345,
"propertyName": "phone",
"propertyValue": "+12145550132",
"changeSource": "CRM_UI"
}📋 Setup Checklist
Get Your Ringback Webhook URLs
All webhook endpoints are under /api/webhooks/. Note the full URLs (e.g., https://yourapp.com/api/webhooks/twilio/sms).
Configure in Provider Dashboard
Paste each URL into the corresponding provider's webhook settings. See table above for exact locations.
Enable Required Events
Select only the events listed above. Extra events increase noise and processing time.
Set Signature Secrets
Twilio: Copy Auth Token from Console. Stripe: Copy Webhook Signing Secret. HubSpot: Copy Client Secret.
Test Each Webhook
Use provider's 'Test Webhook' button or trigger a real event (missed call, SMS reply, subscription change).
Verify in Ringback
Check Supabase ring_webhook_event table — each received webhook logs with processed_at timestamp.
🛠️ Local Development Testing
- Use ngrok/cloudflared for local tunnel: ngrok http 3000
- Update webhook URLs in provider dashboards to https://xxx.ngrok.io/api/webhooks/...
- Set env vars: TWILIO_AUTH_TOKEN, STRIPE_WEBHOOK_SECRET, HUBSPOT_CLIENT_SECRET
- Trigger test events: Twilio 'Test Webhook', Stripe CLI 'stripe trigger', HubSpot test button
- Check terminal logs for webhook receipt and processing
🔧 Troubleshooting
Webhook not receiving requests
- URL is publicly accessible (no localhost, no auth, no VPN)
- HTTPS with valid cert (Let's Encrypt OK)
- Provider firewall/IP allowlist includes your domain
- Correct HTTP method (POST) and path
Signature verification fails
- Twilio: Using Auth Token (not Account SID) from correct project
- Stripe: Using Webhook Signing Secret (whsec_...) from Stripe Dashboard
- HubSpot: Using Client Secret from App settings
- Raw request body used for verification (no middleware parsing before validation)
Webhook received but lead not created
- Check ring_webhook_event table — status=processed means Ringback handled it
- Verify phone_number_id exists and is verified
- Check ring_lead table for new records
- Twilio: Ensure CallStatus is 'no-answer', 'busy', or 'failed' (not 'completed')
Duplicate webhook processing
- ring_webhook_event.idempotency_key prevents duplicates
- Key format: {provider}:{event_type}:{resource_id}
- If duplicates persist, check provider retry settings (disable if possible)
Stripe webhook: subscription not updating
- Event type is customer.subscription.updated (not invoice.payment_succeeded)
- Customer metadata has ringback_user_id linked
- Check ring_crm_sync_log for sync errors
🔑 Idempotency & Retries
All webhooks are idempotent. Ringback stores idempotency_key in ring_webhook_event table.
Key format: provider:event_type:resource_id
Example: twilio:sms:SMxxxxxxxxxxxx
Retries: If your endpoint returns 5xx or times out (over 10s), provider retries with exponential backoff. Ringback processes each unique key only once — safe to retry.
Manual replay: In Supabase, find the event in ring_webhook_event, copy payload, POST to webhook URL with same signature.