# Offer Wall

Source: https://docs.aon.pro/guides/offer-wall

> Derived from the same AON Docs release as the source page.

An Offer Wall is a Developer Portal placement type (`offerwall`) that shows a scrollable list of offers your users can browse and open. Create an **Offer Wall** placement in your application's Placements page in the [Developer Portal](https://developer.aon.pro/). The placement id (`plc_…`) is the only identity the wall needs — you do not send an API key.

There are two ways to show the wall:

| Option | Use it when | What you build |
| --- | --- | --- |
| Hosted page | You want a wall live with no code, or your app can open a web view. | Nothing: open the AON-hosted link in a web view or browser. |
| API | You want the wall rendered in your own native or web UI, with your own layout and styling. | A list screen that calls Offer Query with your placement id and pages through the results. |

Both options use the same placement, the same offers, and the same `sub_id` attribution, so you can start with the hosted page and move to the API later.

## Hosted page (no code)

Every Offer Wall placement has a hosted page. Replace the placement id with yours and `{USER_ID}` with your own identifier for the user:

Hosted Offer Wall link

Response

```
https://offerwall.aon.pro/plc_7c2e0dR9kL4mN8pQ?sub_id={USER_ID}
```

-   Open the link in an in-app web view (or the system browser) from wherever your users should find the wall.
-   The page shows the wall's current offers and handles the paused and empty states for you.
-   It takes the same attribution slots as the API: `sub_id` plus optional `sub_id_2` … `sub_id_5`.

On an Offer Wall placement, the Developer Portal shows this link with copy, QR code, and open actions. The placement's **Integration & test** dialog also has a **Copy for LLM** button that copies an integration brief for this exact placement, ready to paste into a coding assistant.

## API

Call [Offer Query](https://docs.aon.pro/api/offer-query) with your placement id in the `X-AON-Placement-Id` header (or as the top-level body field `placement_id`). No `Authorization` header is needed — the placement is the identity, and a key sent alongside it is ignored for identity.

Offer Wall page request

curl

```
curl --request POST \
  "https://api.aon.pro/v1/offers/query" \
  --header "Content-Type: application/json" \
  --header "AON-Protocol-Version: 1.0" \
  --header "X-AON-Placement-Id: plc_7c2e0dR9kL4mN8pQ" \
  --data '{
    "context": {},
    "pagination": { "limit": 20, "offset": 0 }
  }'
```

| Header | Value |
| --- | --- |
| `Content-Type` | `application/json` |
| `AON-Protocol-Version` | `1.0` |
| `X-AON-Placement-Id` | Your Offer Wall placement id, `plc_…` |

The request body differs from other placement types in two ways, for Offer Wall placements only:

-   `intent` may be omitted. The server supplies a neutral one, because the wall is browsed rather than asked.
-   `pagination` (`{ "limit": 20, "offset": 0 }`) is accepted under Protocol v1.0. Top-level `limit` and `offset` are accepted too. `limit` is 1–20 and defaults to 3 when omitted, so always send it.

> Other placement types are unchanged: under v1.0 they still require `intent` and reject `pagination`.

### Response

The response uses the standard envelope (`code`, `message`, `data`, `extra`). Offers are in `data.offers` in the v1.0 Offer shape, and Offer Wall placements also return paging state in `extra.pagination`:

Offer Wall response (trimmed to one offer)

JSON

```
{
  "code": "SUCCESS",
  "message": "",
  "data": {
    "request_id": "0195ef94-f17d-7a4f-b6e0-2c52bb49e13f",
    "protocol_version": "1.0",
    "language": "en",
    "offers": [
      {
        "offer_id": "019fc211-c6cd-7e62-9c4d-699c243e6c96",
        "offer_instance_id": "019fc211-c695-7bd2-9e1b-9a06c2952770",
        "offer_info": {
          "title": "TeamFlow Pro Plan",
          "short_description": "Docs, wikis, and planning in one workspace.",
          "description": "Collaborative workspace for docs, wikis, and project planning."
        },
        "entity": {
          "id": "ent_teamflow",
          "name": "TeamFlow",
          "logo": "https://cdn.teamflow.example/logo.png"
        },
        "material": [
          {
            "url": "https://cdn.teamflow.example/cover-1200x628.png",
            "format": "image"
          }
        ],
        "claims": [
          {
            "kind": "user_benefit",
            "text": "14-day free trial"
          }
        ],
        "action": {
          "type": "open_url",
          "name": "Start free trial",
          "payload": {
            "url": "https://aon.link/oyMJZTta"
          }
        }
      }
    ]
  },
  "extra": {
    "pagination": {
      "limit": 20,
      "offset": 0,
      "returned": 20,
      "total": 37,
      "has_more": true,
      "next_offset": 20
    }
  }
}
```

| `extra.pagination` field | Meaning |
| --- | --- |
| `limit`, `offset` | The page you asked for |
| `returned` | Offers in this page |
| `total` | Offers this wall can serve right now. For walls that draw on the AON network, it can change between pages. |
| `has_more` | Whether another page is available |
| `next_offset` | The `offset` to send for the next page |

### Paging

Request the first page with `offset: 0`. While `extra.pagination.has_more` is `true`, request the next page with `offset` set to `extra.pagination.next_offset` — for example, when the user scrolls near the end of the list. Stop when `has_more` is `false`. Drive paging from `has_more` and `next_offset` rather than from `total`, since `total` can change between pages.

### Render each offer

| Show | Field |
| --- | --- |
| Title | `offer_info.title` |
| Description | `offer_info.short_description`, falling back to `offer_info.description` |
| Brand name and logo | `entity.name`, `entity.logo` |
| Cover image | The first `material[]` item with `format` `"image"`, falling back to `entity.logo` |
| Badge | `claims[].text` |
| Tap target | `action.payload.url` — the tracked click link to open when the user taps the offer |

## Attribution with sub\_id

Append your own attribution values to `action.payload.url` as query parameters before opening it: `sub_id`, plus optional `sub_id_2` … `sub_id_5`. Conversions come back on your [conversion Webhook](https://docs.aon.pro/api/webhooks) with the same `sub_id` values, so you can credit the right user.

> Do not cache or rewrite click links beyond appending `sub_id` parameters. Open `action.payload.url` as returned so the click is recorded — see [Tracking](https://docs.aon.pro/api/tracking).

Conversion Webhooks are always delivered on Protocol v1.0, with `AON-Protocol-Version: 1.0`.

## Checklist

-   Offer Wall placement created in Developer Portal.
-   [Webhook](https://docs.aon.pro/api/webhooks) endpoint configured to receive conversions.

Hosted page:

-   Hosted link opened in a web view, with `sub_id` set to your user id.

API:

-   Offer Query sent with `X-AON-Placement-Id`, `AON-Protocol-Version: 1.0`, and `pagination.limit` set explicitly.
-   Next pages fetched with `extra.pagination.next_offset` while `extra.pagination.has_more` is `true`.
-   `sub_id` appended to `action.payload.url` before opening it.

## Next

[Return to Quick Start](https://docs.aon.pro/quickstart)
