/** * Stripe Checkout Session capture. * * WHY THIS EXISTS * syncStripePaymentLinks stamps `client_reference_id` onto buy.stripe.com * anchors, and deliberately never onto checkout.stripe.com — a Checkout Session * URL ignores the param because the session already exists server-side. That * leaves the single most common SaaS pattern uncovered: the merchant's backend * creates a Session and the browser is sent to checkout.stripe.com/c/pay/cs_... * The payment then reaches our webhook with no visitor at all. * * Measured 2026-07-25, 30d: of payers arriving via Stripe webhooks, 0.5% (one * tenant, 128/28,187) and 13.3% (another, 13/98) had ANY web pageview on the * same visitor. Not a misconfiguration — no tenant is wired, because being * wired currently requires the merchant to hand-write client_reference_id. * * WHAT THIS DOES * The session id must reach the browser for the redirect to happen at all, so * we observe it rather than trying to inject anything: * 1. fetch/XHR response bodies — `{url}` or `{sessionId}` from the * merchant's own create-session endpoint * 2. anchor clicks + window.open — direct links to checkout.stripe.com * A server-side 302 straight to Stripe never exposes the id to JS and is NOT * covered here; that case falls back to the email bridge. * * WHY THIS IS SAFE TO DEFAULT ON, WHEN autoIdentifyAPI IS NOT * autoIdentifyAPI scans the same traffic for EMAILS, which is why it defaults * off: an admin viewing a customer record gets identified as that customer, and * a wrong email propagates into Meta advanced matching. A `cs_live_...` token is * unambiguous, belongs to exactly one checkout, and is not PII. There is no * mis-identification failure mode to guard against — only the wrapper itself, * which is why every hook below is transparent and failure-isolated. */ export type StripeSessionSink = (sessionId: string) => void; export interface StripeSessionWatcherOptions { /** Emit at most this many distinct session ids per page. */ maxSessions?: number; /** Test seam. */ maxScanBytes?: number; } export declare function extractSessionId(text: string | null | undefined): string | null; /** * True when `href` points at a Stripe-hosted checkout. Uses the URL API and * exact host equality — `a[href*="checkout.stripe.com"]` would match * `evil.com/checkout.stripe.com/x` and `checkout.stripe.com.evil.com`. */ export declare function isCheckoutUrl(href: string, base?: string): boolean; export declare class StripeSessionWatcher { private sink?; private seen; private disposers; private started; private readonly maxSessions; private readonly maxScanBytes; constructor(options?: StripeSessionWatcherOptions); start(sink: StripeSessionSink): void; stop(): void; /** Report a session id at most once, and never more than maxSessions per page. */ private emit; /** * Scan a Response WITHOUT disturbing the merchant's own read. `clone()` must * happen synchronously, before the caller can consume the body; the read of * the clone is deliberately not awaited by the caller. */ private scanResponse; private hookFetch; private hookXhr; /** * Direct links to checkout.stripe.com. Capture phase so we still see the click * when the merchant's own handler calls stopPropagation(). */ private hookClicks; private hookWindowOpen; } //# sourceMappingURL=stripe-session.d.ts.map