FlexPrice sends webhook events to notify your application when events happen in your account. Webhooks are particularly useful for asynchronous events like payment confirmations, subscription updates, and invoice status changes.
How Webhooks Work
When an event occurs in FlexPrice:
FlexPrice creates a webhook event payload
The event is published to Kafka for reliable delivery
The webhook service delivers the event to your configured endpoint
Your application returns a 2xx status code to acknowledge receipt
Webhook Events
FlexPrice supports the following webhook event types:
Invoice Events
Event Name Description invoice.create.draftedInvoice created in draft status invoice.update.finalizedInvoice finalized and ready for payment invoice.update.paymentInvoice payment status updated invoice.update.voidedInvoice voided/cancelled invoice.updateInvoice updated invoice.payment.overdueInvoice payment is overdue invoice.communication.triggeredInvoice email/SMS sent
Subscription Events
Event Name Description subscription.createdNew subscription created subscription.draft.createdSubscription created in draft status subscription.activatedSubscription activated subscription.updatedSubscription details updated subscription.pausedSubscription paused subscription.cancelledSubscription cancelled subscription.resumedPaused subscription resumed subscription.renewal.dueSubscription renewal is due
Payment Events
Event Name Description payment.createdPayment record created payment.updatedPayment details updated payment.successPayment succeeded payment.failedPayment failed payment.pendingPayment pending processing
Customer Events
Event Name Description customer.createdNew customer created customer.updatedCustomer details updated customer.deletedCustomer deleted
Wallet Events
Event Name Description wallet.createdWallet created for customer wallet.updatedWallet details updated wallet.terminatedWallet terminated wallet.transaction.createdWallet transaction recorded wallet.credit_balance.droppedCredit balance below threshold wallet.credit_balance.recoveredCredit balance restored wallet.ongoing_balance.droppedOngoing balance below threshold wallet.ongoing_balance.recoveredOngoing balance restored
Feature Events
Event Name Description feature.createdFeature created feature.updatedFeature updated feature.deletedFeature deleted feature.wallet_balance.alertFeature usage threshold alert
Entitlement Events
Event Name Description entitlement.createdCustomer entitlement granted entitlement.updatedEntitlement updated entitlement.deletedEntitlement revoked
Credit Note Events
Event Name Description credit_note.createdCredit note issued credit_note.updatedCredit note updated
Webhook Payload Structure
All webhook events follow this standard structure:
{
"id" : "evt_..." ,
"event_name" : "invoice.update.finalized" ,
"tenant_id" : "tenant_..." ,
"environment_id" : "env_..." ,
"user_id" : "user_..." ,
"timestamp" : "2024-01-15T10:30:00Z" ,
"payload" : {
// Event-specific data
}
}
Invoice Event Payload
invoice.update.finalized
payment.success
subscription.created
{
"id" : "evt_abc123" ,
"event_name" : "invoice.update.finalized" ,
"tenant_id" : "tenant_xyz" ,
"environment_id" : "env_prod" ,
"timestamp" : "2024-01-15T10:30:00Z" ,
"payload" : {
"invoice" : {
"id" : "inv_123" ,
"invoice_number" : "INV-2024-001" ,
"customer_id" : "cus_abc" ,
"status" : "finalized" ,
"amount_due" : 10000 ,
"currency" : "USD" ,
"due_date" : "2024-02-15T00:00:00Z" ,
"line_items" : [
{
"description" : "Pro Plan - Monthly" ,
"quantity" : 1 ,
"unit_amount" : 10000 ,
"amount" : 10000
}
]
}
}
}
Configuration
Create Webhook Endpoint
Configure a webhook endpoint to receive events:
curl -X POST https://api.flexprice.io/v1/webhook-endpoints \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://yourapp.com/webhooks/flexprice",
"events": [
"invoice.update.finalized",
"payment.success",
"payment.failed",
"subscription.created"
],
"enabled": true
}'
Event Filtering
Subscribe only to events you need:
All Invoice Events
Payment Events Only
All Events
curl -X POST https://api.flexprice.io/v1/webhook-endpoints \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://yourapp.com/webhooks",
"events": [
"invoice.create.drafted",
"invoice.update.finalized",
"invoice.update.payment",
"invoice.update.voided",
"invoice.payment.overdue"
]
}'
Implementation
Basic Webhook Handler
Node.js / Express
Python / Flask
Go
import express from 'express' ;
import { createHmac } from 'crypto' ;
const app = express ();
app . post ( '/webhooks/flexprice' , express . raw ({ type: 'application/json' }), ( req , res ) => {
const signature = req . headers [ 'x-flexprice-signature' ];
const payload = req . body ;
// Verify webhook signature
if ( ! verifySignature ( payload , signature , process . env . WEBHOOK_SECRET )) {
return res . status ( 401 ). send ( 'Invalid signature' );
}
const event = JSON . parse ( payload );
// Handle different event types
switch ( event . event_name ) {
case 'invoice.update.finalized' :
handleInvoiceFinalized ( event . payload . invoice );
break ;
case 'payment.success' :
handlePaymentSuccess ( event . payload . payment );
break ;
case 'subscription.created' :
handleSubscriptionCreated ( event . payload . subscription );
break ;
default :
console . log ( `Unhandled event: ${ event . event_name } ` );
}
res . status ( 200 ). send ( 'OK' );
});
function verifySignature ( payload , signature , secret ) {
const hmac = createHmac ( 'sha256' , secret );
hmac . update ( payload );
const expectedSignature = hmac . digest ( 'hex' );
return signature === expectedSignature ;
}
Security
Signature Verification
All webhook requests include an X-Flexprice-Signature header for verification:
Extract Signature
Get the X-Flexprice-Signature header from the request
Compute HMAC
Create an HMAC SHA-256 hash of the raw request body using your webhook secret
Compare
Use constant-time comparison to match the computed hash with the signature header
Always verify webhook signatures before processing events to prevent unauthorized requests.
Best Practices
Use HTTPS - Only accept webhooks over HTTPS endpoints
Verify Signatures - Always validate the webhook signature
Use Constant-Time Comparison - Prevent timing attacks when comparing signatures
Idempotency - Handle duplicate webhook deliveries gracefully
Async Processing - Process webhooks asynchronously to avoid timeouts
Error Handling - Return 2xx status codes even if processing fails internally
Webhook Architecture
FlexPrice’s webhook system uses Kafka for reliable delivery:
// Webhook publisher publishes to Kafka
type WebhookPublisher interface {
Publish ( ctx context . Context , event * types . WebhookEvent ) error
}
// Webhook payload factory creates event-specific payloads
type PayloadBuilderFactory interface {
GetBuilder ( eventType string ) ( PayloadBuilder , error )
}
// Registered webhook event builders
builders := map [ string ] PayloadBuilder {
"invoice.update.finalized" : NewInvoicePayloadBuilder (),
"payment.success" : NewPaymentPayloadBuilder (),
"subscription.created" : NewSubscriptionPayloadBuilder (),
"customer.created" : NewCustomerPayloadBuilder (),
"wallet.transaction.created" : NewTransactionPayloadBuilder (),
// ... all other event types
}
Testing
Test Webhook Locally
Use tools like ngrok to expose your local server:
# Start ngrok
ngrok http 3000
# Configure webhook endpoint with ngrok URL
curl -X POST https://api.flexprice.io/v1/webhook-endpoints \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"url": "https://abc123.ngrok.io/webhooks",
"events": ["*"]
}'
Trigger Test Events
Create test events to verify your webhook handler:
curl -X POST https://api.flexprice.io/v1/webhook-endpoints/{endpoint_id}/test \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"event_name": "invoice.update.finalized"
}'
Monitoring
View Webhook Deliveries
Check webhook delivery status and logs:
curl -X GET https://api.flexprice.io/v1/webhook-endpoints/{endpoint_id}/deliveries \
-H "Authorization: Bearer YOUR_API_KEY"
Response:
{
"deliveries" : [
{
"id" : "del_123" ,
"event_id" : "evt_abc" ,
"event_name" : "invoice.update.finalized" ,
"status" : "succeeded" ,
"response_code" : 200 ,
"attempted_at" : "2024-01-15T10:30:00Z"
},
{
"id" : "del_124" ,
"event_id" : "evt_def" ,
"event_name" : "payment.success" ,
"status" : "failed" ,
"response_code" : 500 ,
"error" : "Internal server error" ,
"attempted_at" : "2024-01-15T10:35:00Z" ,
"retry_at" : "2024-01-15T10:40:00Z"
}
]
}
Troubleshooting
Common Issues
Verify endpoint URL is publicly accessible
Check firewall rules allow FlexPrice IPs
Ensure endpoint returns 2xx status code
Verify webhook endpoint is enabled
Signature verification fails
Use raw request body (don’t parse JSON first)
Verify webhook secret is correct
Use constant-time comparison
Check for encoding issues
Check event subscription configuration
Verify webhook endpoint is active
Review delivery logs for failures
Check for rate limiting on your endpoint
Implement idempotency using event.id
Track processed event IDs
Return 2xx even if already processed
Next Steps
Stripe Integration Configure Stripe integration
API Reference Explore webhook endpoint API