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

# Presenting Offers

> Present Encore retention offers to users at key moments in your React Native app.

## Overview

Encore allows you to present targeted offers to users in exchange for rewards (free trials, discounts, credits) at critical moments like cancellation flows or feature paywalls. The SDK uses a callback pattern — you register purchase and passthrough handlers, then call `show()` wherever you need an offer.

***

## Present Offers

Presenting an Encore offer is a single line:

```tsx theme={null}
const result = await Encore.placement('cancellation_flow').show();
```

> **Important:** When presenting offers in critical flows (like cancellation), your `onPassthrough` handler ensures users are never blocked from completing their intended action.

<Info>
  Register handlers before presenting. See [Handle Offer Results](#handle-offer-results) below.
</Info>

***

## Handle Offer Results

<Tip>
  **Choosing your integration shape**: This page shows the handler pattern. If your call site has direct access to purchase logic, the async-result pattern is often cleaner. See [Integration Patterns](/concepts/integration-patterns) for the decision tree and [React Native Integration Patterns](/publishers/react-native/guides/integration-patterns) for TypeScript examples.
</Tip>

Register handlers that tell the SDK how to complete purchases and what to do when a user dismisses. Register these once at app startup, after `configure()` and `registerCallbacks()`.

### Register `onPurchaseRequest`

Called when a user accepts an offer. Use this to trigger a purchase via your billing library.

<Warning>
  You **must** call `completePurchaseRequest()` in every code path — both success and failure. Failing to do so will block the SDK from presenting future offers.
</Warning>

```tsx theme={null}
const unsubscribe = Encore.onPurchaseRequest(async ({ productId, placementId }) => {
  try {
    await yourBillingLibrary.purchase(productId);
    await Encore.completePurchaseRequest(true);
  } catch (error) {
    await Encore.completePurchaseRequest(false);
  }
});
```

<Tip>
  See [onPurchaseRequest()](../reference/on-purchase-request) for RevenueCat, react-native-iap, and custom examples.
</Tip>

### Register `onPassthrough`

Called when the user dismisses the offer or no offers are available. Use this to resume the user's original action (e.g., proceed with cancellation).

```tsx theme={null}
const unsubscribe = Encore.onPassthrough(({ placementId }) => {
  // Resume your original user flow
});
```

### `onPurchaseComplete` (Optional)

Fires after a native purchase completes (when no `onPurchaseRequest` handler is set on the native side). Use this to sync purchase state with your subscription manager.

```tsx theme={null}
const unsubscribe = Encore.onPurchaseComplete(({ productId, transactionId }) => {
  // Sync purchase state
});
```

### Summary

| Callback             | When it fires                         | Required? |
| -------------------- | ------------------------------------- | --------- |
| `onPurchaseRequest`  | User accepts the offer                | Yes       |
| `onPassthrough`      | User dismisses or no offers available | Yes       |
| `onPurchaseComplete` | Purchase finishes natively            | Optional  |

<Info>
  Register `onPurchaseRequest` and `onPassthrough` before presenting any placements.
</Info>

***

## Full Example

```tsx theme={null}
import Encore, { EncoreProvider } from '@tryencorekit/react-native';

// In your App component
export default function App() {
  return (
    <EncoreProvider apiKey="pk_your_api_key">
      <MainApp />
    </EncoreProvider>
  );
}

// In a screen component
function SubscriptionScreen() {
  useEffect(() => {
    const unsub1 = Encore.onPurchaseRequest(async ({ productId }) => {
      try {
        await billingService.purchase(productId);
        await Encore.completePurchaseRequest(true);
      } catch (error) {
        await Encore.completePurchaseRequest(false);
      }
    });

    const unsub2 = Encore.onPassthrough(({ placementId }) => {
      proceedWithCancellation();
    });

    return () => {
      unsub1();
      unsub2();
    };
  }, []);

  const handleCancel = async () => {
    await Encore.placement('cancellation_flow').show();
  };

  return (
    <Button title="Cancel Subscription" onPress={handleCancel} />
  );
}
```

***

## Next Steps

* [SDK Reference](../reference/configure) - Complete API documentation
