Skip to main content
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:
  1. FlexPrice creates a webhook event payload
  2. The event is published to Kafka for reliable delivery
  3. The webhook service delivers the event to your configured endpoint
  4. Your application returns a 2xx status code to acknowledge receipt

Webhook Events

FlexPrice supports the following webhook event types:

Invoice Events

Event NameDescription
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 NameDescription
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 NameDescription
payment.createdPayment record created
payment.updatedPayment details updated
payment.successPayment succeeded
payment.failedPayment failed
payment.pendingPayment pending processing

Customer Events

Event NameDescription
customer.createdNew customer created
customer.updatedCustomer details updated
customer.deletedCustomer deleted

Wallet Events

Event NameDescription
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 NameDescription
feature.createdFeature created
feature.updatedFeature updated
feature.deletedFeature deleted
feature.wallet_balance.alertFeature usage threshold alert

Entitlement Events

Event NameDescription
entitlement.createdCustomer entitlement granted
entitlement.updatedEntitlement updated
entitlement.deletedEntitlement revoked

Credit Note Events

Event NameDescription
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

{
  "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:
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

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:
1

Extract Signature

Get the X-Flexprice-Signature header from the request
2

Compute HMAC

Create an HMAC SHA-256 hash of the raw request body using your webhook secret
3

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
  • 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