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

# S2S Impression API

> Report affiliate ad impressions server-to-server for view-through attribution

Affiliate partners use this endpoint to report an ad impression from their server, so Linkrunner can credit a view-through install. For the setup guide and the attribution rules, see [Server-to-Server Impressions](/affiliate-partners/s2s-impressions).

## Endpoint

```
GET https://s2s.linkrunner.io/v1/impression/{app_id}
GET https://s2s.linkrunner.io/v1/impression?app_id={app_id}
GET https://s2s.linkrunner.io/v1/impression?d={domain}
```

No API key is needed. The advertiser is identified by the app ID (or the tracking link's domain) and the campaign by `c`. The campaign must belong to your partner account, and the advertiser must have turned on S2S traffic and view-through for you.

## Parameters

Send all parameters as URL-encoded query parameters. Each value is limited to 256 characters.

| Parameter         | Alias                     | Required                | Description                                                                                                                                                                                          |
| ----------------- | ------------------------- | ----------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `app_id`          | path                      | One of `app_id` or `d`  | The app's Android package name (`com.example.app`) or App Store ID (`id1234567890` or `1234567890`). Can also be sent in the path: `/v1/impression/{app_id}`.                                        |
| `d`               |                           | One of `app_id` or `d`  | Domain of your Linkrunner tracking link, for example `app.example.com`. Wins over `app_id` when both are sent.                                                                                       |
| `c`               |                           | Yes                     | Campaign code, the `c` value of your tracking link. Must match a campaign of that app or domain exactly.                                                                                             |
| `tid`             | `clickid`                 | Yes                     | Your unique impression ID. Returned in the `{click_id}` and `{tid}` postback macros.                                                                                                                 |
| `gaid`            | `advertising_id`          | One of `gaid` or `idfa` | Google Advertising ID, as a UUID.                                                                                                                                                                    |
| `idfa`            |                           | One of `gaid` or `idfa` | Apple IDFA, as a UUID.                                                                                                                                                                               |
| `impression_time` |                           | No                      | Unix timestamp of the impression, in milliseconds or seconds. Defaults to the time of the request.                                                                                                   |
| `vt_lookback`     | `af_viewthrough_lookback` | No                      | Your view-through window for this impression: `1h` to `24h`, a bare number of hours (`6`), or `1d`. Longer values are capped at 24 hours. It can only shorten the window the advertiser set for you. |
| `ip`              | `af_ip`                   | No                      | The user's device IP. Stored for reporting, never used for matching. Only public addresses are kept.                                                                                                 |
| `ua`              | `af_ua`                   | No                      | The user's device user agent. Stored for reporting.                                                                                                                                                  |
| `s2`              | `af_sub1`                 | No                      | Passthrough value, returned in `{s2}`.                                                                                                                                                               |
| `s3`              | `af_sub2`                 | No                      | Passthrough value, returned in `{s3}`.                                                                                                                                                               |
| `s4`              | `af_sub3`                 | No                      | Passthrough value, returned in `{s4}`.                                                                                                                                                               |

Every impression needs a `gaid` or an `idfa`. View-through attribution matches on device ID only, so unlike [S2S clicks](/api-reference/s2s-clicks), an IP address alone is rejected.

If both a name and its alias are sent, the name wins. `click_time` is ignored on this endpoint; use `impression_time`. `pid`, `af_siteid` and `af_lang` are ignored, so an AppsFlyer impression template works once the host and `c` are changed.

## Responses

The response is always JSON.

<CodeGroup>
  ```json 200 Accepted theme={null}
  {
    "status": "accepted",
    "impression_id": "dfa5b5ed-54c2-5f5b-bc48-2385c336fed8"
  }
  ```

  ```json 400 Rejected theme={null}
  {
    "status": "rejected",
    "reason": "missing_device_id"
  }
  ```
</CodeGroup>

`impression_id` is Linkrunner's ID for the impression. It is the same for every retry of the same `tid` on the same campaign.

### Status codes

| Status | Reason                         | Meaning                                                                                                                                         | Retry                    |
| ------ | ------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------ |
| 200    |                                | Impression recorded.                                                                                                                            |                          |
| 400    | `missing_app`                  | Neither `app_id` nor `d` was sent.                                                                                                              | No                       |
| 400    | `missing_c`, `missing_tid`     | A required parameter is missing or empty.                                                                                                       | No                       |
| 400    | `missing_device_id`            | No `gaid` and no `idfa`. An all-zero ID counts as missing.                                                                                      | No                       |
| 400    | `invalid_device_id`            | `gaid` or `idfa` is not a UUID, for example `null` or `unknown`.                                                                                | No                       |
| 400    | `unreplaced_macro`             | A value still contains a macro, such as `{gaid}` or `%7Bgaid%7D`.                                                                               | No                       |
| 400    | `value_too_long`               | A value is longer than 256 characters.                                                                                                          | No                       |
| 400    | `invalid_impression_time`      | `impression_time` is not a Unix timestamp.                                                                                                      | No                       |
| 400    | `impression_too_old`           | `impression_time` is more than 24 hours ago. A time in the future is treated as now.                                                            | No                       |
| 400    | `invalid_viewthrough_lookback` | `vt_lookback` is `0`, negative, fractional, or not in hours or days.                                                                            | No                       |
| 400    | `unknown_app`                  | No Linkrunner project has this app ID.                                                                                                          | No                       |
| 400    | `ambiguous_app`                | More than one of the advertiser's projects with S2S on for you has this app ID and campaign code (for example test and live). Send `d` instead. | No                       |
| 400    | `unknown_domain`               | `d` is not a Linkrunner click domain.                                                                                                           | No                       |
| 400    | `unknown_campaign`             | `c` does not match a campaign of that app or domain.                                                                                            | No                       |
| 403    | `partner_not_enabled`          | The advertiser hasn't turned on S2S traffic for the partner that owns campaign `c`.                                                             | No                       |
| 403    | `view_through_disabled`        | S2S traffic is on, but the advertiser hasn't turned on view-through for this partner.                                                           | No                       |
| 404    | `s2s_disabled`                 | The S2S impression API is turned off.                                                                                                           | No                       |
| 429    | `rate_limited`                 | Too many impressions for this campaign.                                                                                                         | Yes, after `Retry-After` |
| 503    | `unavailable`                  | A temporary error.                                                                                                                              | Yes, after `Retry-After` |

## Examples

<CodeGroup>
  ```bash cURL theme={null}
  curl -G "https://s2s.linkrunner.io/v1/impression/com.example.app" \
    --data-urlencode "c=OgWmhiSXhG" \
    --data-urlencode "tid=imp-7f3a91" \
    --data-urlencode "gaid=38400000-8cf0-11bd-b23e-10b96e40000d" \
    --data-urlencode "impression_time=1790585271181" \
    --data-urlencode "vt_lookback=6h" \
    --data-urlencode "s2=banner_top"
  ```

  ```javascript Node.js theme={null}
  const params = new URLSearchParams({
    c: "OgWmhiSXhG",
    tid: impressionId,
    gaid: advertisingId,
    impression_time: String(Date.now()),
    vt_lookback: "6h",
    s2: "banner_top",
  });

  const res = await fetch(`https://s2s.linkrunner.io/v1/impression/com.example.app?${params}`);
  const body = await res.json(); // { status: "accepted", impression_id: "..." }
  ```

  ```python Python theme={null}
  import time, requests

  res = requests.get("https://s2s.linkrunner.io/v1/impression/com.example.app", params={
      "c": "OgWmhiSXhG",
      "tid": impression_id,
      "gaid": advertising_id,
      "impression_time": int(time.time() * 1000),
      "vt_lookback": "6h",
      "s2": "banner_top",
  }, timeout=5)
  body = res.json()  # {"status": "accepted", "impression_id": "..."}
  ```
</CodeGroup>

An iOS impression, with the advertiser's default window:

```
https://s2s.linkrunner.io/v1/impression/id1234567890?c=OgWmhiSXhG&tid=imp-7f3a92&idfa=6D92078A-8246-4BA4-AE5B-76104861E7DC
```

## Retries and deduplication

The same `tid` on the same campaign always maps to the same `impression_id`, and the impression is stored once, so it is safe to retry. Retry only `429` and `503`, after the delay in the `Retry-After` header. Keep `tid` unique per impression: a reused `tid` is treated as a retry of the earlier impression, so the new one is not recorded.
