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

# Paddle integration

> Track purchases made through Paddle Billing and attribute them to the partner who referred the customer

The Paddle integration has two parts, and both are required:

1. **Authorize Paddle** so Partnero receives the payments your customers make, including renewals.
2. **Add referral tracking to your site** so Partnero knows which partner referred each customer.

Authorization on its own gives Partnero payments it cannot attribute to anyone. Step 2 is what creates the
referred customer the payments attach to.

<Note>
  Your program's own integration guide, with your program ID already filled in, lives in the app under
  **Integration** → **Guides**. It is the source of truth for the snippets below.
</Note>

This page covers **Paddle Billing**, the default Paddle experience. If you signed up before 8 August 2023 you
may still be on Paddle Classic — see [Integrate Paddle Classic](/integrations/integrate-paddle-classic).

## Step 1: Authorize Paddle

1. In Paddle, go to **Developer Tools** → **Authentication** and generate an API key.
2. In Partnero, go to **Integration** and scroll to **Apps & Integrations**.
3. Click **Authorize** next to Paddle, paste the API key, and click **Authorize**.

You do not configure Paddle notifications yourself. Partnero creates the webhooks it needs when you authorize.

## Step 2: Add referral tracking to your site

This is what tells Partnero which partner referred a customer. Without it, Paddle sends Partnero payments it
cannot attribute to anyone.

### Install the tracking script

Every method starts here. This snippet identifies visitors arriving through a partner's referral link and stores
the partner key in a first-party cookie.

**Copy your own snippet from the app** — don't retype the one below. It is generated per program and already
contains your program ID:

1. Open the program and go to **Integration**.
2. Copy the **PartneroJS** snippet shown there. It also appears inside every guide on the **Guides** tab.

Paste it before the closing `</head>` tag on every page a referred visitor might land on — ideally site-wide.

For reference, the snippet looks like this, where `YOUR_PROGRAM_ID` is filled in for you:

```html theme={"system"}
<!-- PartneroJS -->
<script>
(function(p,t,n,e,r,o){p['__partnerObject']=r;function f(){var c={a:arguments,q:[]};var r=this.push(c);return "number"!=typeof r?r:f.bind(c.q);}
f.q=f.q||[];p[r]=p[r]||f.bind(f.q);p[r].q=p[r].q||f.q;o=t.createElement(n);var _=t.getElementsByTagName(n)[0];o.async=1;
o.src=e+'?v'+(~~(new Date().getTime()/1e6));_.parentNode.insertBefore(o,_);})(window,document,'script','https://app.partnero.com/js/universal.js','po');
po('program', 'YOUR_PROGRAM_ID', 'load');
</script>
<!-- End PartneroJS -->
```

<Warning>
  Unlike the Stripe integration, PartneroJS does not pass anything to Paddle on its own. If customers buy
  through a Paddle checkout you must also add one of the Overlay checkout scripts below.
</Warning>

### Then choose a method

<Tabs>
  <Tab title="Overlay: Paddle.Checkout.open()">
    Use this if you open the checkout with Paddle's
    [`Paddle.Checkout.open()` method](https://developer.paddle.com/build/checkout/build-overlay-checkout#paddle.checkout.open\(\)-method).

    The script wraps `Paddle.Checkout.open` so every checkout carries the partner key in `customData`. Place it
    at the bottom of the page, directly above the closing `</body>` tag.

    ```html theme={"system"}
    <script>
    const partnerKey = (document.cookie.match(/(^| )partnero_partner=([^;]+)/) || [])[2];
    if (partnerKey) {
      const originalOpen = Paddle.Checkout.open;
      Paddle.Checkout.open = function(options) {
        options.customData = options.customData || {};
        options.customData.customer_key = decodeURIComponent(partnerKey);
        return originalOpen.call(this, options);
      };
    }
    </script>
    ```
  </Tab>

  <Tab title="Overlay: HTML data attributes">
    Use this if your checkout is triggered by Paddle's
    [HTML data attributes](https://developer.paddle.com/build/checkout/build-overlay-checkout#html-data-attributes)
    on `.paddle_button` elements.

    The script sets `data-custom-data` on each button. Place it at the bottom of the page, directly above the
    closing `</body>` tag.

    ```html theme={"system"}
    <script>
    document.querySelectorAll('.paddle_button').forEach(button => {
      const cookieValue = (document.cookie.match(/(^| )partnero_partner=([^;]+)/) || [])[2];
      if (cookieValue) {
        button.setAttribute('data-custom-data', JSON.stringify({
          customer_key: decodeURIComponent(cookieValue)
        }));
      }
    });
    </script>
    ```
  </Tab>

  <Tab title="User sign-up">
    Use this if customers sign up on your platform before paying. Partnero creates the customer and links it to
    the partner at sign-up, so every later Paddle purchase by that customer is attributed automatically. No
    Overlay script is needed.

    For that to work Partnero has to recognise the payer, so pass the same key in Paddle's `custom_data` as
    `customer_key` when you create the Paddle customer or transaction.

    Run this immediately after the user signs up. Attribution is read from the `partnero_partner` cookie:

    ```html theme={"system"}
    <script>
    po('customers', 'signup', {
      data: {
        key: 'customer_123456',
        name: 'John',
        email: 'john.doe@partnero.com'
      }
    });
    </script>
    ```

    Or create the customer from your backend, passing the partner key you read from the cookie:

    ```bash theme={"system"}
    curl -X POST https://api.partnero.com/v1/customers \
      -H "Authorization: Bearer YOUR_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "partner": {
          "key": "PARTNER_KEY_FROM_COOKIE"
        },
        "key": "customer_123456",
        "email": "customer@partnero.com",
        "name": "John Doe"
      }'
    ```

    Your API key is in the app under **Integration** → **API**. Keep it server-side.
  </Tab>
</Tabs>

<Note>
  In a refer-a-friend program the cookie is `partnero_referral` instead of `partnero_partner`, and the referrer
  is sent as `referring_customer.key`. The Overlay scripts are otherwise identical.
</Note>

## What gets tracked

Once both steps are done, Partnero records completed purchases and new subscriptions made by your referred
customers, and reverses the commission automatically when a payment is refunded.

## Attribution from your own backend

When a visitor arrives through a referral link, PartneroJS stores the partner key in a first-party cookie named
`partnero_partner` (`partnero_referral` in a refer-a-friend program). That cookie is where the partner key comes
from — read it on your server from the incoming request headers.

If you create Paddle transactions server-side, pass the key in Paddle's `custom_data`:

* `customer_key` — the key of the customer in Partnero. If no customer matches it, Partnero falls back to
  treating the value as a partner key, which is why the Overlay scripts above can use the same field.
* `partner_key` — attribute the sale to that partner even when no customer record exists yet.
* `client_reference_id` — equivalent to `customer_key` used as a partner key, for parity with Stripe.

Partnero reads these from the transaction and from the Paddle customer's own `custom_data`. If your Paddle
custom data already uses a different field name for the customer, map it instead of renaming your own field:
open the Paddle integration in the app and set **Paddle integration mapping**.

## Troubleshooting

<AccordionGroup>
  <Accordion title="Purchases are not appearing in Partnero">
    Check step 2 actually ran. Open the customer in Partnero and confirm it exists and has a partner attached.
    A payment Partnero cannot tie to a customer is not attributed to anyone.
  </Accordion>

  <Accordion title="Checkouts carry no attribution">
    PartneroJS alone does not reach Paddle. Confirm one of the Overlay scripts is on the page that opens the
    checkout, below the checkout markup and above the closing `</body>` tag, and that the
    `partnero_partner` cookie is set when you arrive through a referral link.
  </Accordion>

  <Accordion title="The customer exists but the sale is attributed to nobody">
    Partnero could not recognise the payer. The `customer_key` in Paddle's custom data must match the customer
    key in Partnero character for character. Paddle does not fall back to matching on email the way Stripe
    does, so an email-only match is not enough.
  </Accordion>

  <Accordion title="Nothing is tracked after a renewal">
    Renewals arrive on the Paddle webhooks Partnero creates at authorization, so this needs step 1. Creating
    the customer alone is not enough.
  </Accordion>

  <Accordion title="I am on Paddle Classic">
    Paddle Classic uses `passthrough` rather than `custom_data`, and its webhooks are not created
    automatically. Follow [Integrate Paddle Classic](/integrations/integrate-paddle-classic) instead.
  </Accordion>
</AccordionGroup>

## Next steps

<CardGroup cols={2}>
  <Card title="Paddle Classic" icon="clock-rotate-left" href="/integrations/integrate-paddle-classic">
    The pre-2023 Paddle integration
  </Card>

  <Card title="Transactions API" icon="code" href="/api-reference/transactions/create">
    Record transactions yourself
  </Card>
</CardGroup>


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