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

# Postback URL tracking (inbound S2S)

> Track affiliate sign-ups and sales with a keyless postback URL. Partnero appends a click_id to every referral visit; your server sends it back at conversion — no cookies, no JavaScript, no API key.

Postback URL tracking lets your server report conversions to Partnero using a **click ID** instead of cookies or the PartneroJS snippet. Partnero appends a `click_id` query parameter to every referral-link visit; you store it and send it back when the visitor signs up or purchases.

Unlike the [REST API](/guides/tracking/server-to-server), the postback URL requires **no API key** — attribution is scoped by your program's public ID and a valid click ID.

## How it works

1. **A visitor clicks a partner's referral link.** Partnero records the click and generates a unique click ID.
2. **Your site receives the click ID** — as a `click_id` query parameter on the landing URL, in the `partnero_click_id` cookie set by PartneroJS, or as a response from the click registration API (see [Where the click ID comes from](#where-the-click-id-comes-from)).
3. **You store the `click_id` value** — in your session, database, or any storage that survives until conversion.
4. **Your server calls the postback URL** with that `click_id` when the visitor converts. Partnero matches it to the click and attributes the sign-up or sale to the right partner.

Because the browser plays no part at conversion time, attribution survives ad-blockers, blocked cookies, Safari ITP, in-app browsers, and cross-device flows.

## Where the click ID comes from

Partnero generates a click ID in three ways. All three create the same click record — pick whichever fits your setup.

### 1. Referral link redirect

If your referral links go through a connected tracking domain (for example `go.yourdomain.com/john`), the redirect automatically appends the click ID to the destination URL:

```
https://your-site.com/?click_id=Ab3xK9
```

Read it from the query string on your landing page. Nothing else to set up.

### 2. PartneroJS (direct links)

If referral links point straight at your site (for example `https://your-site.com/?aff=john`) there is no redirect, so the [PartneroJS snippet](/guides/tracking/javascript-tracking) registers the click for you. On a referred visit it requests a click ID and stores it in a first-party cookie:

```
partnero_click_id=Ab3xK9
```

Read the cookie server-side at conversion time. The snippet also injects the click ID as a hidden `partnero_click_id` input into any `<form data-partnero>` form. If the visitor arrived through a redirect that already carries a `click_id` parameter, the snippet reuses it instead of registering a duplicate click.

### 3. Click registration API

Use this when neither of the options above fits: your referral links point straight at your site, but you don't run PartneroJS — for example a backend-only integration, a mobile app, or a server-rendered site without the snippet. Your own code registers the click and receives the click ID in return.

<Steps>
  <Step title="Capture the referral key on landing">
    When a visitor arrives through a referral link like `https://your-site.com/?aff=john`, read the partner's referral key (`john`) from the URL — the same way you would for any referral tracking.
  </Step>

  <Step title="Register the click">
    Send the referral key to the click registration endpoint. `{pub_id}` is your program's public ID, shown on the Postbacks page. No API key is needed.

    ```bash theme={null}
    curl -X POST "https://api.partnero.com/pub/v1/s2s/clicks/{pub_id}" \
      -H "Content-Type: application/json" \
      -d '{"partner": "john", "url": "https://your-site.com/?aff=john&clickId=TRACKER_CLICK_ID"}'
    ```

    | Parameter | Required | Description                                                                                                                                                             |
    | --------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
    | `partner` | Yes      | The partner's referral key captured in step 1                                                                                                                           |
    | `url`     | No       | The full landing URL. If it contains any [trackable query parameters](#trackable-query-parameters-sub-ids) (like `clickId` above), their values are captured as sub-IDs |
  </Step>

  <Step title="Store the returned click ID">
    A successful registration returns the click ID:

    ```json theme={null}
    {"status": 1, "click_id": "Ab3xK9"}
    ```

    Store it with the visitor's session or user record, and send it back in the [postback](#the-postback-endpoint) when they convert.
  </Step>
</Steps>

<Note>
  Register one click per referred landing — not on every page view. Like the postback endpoint, this endpoint responds `200` with an empty JSON body on any failure (unknown program, unknown partner, or postback tracking disabled), and requests are rate-limited to 60 per minute per IP.
</Note>

## Enable postback tracking

1. In the Partnero dashboard, open **Program → Integration → Postbacks** (affiliate programs).
2. In the **Inbound S2S tracking** section, switch on **Postback (S2S) tracking**.

The section then shows your program's unique postback endpoint and copy-ready example requests. Once enabled, referral-link redirects automatically start carrying the `click_id` parameter, PartneroJS starts registering clicks on direct referral visits, and the click registration API becomes active.

## The postback endpoint

```
GET|POST https://api.partnero.com/pub/v1/s2s/postback/{pub_id}
```

* `{pub_id}` is your program's public ID — the same ID used by the PartneroJS snippet. You don't need to build the URL yourself: the Postbacks page shows your program's complete endpoint, ready to copy.
* Both `GET` (query parameters) and `POST` (form or JSON body) are accepted.
* **No authentication token is required.** Requests are matched by the `click_id` value; requests with an unknown `click_id` are silently ignored.
* The endpoint always responds `200 OK`, whether or not the postback matched a click. This is intentional: it prevents third parties from probing for valid click IDs.

Two events are supported, selected with the `event` parameter.

### Register a sign-up (`customer_create`)

| Parameter  | Required | Description                                                    |
| ---------- | -------- | -------------------------------------------------------------- |
| `click_id` | Yes      | The click ID captured from the landing URL                     |
| `event`    | Yes      | `customer_create`                                              |
| `key`      | Yes      | Your unique identifier for the customer (user ID, email, etc.) |
| `email`    | No       | Customer email                                                 |
| `name`     | No       | Customer name                                                  |

```bash theme={null}
curl "https://api.partnero.com/pub/v1/s2s/postback/{pub_id}?click_id=Ab3xK9&event=customer_create&key=user_512&email=jane@example.com"
```

The customer is created and attributed to the partner from the click record.

### Register a sale (`transaction_create`)

| Parameter                  | Required | Description                                                             |
| -------------------------- | -------- | ----------------------------------------------------------------------- |
| `click_id`                 | Yes      | The click ID captured from the landing URL                              |
| `event`                    | Yes      | `transaction_create`                                                    |
| `key`                      | Yes      | Your unique transaction identifier (order ID, invoice ID)               |
| `amount`                   | Yes      | Transaction amount                                                      |
| `action`                   | No       | Transaction action label (e.g. `sale`)                                  |
| `customer[key]`            | No       | Customer key; defaults to the customer already linked to the click      |
| `options[create_customer]` | No       | Set to `true` to create the customer on the fly if it doesn't exist yet |

```bash theme={null}
curl "https://api.partnero.com/pub/v1/s2s/postback/{pub_id}?click_id=Ab3xK9&event=transaction_create&key=order_1201&amount=49.90&options[create_customer]=true"
```

The transaction flows through the normal pipeline — commission calculation, webhooks, notification emails, and [outbound affiliate postbacks](/guides/postbacks/affiliate-postbacks).

<Tip>
  If you register the sign-up with `customer_create` first, you can skip `options[create_customer]` on the sale — the click record already knows the customer.
</Tip>

## Trackable query parameters (sub-IDs)

Partners who run traffic through their own tracking platforms append extra parameters to referral links — typically their tracker's click ID or campaign sub-IDs:

```
https://go.yourdomain.com/john?clickId=TRACKER_CLICK_ID&affS1=campaign-42
```

To capture these values, define the parameter names under **Program settings → Referral link customization → Trackable query parameters**. At click time Partnero stores the values on the click record. They are then available:

* in click analytics, and
* as placeholders in [affiliate postbacks](/guides/postbacks/affiliate-postbacks#placeholders), so the partner's tracker gets its own click ID echoed back at conversion.

You can add up to 50 parameter names per program. Common industry names (`clickid`, `sub1`, `aff_sub`, `s1`, …) are available as one-click suggestions in the dashboard.

## Storing the click ID

Read `click_id` from the landing URL (redirect setups) or from the `partnero_click_id` cookie (PartneroJS setups) and persist it the same way you would a referral key:

<Tabs>
  <Tab title="Server (session)">
    ```javascript theme={null}
    app.get('/', (req, res) => {
      const clickId = req.query.click_id || req.cookies.partnero_click_id;
      if (clickId) {
        req.session.partneroClickId = clickId;
      }
      res.render('home');
    });
    ```
  </Tab>

  <Tab title="Browser (forward to backend)">
    ```javascript theme={null}
    const clickId = new URLSearchParams(window.location.search).get('click_id');
    if (clickId) {
      fetch('/api/track-landing', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ click_id: clickId })
      });
    }
    ```
  </Tab>

  <Tab title="At conversion (server)">
    ```javascript theme={null}
    const url = new URL(`https://api.partnero.com/pub/v1/s2s/postback/${PUB_ID}`);
    url.search = new URLSearchParams({
      click_id: session.partneroClickId,
      event: 'transaction_create',
      key: order.id,
      amount: order.amount,
      'options[create_customer]': 'true'
    });

    await fetch(url); // no API key needed
    ```
  </Tab>
</Tabs>

## Postback URL tracking vs. REST API

|                     | Postback URL *(this guide)*                               | [REST API](/guides/tracking/server-to-server)    |
| ------------------- | --------------------------------------------------------- | ------------------------------------------------ |
| Authentication      | None — matched by `click_id`                              | `Authorization: Bearer` API key                  |
| Attribution carrier | Partnero-generated click ID                               | Referral key you capture from the URL            |
| Response on failure | Always `200` (silent)                                     | Standard HTTP errors                             |
| Best for            | Simple keyless integration, tracker-style postback setups | Full control, richer customer/transaction fields |

## Checklist

1. Enable **Postback (S2S) tracking** under **Program → Integration → Postbacks**.
2. Store the `click_id` from the landing URL between click and conversion.
3. Call the postback endpoint with `event=customer_create` at sign-up.
4. Call it with `event=transaction_create` at purchase.
5. Optionally, define **trackable query parameters** so partner sub-IDs are captured too.

## Frequently asked questions

<AccordionGroup>
  <Accordion title="Does the postback endpoint need an API key?">
    No. Requests are scoped by your program's public ID and matched by the `click_id`; unknown click IDs are ignored.
  </Accordion>

  <Accordion title="Why does the endpoint always return 200?">
    To avoid leaking which click IDs are valid. To debug deliveries, open **Logs** in the Inbound S2S tracking section of the Postbacks page — every incoming request is recorded with its parameters and outcome (`success`, `failed`, or `ignored`).
  </Accordion>

  <Accordion title="Can I use GET and POST interchangeably?">
    Yes. GET takes query parameters; POST accepts the same fields as form data or JSON.
  </Accordion>

  <Accordion title="What happens if the same click_id is sent twice?">
    Both events are safe to retry. `customer_create` is idempotent — if a customer with the same `key` already exists, the request succeeds and returns the existing customer. Transactions are deduplicated by your transaction `key` — send a unique order or invoice ID per sale.
  </Accordion>
</AccordionGroup>

## Next steps

<CardGroup cols={2}>
  <Card title="Affiliate postbacks" icon="arrow-right-from-bracket" href="/guides/postbacks/affiliate-postbacks">
    Echo conversions back to your partners' tracking platforms
  </Card>

  <Card title="REST API S2S tracking" icon="server" href="/guides/tracking/server-to-server">
    API-key-based server-side tracking with full field control
  </Card>
</CardGroup>
