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

# Stripe Checkout Integration

> Pass affiliate attribution into Stripe sessions so AgentRef can match payments to clicks and create commissions automatically.

AgentRef resolves conversions by finding the click token (`agentref_cid`) on a Stripe payment event. How you get that token into Stripe depends on which Stripe surface you use.

## Choose the checkout route first

Before editing code, decide which route applies:

* **Route A — Hosted Stripe on the AgentRef website:** Payment Link, Buy Button, or Pricing Table is on the website where AgentRef is installed.
* **Route B — Website custom checkout:** Buy button is on the AgentRef website and calls your backend to create Stripe Checkout.
* **Route C — External app checkout:** Buy button is in a Chrome extension, desktop app, mobile app, external dashboard, or another surface where AgentRef is not installed.

If Route C applies, do not stop at adding metadata support to the external app request. Route checkout through the AgentRef website first so the website can read the first-party AgentRef cookie before creating the Stripe Checkout Session.

## How `getCheckoutMetadata()` works

The tracking script stores a `agentref_cid` click token in a first-party cookie when a visitor arrives through an affiliate link. At checkout time, your code reads that token and embeds it into the Stripe session before the customer pays.

```js theme={null}
// Returns { agentref_cid, agentref_pid, agentref_source }
// Returns {} if no active attribution exists (visitor came directly)
const meta = window.AgentRef.getCheckoutMetadata();
```

When Stripe fires `checkout.session.completed` or `invoice.paid`, AgentRef's webhook reads the metadata and matches the payment to the original click.

<Info>
  If `getCheckoutMetadata()` returns an empty object, the visitor has no affiliate attribution. You can still call your checkout API – AgentRef will simply not create a conversion for that payment.
</Info>

## Integration by Stripe surface

<Tabs>
  <Tab title="Stripe Checkout (custom session)">
    This is the most common integration – you create a Checkout Session server-side and redirect the customer to it.

    **Step 1:** Read the tracking metadata on your frontend:

    ```js theme={null}
    window.AgentRef.ready(async function() {
      const trackingMeta = window.AgentRef.getCheckoutMetadata();

      const response = await fetch('/api/create-checkout', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          priceId: 'price_xxx',
          agentrefMeta: trackingMeta,
        }),
      });

      const { url } = await response.json();
      window.location.href = url;
    });
    ```

    **Step 2:** Pass the metadata into the Stripe session on your backend:

    <CodeGroup>
      ```js Node.js theme={null}
      const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);

      app.post('/api/create-checkout', async (req, res) => {
        const { priceId, agentrefMeta } = req.body;

        const session = await stripe.checkout.sessions.create({
          mode: 'subscription',
          line_items: [{ price: priceId, quantity: 1 }],
          success_url: 'https://yoursite.com/success',
          cancel_url: 'https://yoursite.com/pricing',
          // Pass AgentRef metadata – this is what the webhook reads
          metadata: {
            ...agentrefMeta,
          },
        });

        res.json({ url: session.url });
      });
      ```

      ```python Python theme={null}
      import stripe
      import json
      from flask import request, jsonify

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

      @app.route("/api/create-checkout", methods=["POST"])
      def create_checkout():
          data = request.get_json()
          price_id = data.get("priceId")
          agentref_meta = data.get("agentrefMeta", {})

          session = stripe.checkout.Session.create(
              mode="subscription",
              line_items=[{"price": price_id, "quantity": 1}],
              success_url="https://yoursite.com/success",
              cancel_url="https://yoursite.com/pricing",
              metadata=agentref_meta,
          )

          return jsonify({"url": session.url})
      ```
    </CodeGroup>
  </Tab>

  <Tab title="Stripe Payment Links">
    If you use Stripe Payment Links (links to `buy.stripe.com`), the tracking script instruments them **automatically**. No backend changes needed.

    When the script detects an active click token, it appends `?client_reference_id=<clickToken>` to any `buy.stripe.com` link on the page using a `MutationObserver`. AgentRef reads this field from the Stripe webhook.

    Make sure your tracking script is loaded before the customer can click the payment link. The standard `async` script tag is sufficient – the observer fires on DOM mutations so late-rendered links are also covered.

    <Warning>
      Automatic Payment Link instrumentation only works when the tracking script is on the same page as the link. If you link to your Stripe Payment Link from a third-party site or email, use [Server-side tracking](/tracking/server-side) instead.
    </Warning>
  </Tab>

  <Tab title="Stripe Pricing Table">
    Stripe's embedded `<stripe-pricing-table>` web component is also instrumented automatically. The script sets the `client-reference-id` attribute on the element when a click token is present.

    ```html theme={null}
    <!-- Your pricing table element – the script will add client-reference-id automatically -->
    <stripe-pricing-table
      pricing-table-id="prctbl_xxx"
      publishable-key="pk_live_xxx"
    ></stripe-pricing-table>

    <script
      src="https://www.agentref.co/api/tracking/script.js?pid=YOUR_PROGRAM_ID"
      async
    ></script>
    ```

    The result is equivalent to setting it manually:

    ```html theme={null}
    <stripe-pricing-table
      pricing-table-id="prctbl_xxx"
      publishable-key="pk_live_xxx"
      client-reference-id="clk_a1b2c3d4e5"
    ></stripe-pricing-table>
    ```

    <Note>
      The script uses a `MutationObserver` to catch pricing tables that render after the page loads (e.g., in SPAs). You do not need to wait for the script to load before rendering the pricing table.
    </Note>
  </Tab>

  <Tab title="Custom payment flow">
    If you use Stripe.js or the Payment Intents API directly, read `window.AgentRef.getCheckoutMetadata()` on the client, send it to your server, and embed it into the PaymentIntent or Customer metadata:

    <CodeGroup>
      ```js Node.js theme={null}
      app.post('/api/pay', async (req, res) => {
        const { agentrefMeta } = req.body;

        const paymentIntent = await stripe.paymentIntents.create({
          amount: 2900,
          currency: 'usd',
          metadata: {
            ...(agentrefMeta || {}),
          },
        });

        res.json({ clientSecret: paymentIntent.client_secret });
      });
      ```

      ```python Python theme={null}
      @app.route("/api/pay", methods=["POST"])
      def pay():
          data = request.get_json()
          metadata = data.get("agentrefMeta", {})

          payment_intent = stripe.PaymentIntent.create(
              amount=2900,
              currency="usd",
              metadata=metadata,
          )

          return jsonify({"clientSecret": payment_intent["client_secret"]})
      ```
    </CodeGroup>
  </Tab>

  <Tab title="External app or extension">
    If the buy button lives outside the website where the AgentRef script is installed, route it through your website before sending the user to Stripe.

    ```txt theme={null}
    Chrome extension or external app
    -> https://yoursite.com/checkout/start?plan=pro
    -> your website reads AgentRef metadata
    -> your backend creates Stripe Checkout with that metadata
    -> redirect to Stripe
    ```

    The checkout start page should run on the same root domain as your AgentRef script. A typical implementation renders a minimal page, calls `window.AgentRef.getCheckoutMetadata()`, posts the metadata to your existing checkout endpoint, and redirects to the returned Stripe Checkout URL.

    <Warning>
      If an AI coding agent needs to reroute an existing buy button to this website checkout start page, it should explain the change and ask you before editing. Do not let it silently restructure checkout.
    </Warning>
  </Tab>
</Tabs>

## Verifying attribution

After completing a test purchase, you can confirm attribution was captured correctly by checking the conversion in your AgentRef dashboard. The conversion will appear under **Conversions** with status `pending`.

To verify programmatically, look at the Stripe session's metadata in the Stripe dashboard – you should see `agentref_cid`, `agentref_pid`, and `agentref_source` fields populated for custom checkout flows. For Payment Links, Buy Buttons, and Pricing Tables, verify that Stripe received the click token via `client_reference_id`.

<Tip>
  Use [Debug Mode](/tracking/debug-mode) to inspect cookies and confirm `agentref_cid` is set before triggering a test checkout.
</Tip>

## What happens without metadata

If a Stripe payment event arrives without `agentref_cid` in the metadata (and without a `client_reference_id` for Payment Links/Pricing Tables), AgentRef will not create a conversion for that payment. The payment is not affected – only the affiliate attribution is skipped.

Coupon-based attribution does not require metadata. If the customer uses a coupon code linked to an affiliate, a conversion is created regardless of whether tracking cookies were set.
