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

# POST /offers/feed

> Endpoint contract for POST /offers/feed: fetch a ranked batch of offers for one user.

Returns the bandit-ranked eligible offers for one user, up to `limit`, so you can render them in your own UI and cycle through them. Each offer carries its own `impressionUid` and a branded short `clickUrl`.

```http theme={null}
POST https://api.encorekit.com/encore/publisher/sdk/v1/offers/feed
```

<Note>
  Calling this endpoint is **not** the impression. When you actually display an offer, confirm it with [`POST /offers/impressions/{impressionUid}/delivered`](/publishers/offers-api/reference/delivered). For the scenario walkthrough (render, confirm, route the tap), see the [Rewarded Actions guide](/publishers/offers-api/guides/rewarded-actions); to fetch your full curated inventory instead of a ranked selection, see [`POST /offers/catalog`](/publishers/offers-api/reference/catalog).
</Note>

## Authentication

Pass your publishable key in the `X-API-Key` header (`pk_live_*` for production, `pk_test_*` for development). Multi-app projects also send `X-Platform: api`. Test keys return offers but do no impression or conversion tracking. The full model, including the API platform app type, is in the [overview's Authentication section](/publishers/offers-api/overview#authentication).

## Request

### Structure

```typescript theme={null}
interface OffersFeedRequest {
  clientId: string;              // required: stable per-operator identifier
  userId: string;                // required: stable end-user identifier
  limit?: number;                // 1-25, default 10
  attributes: {
    countryCode: string;         // required: ISO 3166-1 alpha-2, two uppercase letters
    language: string;            // required: BCP-47 language tag
    platform?: 'android' | 'ios' | 'web';  // the END USER's device platform; never 'api'
  };
}
```

### Field Reference

| Field                    | Type    | Required | Description                                                                                                                                                                                                                                             |
| ------------------------ | ------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `clientId`               | string  | Yes      | Stable per-operator identifier: the business, account, or operator the offers are rendered on behalf of. Carried through as an analytics dimension so impressions, clicks, and conversions can be broken down per client.                               |
| `userId`                 | string  | Yes      | End-user identifier on your surface. Seeds bandit ranking and is the userId on the transaction created at click time, plus the userId dimension on the click event. Keep it stable per user.                                                            |
| `limit`                  | integer | No       | How many offers to return. Range `1` to `25`, default `10`. You control display order and cycle through them. Fewer may be returned when fewer eligible offers exist.                                                                                   |
| `attributes.countryCode` | string  | Yes      | ISO 3166-1 alpha-2, two uppercase letters (for example `"US"`, `"GB"`, `"CA"`). Drives geo-targeting and the country dimension on analytics.                                                                                                            |
| `attributes.language`    | string  | Yes      | BCP-47 language tag (for example `"en"`, `"es"`). Drives creative locale resolution.                                                                                                                                                                    |
| `attributes.platform`    | string  | No       | The **end user's** device platform: `"android"`, `"ios"`, or `"web"`. Optional for API-platform apps: omit it to receive all entitled, geo-eligible offers; send it to narrow the feed to creatives that support that surface. Never send `"api"` here. |

<Note>
  **API-platform apps receive every eligible offer by default.** An app created with platform **API** gets all entitled, geo-eligible offers with no per-platform trimming, which is ideal when you serve a mixed-platform audience from your own server. To narrow a single request to one surface, send that end user's device platform in `attributes.platform`.
</Note>

## Response

### Structure

```typescript theme={null}
interface OffersFeedResponse {
  success: true;
  offers: Array<{
    impressionUid: string;              // per-offer impression handle (UUID)
    clickUrl: string;                   // branded short link on link.encorekit.com
    title: string;                      // offer headline
    description: string | null;         // short supporting line
    imageUrl: string;                   // wide banner creative (~2.4:1)
    additionalImages: string[];         // extra image URLs; may be empty
    advertiserName: string;             // advertiser / brand name
    advertiserLogo: string | null;      // roughly square logo URL
    perk?: string | null;               // campaign value proposition
    badgeLabel: 'free_trial' | 'discount' | null;  // constrained promo badge
  }>;
}
```

### Field Reference

| Field                       | Type                                     | Description                                                                                                                                                                                                                           |
| --------------------------- | ---------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `success`                   | `true`                                   | Always `true` on a 200. Non-success outcomes come back as 4xx/5xx; see [Status codes](#status-codes).                                                                                                                                 |
| `offers`                    | array                                    | A ranked list of offers, best first. **Empty array** when no eligible offers were found for this user (geo-targeted out, no active campaigns, all creatives filtered by platform). Never a 404.                                       |
| `offers[].impressionUid`    | UUID                                     | Per-offer impression handle. Use it to confirm the impression when you display this offer via [`POST /offers/impressions/{impressionUid}/delivered`](/publishers/offers-api/reference/delivered). Not end-user-visible.               |
| `offers[].clickUrl`         | URL                                      | Branded short link on the fixed host `link.encorekit.com`. Open it when the user taps this offer: it 302-redirects to the advertiser with attribution and registers the click/claim. End-user-visible. **Always wire the tap to it.** |
| `offers[].title`            | string                                   | Headline of the offer. Use as the lead line in your UI.                                                                                                                                                                               |
| `offers[].description`      | string \| `null`                         | Short supporting line about the offer (for example `"Limited time offer"`). May be `null`.                                                                                                                                            |
| `offers[].imageUrl`         | URL                                      | Wide banner creative. Render it as the offer's hero image; see [Image fields](#image-fields).                                                                                                                                         |
| `offers[].additionalImages` | array of URL                             | Extra image URLs for this offer; ratio not guaranteed. **May be empty.** Render ratio-agnostic.                                                                                                                                       |
| `offers[].advertiserName`   | string                                   | The advertiser / brand name (for example `"Acme"`).                                                                                                                                                                                   |
| `offers[].advertiserLogo`   | URL \| `null`                            | The advertiser's logo image URL (roughly square), or `null` when the advertiser has no logo set.                                                                                                                                      |
| `offers[].perk`             | string \| `null`                         | The campaign value proposition (for example `"3 months free"`), or `null`. May also be **absent** from the object.                                                                                                                    |
| `offers[].badgeLabel`       | `"free_trial"` \| `"discount"` \| `null` | Constrained promo badge for the offer card, or `null` when the campaign has none. Map the enum to your own display text. Distinct from `perk` (the longer value proposition).                                                         |

The response carries **no internal identifiers** beyond each offer's `impressionUid`. Offer ids, campaign ids, creative ids, and request ids are not returned; they are still computed server-side for analytics.

### Image fields

| Field                | Aspect ratio                              | Nullable           | How to render                                                                                                           |
| -------------------- | ----------------------------------------- | ------------------ | ----------------------------------------------------------------------------------------------------------------------- |
| `advertiserLogo`     | \~**1:1 (square)**, not strictly enforced | Yes                | Render in a 1:1 frame with `object-fit: contain`; handle `null` by hiding the mark or falling back to `advertiserName`. |
| `imageUrl`           | **\~2.4:1 wide banner** (NOT 16:9)        | No                 | Design the slot for \~2.4:1, or use `object-fit: cover`.                                                                |
| `additionalImages[]` | Not guaranteed                            | Array may be empty | Render ratio-agnostic (`object-fit: contain` in a flexible frame).                                                      |

<Warning>
  `imageUrl` is a **wide \~2.4:1 banner**, not 16:9. A 16:9 slot will crop or letterbox it.
</Warning>

## Example

```bash theme={null}
# X-Platform is only needed for multi-app projects; single-app keys can omit it.
curl --location --request POST 'https://api.encorekit.com/encore/publisher/sdk/v1/offers/feed' \
  --header 'X-API-Key: YOUR_API_KEY' \
  --header 'X-Platform: api' \
  --header 'Content-Type: application/json' \
  --data '{
    "clientId": "client-42",
    "userId": "user-8b3f7c10",
    "limit": 10,
    "attributes": {
      "countryCode": "US",
      "language": "en",
      "platform": "ios"
    }
  }'
```

```json theme={null}
{
  "success": true,
  "offers": [
    {
      "impressionUid": "550e8400-e29b-41d4-a716-446655440000",
      "clickUrl": "https://link.encorekit.com/Xa3kPq7T",
      "title": "Get 50% Off",
      "description": "Limited time offer",
      "imageUrl": "https://cdn.example.com/banner.png",
      "additionalImages": ["https://cdn.example.com/img2.png"],
      "advertiserName": "Acme",
      "advertiserLogo": "https://cdn.example.com/acme-logo.png",
      "perk": "3 months free",
      "badgeLabel": "discount"
    }
  ]
}
```

## Status codes

| Code          | Meaning                                                                                                                           |
| ------------- | --------------------------------------------------------------------------------------------------------------------------------- |
| `200`         | Success. `offers` may be an empty array if no eligible offers.                                                                    |
| `400`         | Malformed request (missing required field, invalid `attributes.countryCode`, `limit` out of range). Don't retry; fix the request. |
| `401`         | Missing or invalid `X-API-Key`.                                                                                                   |
| `409`         | The client has exceeded their trial limit (rare).                                                                                 |
| `429`         | Rate-limited. Back off and retry.                                                                                                 |
| `503`         | Server temporarily over capacity. Retry with backoff.                                                                             |
| `5xx` (other) | Encore-side failure. Render nothing and proceed without offers.                                                                   |

### Retry guidance

* **Retries are not deduplicated server-side.** Every `/offers/feed` call generates fresh short links and analytics rows, so only fetch a feed once per placement you intend to render.
* Use exponential backoff with jitter (for example 200ms, 1s, 5s, max 3 retries) for transient failures (429 / 503 / network).
* After exhausting retries, render nothing. The end-user experience should never degrade because of an Encore outage.

## Related

* [`POST /offers/impressions/{impressionUid}/delivered`](/publishers/offers-api/reference/delivered): confirm each offer's impression when it is displayed.
* [Rewarded Actions guide](/publishers/offers-api/guides/rewarded-actions): the full fetch, render, confirm, click pattern.
* [`POST /offers/catalog`](/publishers/offers-api/reference/catalog): full eligible inventory for curated surfaces.
* [API Reference overview](/publishers/offers-api/overview): auth, the impression model, and feed vs catalog.
