Skip to main content
The Encore API is the REST integration tier: you own the moment and the UI, Encore returns premium brand offers (real perks brands fund to acquire customers) as plain JSON, and every economic fact (the impression, the claim, the completion) is recorded server-side. Choose it when your own code already detects the moment and you render the offer yourself; choose the iOS, Android, or Web SDK when you want Encore’s managed rendering and purchase plumbing.

The flow

Every integration is the same five-stage flow; only the selection mode varies.
1

Select offers

One POST in your chosen selection mode: ranked feed, full catalog, single message pick, or a permanent creator link.
2

Deliver on your surface

Render the offer in your UI, message, or page. On the feed, confirm each offer’s impression with POST /offers/impressions/{impressionUid}/delivered when it is actually shown.
3

The user claims

Route the tap to the offer’s tokenized clickUrl. Encore records an attributed transaction (bound to your app, the offer, the creative, and your userId) and 302-redirects to the advertiser. See The claim model.
4

Activation is verified

The completion is verified server-side on the advertiser’s side. Only a verified completion counts, and pays.
5

React to the completion

Encore POSTs a signed offer_completed event to your server: see Receive Completion Events.
The complete worked example of this flow is the Rewarded Actions guide; the guides cover only what differs per selection mode.

Choosing a selection mode

Rule of thumb: if the offer appears at a moment, use the feed. Per-offer exposure measurement (the served/delivered split below) exists only on the feed, so feed-based integrations are the ones whose impressions Encore can fully account for.

Authentication

Every endpoint authenticates with the publishable key from your dashboard, passed in the X-API-Key header: pk_live_* for production, pk_test_* for development.
Integrating directly over REST with no SDK? Create a single app with platform API in the dashboard; you get one publishable key. If your key spans multiple platform-specific apps (a multi-app project), also send an X-Platform header so Encore knows which app to resolve; otherwise the request is rejected with a 401 carrying X-Platform header required for multi-app projects (the key is valid; the header is what’s missing):
X-Platform must name a platform your project actually has an app for. In particular, X-Platform: api resolves only if the project contains an API-platform app, created in the dashboard: sending it without one returns 401 Invalid API key even though the key is valid, so the fix is to create the API app (or name a platform the project does have), never to rotate the key. A single-app key does not need X-Platform. An API app receives offers as data only. Encore’s server-rendered offer surfaces exist for iOS, Android, and web apps through their SDKs; an api app is never served one, so on this tier every screen the user sees is yours.

What a test key serves

Whether a serve response carries your real inventory or the demo catalog is decided by the key. No header, build flag, or SDK setting overrides that choice. The one carve-out is not a serve response at all: POST /offers/catalog with includeAllRegions: true is a config-time discovery mode, and it returns your real inventory under either key. X-Platform is not an exception to this. It resolves which app in a multi-app project handles the request, and that changes which of your campaigns are eligible. It does not change whether you are served your inventory or the demo catalog, and the demo catalog itself is the same whichever app resolves.
A test key does not return your offers. pk_test_* serves a demo catalog instead of your inventory on every serve response, whether you call the API directly or through an SDK. It replaces your inventory rather than adding to it. If your campaigns are missing from a test-key response, that is the expected behavior and not a targeting problem.To see your own inventory, use pk_live_*. That traffic is real, so it lands in your dashboard.
The demo catalog exists so you can exercise a complete claim without a live campaign, a real advertiser, or a payout. Most demo offers point at a fake advertiser page Encore hosts, and they differ in how they settle so you can rehearse each branch your integration has to handle:
  • one settles the moment the demo form is submitted, for the straightforward path
  • one settles after a short delay, so you can watch a claim resolve on a later poll
  • one never settles at all, so you can see what an abandoned conversion looks like
  • one leads to a real App Store listing, for the app-return path
Each demo offer names its own behavior. Read quickInstructions on the offer’s creative: it states the behavior in plain words, so you can tell a slow settlement from a broken one without guessing.
The offer that never settles says so instead: Tap through, then close the page WITHOUT submitting. Read it from the response rather than from a list here, because the catalog can change and the response cannot go stale. One demo offer is deliberately excluded from strict-unlock requests. Each offer advertises a settlement time, and a strict-unlock request filters the catalog to offers that advertise a time within the ceiling it sends. One demo offer advertises a time well beyond the usual ceiling, so a strict-unlock request does not receive it. That absence is the intended behavior: it lets you confirm your integration handles a catalog that a strict-unlock request has narrowed. An offer’s advertised settlement time is what the filter reads. It is separate from how long that offer actually takes to settle. Every demo offer is marked. Offers carry an isDemo field on every offer-serving surface, so you never have to infer it from the brand name or the key you happened to send:
It is true on a demo offer. On ordinary inventory the shape differs by surface: /offers/search serializes the field as false, while the other surfaces omit it. Test for truthiness, which is correct everywhere, rather than comparing against false or checking whether the key exists. Use it to label a demo offer in a development build, and, more importantly, to stop one reaching a real user: a test key shipped in a release build serves this catalog, and isDemo is the check that turns that into a visible failure rather than a subtly wrong experience. Demo conversions are inert on purpose. They never create a payable obligation and never count against a user’s trial limits, so you can claim the same demo offer as many times as you need.
What “not recorded” means. A test key still mints links and accepts delivered calls. It simply records no impressions, clicks, or conversions from them. Use pk_live_* for anything that should show up in your dashboard.Creator links follow the same rule. The environment is captured when the link is minted, because the click itself is an end user opening a short URL with no key attached. So a link minted with pk_test_* carries the test flag, and its clicks are excluded from your analytics rather than counted as production traffic. A test mint and a live mint of the same creator and campaign are separate links with separate slugs, so a test never taints the live one.Creator links do differ from the rest of this page in one way: they mint against your real campaigns even under a test key. The demo catalog is not part of creator-link minting.

The impression model

The API splits “we handed you an offer” from “the user actually saw it”:
  • Served (the baseline). When the feed returns offers, the server records each returned offer as served. This is bookkeeping, not an impression: calling the feed is not the impression, because you fetch a batch and may only ever show some of it.
  • Delivered (the impression). When you actually render an offer, you confirm it with POST /offers/impressions/{impressionUid}/delivered using the per-offer impressionUid from the feed response. An offer you fetch but never confirm stays in the served baseline, never a confirmed impression.
This split is what makes API-tier exposure honest: the served baseline measures what Encore selected, the delivered confirmation measures what your users were shown, and the gap between them is visible instead of assumed. Your dashboard reports the confirmed number. Impressions are the offers you confirmed, with the served baseline shown beside them rather than folded into them. Every API integration is measured this way, so a feed integration that has not adopted delivered yet reads zero impressions against real served traffic. That reads as an unfinished integration rather than an idle app, and the confirmation call is what closes it.

The claim model

Every offer carries a tokenized clickUrl. When the user taps, you open that URL; Encore records an attributed transaction and 302-redirects the user to the advertiser. A claim is not a conversion. The claim is a fact about the offer flow: the user tapped through. The completion is verified separately on the advertiser side, and only a verified completion pays out. To react to completions from your server (grant a reward, credit a balance), use the offer_completed webhook.

What’s in this section

Rewarded Actions (start here)

The one end-to-end walkthrough: the complete worked feed pattern, from milestone to attributed claim

Curated Catalog

Pull your addressable inventory and curate your own surface

Automated Messaging

Append an offer to outbound automated messages

Creator Links

Permanent per-creator tracking links and a stats endpoint

Receive Completion Events

Wire the offer_completed webhook to react to verified completions
Endpoint contracts live in the Reference group: /offers/feed, /offers/impressions/{impressionUid}/delivered, /offers/catalog, /offers/message, Creator Links endpoints, /users/attributes, and the offer_completed webhook.