> ## 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.

# Subscriptions, trials, renewals, and refunds

> Understand how Biqli handles Stripe subscription revenue and post-purchase changes.

Stripe subscription Checkout produces several related events. Biqli separates attribution, trial leads, and paid invoices so a zero-value trial is not mistaken for revenue and each renewal remains independently idempotent.

## Paid subscription without a trial

Create Checkout with `mode: 'subscription'`, register the exact Checkout Session, and let Stripe deliver both Checkout and invoice events.

```ts theme={null}
const session = await stripe.checkout.sessions.create({
  mode: 'subscription',
  customer: stripeCustomerId,
  line_items: [{price: 'price_monthly_example', quantity: 1}],
  success_url: 'https://app.example.com/billing/success',
  cancel_url: 'https://app.example.com/billing/cancel',
});
```

`checkout.session.completed` establishes the customer, subscription, invoice, and payment hierarchy. Biqli does not create the subscription sale from that event. The canonical sale comes from `invoice.paid`.

This prevents the first subscription charge from being counted once as Checkout and again as an invoice.

## Subscription with a trial

Add trial settings through Stripe's supported Checkout parameters:

```ts theme={null}
const session = await stripe.checkout.sessions.create({
  mode: 'subscription',
  customer: stripeCustomerId,
  line_items: [{price: 'price_monthly_example', quantity: 1}],
  subscription_data: {trial_period_days: 7},
  success_url: 'https://app.example.com/billing/trial-started',
  cancel_url: 'https://app.example.com/billing/cancel',
});
```

After exact Checkout registration:

1. a `trialing` subscription creates one **Stripe Free Trial** lead;
2. its zero-value invoice creates no sale;
3. the first non-zero `invoice.paid` creates a subscription sale;
4. later cycle invoices create independent renewal sales.

If your application also records **Signed up**, one customer can correctly have two leads: application signup and Stripe trial.

The trial's stable identity combines the Stripe environment, account, subscription, and trial start time. Repeated created or updated events for the same trial do not increase the lead count.

## Out-of-order events

Stripe may deliver `customer.subscription.created` before `checkout.session.completed`. The early event cannot yet prove which Biqli click owns the subscription.

Biqli temporarily fails the event when an eligible Checkout mapping is still pending. The webhook ledger adds a short exponential backoff. After Checkout establishes the object hierarchy, a Stripe retry processes the trial once.

This temporary `500 processing_failed` is expected for that ordering. It needs investigation only when retries continue after Checkout has been processed.

Invoices can also arrive before Checkout. When the invoice includes a uniquely eligible email mapping, Biqli can resolve it safely. Otherwise it waits for or ignores the missing attribution rather than guessing.

## Initial payment versus renewal

Every non-zero paid Stripe invoice is a separate sale with the Stripe invoice ID as its financial identity.

| Stripe billing reason                          | Biqli activity                                                                             |
| :--------------------------------------------- | :----------------------------------------------------------------------------------------- |
| `subscription_create` or `subscription_update` | Initial or changed subscription payment, shown as a purchase when product details exist.   |
| `subscription_cycle`                           | Recurring payment, shown as **Renewed …** when product details exist.                      |
| Non-subscription paid invoice                  | **Stripe Invoice Payment** when it can be attributed through a supported object hierarchy. |

The visible event time uses Stripe's paid timestamp when available. A test clock can therefore produce a renewal dated in the future relative to the wall-clock time when you are viewing the report.

## Upgrades, downgrades, and prorations

Biqli records a sale when Stripe sends a non-zero `invoice.paid` that remains connected to the attributed subscription. It uses Stripe's paid amount rather than reconstructing plan mathematics in Biqli.

An immediate plan change can therefore produce a paid invoice with billing reason `subscription_update`. It is a new sale if the amount is greater than zero. A zero-value change creates no sale.

## Cancellation

`customer.subscription.updated` keeps trial handling idempotent but does not create a cancellation conversion. Canceling immediately or at period end does not alter already paid revenue.

Expected behavior:

* cancel at period end: the subscription may remain active until the current period ends;
* immediate cancellation: no additional sale is created;
* a final paid invoice: recorded only if Stripe actually sends a non-zero `invoice.paid`;
* no later invoice: no renewal appears.

If your product needs cancellation analytics, record a separate application event in your own product analytics. Do not represent cancellation as negative Stripe revenue.

## Partial refund

A successful refund smaller than the original sale reduces its net attributed revenue and appears as **Partial refund**.

For a `$25.99` sale and `$5.00` refund:

* sales remain `1`;
* gross sale history remains `$25.99`;
* the refund activity is `-$5.00`;
* net attributed revenue becomes `$20.99`.

## Full refund and multiple refunds

Biqli sums successful refunds linked to the sale and caps the net adjustment at the original sale value. A second refund that returns the remaining amount produces **Refund completed** and net revenue `$0.00`.

Each refund is identified by its Stripe `re_...` ID. Repeated `refund.created` and `refund.updated` deliveries update that refund rather than subtracting it twice.

## Failed and pending refunds

Pending and `requires_action` refunds are retained as lifecycle state but do not reduce report revenue until they succeed. Failed and canceled refunds do not reduce revenue.

A successful refund delivered before the original sale is available temporarily fails so Stripe can retry it after sale attribution exists. For some charge-only refund payloads, Biqli may read the charge from Stripe to obtain its PaymentIntent and link it back to the sale.

## Product labels

Biqli uses the first embedded invoice line description and product reference when Stripe includes them in the permitted invoice payload. Activity can appear as:

* **Purchased 1 × Acme Pro (at \$12.00 / month)**;
* **Renewed 1 × Acme Pro (at \$12.00 / month)**;
* a generic **Purchase** or **Subscription renewed** when no safe product label is present.

The label does not affect amount, attribution, or idempotency.

Continue with [Testing and operations](/developers/integrations/stripe/operations).
