# Offer Carousel

This guide walks you through the process of integrating the Offer Carousel SDK into your React Native application. By using this SDK, you can easily connect to Engine by MoneyLion’s financial network, authenticate with the Engine API, and give your users access to a wide range of financial products.

The Offer Carousel SDK allows you to display a curated list of static offers across key product categories, including:

* Earned Wage Access (EWA)
* Credit Builder
* Debt Relief

#### What’s Covered in This Guide

* **Software Requirements:** Prerequisites for Integrating the SDK
* **Installation & Initialization:** How to get started quickly
* **Customization Options:** Tailor the experience to match your app’s theme and branding
* **User Experience Preview**: Sample screenshots to visualize the integration (final appearance may vary based on your theme and font settings)

## Setup Instructions

#### **Step 1: Request an API Token**

Before you can use the Engine SDK, you’ll need to request an API token from your Partner Manager. This `subAccountToken` is used to authenticate with the Engine API and provides access to different financial institutions.  If you’re looking to have multiple instances of an offer carousel, leverage unique tokens per instance for distinct tracking and offer control.

Along with your unique `subAccount` token, you will receive a `channel` and `zone` value which is also required to define each unique instance of your SDK embed.&#x20;

Optionally, your Partner Manager can generate a `searchAPIToken` on your behalf to enable you to control which product types appear in each offer carousel instance.

#### **Step 2: Confirm Software Requirements**

Requirements:

* React Native version >= 0.59.0
* Node.js >= 18
* TypeScript (optional but recommended)

Package Size:

* SDK Bundle Size: 1.62 MB Unpacked

#### **Step 3: Install the SDK**

Install the SDK from npm using the command using your package manager, e.g.

* `npm install @moneylion/offer-carousel`
* `yarn add @moneylion/offer-carousel`

{% hint style="info" %}
👉 Refer to our NPM readme to set up and run the example app:\
<https://www.npmjs.com/package/@moneylion/react-native-offer-carousel>
{% endhint %}

#### **Step 4: Initialize the SDK**

In your app, you’ll need to initialize the SDK by rendering the Offer Carousel React component. You would need to pass in the required properties to see your entitled static offers. Refer to the “Offer Carousel SDK Properties” section below.

To implement the Offer Carousel SDK into your app, you can use the following sample code snippet. Please ensure you wrap this snippet in a self-closing \`<\` and \`/>\` tag, as demonstrated in the screenshot above.&#x20;

Lead IP Address is captured automatically by the SDK from the user's device; you do **not** need to pass this field in your integration.

{% hint style="info" %}
Note: The wrapping tags have been omitted from the text below to prevent triggering a CSS attack warning on this page.
{% endhint %}

{% code fullWidth="false" %}

```typescript
import {MoneyLionOfferCarousel} from "@moneylion/react-native-offer-carousel;
import { Text, View } from "react-native";

export default function App() {
   return (<EngineOfferCarousel
      subAccountToken={bearerToken}              
      channel={channel}      
      zone={zone}     
      searchAPIToken={bearerToken} // optional
      productType={"CreditBuilderLoan"}
      query={"Student Loan"} // overrides productType and requires "searchAPIToken" to leverage
      isDev={false} 
      fontFamily={{
	   normal: "BatonTurbo-Regular",
	   medium: "BatonTurbo-Medium",
	   bold: "BatonTurbo-Regular",
	}}
	isDarkTheme={true}
      userData={{ email: "example@mail.com"}}
      showCardBorder={true}
      showDescriptionPoints={true}
      title={"Your Credit Offers"}
      subtitle={""}
      showProductTypeLabel={true}
      fallbackUI={<View> <Text>Something went wrong</Text> </View>}
      tags={"tag.traffic=home_tab&tag.medium=offers_section"}
	/*
	  * Refer to the full list of available properties and callbacks in Offer Carousel SDK Properties table.
	*/ 
   );
}
```

{% endcode %}

## User Experience & Demo

<div><figure><img src="https://3849802388-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MeMvVDbjd8vJWZ9Hwf0%2Fuploads%2F3cUjrVhyJ6QRKdT6kxxO%2FBorder.png?alt=media&#x26;token=47e9e02c-ab17-41e2-97f2-b3bea951584c" alt=""><figcaption><p> Carousel SDK: Example App Page</p></figcaption></figure> <figure><img src="https://3849802388-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MeMvVDbjd8vJWZ9Hwf0%2Fuploads%2FhZoLuwUPWzxtOgYvOxR5%2FVertical%20View%20Full.png?alt=media&#x26;token=3fd22eb9-73c1-4fde-85b8-71e4990e3535" alt="" width="281"><figcaption><p>Offer Carousel SDK: Offers Wall</p></figcaption></figure></div>

## Adding Client Tags for Reporting

The Engine Mobile SDK supports adding your unique Client Tags to track performance of specific campaigns or users. All Client Tag data is attributed to the lead level.

Client Tags can be added by including a `clientTags` attribute at the top level of the request body, where the value is an array of strings. We strongly recommend only including one element per array for ease of reporting/attribution - if you want two separate tags, include the second tag under a different key. There is no limit to the number of keys in the clientTags object.&#x20;

### Example

Here is a sample code snippet of how you might implement the Mobile SDK into your app, with sample `clientTags` appended:

```jsx
<EngineSdk
    bearer="{your_token}"
    primaryColor=”#11aa34”
    secondaryColor=”#444444”
    prefilledData={ any data you don't want to ask for again }
    "clientTags": {
        "clientId": ["client1"],
        "trafficsource": ["email"],
        "campaignId": ["campaign1"]
    }
    { ...optional Event Handlers, please see Event Handler section }
/>
```

See our [GET Lead Client Tags](https://engine.tech/docs/api-reference/#get-lead-client-tags) endpoint for information on attributing lead analytics to your own client tags, if you decide to hit our Analytics API for reporting.

### Supported Client Tag Keys

If you plan for the Engine team to set up reporting (i.e. you do not plan to hit our Analytics API), these are the only keys that are currently fully supported. If a different key is needed, please reach out to your partner manager - we *may* be able to accommodate, but adding nonstandard keys will increase the time it takes Engine to report Client Tag values back to you, and is therefore not recommended.

* agentId
* campaignId
* clientId
* deviceid
* medium
* sourceId
* subid
* subid1
* subid2
* subid3
* target
* trafficsource
* userid

## Prefilling Lead Data

The `prefilledData` object should be structured with any fields you want the user not to have to answer themselves, if you already have that info available. Here is an example of `prefilledData` as a Javascript Object. You may prefill as many of these fields as desired; the only 3 *required* are `firstName`, `lastName`, and `email`.

```jsx
{
    "firstName": "Bob", // required
    "lastName": "Dylan", // required
    "email": "bobdylan@gmail.com", // required
    "loanAmount": 7500, 
          // you can instead use "defaultSliderLoanAmount", if you want to suggest a default loan amount but still allow the user to edit it.
          // if "loanAmount" is prefilled, "defaultSliderLoanAmount" will be ignored
    "purpose": "credit_card_refi",
    "dateOfBirth": new Date("1990-01-01"),
    "address": {
      "street": "1600 Pennsylvania Avenue",
      "city": "Washington",
      "state": "DC",
      "zip": "20500"
    },
    "primaryPhone": "2325624852",
    "creditRating": "good",
    "propertyStatus": "own_with_mortgage",
    "educationLevel": "associate",
    "employmentStatus": "employed",
    "annualIncome": "20000",
    "hasDirectDeposit": false,
    "ssn": "512-54-7862",
    "bankRoutingNumber": "123456789",
    "bankAccountNumber": "55555555555"
}
```

{% hint style="info" %}
**Prefilled values cannot be edited by the user** on the final confirm-details screen (before submitting the form). If the user's info is incorrect (e.g. Address is incorrect outdated), the user should edit the info in your app directly.
{% endhint %}

### Example React Native Implementation

Here is a sample code snippet of how you might implement the Mobile SDK into your app, with all `prefilledData` fields populated:

<pre class="language-jsx"><code class="lang-jsx">&#x3C;EngineSdk
<strong>    bearer="{your_token}"
</strong>    primaryColor=”#11aa34”
    secondaryColor=”#444444”
    prefilledData={
              "firstName": "Bob", // required
              "lastName": "Dylan", // required
              "email": "bobdylan@gmail.com", // required
              "loanAmount": 7500, 
                    // you can instead use "defaultSliderLoanAmount", if you want to suggest a default loan amount but still allow the user to edit it.
                    // if "loanAmount" is prefilled, "defaultSliderLoanAmount" will be ignored
              "purpose": "credit_card_refi",
              "dateOfBirth": new Date("1990-01-01"),
              "address": {
                "street": "1600 Pennsylvania Avenue",
                "city": "Washington",
                "state": "DC",
                "zip": "20500"
              },
              "primaryPhone": "2325624852",
              "creditRating": "good",
              "propertyStatus": "own_with_mortgage",
              "educationLevel": "associate",
              "employmentStatus": "employed",
              "annualIncome": "20000",
              "hasDirectDeposit": false,
              "ssn": "512-54-7862",
              "bankRoutingNumber": "123456789",
              "bankAccountNumber": "55555555555"
            }
    clientTags={ ...optional Client Tags, please see following Client Tag section }
    {...optional Event Handlers, please see Event Handler section}
    />
</code></pre>

{% hint style="info" %}
For any of these fields, *DO NOT* prefill any fields that are empty or otherwise unavailable. If you do not have info for a particular field available to prefill, omit that field in your `prefilledData`object.
{% endhint %}

For example, this is **incorrect**:

```
{..."firstName": "Bob", "lastName": "Dylan", "address": {}, ...otherAttributes}  
// empty address is prefilled, which prevents the user from submitting complete info, and they will not receive offers
```

This is **correct**:

```
{"firstName": "Bob", "lastName": "Dylan", ...otherAttributes} 
//address is not prefilled, which forces the user to input their address in the UI and will allow them to submit complete info and be considered for offers
```

### PrefilledData Type Validations

The data should follow a type schema, described here in Typescript notation:

```typescript
interface PrefilledLeadData {
    firstName: string;
    lastName: string;
    email: string;
    loanAmount?: number; // whole numbers only
    defaultSliderLoanAmount?: number | string; // if you want the loan amount slider to default to something other than 5000 but want to allow the user to edit the amount, enter it here
    purpose?: LoanPurpose; // enum below
    dateOfBirth?: Date;
    address?: AddressData; // enum below
    primaryPhone?: string; // leading 1 is fine, but no "+" or "-" chars allowed
    phoneConsent?: boolean;
    ssn?: string; // 9 digits with or without hyphens
    creditRating?: CreditRating; // enum below
    propertyStatus?: PropertyStatus; // enum below
    educationLevel?: EducationLevel; // enum below
    employmentStatus?: EmploymentStatus; // enum below
    annualIncome?: AnnualIncomeBracket; // enum below
    hasDirectDeposit?: boolean;
    bankRoutingNumber?: string; (must be exactly 9 digits)
    bankAccountNumber?: string;
}

interface AddressData {
/** Primary street address */
    street?: string;
    /** (Optional) Apartment Suite */
    apartment?: string;
    city?: string;
    state?: string; // must be a valid 2-letter abbreviation
    zip?: string;
}
```

### Enums/Accepted Values for Certain Fields

Certain fields, although strings, must be within a predetermined list of accepted values. Here are those values:

```tsx
type LoanPurpose = "debt_consolidation" | "credit_card_refi" | 
"home_improvement" | "large_purchases" | "other";

type CreditRating = "excellent" | "good" | "fair" | "poor" | "limited";

type PropertyStatus = "own_with_mortgage" | "rent";

type EducationLevel = "high_school" | "associate" |  "bachelors" |  "masters" |
"other_grad_degree" |  "other";

type EmploymentStatus = "employed" | "self_employed" | "not_employed" | "retired" | 
"military" | "other";

type AnnualIncomeBracket = "20000" | "40000" | "60000" | "100000" | "120000" | "121000";
```

### PrefilledData Sanitization

Prefilled Data must align with the type validations above, and any fields with an accepted value enum must be within that enum. If you (the partner) prefill user data, and any type/value is invalid, that attribute will be stripped, and the lead will have to enter it again manually.

## UI Customizations

### Fonts and Colors

To maintain brand consistency within your app experience, the Offer Carousel SDK supports font and color customization with the following requirements:

**Fonts:**

* Any custom fonts must be pre-installed in the host application (ie the partner’s app).
  * For example, if Partner ABC wants to use a custom font, that font must already be supported and linked within their hosted app.
  * The SDK will reference fonts by name via the `fontFamily` property.

**Colors:**

* The SDK supports the full range of hex color codes, consistent with what’s supported in the Payload platform across partner pages, embeds, and SDKs.
  * Ideally, partners should use an existing brand configuration (if one has been set up previously).
  * Alternatively, partners can provide their preferred hex codes, and we will apply them during setup.This includes all standard 16 million+ hex color values, like those found in this[ HTML color picker](https://htmlcolorcodes.com/color-picker/).

### Branding

We manage branding for your Offer Carousel SDK by creating a unique brand for each partner, applied consistently across all carousels. The brand's color palette defines its visual style, with theme colors generated to match and establish the application's overall look and feel.&#x20;

* **Color Palette**: A Brand's Palette defines the colors and style used in our experiences.&#x20;
  * Note: any colors not defined will be generated such that they align with the colors provided.&#x20;
* **Theme Colors**: The theme colors are used to define the look and feel of the application. The colors can be generated using the colors provided in the color palette above.

### SDK Properties for Customization

The SDK provides the following properties to customize the appearance of the component:

#### isDarkTheme

By setting this property, you can configure the SDK to match your app’s theme.

<br>

<figure><img src="https://3849802388-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MeMvVDbjd8vJWZ9Hwf0%2Fuploads%2FQHxCVENYMRWBTjof1Ea1%2FDark%20Mode.png?alt=media&#x26;token=450b9004-e816-4a03-a9d9-3458618e818c" alt=""><figcaption><p>Example Offer Carousel with isDarkTheme set to true</p></figcaption></figure>

#### showProductTypeLabel:

This property controls the visibility of the offer type on top of the offer card.

<figure><img src="https://3849802388-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MeMvVDbjd8vJWZ9Hwf0%2Fuploads%2FDVcfAhexKNzqjJVwaYl6%2FLight%20Mode.png?alt=media&#x26;token=48df973f-9263-4010-a271-c804664fc26e" alt=""><figcaption><p>Example Offer Carousel with showProductTypeLabel set to true for offers with type “Income Opportunities”</p></figcaption></figure>

#### showCardBorder:

Improve visibility of the offer cards by making them more distinct from the background. This is particularly useful when the container's background color is similar to the offer card's background color.

<div><figure><img src="https://3849802388-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MeMvVDbjd8vJWZ9Hwf0%2Fuploads%2F9y1Jw9LMQSkBDFUogK5v%2FNo%20Border.png?alt=media&#x26;token=5d0e3575-9ae9-44d2-95c7-074d8d09e4d8" alt=""><figcaption><p>With showCardBorder set to false</p></figcaption></figure> <figure><img src="https://3849802388-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MeMvVDbjd8vJWZ9Hwf0%2Fuploads%2F3cUjrVhyJ6QRKdT6kxxO%2FBorder.png?alt=media&#x26;token=47e9e02c-ab17-41e2-97f2-b3bea951584c" alt=""><figcaption><p>With showCardBorder set to true</p></figcaption></figure></div>

#### fontFamily:

This property updates the fonts used by the offer carousel. By default, the SDK will use system fonts.

<div><figure><img src="https://3849802388-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MeMvVDbjd8vJWZ9Hwf0%2Fuploads%2FkwL3VgU1bJ28rnigrjGD%2FMontserat%20Font.png?alt=media&#x26;token=93c762f3-cd63-408e-960d-7f364c559e34" alt=""><figcaption><p>Example offer with Montserrat font</p></figcaption></figure> <figure><img src="https://3849802388-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MeMvVDbjd8vJWZ9Hwf0%2Fuploads%2FDVcfAhexKNzqjJVwaYl6%2FLight%20Mode.png?alt=media&#x26;token=48df973f-9263-4010-a271-c804664fc26e" alt=""><figcaption><p>Example offer with Baton Turbo font</p></figcaption></figure></div>

## All SDK Properties&#x20;

<table data-full-width="true"><thead><tr><th width="222.8931884765625">Property Name</th><th width="158.854248046875">Type</th><th width="107.380126953125">Required</th><th width="106.57421875">Default</th><th width="409.71875">Description</th><th>Example</th></tr></thead><tbody><tr><td>channel</td><td>string</td><td>Yes</td><td>-</td><td>The distribution channel identifier</td><td>"direct"</td></tr><tr><td>zone</td><td>string</td><td>Yes</td><td>-</td><td>The zone identifier for offer targeting</td><td>"marketplace"</td></tr><tr><td>subAccountToken</td><td>string</td><td>Yes</td><td>-</td><td>Unique token to fetch relevant offers</td><td>"eyJhbG..."</td></tr><tr><td>searchAPIToken</td><td>string</td><td>No</td><td>-</td><td>Token for the search API</td><td>"search_token_xyz"</td></tr><tr><td>productType</td><td>string</td><td>No</td><td>-</td><td>Specific product type to filter offers</td><td><p>DebtSettlement</p><p>CreditBuilderLoan</p><p>CashAdvance</p><p>EarnedWageAccess</p></td></tr><tr><td>query</td><td>string</td><td>No</td><td>-</td><td>Search query for filtering offers. Note: This Make sure to get searchAPIToken before using this prop.</td><td>"credit cards"</td></tr><tr><td>tags</td><td>string</td><td>No</td><td>-</td><td>Custom tags for offer filtering. Each item must be prefixed with tag.</td><td>"tag.tag1=value1&#x26;tag.tag2=value2"</td></tr><tr><td>fontFamily</td><td>Partial&#x3C;FontFamily></td><td>No</td><td>Fallbacks to system font</td><td>Custom font family configuration.<br>Make sure the fonts are properly installed in your app.</td><td><p>{</p><p>regular: "Roboto-Regular",</p><p>medium: "Roboto-Medium",</p><p>bold: "Roboto-Bold"</p><p>}</p></td></tr><tr><td>isDev</td><td>boolean</td><td>Yes</td><td>-</td><td>Enable development mode. You can use this property to view the production offers as well, by turn it to false.</td><td>false</td></tr><tr><td>showCardBorder</td><td>boolean</td><td>No</td><td>false</td><td>Show a border around the offer cards</td><td>true</td></tr><tr><td>showDescriptionPoints</td><td>boolean</td><td>No</td><td>true</td><td>Display the offer description as bullet points</td><td>false</td></tr><tr><td>title</td><td>string</td><td>No</td><td>-</td><td>Custom title for the carousel</td><td>"Featured Offers"</td></tr><tr><td>subtitle</td><td>string</td><td>No</td><td>-</td><td>Custom subtitle for the carousel</td><td>"Personalized for you"</td></tr><tr><td>isDarkTheme</td><td>boolean</td><td>No</td><td>false</td><td>Enable dark theme mode.</td><td>true</td></tr><tr><td>showProductTypeLabel</td><td>boolean</td><td>No</td><td>false</td><td>Whether to display product type labels</td><td>true</td></tr><tr><td>fallbackUI</td><td>React.ReactNode</td><td>No</td><td>-</td><td>Custom UI to show on error</td><td>&#x3C;ErrorComponent /></td></tr><tr><td>userData</td><td>{<br>email?: string<br>}</td><td>No</td><td>-</td><td>User data for offer personalization</td><td><p>{</p><p>email: "<a href="mailto:john@example.com">john@example.com</a>"</p><p>}</p></td></tr></tbody></table>

## Event Handlers for Real-Time Tracking in the Offer Carousel Mobile SDK

The Engine Offer Carousel SDK has multiple real-time Event Handlers so you can track activity in the SDK in real time.

<table data-full-width="true"><thead><tr><th width="138.6080322265625">Event Property</th><th width="462.109375">Type</th><th width="112.9700927734375">Required</th><th width="265.9493408203125">Description</th><th>Example</th></tr></thead><tbody><tr><td>onLoad</td><td>(numOffers: number) => void</td><td>No</td><td>Called when offers are loaded. Make sure to use the callback value to show the appropriate UI.</td><td>(count) => console.log(${count} offers loaded)</td></tr><tr><td>onInitialize</td><td>(props: onInitializeProps) => void<br><br>onInitializeProps {<br>    timestamp: string;<br>}</td><td>No</td><td>Called when the SDK is initialized.</td><td>(props) => console.log(props)</td></tr><tr><td>onRateTableSubmit</td><td><p>(props: onRateTableSubmitProps) => void</p><p><br>onRateTableSubmitProps {<br>    timestamp: string;</p><p>    productTypes: string[];</p><p>    resultType: ResultType;</p><p>    defaultProductType: string;<br>}</p></td><td>No</td><td>Called when a rate table submission is made.</td><td>(props) => console.log(props)</td></tr><tr><td>onRateTableResponse</td><td><p>(props: onRateTableResponseProps) => void<br><br>onRateTableResponseProps {<br>    timestamp: string;</p><p>    isError: boolean;</p><p>    offers: BaseOffer[];</p><p>    rateTableUuid: string;</p><p>    leadUuid: string;<br>}</p></td><td>No</td><td>Called when a response for a rate table is received.</td><td>(props) => console.log(props)</td></tr><tr><td>onOfferDisplayInViewport</td><td><p>(props: onOfferDisplayInViewportProps) => void<br><br>onOfferDisplayInViewportProps {</p><p>   timestamp: string;</p><p>   offerUuid: string;</p><p>   rateTableUuid: string;</p><p>   leadUuid: string;</p><p>   offer: BaseOffer;</p><p>   offerIndex: number;</p><p>   context: "horizontal_scroll" | "vertical_scroll";</p><p>}</p><p><br></p></td><td>No</td><td>Called when an offer is displayed in the viewport.</td><td>(props) => console.log(props)</td></tr><tr><td>onOfferClick</td><td><p>(props: onOfferClickProps) => void</p><p>onOfferClickProps {</p><p>    timestamp: string;</p><p>    offerUuid: string;</p><p>    rateTableUuid: string;</p><p>    leadUuid: string;</p><p>    offer: BaseOffer;</p><p>    offerIndex: number;</p><p>    context: "horizontal_scroll" | "vertical_scroll" | "offer_details";</p><p>}</p></td><td>No</td><td>Called when an offer is clicked.</td><td>(props) => console.log(props)</td></tr><tr><td>onOfferDetailsPageOpen</td><td><p>(props: onOfferDetailsPageOpenProps) => void</p><p>onOfferDetailsPageOpenProps {</p><p>    timestamp: string;</p><p>    offerUuid: string;</p><p>    rateTableUuid: string;</p><p>    leadUuid: string;</p><p>    offer: BaseOffer;</p><p>    offerIndex: number;</p><p>    context: "horizontal_scroll" | "vertical_scroll";</p><p>}</p></td><td>No</td><td>Called when the offer details page is opened.</td><td>(props) => console.log(props)</td></tr><tr><td>onOfferDetailsPageClose</td><td><p>(props: onOfferDetailsPageCloseProps) => void</p><p>onOfferDetailsPageCloseProps {</p><p>    timestamp: string;</p><p>    offerUuid: string;</p><p>    rateTableUuid: string;</p><p>    leadUuid: string;</p><p>    offer: BaseOffer;</p><p>    offerIndex: number;</p><p>}</p></td><td>No</td><td>Called when the offer details page is closed.</td><td>(props) => console.log(props)</td></tr><tr><td>onError</td><td><p>(error: MoneyLionOfferCarouselError) => void MoneyLionOfferCarouselError { </p><p>  code: ErrorCodes; </p><p>  severity: "warning" | "error"; </p><p>  message: string; </p><p>  timestamp: string; </p><p>  sdkVersion: string; </p><p>  error?: Error | unknown; </p><p>  statusCode?: number; </p><p>  additionalInfo?: Record&#x3C;string, unknown>; </p><p>}</p></td><td>No</td><td>Called when an error occurs.</td><td><p>{ </p><p>code: “NETWORK_REQUEST_ERROR”, message: “Failed to fetch offers for product types", timestamp:”2025-07-24T10:12:02.492Z", error: Error: 400, version: “1.7.3”, statusCode: 400, additionalInfo: { context: ... } }</p></td></tr></tbody></table>

## Error Handling

The SDK provides a comprehensive `onError` callback to manage various issues. This callback is invoked for configuration errors, network errors, flow errors, and potential UI errors. The coverage of errors includes the following, each with a corresponding error code:

{% code fullWidth="false" %}

```typescript
ErrorCodes { 
  // Configuration 
  MISSING_CONFIG = "MISSING_CONFIG", 

  // UI
  UI_CRASH = "UI_CRASH", 

  // Flow 
  FLOW_ERROR = "FLOW_ERROR", 

  // Network 
  NETWORK_REQUEST_ERROR = "NETWORK_REQUEST_ERROR", 
  NETWORK_SERVER_ERROR = "NETWORK_SERVER_ERROR", 
  NETWORK_OTHER_ERROR = "NETWORK_OTHER_ERROR", 
}
```

{% endcode %}

For configuration and server errors, the `onError` callback returns a `statusCode` representing the HTTP error response.

```
{ 
  code: "NETWORK_SERVER_ERROR”, 
  statusCode: 500, 
  message: “Failed to fetch configuration ", 
  timestamp:”2025-07-24T10:12:02.492Z", 
  severity: “error”, 
  version: “1.7.3”, 
  additionalInfo: { channel: “channel”, } 
}
```

`additionalInfo` contains additional information that is relevant to the error that occured. Some examples of what information it could contain:

* \`channel\` (string) - Configuration channel identifier
* \`zone\` (string) - Configuration zone identifier
* \`isDev\` (boolean) - Development environment flag
* \`query\` (string) - Search query string
* \`Context\` (object) - Configuration context object containing brand, subaccount, signals, etc.
* \`pageDataParams\` (object) - Parameters used to fetch page data including \`productType\`, \`query\`, \`tags\`, etc.
* \`pageData\` - Result object containing fetched page data (offers), including \`leadUuid\`,
* rateTableUuid\`, etc.
* \`productTypes\` (string\[]) - Array of product type strings
* \`customClientTags\` (Record\<string, string\[]>) - Custom client tags as key-value pairs
* \`payload\` (object) - Request payload object for API requests

To provide a fallback UI in case of failure, you can utilize the `fallbackUI` property to pass in a custom React component. Note that this will only show when there’s some error in rendering logic. API errors should be handled by the `onError` callback.

## Offer Enablements (Minimums & Maximums)

To ensure a smooth and consistent user experience, the Offer Carousel SDK enforces the following rules:

* **Minimum Requirement**: At least one offer must be available for the carousel to be displayed. If no offers are returned, the carousel will not render.
* **Maximum Limit**: There is no upper limit to the number of offers the SDK can display.

## Custom Audiences

Custom Audiences enable precise targeting for select Earned Wage Access (EWA) and Credit Builder offers, driving higher engagement and conversion rates. By reaching only the most relevant users, partners benefit from improved performance, increased offer volume from supply partners, and accelerated acquisition growth.

Key features include:

* **Suppression:** Preventing existing customers from seeing duplicate offers, reducing fatigue and improving the user experience. We support suppression for select offers from these partners:
  * EWA: Tilt, Current, Chime, EarnIn, and Brigit
  * Credit Builders: CreditStrong
* **Coming Soon – Remarketing**: Re-engage churned customers with targeted offers at a lower payout, boosting retention and maximizing customer value.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://even-financial.gitbook.io/developer-center/embeddable-integrations/mobile-sdks/react-native/offer-carousel.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
