Skip to main content
Stripe sends payments, subscriptions, refunds, and disputes to Datalyr through the Stripe Connect webhook.

Connect

1

Open the source

Open Sources, find Stripe, and select connect.
2

Authorize the account

Complete the Stripe OAuth flow. Choose the Stripe account this workspace bills through.
3

Stamp the visitor ID

Follow the two sections below that match your checkout.
We own the endpoint https://webhooks.datalyr.com/stripe-connect and its signing secret, so you create no endpoint in Stripe.
Do not re-create the retired endpoint https://webhooks.datalyr.com/stripe/WORKSPACE_PUBLIC_ID. It returns HTTP 410, and the payments you send there are recorded nowhere.
Pass the visitor ID whenever you create the Stripe object yourself. It’s the only deterministic link to the web visit. Without it, we fall back to email matching.

Checkout Sessions

The Checkout handler reads client_reference_id and nothing else, so metadata.visitor_id is ignored on a Checkout Session.

PaymentIntents, Subscriptions, and Customers

Each of these handlers reads metadata.visitor_id, then metadata.datalyr_id. The Web SDK decorates these automatically. It never touches checkout.stripe.com Session URLs. The SDK also adds prefilled_email after identify(), unless privacyMode is strict. Your own value always wins. Set stripePaymentLinks: false to disable this. window.open(paymentLink) calls and links inside an iframe or shadow DOM are not decorated.

Identity resolution

We resolve the visitor in this order, per event. No match writes a synthetic visitor_id: stripe_<customer_id>, or stripe_guest_<hash> for a guest with an email, or stripe_<object_id>. Refund and dispute rows always use stripe_refund_<id> and stripe_dispute_<id>, with no lookup.

Event mapping

The Datalyr event name equals the Stripe event type, except where this table says otherwise. These six types return 200 and record nothing. checkout.session.completed records nothing when payment_status is not paid.

Revenue

The event value is gross, before tax and processor fees. We divide the Stripe minor-unit amount by a per-currency divisor: Reported net revenue is cash, minus refunds, minus dispute withdrawals, plus reinstatements. Processor fees arrive as a separate non-cash row, stripe.balance_transaction.fee_fact, with value 0:
We serve net proceeds only when every cash movement has a matching fee fact. Otherwise the value is null.
USD conversion is all-or-nothing per hour. A missing FX rate for one event nulls revenue_usd, net_revenue_usd, refund_amount_usd, dispute_amount_usd, and mrr_usd for that hour. fx_coverage_ratio reports how much of the hour converted.
Top-level currency is the real Stripe currency, uppercased. We apply no conversion at write time.

Delivery behavior

We accept multiple v1= signatures, so rotating your secret won’t break delivery.

Subscription state

We compute MRR from subscription items with exact decimal arithmetic. MRR is unavailable for a subscription that is paused, discounted, metered, tiered, on a schedule, priced with transformed_quantity, mixed-currency, or non-fixed. active_mrr_usd is served only when the baseline snapshot is complete and no subscription is incomplete.

Every HTTP status

Every 503 carries Retry-After, so Stripe redelivers. We never answer 200 for an infrastructure failure, because that would drop the payment.

Verify

  1. Open your pricing page in a private window with ?utm_source=doctest.
  2. Open Events. Confirm a pageview row exists.
  3. Complete one Stripe test payment through your production code path.
  4. Open Events. Find the checkout.session.completed or payment_intent.succeeded row.
  5. Confirm value, currency, and event_data.ledger_type.
  6. Confirm visitor_id does not start with stripe_.

When it does not work

Next, create a conversion rule so these payments reach your ad platforms.