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

# Stripe integration

> Install the Tolt app from the Stripe App Marketplace. Every payment, renewal and refund from a referred customer flows into Tolt.

Tolt reads payments straight from your Stripe account through the [Tolt app](https://marketplace.stripe.com/apps/tolt). You pass the referral to Stripe once, at checkout. From then on, every charge, renewal, trial and refund from that customer is matched to the partner and turned into commissions automatically.

Browsertolt.jsYour servercheckoutStripepaymentsToltattribution*1*?ref=sam*2*tolt\_referral: clk\_3nVb…*3*metadata.tolt\_referral*4*charge.succeeded*5*commission for Sam

## Install the Tolt app

**1. Find Tolt on the Stripe App Marketplace**

Open [marketplace.stripe.com/apps/tolt](https://marketplace.stripe.com/apps/tolt) and click **Install from partner**. It takes you to Tolt to finish connecting. You can also start inside Tolt, under **Settings → Integrations → Stripe**.

![The Tolt app on the Stripe App Marketplace](https://mintcdn.com/tolt-29/IdZ6_r2VYMOh5a6x/images/dashboard/stripe-marketplace-light.webp?fit=max\&auto=format\&n=IdZ6_r2VYMOh5a6x\&q=85\&s=9d210acf8d1b54251052a7e34527eef7)

**2. Approve access in Stripe**

In Tolt, click **Install the Tolt app**. Stripe shows what the app can access. Approve it and Stripe sends you back to Tolt. Access is read-only, except coupons and promotion codes, which Tolt creates for [partner discount codes](/tracking/promo-codes).

| Stripe data | Access |
| - | - |
| Charges and refunds, Checkout Sessions, Customers, Events, Invoices, Payment Intents, Products, Subscriptions | Read-only |
| Coupons, Promotion codes | Read and write |

**3. You're connected**

The Stripe integration page now shows a **Disconnect** button, and payments start syncing right away. Stay on this page for the next part: passing the referral to Stripe.

![The Stripe integration page in Tolt, connected](https://mintcdn.com/tolt-29/IdZ6_r2VYMOh5a6x/images/dashboard/stripe-integration-light.webp?fit=max\&auto=format\&n=IdZ6_r2VYMOh5a6x\&q=85\&s=b499bf0130280d6d9cdf78e8e7f56ca4)

> [!WARNING]
>
> With Stripe connected, Tolt records payments for you. Don't also call `POST /v2/transactions` for the same charges, or commissions double count.

## Pass the referral to Stripe

Add [tolt.js](/tracking/script) to every page of your site and app. It records the click and exposes the referral as `window.tolt_referral`. Then hand it to Stripe with whatever you use to take payments.

**Checkout Session**

Send the referral from the browser to your server:

```js Browser theme={"system"}
const res = await fetch("/api/checkout", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ referral: window.tolt_referral }),
});
window.location.href = (await res.json()).url;
```

Then put it on the session as `metadata.tolt_referral`:

```ts TypeScript theme={"system"}
import Stripe from "stripe";

const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);

export async function POST(req: Request) {
  const { referral } = await req.json();
  const session = await stripe.checkout.sessions.create({
    mode: "subscription",
    line_items: [{ price: "price_1QxYz2LmZx7RtYw3nVbHc5dP", quantity: 1 }],
    success_url: "https://acme.com/welcome",
    cancel_url: "https://acme.com/pricing",
    metadata: referral ? { tolt_referral: referral } : undefined,
  });
  return Response.json({ url: session.url });
}
```

```python Python theme={"system"}
import os
import stripe

stripe.api_key = os.environ["STRIPE_SECRET_KEY"]


def create_checkout(referral: str | None):
    params = {
        "mode": "subscription",
        "line_items": [
            {"price": "price_1QxYz2LmZx7RtYw3nVbHc5dP", "quantity": 1}
        ],
        "success_url": "https://acme.com/welcome",
        "cancel_url": "https://acme.com/pricing",
    }
    if referral:
        params["metadata"] = {"tolt_referral": referral}
    return stripe.checkout.Session.create(**params)
```

**Payment Links**

Add `data-stripe-type="payment_links"` to the script. tolt.js appends `client_reference_id` to every `buy.stripe.com` link on the page.

```html HTML theme={"system"}
<script
  async
  src="https://cdn.tolt.io/v2/tolt.js"
  data-tolt="YOUR_PUBLIC_ORG_KEY"
  data-stripe-type="payment_links"
></script>
```

On a custom checkout domain, add `data-stripe-domain="https://pay.acme.com"` and pick **Custom domain** on the integration page. To do it yourself, append `?client_reference_id=<referral>` to the link.

**Pricing Table**

Add `data-stripe-type="pricing_table"`. tolt.js sets `client-reference-id` on every `<stripe-pricing-table>`.

```html HTML theme={"system"}
<script
  async
  src="https://cdn.tolt.io/v2/tolt.js"
  data-tolt="YOUR_PUBLIC_ORG_KEY"
  data-stripe-type="pricing_table"
></script>
```

Or set it yourself: `table.setAttribute("client-reference-id", window.tolt_referral)`.

**Buy Button**

Add `data-stripe-type="buy_button"`. tolt.js sets `client-reference-id` on every `<stripe-buy-button>`.

```html HTML theme={"system"}
<script
  async
  src="https://cdn.tolt.io/v2/tolt.js"
  data-tolt="YOUR_PUBLIC_ORG_KEY"
  data-stripe-type="buy_button"
></script>
```

Or set it yourself: `button.setAttribute("client-reference-id", window.tolt_referral)`.

**Stripe API**

Creating customers or subscriptions on your server? Put the referral on the customer. Every later charge and renewal stays with the partner.

```ts TypeScript theme={"system"}
const customer = await stripe.customers.create({
  email: "jane@example.com",
  metadata: { tolt_referral: referral },
});
```

```python Python theme={"system"}
customer = stripe.Customer.create(
    email="jane@example.com",
    metadata={"tolt_referral": referral},
)
```

Already know the partner? Use `tolt_partner` (a Tolt partner id) or `tolt_partner_external_id` instead.

> [!NOTE]
>
> Tolt matches Stripe checkouts through the Stripe customer, and subscriptions always create one. For one-time payments, make sure a customer is created too: `customer_creation: "always"` on a Checkout Session, or the customer-creation option on a Payment Link (Buy Buttons use Payment Links). A guest checkout without a customer can't be credited to a partner.

## How Tolt finds the partner

Every Stripe payment is checked against a fixed list of signals, in order. The first one that matches decides the partner. If none match, the payment isn't a referral and Tolt ignores it.

### Metadata keys

Put one of these keys in Stripe `metadata`. Pick whichever id you have at hand.

| Key | Value | Use it when |
| - | - | - |
| `tolt_referral` | The click id from `window.tolt_referral` | The buyer came through a partner link. The most common case. |
| `tolt_customer` | A Tolt customer id, or the identifier you passed to `tolt.signup()` | The customer already signed up in Tolt before paying. |
| `tolt_partner` | A Tolt partner id, like `part_8fKq2LmZ` | You know the partner but there's no click, like a deal closed by sales. |
| `tolt_partner_external_id` | Your own id for the partner | Same, using your id instead of Tolt's. |

`tolt_click`, `tolt_partner_id` and `tolt_partner_external` are accepted as aliases. If one object has several keys, Tolt uses `tolt_customer` first, then `tolt_referral`, then the partner keys. With a partner key and no existing customer, Tolt creates the customer as a lead for that partner.

### Where to put them

| Stripe object | How to set it | What it covers |
| - | - | - |
| Customer | `metadata` on `customers.create` or `customers.update` | Every charge, subscription and checkout from that customer. The safest choice. |
| Checkout Session | `metadata` on `checkout.sessions.create` | That checkout and the customer it creates. |
| Subscription | `metadata` on `subscriptions.create`, or `subscription_data` in Checkout | That subscription and its renewals. |
| Charge | `metadata` on the charge | That one payment. |

### Without metadata

* **`client_reference_id`**: Checkout, Payment Links, Pricing Tables and Buy Buttons accept it, and tolt.js can set it for you. It must be the click id from `window.tolt_referral`.
* **Email**: if the Stripe customer's email matches a customer already in Tolt, from `tolt.signup()` or the API, the payment goes to that customer's partner. Nothing to set up, as long as your app and Stripe use the same email.
* **Promotion codes**: a promotion code that belongs to a partner in Tolt credits that partner, even without a click. See [Promo codes](/tracking/promo-codes).

### Lookup order

For every payment, Tolt asks these questions in order and stops at the first yes. If every answer is no, the payment isn't a referral.

1. **Has Tolt matched this Stripe customer before?** Then it's the same partner as last time. This is how renewals are credited.
2. **Does the Stripe customer have Tolt metadata?** `tolt_referral`, `tolt_customer` or a partner key on the customer.
3. **Does the payment itself have Tolt metadata?** The same keys on the charge, subscription or checkout session.
4. **Does the checkout have a `client_reference_id`?** Checkout Sessions, Payment Links, Pricing Tables and Buy Buttons only.
5. **Does the email match a customer in Tolt?** One created earlier by `tolt.signup()` or the API.
6. **Was a partner's promotion code used?** On the invoice, subscription or checkout.

Once a payment matches, Tolt saves the Stripe customer id. Every later payment from that customer stops at question 1, so renewals keep going to the same partner, even if the metadata is removed.

## What Tolt syncs

The app listens to these Stripe events. Nothing to configure.

| Stripe event | What happens in Tolt |
| - | - |
| `charge.succeeded` | A paid transaction, and your commission flows run on it. Renewals too. |
| `checkout.session.completed` | The customer is matched to the partner from the session. |
| `customer.subscription.created`, `.updated` | Customer status follows the subscription: trialing, active or canceled. |
| `customer.subscription.deleted` | The customer is marked canceled, unless another subscription is still active. |
| `charge.refunded` | Unpaid commissions are zeroed. Paid ones get a matching negative commission. Any refund, even a partial one, reverses the whole commission. |
| `promotion_code.updated`, `coupon.deleted` | Partner discount codes are removed when you deactivate them in Stripe. |

## See it in Tolt

Each payment shows up under **Customers → Transactions** a few seconds after Stripe confirms it, and you can search the list by its Stripe charge id. Commissions follow under **Commissions**.

![Stripe payments listed as transactions in Tolt](https://mintcdn.com/tolt-29/IdZ6_r2VYMOh5a6x/images/dashboard/stripe-transactions-light.webp?fit=max\&auto=format\&n=IdZ6_r2VYMOh5a6x\&q=85\&s=22b85fea7ce00981d474d90c64af953e)

> [!TIP]
>
> Stripe test mode isn't synced, and the app can't be installed in a sandbox. Test with a small live purchase through a partner link, then refund it to see the commission reverse.

## Details

> **Free trials**
>
> A trial makes the customer **trialing** in Tolt, linked to the partner. No transaction or commission until the first paid invoice, which arrives as a normal `charge.succeeded`.

> **Taxes and discounts**
>
> By default the tracked amount is what Stripe captured: after discounts, including tax. Turn on **Exclude Stripe tax in the tracking amount** on the integration page to use the invoice total before tax instead.

> **Currencies**
>
> Payments in another currency are converted to your program currency at the latest exchange rate. The transaction keeps both the original and the converted amount.

> **Skip a charge**
>
> Add `metadata.tolt_handle = "exclude"` to a charge and Tolt ignores it. Useful for internal or manual charges.

> **Disconnect**
>
> Uninstall the Tolt app in Stripe and Tolt disconnects automatically. If you click **Disconnect** in Tolt instead, also remove the app under **Settings → Installed apps** in Stripe.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.