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

# Offer Catalog Integration

> Fetch the Encore offers your app may serve a given user via a single REST call. The endpoint returns the eligible offers (entitlement and geography already applied), each with its creatives, so you curate and render them however you like.

## Overview

If you display offers to your users on your own surface, Encore can supply the offers to fill it. You call one REST endpoint, get back the set of offers your app is allowed to serve to a specific end user, and render them in your own UI. There is no SDK to install and no webhook to host.

Encore does the eligibility work for you. Every response is already filtered by two rules you cannot override:

* **Entitlement.** Only offers your app is permitted to serve (your account's opt-outs and any allow-list restrictions) are ever returned.
* **Geography.** Only offers redeemable in the end user's country are returned. Offers a user could not redeem are never shown.

You do the presentation work: pick which of the returned offers to feature, order them, and fall back to others when your first choices are not available for a given user.

***

## Typical usage pattern

Two **hard filters**, entitlement and geography, always run on Encore's side, so any offer you receive is one your app is allowed to serve and the end user can redeem. Your **curation**, which offers to feature and in what order, is a **soft filter** you apply on top, on your side. That split is the whole pattern.

**Once, at configuration time.** Call the endpoint with `includeAllRegions: true` to pull your full addressable inventory. Each offer includes its `targetCountries`, so you can see where every offer is available. Choose the offers you want to feature and save their `id`s in your own configuration. Re-run whenever you want to refresh what is available to you. This view skips the geography filter and is for planning only, not for display.

**On every render.** Call the endpoint with a stable `userId` for the end user and their country (or their forwarded IP). Encore returns the offers that user is eligible for, already entitlement- and geography-filtered, each creative carrying a `clickUrl`. Then, on your side:

1. Keep the returned offers whose `id` is in your featured list, in your preferred order.
2. If none of your featured offers came back for this user, fall back to the other returned offers so your surface is never empty.
3. Render each offer, and when the user taps one, send them to that creative's `clickUrl` so the tap is attributed (see [Click tracking and attribution](#click-tracking-and-attribution)).

**Why filter on your side rather than sending us your featured `id`s?** Because the hard filters can remove some of your picks for a given user (for example, offers that are all US-only when the user is in Romania). If we narrowed to your list on the server, you would be left with nothing to show. Returning the whole eligible set lets you fall back gracefully. And you can never accidentally show an ineligible offer, because everything we return has already passed the hard filters.

***

## Authentication

Pass your publishable key in the `X-API-Key` header:

```bash theme={null}
X-API-Key: pk_live_...
```

If your key spans multiple platform-specific apps (a multi-app project), also send an `X-Platform` header so we know which app to resolve; otherwise the request is rejected with `X-Platform header required for multi-app projects`:

```bash theme={null}
X-Platform: ios   # one of: ios | android | web
```

A single-app key does not need `X-Platform`. Your app is identified entirely by the key (plus platform, if multi-app). You never name another app, and you only ever receive offers your app is entitled to.

***

## Serving a user

```bash theme={null}
curl -X POST https://api.encorekit.com/encore/publisher/sdk/v1/offers/catalog \
  -H "X-API-Key: pk_live_..." \
  -H "X-Platform: ios" \
  -H "Content-Type: application/json" \
  -d '{ "userId": "<your stable end-user id>", "countryCode": "US" }'
```

Response:

```json theme={null}
{
  "success": true,
  "offers": [
    {
      "id": "b1a7c0de-0000-4000-8000-000000000001",
      "name": "Apple Music - 3 months free",
      "perk": "3 months of Apple Music free",
      "oldPrice": "10.99",
      "newPrice": "0.00",
      "targetCountries": ["US", "CA"],
      "organization": {
        "id": "…",
        "name": "Apple",
        "description": "…",
        "url": "https://www.apple.com",
        "logoUrl": "https://…/apple-logo.png"
      },
      "creatives": [
        {
          "id": "…",
          "title": "Get 3 months of Apple Music free",
          "subtitle": "…",
          "description": "…",
          "primaryImageUrl": "https://…/creative.png",
          "logoUrl": "https://…/logo.png",
          "additionalImages": ["https://…/alt.png"],
          "ctaText": "Claim Offer",
          "supportedPlatforms": ["ios", "android", "web"],
          "clickUrl": "https://api.encorekit.com/encore/click/eyJhcHBJZCI6…"
        }
      ]
    }
  ],
  "metadata": { "total": 8, "limit": 8, "offset": 0, "hasMore": false },
  "locale": "en"
}
```

Each offer carries the fields you need to render an offer card — the offer's name, `perk`, optional `oldPrice`/`newPrice`, the advertiser (`organization`), and one or more `creatives` (image, title, description, CTA, supported platforms) — plus each creative's `clickUrl`. It deliberately does **not** include Encore's internal or commercial fields (payout amounts, the raw advertiser destination URL, tracking parameters, internal notes/config): to send a user to an offer you always use the `clickUrl`, never a raw link (see [Click tracking and attribution](#click-tracking-and-attribution)). By default the whole eligible set is returned, so you normally take it all and curate on your side; to page, pass `limit` (and `offset`) and `hasMore` tells you when to stop.

### Geography is required

Encore never serves an offer a user cannot redeem, so the serve call needs to know the end user's country. Provide it one of two ways:

* **`countryCode`** in the body (ISO 3166-1 alpha-2, for example `"US"`, `"GB"`). Use this when you call from your server and already know the user's country.
* **The end user's IP**, forwarded via the standard `X-Forwarded-For` header. Use this when the call originates from the user's device, or when your proxy passes the user's IP through.

If neither is present, the call returns `400`. We do not guess a default country, because that could serve the wrong region's offers.

### Diagnosing a missing pick

The response contains only offers eligible for this user, so a featured offer you expected may be absent. To tell why, compare against your config-time inventory (the `includeAllRegions` call): if the offer is in that inventory but not in this response, its `targetCountries` did not include the user's country. If it is not in the inventory at all, your app is not entitled to it. See [Typical usage pattern](#typical-usage-pattern) for the full request-and-filter loop.

***

## Click tracking and attribution

Every creative in a serve response carries a `clickUrl`. When the end user taps an offer, route them to that creative's `clickUrl`. Encore records an attributed transaction, then responds with a `302` redirect that sends the user on to the advertiser. You do not build any tracking links yourself and you do not host a redirect.

A few rules keep attribution correct:

* **Use the `clickUrl` exactly as returned.** Treat it as opaque and do not modify, wrap, or rebuild it. Each `clickUrl` is signed and bound to a specific offer, creative, and user, so any change invalidates it.
* **Send a stable `userId` on every serve call.** Use the same value for the same end user across renders. That identifier is what the recorded transaction is attributed to, and it drives per-user protections at tap time.
* **One `clickUrl` per creative.** Route the user to the `clickUrl` on the exact creative they tapped, not a shared or reused one.

For example, when a user taps the Apple Music offer, open the `clickUrl` from that offer's creative:

```
https://api.encorekit.com/encore/click/eyJhbGciOi…
```

Encore handles the rest: it records the click and redirects the user to Apple.

**Config mode has no click URLs.** A call with `includeAllRegions: true` is for planning, not display, so it returns no `userId` binding and no `clickUrl`s. Only serve calls (scoped to a user and their country) return `clickUrl`s you can route taps to.

***

## Building your curation

To see everything your app can offer, regardless of any single user's geography, call with `includeAllRegions`:

```bash theme={null}
curl -X POST https://api.encorekit.com/encore/publisher/sdk/v1/offers/catalog \
  -H "X-API-Key: pk_live_..." \
  -H "X-Platform: ios" \
  -H "Content-Type: application/json" \
  -d '{ "includeAllRegions": true }'
```

This returns your full addressable inventory (entitlement still applies), with each offer's `targetCountries`. Use it to decide which offers to feature and to understand each offer's coverage. Do not render offers straight from this view to end users, since it is not geography-filtered. Anything you display must come from a serve call scoped to that user's country.

***

## Request fields

| Field               | Type                                  | Notes                                                                                                                                                                                                                                                                                   |
| ------------------- | ------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `userId`            | string, required on serve             | A stable identifier for the end user you are serving. Bound into each creative's `clickUrl` so a tap records an attributed transaction for that user. Use the same value across renders for the same user. Not used in config mode (`includeAllRegions`), which returns no `clickUrl`s. |
| `clientId`          | string, optional                      | Identifier for the operator or sub-publisher on whose behalf offers are shown. Carried through as an analytics dimension. Defaults to `userId` when omitted.                                                                                                                            |
| `countryCode`       | string (ISO 3166-1 alpha-2), optional | End user's country. Overrides IP-based detection. Required, via this field or a forwarded IP, unless `includeAllRegions` is set.                                                                                                                                                        |
| `includeAllRegions` | boolean, optional                     | Config-time only. Skips geography filtering and returns your full inventory with `targetCountries`. Not for display.                                                                                                                                                                    |
| `limit`             | integer 1 to 100, optional            | Page size. Omit to return ALL eligible offers (the default).                                                                                                                                                                                                                            |
| `offset`            | integer, optional                     | Page offset (default 0).                                                                                                                                                                                                                                                                |

Full field-level detail lives in the API reference.

***

## What Encore handles vs what you handle

| Handled by Encore (server side)                               | Handled by you (client side)                                 |
| ------------------------------------------------------------- | ------------------------------------------------------------ |
| Which offers your app may serve (entitlement)                 | Which eligible offers to feature                             |
| Which offers are redeemable in the user's country (geography) | Ordering and layout                                          |
| Attaching each offer's creatives and organization             | Falling back to other offers when your picks are unavailable |
| Removing offers with no renderable creative                   | Rendering the offers in your own layout                      |
