Webhooks
Webhook integrations — Stripe payment events, Twilio SMS delivery, and Sendro email tracking with signature verification.
Webhooks
NextRoute processes incoming webhooks from three external services: Stripe (payments), Twilio (SMS delivery), and Sendro (email delivery). These webhooks keep your data in sync with external payment and communication platforms.
Stripe Webhooks
Endpoint
POST https://api.nextroute.app/api/webhooks/stripeThis endpoint receives events from Stripe and processes them to update invoice statuses, create payment records, manage subscriptions, and handle refunds.
Signature Verification
Every Stripe webhook is verified using the Stripe-Signature header and your STRIPE_WEBHOOK_SECRET. If the signature is invalid or missing, the request is rejected with a 400 status.
Configure the webhook secret in your environment:
STRIPE_WEBHOOK_SECRET=whsec_xxxxxxxxxxxxxxxxxxxxxSupported Events
| Event | Action |
|---|---|
invoice.paid | Marks the matching invoice as paid, creates a payment record |
invoice.payment_failed | Marks the matching invoice as overdue |
payment_intent.succeeded | Marks invoice as paid, creates payment record with card details |
payment_intent.payment_failed | Updates payment record status to failed |
customer.subscription.updated | Updates tenant subscription status and customer billing status |
customer.subscription.deleted | Sets tenant and customer status to canceled |
checkout.session.completed | Links the Stripe subscription to the tenant after checkout |
setup_intent.succeeded | Saves the payment method (card brand, last4, expiry) to the customer |
charge.refunded | Updates payment status to refunded or partially_refunded, updates invoice if fully refunded |
Event Processing Details
invoice.paid
When Stripe confirms an invoice is paid:
- The matching NextRoute invoice is looked up by
stripe_payment_intent_id - The invoice status is set to
paidandpaid_atis recorded - A
paymentrecord is created with the Stripe payment intent ID - Card details (brand, last4) and receipt URL are saved if available
- Duplicate payments are prevented by checking for existing records
payment_intent.succeeded
For direct payment intents (e.g., Tap to Pay):
- The invoice is looked up by
stripe_payment_intent_id - Card details are extracted from the charge object
- Payment method type is determined (
tap_to_payfor card-present,stripe_onlineotherwise) - If no matching invoice is found, the system falls back to matching by
stripe_customer_id
setup_intent.succeeded
When a customer saves a payment method:
- The payment method details are fetched from Stripe
- Card brand, last4, and expiry are stored in
customer_payment_method - If this is the customer's first payment method, it is automatically set as default
charge.refunded
Handles both full and partial refunds:
- Full refund (refunded amount >= total): payment status =
refunded, invoice status =refunded - Partial refund: payment status =
partially_refunded, refund amount is recorded
Configuring Stripe Webhooks
In your Stripe Dashboard:
- Go to Developers > Webhooks
- Click Add endpoint
- Set the URL to
https://api.nextroute.app/api/webhooks/stripe - Select the events listed above
- Copy the Signing secret and set it as
STRIPE_WEBHOOK_SECRET
Twilio Webhooks (SMS Delivery)
Endpoint
POST https://api.nextroute.app/api/webhooks/twilioReceives SMS delivery status updates from Twilio and maps them to NextRoute communication log statuses.
Status Mapping
| Twilio Status | NextRoute Status |
|---|---|
queued | pending |
sending | pending |
sent | sent |
delivered | delivered |
failed | failed |
undelivered | failed |
The webhook matches messages using the MessageSid (or SmsSid) field and updates the corresponding communication_log record.
Configuring Twilio Webhooks
In your Twilio Console:
- Go to Phone Numbers > Active Numbers
- Select your number
- Under Messaging, set the status callback URL to
https://api.nextroute.app/api/webhooks/twilio
Sendro Webhooks (Email Delivery)
Endpoint
POST https://api.nextroute.app/api/webhooks/sendroReceives email delivery status updates from Sendro and updates communication log records.
Signature Verification
Sendro webhooks are verified using HMAC-SHA256. The raw request body is signed with your SENDRO_WEBHOOK_SECRET, and the result is compared against the X-Webhook-Signature header.
The expected signature format is:
v1=<hex-encoded HMAC-SHA256>Configure the secret in your environment:
SENDRO_WEBHOOK_SECRET=your_sendro_webhook_secretSupported Events
| Sendro Event | NextRoute Status |
|---|---|
email.delivered | delivered |
email.bounced | bounced |
email.failed | failed |
email.opened | opened |
email.complained | complained |
Payload Format
{
"type": "email.delivered",
"emailId": "msg_abc123"
}The emailId is matched against the external_id field in the communication_log table.
Security Best Practices
- Always verify signatures — never process webhooks without verifying the signature. All three webhook endpoints enforce verification.
- Use HTTPS — webhook URLs must use HTTPS to prevent man-in-the-middle attacks.
- Idempotency — webhook handlers check for existing records before creating duplicates. Events may be delivered more than once.
- Return 200 quickly — all webhook handlers return a
200status to acknowledge receipt, even if downstream processing encounters errors. This prevents unnecessary retries.
Retry Behavior
| Service | Retry policy |
|---|---|
| Stripe | Retries up to 3 days with exponential backoff |
| Twilio | Single delivery attempt |
| Sendro | Configurable in Sendro dashboard |
Related Pages
- Billing & Payments — configuring Stripe integration
- Notifications — email and SMS notification settings
- API Authentication — securing API endpoints