Redeems a transaction that show() recorded in
deferred mode. It renders the redemption screen for the pending transaction, and on the
user’s CTA tap opens the advertiser in a new tab (synchronously, inside the click gesture, to
dodge popup blockers) and emits the provisional grant. This is phase 2 of the two-phase flow.
When to use this
Call redeem() after a deferred show() resolved
claimed and your own conversion / save step has run. Call it in response to a user gesture
(e.g. a button click) so the advertiser tab opens reliably.
Do not call redeem() in immediate mode — the
transaction is already redeemed inline and redeem() resolves none.
Signature
function redeem(options?: RedeemOptions): Promise<RedeemResult>
RedeemOptions
interface RedeemOptions {
placement?: string; // resolve the transaction made at this placement
host?: { name: string; status?: string; logoUrl?: string }; // optional host product card rendered as "Active"
}
| Field | Type | Required | Description |
|---|
placement | string | No | Resolve the transaction claimed at this placement; never crosses to another placement’s transaction. |
host | { name: string; status?: string; logoUrl?: string } | No | Host product card rendered as “Active” on the redemption screen. |
There is no transactionId option — no transaction handle ever crosses the API. redeem()
resolves the pending transaction internally:
placement — the transaction claimed at that placement; never crosses to another
placement (resolves none if that placement has none).
- Otherwise — the single most-recent pending transaction for this user.
Your code never needs to check whether anything is pending: call redeem() when your flow
is ready, and it resolves { status: 'none' } if there is nothing to redeem.
RedeemResult
type RedeemResult =
| { status: 'redeemed' } // advertiser redirect fired for the pending transaction
| { status: 'dismissed'; reason?: NotGrantedReason } // sheet closed without redeeming — see below
| { status: 'expired' } // reserved — see note below
| { status: 'none' }; // STRICTLY: no live pending transaction to redeem
The arms carry no transaction payload. redeem() never rejects — the error contract
mirrors show(): a user-driven close resolves dismissed (no reason or a user reason), and an
internal failure resolves dismissed with reason: { type: 'error', error }. On an error the
pending transaction is untouched, so calling redeem() again later is safe. none always means
exactly “nothing pending — don’t retry”; it is never an error in disguise.
expired is part of the type union but is not emitted by the current SDK: an expired
transaction (past its ~7-day TTL) fails resolution and is returned as none. Handle none as
“nothing to redeem”; treat expired as reserved for a future change.
Examples
Redeem the latest claim
import Encore from '@encorekit/web-sdk';
const result = await Encore.redeem();
if (result.status === 'redeemed') {
// Advertiser tab opened; provisional grant sent; transaction marked redeemed.
} else if (result.status === 'none') {
// Nothing pending — claim an offer with show() first. (Not retryable.)
} else if (result.status === 'dismissed' && result.reason?.type === 'error') {
// Internal failure — the pending transaction is untouched; safe to retry later.
}
Two-phase flow, no handle
const shown = await Encore.show();
if (shown.status === 'claimed') {
// ... your conversion runs ...
await Encore.redeem(); // resolves the pending transaction internally
}
Pending transactions are stored locally with a ~7-day TTL, so the deferred flow survives a
page reload: after the reload, calling redeem() still resolves the claim.
placement(id).redeem()
Redeems the transaction claimed at a named placement,
equivalent to Encore.redeem({ placement: id }). It never crosses to another placement’s
transaction.
// Phase 1 — claim at a named placement
await Encore.placement('cancel_flow').show();
// Phase 2 — redeem that placement's transaction
const outcome = await Encore.placement('cancel_flow').redeem();
Gotchas
- Open the tab inside the gesture. The advertiser tab is opened synchronously on the CTA
tap. Trigger
redeem() from a user action, not a timer or a detached promise, or popup
blockers may swallow the redirect.
- Expired claims resolve as
none. A transaction past its ~7-day TTL fails resolution and
comes back as none (not expired) in the current SDK — see the note above.
- TRANSACTION_ID substitution. If the offer’s
advertiserUrl contains the literal
TRANSACTION_ID, it is replaced with the transaction id when the redirect fires, and the
offer’s trackingParameters are appended.
redeemed makes no conversion claim. It means the redirect fired — advertiser
conversion happens later, asynchronously. Verify conversions and entitlements server-side,
by user, via the
Encore’s server-side verification —
never from the client.
show() — phase 1 of the flow.
- Redemption Modes — full walkthrough, the Transaction shape, and why deferred needs
redeem() while immediate doesn’t.
- placement — named placements.