> ## Documentation Index
> Fetch the complete documentation index at: https://learn.biq.li/llms.txt
> Use this file to discover all available pages before exploring further.

# Stripe attribution and identity

> Preserve a Biqli click, map Stripe objects, and keep signup and payment activity on one customer.

Stripe reports what happened to a payment. It does not know which Biqli campaign click caused it. Your integration must preserve that relationship before the customer leaves your site for Checkout.

## Capture the click

Install the browser SDK with a publishable key from the same workspace connected to Stripe:

```html theme={null}
<script
  src="https://biq.li/sdk/dist/auto.global.js"
  data-publishable-key="biqli_pk_xxxxxxxxx"
></script>
```

When a visitor arrives through a Biqli link, the destination URL contains `bq_id`. With consent granted, the SDK validates and stores that click ID as first-party attribution.

```js theme={null}
const clickId = window.Biqli.getClickId();

if (!clickId) {
  // You can still offer Checkout, but it will not be a Biqli-attributed sale.
}
```

Do not create a synthetic click when a real short-link redirect already supplied one. A test-only “record click” control creates a separate click and can make the journey harder to audit.

## Register the Checkout identity

The strongest mapping binds the exact Stripe Checkout Session ID to the exact click:

```ts theme={null}
await biqli.storeStripeSession({
  stripe_account_id: 'acct_example123',
  stripe_environment: 'sandbox',
  stripe_session_id: 'cs_test_example123',
  customer_email: 'buyer@example.com',
});
```

The SDK supplies its stored `bq_id` unless you explicitly pass one. Biqli rejects a click that is expired, invalid, or owned by another workspace. It also rejects a Checkout Session whose `cs_live_...` or `cs_test_...` mode conflicts with the connected environment.

After Stripe delivers Checkout, Biqli expands the relationship to the Stripe customer, subscription, invoice, PaymentIntent, and charge identifiers present in the supported events. Exact Checkout and subscription identities cannot be silently remapped to another click.

## Mapping lifetime

Two registration forms have different lifetimes:

| Registration                         | Default eligibility window | Use                                                                                  |
| :----------------------------------- | :------------------------- | :----------------------------------------------------------------------------------- |
| Exact `stripe_session_id`            | 90 days                    | Recommended. Supports a known Checkout Session and durable object hierarchy.         |
| Pending mapping without a session ID | 24 hours                   | Fallback while the Checkout ID is not yet available. Requires safe resolution later. |

An attributed subscription remains mapped for its later invoices. Shorter Checkout, customer, invoice, and payment-object mappings limit accidental reuse while preserving the recurring subscription relationship.

These are service defaults and can change. Do not build a customer experience that intentionally waits near an attribution deadline.

## Unique-email fallback

If no exact Checkout Session mapping exists, Biqli can use a normalized customer email only when exactly one eligible, unconsumed pending mapping exists for that connected Stripe account.

The fallback is deliberately narrow:

* two eligible pending mappings for the same email are ambiguous and rejected;
* an expired mapping is ignored;
* a mapping from another Stripe connection or workspace is ignored;
* a consumed pending mapping cannot attribute another Checkout;
* email never overrides a conflicting exact object mapping.

Use the fallback for recovery, not as your primary integration. Register the exact `cs_...` ID whenever possible.

## Record a real signup lead

Your application can record a signup before Checkout. Create the Stripe Customer on your server, then use the Stripe-scoped external identity for the Biqli lead:

```ts theme={null}
import Stripe from 'stripe';
import {Biqli} from '@biqli/sdk';

const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);
const biqli = new Biqli({apiKey: process.env.BIQLI_API_KEY!});
const stripeAccountId = process.env.STRIPE_ACCOUNT_ID!;

const customer = await stripe.customers.create({
  name: 'Ada Lovelace',
  email: 'ada@example.com',
});

await biqli.track.lead({
  clickId,
  eventId: `signup:${customer.id}`,
  eventName: 'Signed up',
  customerExternalId: `stripe:${stripeAccountId}:${customer.id}`,
  customerName: customer.name ?? undefined,
  customerEmail: customer.email ?? undefined,
});
```

Pass that same Stripe Customer ID when your server creates Checkout. Stripe webhook sales then use the same `stripe:<account>:<customer>` identity, so signup, trial, sale, renewal, and refund activity stays on one Biqli customer.

<Warning>
  Create the lead from a trusted server. Do not accept an arbitrary Stripe Customer ID from the browser without checking that it belongs to the authenticated application user.
</Warning>

## Guest Checkout identity

When Checkout has no Stripe Customer, Biqli can create an account-scoped guest identity from a normalized email. This supports a one-time guest purchase but is weaker than a stable Stripe Customer ID.

Prefer creating or reusing a Stripe Customer when you need:

* a real signup lead and later payment on one customer;
* subscriptions or trials;
* multiple purchases by the same customer;
* durable support and reconciliation.

## Attribution model

The workspace's first-click or last-click model controls how eligible customer attribution is selected by the shared conversion system. The Stripe mapping still starts from a concrete click. The model does not authorize Biqli to guess a click from general Stripe account history.

If a Stripe Customer returns through a newer campaign, exact Checkout and subscription mappings remain immutable. A new Checkout can establish a new object hierarchy without rewriting an older sale.

## Geography and device fields

Browser, platform, referrer, country, region, and city come from the attributed Biqli click. They do not come from Stripe billing details. This keeps acquisition reporting tied to the marketing visit rather than the payment method.

## Consent

`storeStripeSession()` requires browser tracking consent. When consent is disabled, the SDK clears stored attribution and rejects the call with `consent_required`.

Your backend has separate obligations. Persist and enforce the user's consent or other legal basis before sending a signup lead from your server. A browser toggle does not automatically authorize server-side tracking.

Continue with [Stripe Checkout implementation](/developers/integrations/stripe/checkout).
