Connect Stripe to RELO's data backbone for CPA tracking, purchase attribution, and subscription lifecycle monitoring via server-side webhooks.
RELO's data backbone accepts Stripe webhooks for CPA (Cost Per Action) tracking. When a customer completes a purchase or a subscription event occurs, Stripe sends the event payload to our Go ingest service. These are processed as model.Event records and written to ClickHouse for analytics.
The integration supports one-time purchases, subscription checkouts, and full subscription lifecycle tracking (creation, updates, cancellations).
checkout.session.completedFired when a customer completes a Stripe Checkout session. Covers both one-time purchases and initial subscription checkouts. Revenue is extracted from the session's amount_total.
invoice.paidFired when a subscription invoice is paid. The handler skips invoices with billing_reason: subscription_create to avoid double-counting the initial checkout (already captured by checkout.session.completed). Only subsequent renewal invoices are processed.
customer.subscription.created / updated / deletedSubscription lifecycle events. Tracked as custom events for analytics (churn analysis, plan changes, etc.). These events do not carry revenue and do not trigger identity resolution.
STRIPE_WEBHOOK_SECRET environment variable on the backbone server. Without this, all incoming requests will be rejected.
checkout.session.completedinvoice.paidcustomer.subscription.createdcustomer.subscription.updatedcustomer.subscription.deletedThe signing secret must be configured before any events will be accepted. If STRIPE_WEBHOOK_SECRET is empty or missing, the service rejects all Stripe webhook requests with a signature verification failure.
For checkout.session.completed and invoice.paid, the handler extracts revenue from the event payload (amount_total or amount_paid, converted from cents to the base currency unit). Identity resolution links the customer email to a unified device ID via DragonflyDB.
For customer.subscription.* events, the handler records the plan, status, and billing interval as custom event properties. These events do not include customer email in the subscription object, so identity resolution is skipped.
checkout.session.completed — Email extracted from the session's customer_email or customer_details.emailinvoice.paid — Email extracted from the invoice's customer_emailcustomer.subscription.createdcustomer.subscription.updatedcustomer.subscription.deletedThe Stripe subscription object does not contain the customer's email address. These events are recorded without a linked device ID.
The identity resolution flow for purchase events:
Customer email (from Stripe event)
-> SHA-256 hash
-> DragonflyDB lookup: id:email:{hash} -> unified device_id
-> Event written with resolved device_id
Stripe events are mapped to RELO's universal event schema as follows:
| Stripe Event | RELO event_name | event_type | channel |
|---|---|---|---|
checkout.session.completed |
purchase |
purchase |
stripe |
invoice.paid (subscription_cycle) |
subscription_renewal |
custom |
stripe |
invoice.paid (subscription_create) |
Skipped — already captured by checkout.session.completed | ||
customer.subscription.created |
subscription_created |
custom |
stripe |
customer.subscription.updated |
subscription_updated |
custom |
stripe |
customer.subscription.deleted |
subscription_cancelled |
custom |
stripe |
All events are written to the ClickHouse events table with media_source = 'stripe' and channel = 'stripe'. The order_id field is populated with the Stripe session ID, invoice ID, or subscription ID depending on the event type.
Forward Stripe test events to your local backbone instance:
stripe listen --forward-to localhost:4080/postback/stripe
Then trigger test events from another terminal:
stripe trigger checkout.session.completed
stripe trigger invoice.paid
stripe trigger customer.subscription.created
You can also configure the webhook endpoint in Stripe's test mode to point to your staging or production URL. Use the Stripe test card for generating purchase events:
4242 4242 4242 4242
Any future expiry date, any CVC, any billing postal code.
After triggering a test event, verify it was ingested by querying ClickHouse:
SELECT event_id, event_name, event_type, revenue, order_id
FROM events
WHERE media_source = 'stripe'
ORDER BY event_time DESC
LIMIT 10;
Stripe-Signature header