# Welcome

### Built for Enterprise Growth Teams

Nami is the only no-code subscription platform purpose-built to optimize the full revenue funnel — from acquisition to retention — with the speed and intelligence modern growth teams demand.

#### No-Code That Moves Fast

Launch and iterate faster with cloud-based tools that eliminate engineering bottlenecks. From pages to onboarding flows, your team can build, test, and optimize every touchpoint of the subscriber journey — no app update required.

#### Full-Funnel Optimization, Out of the Box

Nami powers every stage of the funnel:

* Top of funnel: Drive conversions with targeted acquisition campaigns and high-converting landing pages.
* Mid-funnel: A/B test native pages, personalize pricing, and surface smart offers that move users to purchase.
* Bottom of funnel: Improve retention with cancel-saver flows, win-backs, and predictive churn models.

#### AI-Powered Revenue Acceleration

Our proprietary machine learning models help you identify high-value users, predict intent, and trigger the right message at the right time — automatically. No guesswork. Just smarter monetization.

#### Trusted by the Enterprise

Fortune 100 companies rely on Nami to manage their subscription infrastructure, optimize revenue outcomes, and deliver personalized subscriber experiences at scale. To learn more, [request a demo](https://www.namiml.com/request-demo).

{% if !visitor.claims.unsigned.plan %}
{% hint style="info" %}
[Looking for docs? Access the documentation portal from the Nami Control Center.](https://app.namiml.com/)
{% endhint %}
{% endif %}


# Key Concepts

An overview of the key Nami platform concepts.

The Nami platform has a few key concepts that are important to understand:

* [App](#app)
* [App Store Platform](#app-store-platform)
* [App Platform](#app-platform)
* [Campaigns](#campaigns)
* [Customer Journey State](#customer-journey-state)
* [Devices](#devices)
* [Entitlements](#entitlements)
* [External Identifiers](#external-identifiers)
* [Pages](#pages)
* [Product SKUs](#product-skus)
* [Users](#users)

Let's take a look at each of these in more detail and see [how they are related](https://docs.namiml.com/docs/introduction-key-concepts#how-do-these-relate).

### App

Your app on the Nami platform. It all starts here. Creating an app is the first step in getting started with Nami.

Your app may run across a multitude of platforms and environments (such as development, staging, and production). All of these may be grouped under a single app to minimize the amount of configuration work needed to manage an app across multiple platforms.

### App Store Platform

An App Store Platform where your app users complete their transactions. Examples of App Store Platforms include:

* Apple's App Store
* Google's Play Store
* Roku

Note the App Store Platform is related to the unique platform that process transactions. In the example of the Apple ecosystem where you have iOS, iPadOS, tvOS, watchOS, and macOS, since they all transact on the App Store, there is only a single App Store Platform for each of these environments.

### App Platform

An App on the Nami Platform may have several App Platforms associated with it. Each App Platform must be associated with a single App Store Platform.

In a simple use case, your app will have one App Platform per App Store Platform that you sell on.

Nami also supports having multiple App Platforms with the same App Store Platform. You may want to use this functionality when you have a different app on the Google Play store for testing and production.

### Campaigns

A Campaign is the object that provides the "How".

How are you going to show your pages and products to your users? Under the hood, Campaigns maintain the rules engine for when and how pages will be presented to your customers.

![](https://files.readme.io/f68df50-Nami.Campaigns_v2.List.jpg)

The Nami Control Center will allow you to configure these rules based on certain Campaign Templates so that you can interact with your users in a way that meets your needs.

### Customer Journey State

The **Customer Journey** is the way a user's purchase relationship with your app changes over time. This is affected by a number of events such as purchases, cancellations, as well as more complex scenarios like free trials and account holds.

Nami models all the signals about a single user and puts these into a single **Customer Journey State** for each user. This state can be used by Campaigns, directly in your app through the SDK, or in any 3rd party integration.

The list of **Journey States** available is:

| Journey State            | Definition                                                                                                                 |
| ------------------------ | -------------------------------------------------------------------------------------------------------------------------- |
| former\_subscriber       | The user has previously had a subscription but does not have one currently.                                                |
| in\_account\_hold        | User is currently in an account hold. **Android Only**                                                                     |
| in\_grace\_period        | The user is currently in grace period due to their payment not processing.                                                 |
| in\_intro\_offer\_period | The user is currently on a discounted price offered when they first make a purchase.                                       |
| in\_pause                | The user's subscription has been paused at their request and will automatically resume. **Android Only**                   |
| in\_trial\_period        | The user is currently in a free trial.                                                                                     |
| is\_cancelled            | The user has cancelled their subscription but still has access to their entitlements until the current billing terms ends. |

### Devices

We create and store a **Device** for each physical device that connects to the Nami servers through our SDKs.

Devices contain a minimal amount of information to help us provide our services. These data include no device fingerprints or other PII and location information is only stored at the country level. For more information, read about how we [design for data privacy](broken://pages/4QBpLa96ixidOddgsEXC).

### Entitlements

An Entitlement is an object that grants a device access to a set of features or content in an app. Entitlements are a property of the app and represent the same concept of access across all platforms.

An app may have multiple Entitlements. For example, you could have one Entitlement that unlocks a set of image filters in your photo utility app and a second Entitlement that unlocks access to a stock photo library.

For your customers, an Entitlement can be **active** or **inactive**. When the Entitlement is **active**, the user should be allowed to access the appropriate paid content or functionality in your app. When the Entitlement is **inactive**, you will want to prevent your users from access paid features.

Entitlement management is a big piece of the Nami platform and we provide tooling to make this management and granting of Entitlements as easy as possible.

### External Identifiers

An **External Identifier** is any unique identifier that can be used to define a **User**.

You can create your own External Identifiers in our SDKs to track your customers. Nami may also create external identifiers from data provided by the purchase platforms or from any 3rd party integrations with the Nami SDK.

External Identifiers have 2 main fields:

* A `key` that serves as a label to define the source of the identifier.
* A `value` that is the actual identifier itself.

External Identifiers on the Nami platform never contain PII.

### Pages

A Page is a few things:

* The visual presentation of your paid offering to your users.
* The checkout page for your users to complete a transaction.
* A Call-To-Action (CTA) that your users must engage with before they can continue to use your app (it must be dismissed).

In the Nami Control Center, building a page is all about selecting the products you wish to offer to your users and setting up the imagery and marketing copy that will be used to present that offer.

![](https://files.readme.io/e6e88fa-Nami.Pages.List.jpg)

App pages come in a variety of forms. Before Nami, these screens were generally hard coded into an app, requiring significant developer time for implementation and maintenance.

![](https://files.readme.io/5a7dbdc-PageOverview.jpg)

Nami shifts management of your app's page to the cloud which allows your team members responsible for revenue to operate independently from your development team.

You can now make changes to the marketing copy or artwork instantaneously without requiring an update and app review. You can even modify which products you offer for sale with just a few clicks.

Since the page is managed from the cloud, you can now have multiple pages to experiment with tone, style, and more.

### Product SKUs

A Product SKU is an in-app purchase SKU or ID as defined within a specific App Platform. Products define the in-app purchase type, price points, bill terms, and other related data.

A Product SKU is specific to an App Platform.

Product SKUs are created within each app store platform and then added to the Nami platform for use in your app. For example, Apple's App Store products are created in App Store Connect.

### Users

A **User** is how we define the users of your app.

Every device that uses our SDK will have an associated User.

In a very simple app, there may be a one-to-one relationship between devices and users. In more complex apps, a User may have many devices (just like your actual customers).

Users are defined by **External Identifiers**. Creating an **External Identifier** allows for multiple devices to be linked together into a single User profile.

Users have a standard set of properties that are always available.

| User Property          | Definition                                                    |
| ---------------------- | ------------------------------------------------------------- |
| Active Entitlements    | A list of all active entitlements for the user.               |
| Customer Journey State | The current state customer journey state for the user.        |
| Devices                | A list of all devices that belong to this user.               |
| External Identifiers   | A list of all External Identifiers associated with this user. |

### How Do These Relate?

Let's first look at the objects that are created in our web portal, the Control Center.

An App on the Nami Platform will have a set of Entitlements, App Platforms, and Campaigns.

A Campaign has a set of Pages that are used in the Campaign.

App Platforms have a set of Product SKUs that grant an Entitlement and are included in Pages.

![](https://files.readme.io/dd72a7f-Key_Concepts.png)

Those also a set of objects that get created through our SDK by your users as they are using the app. These are Devices, External Identifiers, and Users.

Users belong to an App and Devices belong to an App Platform. A device must be an Apple or a Google device, it cannot be both. However, a User may have devices on both the Apple and Google platforms.

A User is linked to multiple devices through an External Identifier.

![](https://files.readme.io/ac18ab8-Key_Concepts_-_SDK.jpeg)


# Evaluating Nami

Nami provides two products, both of which save engineering teams a ton of time.

## No-Code Pages

Nami moves control of your app's pages to a cloud-based CMS.

From a developer perspective, this means you can shift day-to-day management to the non-developers on your team, freeing your time to work on other critical work.

Our page solution works regardless of whether you have your own purchase management code, use a third-party subscription management vendor, or want to use us for subscription management.

There are two supported use cases to use Nami as your Page solution:

**Choose a Template from our Page Gallery**\
Nami has created a growing library of off-the-shell [page templates](broken://pages/YuKWzv0z2tUhHsNmAfuz) based upon common patterns and industry best practices.

**Create your Own Page**\
We provide a no-code page builder that allows you build your own page templates based upon our library of [components](broken://pages/xjxpqbCfzwIjSsN4PHkz).

**Eliminate Hard-Coded Rules**\
Many apps depend on hard-coded rules to govern when a user is presented your page screen. Nami allows you to shift these rules to the cloud, so they can be easily managed and updated in real-time. Read more about managing business rules by [creating a campaign](broken://pages/NlLbbXoEV6CJKtQZWfFI).

## In-App Purchase & Subscription Management

In-app purchases and subscriptions are notorious for being a hassle to implement, let alone test and maintain. We want to help developers stay focused on building a great app experience.

To start, Nami eliminates all of the platform-specific client-side and server-side purchase integration points.

For instance, if you're building an iOS app this means we simplify your use of StoreKit, handle receipt validation, and stand-up the backend to consume Apple's Server-to-Server notifications.

For Android apps, Nami takes care of the complexity of working with the Google Play Billing library, validating purchase tokens, and consuming the real-time developer notifications to make sure your app users' purchase state is up to date.

That's just the beginning! In this article, learn more about how Nami helps developers.

### Adopting In-App Purchases on Apple Platforms

Nami helps make it easier to adopt in-app purchases (including subscriptions) on Apple's App Store platform.

Apple's StoreKit is well-known to be one of the more complex developer frameworks to incorporate into your app. Additionally, new App Store Connect server-side APIs are both necessary and complex to integrate for subscription apps.

Both can be quite frustrating to implement and test, leading to [App Review pitfalls](https://www.namiml.com/blog/the-app-store-rejected-my-app-now-what).

Nami solves this, by simplifying the integration points to one (the Nami SDK) allowing you to follow Apple requirements and best practices without the pain.

Specifically, Nami automatically handles three key integration points:

**StoreKit Purchase Flow**\
The Nami SDK abstracts away much of the complexity required to utilize StoreKit. For example, the Restore Purchase flow or getting In-App Purchase SKProduct details are handled for you automatically.

**Receipt Validation**\
Nami interfaces with the App Store's receipt validation APIs so you don’t have to do any client or server-side receipt validation.

**Server-to-Server Notifications**\
Nami listens for Apple's Server-to-Server notification events on your behalf so you don't need to stand up a server. This provides on-going monitoring of key lifecycle changes so your app can adapt accordingly.

To have Nami listen to Server-to-Server notifications on your behalf, see [Broken mention](broken://pages/KbjkpXL9v5YbkyPGJ22r)

**Easier Purchase Testing**\
Besides implementation details, the Nami SDK helps simplify your purchase testing so you can test purchase flows without managing test users or running up against tedious system prompts just to see how your app reacts to purchase state changes.

### Adopting In-App Purchases on Android

Nami helps make it easier to adopt in-app purchases (including subscriptions) on Google's Play Store platform.

Working with the Google Play Billing library can be tricky. Google releases major updates to the library every year and staying on top of all the latest changes and requirements can take a lot of effort.

Additionally, an implementation of IAPs that meets all of Google's recommendations includes having a server for both purchase token validation and processing of [real-time developer notifications](https://developer.android.com/google/play/billing/getting-ready#configure-rtdn).

Nami solves this, by simplifying the integration points to one (the Nami SDK) allowing you to follow Google's requirements and best practices without the pain.

Specifically, Nami automatically handles three key integration points:

**Google Play Billing Purchase Flow**\
The Nami SDK abstracts away much of the complexity required to utilize the Play Billing Library, including dealing with acknowledging purchases, pending purchases, and other complex cases.

**Purchase Token Validation**\
Nami interfaces with Google's APIs to validate the purchase token so you don't have to write any client or server-side code. Nami validates purchase tokens server-side to help reduce fraud in your app.

**Real-Time Developer Notifications**\
Nami listens for Google's Real-Time Developer Notifications (RTDN) events on your behalf so you don't need to stand up a server. This provides on-going monitoring of key lifecycle changes so your app can adapt accordingly.

To have Nami listen to RTDN events on your behalf, see our [RTDN setup guide](broken://pages/8GiPRgCjWgQLiujHaxTu) .

**Easier Purchase Testing**\
Besides implementation details, the Nami SDK helps simplify your purchase testing so you can test purchase flows without managing test users or running up against tedious system prompts just to see how your app reacts to purchase state changes.

## How to Evaluate the Nami Solution

We have tried to make it straightforward to evaluate Nami through the following resources:

**Documentation**\
You're already here on our documentation portal. Here you'll find Guides and our [SDK Reference](https://docs.namiml.com/sdk-reference/) documentation as well as links to our GitHub repository where you can find the Nami SDK.

**Sample Apps**\
In addition to code snippets you'll find throughout our documentation, we provide sample app projects that you can compile and run.

* Android: [sample app](https://github.com/namiml/nami-android)
* Apple iOS, iPadOS, tvOS: [sample apps](https://github.com/namiml/nami-apple/tree/master/Demo)
* Flutter: [sample apps](https://github.com/namiml/nami-flutter/tree/main/sdk/example/testnami)
* React Native: [sample apps](https://github.com/namiml/react-native-nami-sdk/tree/master/examples)

**Request a Demo**\
If you or someone on your team would like to see Nami in action, [send us a demo request](mailto:info@nami.ml?subject=Demo%20Request).

**Create an Account**\
Create your account in moments to [start your evaluation](https://app.namiml.com).

**Minimal Code to Get Started**\
If you're ready to try Nami in your own project, you can get started with just a few lines of code. Our Add the SDK article will guide you through the steps.

**Privacy By Design**\
We're [Built for Privacy](broken://pages/4QBpLa96ixidOddgsEXC) - see more about [Data Collection](broken://pages/Ofdz8lYiOuhpQrCGpTos).

**Designing the Nami SDK**\
We know it's an honor to be included in your app, and we take our responsibility seriously. To get more insight into how we think about SDK design, review blog post on [SDK Design Goals](https://www.nami.ml/blog/designing-a-mobile-sdk).

**App Standards**\
In order to maintain high standards, our customers need to adhere to [application standards](https://www.nami.ml/legal/app-standards).

**Developer Support**\
We're also available to provide developer support if you have a question or want to walk through implementation details specific to your app. Please [let us know](mailto:info@nami.ml?subject=Developer%20Support), we'd be happy to help!


# configure

Initialize the client-side Nami SDK with your App Platform ID. Required for Nami to see paywalls and campaigns defined in the Nami Control Center.

Initialize the Nami SDK with configure. Pass in the [NamiConfiguration](/sdk-reference/nami/namiconfiguration) object to tailored the SDK for your purposes.<br>

{% tabs fullWidth="true" %}
{% tab title="Apple" %}
{% code fullWidth="true" %}

```swift
import NamiApple

var namiConfig = NamiConfiguration(appPlatformId: "APP_PLATFORM_ID")
namiConfig.logLevel = .warn

Nami.configure(with: namiConfig) { successOrFailure in

}
```

{% endcode %}
{% endtab %}

{% tab title="Android" %}

```kotlin
import android.content.Context
import com.namiml.Nami
import com.namiml.NamiConfiguration
import com.namiml.NamiLogLevel

Nami.configure(
    NamiConfiguration.build(
        context,
        "APP_PLATFORM_ID"
    ) {
        logLevel = NamiLogLevel.WARN
    }
) { configureResult, configureState ->


}
```

{% endtab %}

{% tab title="React Native" %}

```jsx
import { Nami } from 'react-native-nami-sdk';

let configDict = {
 'appPlatformID': 'APP_PLATFORM_ID',
 'logLevel': 'WARN',
};

await Nami.configure(configDict);
```

{% endtab %}

{% tab title="Roku" %}

```brightscript
m.namiManager = CreateObject("roSGNode", "namiSDK:Nami")
m.top.namiManager = m.namiManager

namiConfig = {
    appPlatformId   : "APP_PLATFORM_ID"
    logLevel        : "warn"
}

m.namiManager.callFunc("configure", namiConfig)
```

{% endtab %}

{% tab title="Flutter" %}

```dart
import 'package:nami_flutter/nami.dart';
import 'package:nami_flutter/nami_configuration.dart';
import 'package:nami_flutter/nami_log_level.dart';

var appleAppPlatformId = "YOUR_APPLE_APP_PLATFORM_ID";
var androidAppPlatformId = "YOUR_GOOGLE_OR_AMAZON_APP_PLATFORM_ID";

var namiConfiguration = NamiConfiguration(
    appPlatformIdApple: iosAppPlatformId,
    appPlatformIdGoogle: androidAppPlatformId,
    namiLogLevel: NamiLogLevel.debug);
Nami.configure(namiConfiguration);
```

{% endtab %}

{% tab title="Unity" %}

```cpp
using NamiSDK;

var appPlatformId = Application.platform == RuntimePlatform.Android ? "YOUR_GOOGLE_OR_AMAZON_APP_PLATFORM_ID" : "YOUR_APPLE_APP_PLATFORM_ID";

// if appPlatformId is null or omitted it will use the keys from settings
var configuration = new NamiConfiguration.Builder(appPlatformId) 
   .LogLevel(namiLogLevel.Debug) // if omitted, users Warn log level
   .NamiLanguageCode(NamiLanguageCode.FR) // if omitted, uses device language
  .Build();
Nami.Init(configuration);
```

{% endtab %}

{% tab title="Web" %}

```typescript
import { Nami, NamiConfiguration } from '@namiml/web-sdk';

const configDict: NamiConfiguration = {
 appPlatformId: "APP_PLATFORM_ID",
 logLevel: 'warn',
};

await Nami.configure(configDict);
```

{% endtab %}
{% endtabs %}


# NamiConfiguration

Fields used to configure the Nami SDK

{% tabs %}
{% tab title="Apple" %}

* **appPlatformId** (required): The unique App Platform ID from the Nami Control Center, used to fetch the correct configuration from the server.
* **logLevel** *(optional)*: Controls the SDK’s logging verbosity. Defaults to .warn.
* **namiLanguageCode** *(optional)*: Specifies the desired language for configuration and assets, falling back to the device’s preferred locale.
* **initialConfig** *(optional)*: JSON string used to bootstrap the SDK on first run if server config is unavailable.
* **provisionalGrantTTL** *(optional)*: Sets the duration (in seconds) for temporary entitlements before they expire. Default behavior varies between production and sandbox environments.
* **namiCommands**: Enables feature flags or functionality for testing and internal diagnostics.
  {% endtab %}

{% tab title="Android" %}

* **appPlatformId** (required): The unique App Platform ID from the Nami Control Center, used to fetch the correct configuration from the server.
* **context** (required): The Android Context (typically the Application context) needed to initialize internal SDK components.
* **logLevel** *(optional)*: Controls log output from the SDK. Defaults to NamiLogLevel.WARN. For production builds, it’s recommended to use NamiLogLevel.ERROR or omit entirely.
* **namiLanguageCode** *(optional)*: Specifies the language for paywalls, chosen from the supported NamiLanguageCode values.
* **initialConfig** *(optional)*: JSON string used to bootstrap the SDK on first run if server config is unavailable.
* **provisionalGrantTTL** *(optional)*: Custom duration (in seconds) for temporary entitlements. Defaults to 24 hours for production, 3 minutes for sandbox.
* **settingsList** *(optional)*:  Enables feature flags or functionality for testing and internal diagnostics.
  {% endtab %}

{% tab title="Flutter" %}

* **appPlatformIdApple** (required): The App Platform ID for the iOS version of your app, found in the Nami Control Center under App Settings → Platforms tab.
* **appPlatformIdAndroid** (required): The App Platform ID for the Android version of your app, also available in the Nami Control Center.
* **namiLogLevel** *(optional)*: Controls log verbosity using NamiLogLevel. Defaults to NamiLogLevel.warn. For production, use NamiLogLevel.error or omit the value entirely.
* **extraData** *(optional)*: Accepts a list of string values for feature flags or testing overrides.
  {% endtab %}

{% tab title="React Native" %}

* **appPlatformID** *(required)*: Your unique App Platform ID from the Nami Control Center, used to fetch the correct configuration for this app instance.
* **logLevel** *(required)*: A string representing the SDK’s logging verbosity (e.g., "error", "warn", "info"). For production environments, it’s recommended to use "error".
* **namiCommands** *(optional)*: A list of internal string-based flags to enable experimental or feature-specific SDK behaviors.
* **namiLanguageCode** *(optional)*: A value from NamiLanguageCodes enum used to define the language for paywall content and SDK behavior.
* **initialConfig** *(optional)*: A JSON string used to bootstrap the SDK on startup if no network config is available.
  {% endtab %}

{% tab title="Roku" %}

* **appPlatformId** *(required)*: The App Platform ID for your Roku channel, found in the Nami Control Center under App Settings → Platforms tab. This must be set before any SDK behavior can occur.
* **appFonts** *(optional)*: A list of font files or font references to be used with paywalls or other UI rendered by the SDK.
* **logLevel** *(optional)*: An array of log level strings that determine what debug or error information the SDK will output (e.g., \["error"], \["warn", "info"]).
* **appEnvironment** *(optional)*: Sets the environment for the SDK. Defaults to "staging" if not specified. You can override with "production" when ready.
* **language** *(optional)*: Specifies the language code used by the SDK for paywall localization (e.g., "en", "es").
* **namiCommands** *(optional)*: A list of string-based feature flags used to enable internal or experimental SDK behavior.
* **initialConfig** *(optional)*: A string of JSON configuration used to bootstrap the SDK if a network config request fails.
* **namiHost** *(optional)*: Custom hostname for dedicated Nami environments.
  {% endtab %}

{% tab title="Web" %}

* **appPlatformID** *(required)*: The unique identifier for your app, found in the Nami Control Center under App Settings → Platforms tab.
* **logLevel** *(optional)*: Controls the verbosity of SDK logs. Accepts values from the NamiLogLevel enum. Defaults to NamiLogLevel.WARN. For production, use NamiLogLevel.ERROR.
* **namiCommands** *(optional)*: An array of string-based feature flags to enable internal, beta, or custom behaviors in the SDK.
* **namiLanguageCode** *(optional)*: Selects the language used by paywalls and server configuration, based on values in the NamiLanguageCodes enum.
* **initialConfig** *(optional)*: JSON string or object (InitialConfig or InitialConfigCompressed) used to bootstrap the SDK in offline or pre-loaded mode.
* **formFactor** *(optional)*: A string to indicate the device form factor (e.g., "television", "phone", "desktop", "tablet"), which may influence layout and logic.
* **purchaseChannel** *(optional)*: A string identifier to override or annotate the source of a purchase (e.g., "vizio").
  {% endtab %}
  {% endtabs %}


# NamiLanguageCodes

Languages supported by Nami paywalls.

{% tabs %}
{% tab title="Swift" %}

```swift
@objc public class NamiLanguageCodes : NSObject {
  /// Language Afrikaans
  @objc public static let af = "af"

  /// Language Arabic
  @objc public static let ar = "ar"
   
  /// Language Algerian
  @objc public static let ar_dz = "ar-dz"
   
  /// Language Asturian
  @objc public static let ast = "ast"
   
  /// Language Azerbaijani
  @objc public static let az = "az"
   
  /// Language Bulgarian
  @objc public static let bg = "bg"
   
  /// Language Belarusian
  @objc public static let be = "be"
  
  /// Language Bengali
  @objc public static let bn = "bn"
  
  /// Language Breton
  @objc public static let br = "br"
  
  /// Language Bosnian
  @objc public static let bs = "bs"
  
  /// Language Catalan
  @objc public static let ca = "ca"
  
  /// Language Czech
  @objc public static let cs = "cs"
  
  /// Language Welsh
  @objc public static let cy = "cy"
  
  /// Language Danish
  @objc public static let da = "da"
  
  /// Language German
  @objc public static let de = "de"
  
  /// Language Lower Sorbian
  @objc public static let dsb = "dsb"
  
  /// Language Greek
  @objc public static let el = "el"
  
  /// Language English
  @objc public static let en = "en"
  
  /// Language Australian English
  @objc public static let en_au = "en-au"
  
  /// Language British English
  @objc public static let en_gb = "en-gb"
  
  /// Language Esperanto
  @objc public static let eo = "eo"
  
  /// Language Spanish
  @objc public static let es = "es"
  
  /// Language Argentinian Spanish
  @objc public static let es_ar = "es-ar"
  
  /// Language Colombian Spanish
  @objc public static let es_co = "es-co"
  
  /// Language Mexican Spanish
  @objc public static let es_mx = "es-mx"
  
  /// Language Nicaraguan Spanish
  @objc public static let es_ni = "es-ni"
  
  /// Language Venezuelan Spanish
  @objc public static let es_ve = "es-ve"
  
  /// Language Estonian
  @objc public static let et = "et"
  
  /// Language Basque
  @objc public static let eu = "eu"
  
  /// Language Persian
  @objc public static let fa = "fa"
  
  /// Language Finnish
  @objc public static let fi = "fi"
  
  /// Language French
  @objc public static let fr = "fr"
  
  /// Language Frisian
  @objc public static let fy = "fy"
  
  /// Language Irish
  @objc public static let ga = "ga"
  
  /// Language Scottish Gaelic
  @objc public static let gd = "gd"
  
  /// Language Galician
  @objc public static let gl = "gl"
  
  /// Language Hebrew
  @objc public static let he = "he"
  
  /// Language Hindi
  @objc public static let hi = "hi"
  
  /// Language Croatian
  @objc public static let hr = "hr"
  
  /// Language Upper Sorbian
  @objc public static let hsb = "hsb"
  
  /// Language Hungarian
  @objc public static let hu = "hu"
  
  /// Language Armenian
  @objc public static let hy = "hy"
  
  /// Language Interlingua
  @objc public static let ia = "ia"
  
  /// Language Indonesian
  @objc public static let id = "id"
  
  /// Language Igbo
  @objc public static let ig = "ig"
  
  /// Language Ido
  @objc public static let io = "io"
  
  /// Language Icelandic
  @objc public static let is_is = "is"
  
  /// Language Italian
  @objc public static let it = "it"
  
  /// Language Japanese
  @objc public static let ja = "ja"
  
  /// Language Georgian
  @objc public static let ka = "ka"
  
  /// Language Kabyle
  @objc public static let kab = "kab"
  
  /// Language Kazakh
  @objc public static let kk = "kk"
  
  /// Language Khmer
  @objc public static let km = "km"
  
  /// Language Kannada
  @objc public static let kn = "kn"
  
  /// Language Korean
  @objc public static let ko = "ko"
  
  /// Language Kyrgyz
  @objc public static let ky = "ky"
  
  /// Language Luxembourgish
  @objc public static let lb = "lb"
  
  /// Language Lithuanian
  @objc public static let lt = "lt"
  
  /// Language Latvian
  @objc public static let lv = "lv"
  
  /// Language Macedonian
  @objc public static let mk = "mk"
  
  /// Language Malayalam
  @objc public static let ml = "ml"
  
  /// Language Mongolian
  @objc public static let mn = "mn"
  
  /// Language Marathi
  @objc public static let mr = "mr"
  
  /// Language Burmese
  @objc public static let my = "my"
  
  /// Language Norwegian BokmÃ¥l
  @objc public static let nb = "nb"
  
  /// Language Nepali
  @objc public static let ne = "ne"
  
  /// Language Dutch
  @objc public static let nl = "nl"
  
  /// Language Norwegian Nynorsk
  @objc public static let nn = "nn"
  
  /// Language Ossetic
  @objc public static let os = "os"
  
  /// Language Punjabi
  @objc public static let pa = "pa"
  
  /// Language Polish
  @objc public static let pl = "pl"
  
  /// Language Portuguese
  @objc public static let pt = "pt"
  
  /// Language Brazilian Portuguese
  @objc public static let pt_br = "pt-br"
  
  /// Language Romanian
  @objc public static let ro = "ro"
  
  /// Language Russian
  @objc public static let ru = "ru"
  
  /// Language Slovak
  @objc public static let sk = "sk"
  
  /// Language Slovenian
  @objc public static let sl = "sl"
  
  /// Language Albanian
  @objc public static let sq = "sq"
  
  /// Language Serbian
  @objc public static let sr = "sr"
  
  /// Language Serbian Latin
  @objc public static let sr_latn = "sr-latn"
  
  /// Language Swedish
  @objc public static let sv = "sv"
  
  /// Language Swahili
  @objc public static let sw = "sw"
  
  /// Language Tamil
  @objc public static let ta = "ta"
  
  /// Language Telugu
  @objc public static let te = "te"
  
  /// Language Tajik
  @objc public static let tg = "tg"
  
  /// Language Thai
  @objc public static let th = "th"
  
  /// Language Turkmen
  @objc public static let tk = "tk"
  
  /// Language Turkish
  @objc public static let tr = "tr"
  
  /// Language Tatar
  @objc public static let tt = "tt"
  
  /// Language Udmurt
  @objc public static let udm = "udm"
  
  /// Language Ukrainian
  @objc public static let uk = "uk"
  
  /// Language Urdu
  @objc public static let ur = "ur"
  
  /// Language Uzbek
  @objc public static let uz = "uz"
  
  /// Language Vietnamese
  @objc public static let vi = "vi"
  
  /// Language Simplified Chinese
  @objc public static let zh_hans = "zh-hans"
  
  /// Language Traditional Chinese
  @objc public static let zh_hant = "zh-hant"
}
```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
enum class NamiLanguageCode(val code: String) {
    /** Language Afrikaans **/
    AF("af"),

    /** Language Arabic **/
    AR("ar"),

    /** Language Algerian **/
    AR_DZ("ar-dz"),

    /** Language Asturian **/
    AST("ast"),

    /** Language Azerbaijani **/
    AZ("az"),

    /** Language Bulgarian **/
    BG("bg"),

    /** Language Belarusian **/
    BE("be"),

    /** Language Bengali **/
    BN("bn"),

    /** Language Breton **/
    BR("br"),

    /** Language Bosnian **/
    BS("bs"),

    /** Language Catalan **/
    CA("ca"),

    /** Language Czech **/
    CS("cs"),

    /** Language Welsh **/
    CY("cy"),

    /** Language Danish **/
    DA("da"),

    /** Language German **/
    DE("de"),

    /** Language Lower Sorbian **/
    DSB("dsb"),

    /** Language Greek **/
    EL("el"),

    /** Language English **/
    EN("en"),

    /** Language Australian English **/
    EN_AU("en-au"),

    /** Language British English **/
    EN_GB("en-gb"),

    /** Language Esperanto **/
    EO("eo"),

    /** Language Spanish **/
    ES("es"),

    /** Language Argentinian Spanish **/
    ES_AR("es-ar"),

    /** Language Colombian Spanish **/
    ES_CO("es-co"),

    /** Language Mexican Spanish **/
    ES_MX("es-mx"),

    /** Language Nicaraguan Spanish **/
    ES_NI("es-ni"),

    /** Language Venezuelan Spanish **/
    ES_VE("es-ve"),

    /** Language Estonian **/
    ET("et"),

    /** Language Basque **/
    EU("eu"),

    /** Language Persian **/
    FA("fa"),

    /** Language Finnish **/
    FI("fi"),

    /** Language French **/
    FR("fr"),

    /** Language Frisian **/
    FY("fy"),

    /** Language Irish **/
    GA("ga"),

    /** Language Scottish Gaelic **/
    GD("gd"),

    /** Language Galician **/
    GL("gl"),

    /** Language Hebrew **/
    HE("he"),

    /** Language Hindi **/
    HI("hi"),

    /** Language Croatian **/
    HR("hr"),

    /** Language Upper Sorbian **/
    HSB("hsb"),

    /** Language Hungarian **/
    HU("hu"),

    /** Language Armenian **/
    HY("hy"),

    /** Language Interlingua **/
    IA("ia"),

    /** Language Indonesian **/
    ID("id"),

    /** Language Igbo **/
    IG("ig"),

    /** Language Ido **/
    IO("io"),

    /** Language Icelandic **/
    IS_IS("is"),

    /** Language Italian **/
    IT("it"),

    /** Language Japanese **/
    JA("ja"),

    /** Language Georgian **/
    KA("ka"),

    /** Language Kabyle **/
    KAB("kab"),

    /** Language Kazakh **/
    KK("kk"),

    /** Language Khmer **/
    KM("km"),

    /** Language Kannada **/
    KN("kn"),

    /** Language Korean **/
    KO("ko"),

    /** Language Kyrgyz **/
    KY("ky"),

    /** Language Luxembourgish **/
    LB("lb"),

    /** Language Lithuanian **/
    LT("lt"),

    /** Language Latvian **/
    LV("lv"),

    /** Language Macedonian **/
    MK("mk"),

    /** Language Malayalam **/
    ML("ml"),

    /** Language Mongolian **/
    MN("mn"),

    /** Language Marathi **/
    MR("mr"),

    /** Language Burmese **/
    MY("my"),

    /** Language Norwegian BokmÃ¥l **/
    NB("nb"),

    /** Language Nepali **/
    NE("ne"),

    /** Language Dutch **/
    NL("nl"),

    /** Language Norwegian Nynorsk **/
    NN("nn"),

    /** Language Ossetic **/
    OS("os"),

    /** Language Punjabi **/
    PA("pa"),

    /** Language Polish **/
    PL("pl"),

    /** Language Portuguese **/
    PT("pt"),

    /** Language Brazilian Portuguese **/
    PT_BR("pt-br"),

    /** Language Romanian **/
    RO("ro"),

    /** Language Russian **/
    RU("ru"),

    /** Language Slovak **/
    SK("sk"),

    /** Language Slovenian **/
    SL("sl"),

    /** Language Albanian **/
    SQ("sq"),

    /** Language Serbian **/
    SR("sr"),

    /** Language Serbian Latin **/
    SR_LATN("sr-latn"),

    /** Language Swedish **/
    SV("sv"),

    /** Language Swahili **/
    SW("sw"),

    /** Language Tamil **/
    TA("ta"),

    /** Language Telugu **/
    TE("te"),

    /** Language Tajik **/
    TG("tg"),

    /** Language Thai **/
    TH("th"),

    /** Language Turkmen **/
    TK("tk"),

    /** Language Turkish **/
    TR("tr"),

    /** Language Tatar **/
    TT("tt"),

    /** Language Udmurt **/
    UDM("udm"),

    /** Language Ukrainian **/
    UK("uk"),

    /** Language Urdu **/
    UR("ur"),

    /** Language Uzbek **/
    UZ("uz"),

    /** Language Vietnamese **/
    VI("vi"),

    /** Language Simplified Chinese **/
    ZH_HANS("zh-hans"),

    /** Language Traditional Chinese **/
    ZH_HANT("zh-hant"),
}
```

{% endtab %}

{% tab title="React Native" %}

```jsx
export type NamiLanguageCodes =
  | "af"
  | "ar"
  | "ar-dz"
  | "ast"
  | "az"
  | "bg"
  | "be"
  | "bn"
  | "br"
  | "bs"
  | "ca"
  | "cs"
  | "cy"
  | "da"
  | "de"
  | "dsb"
  | "el"
  | "en"
  | "en-au"
  | "en-gb"
  | "eo"
  | "es"
  | "es-ar"
  | "es-co"
  | "es-mx"
  | "es-ni"
  | "es-ve"
  | "et"
  | "eu"
  | "fa"
  | "fi"
  | "fr"
  | "fy"
  | "ga"
  | "gd"
  | "gl"
  | "he"
  | "hi"
  | "hr"
  | "hsb"
  | "hu"
  | "hy"
  | "ia"
  | "id"
  | "ig"
  | "io"
  | "is"
  | "it"
  | "ja"
  | "ka"
  | "kab"
  | "kk"
  | "km"
  | "kn"
  | "ko"
  | "ky"
  | "lb"
  | "lt"
  | "lv"
  | "mk"
  | "ml"
  | "mn"
  | "mr"
  | "my"
  | "nb"
  | "ne"
  | "nl"
  | "nn"
  | "os"
  | "pa"
  | "pl"
  | "pt"
  | "pt-br"
  | "ro"
  | "ru"
  | "sk"
  | "sl"
  | "sq"
  | "sr"
  | "sr-latn"
  | "sv"
  | "sw"
  | "ta"
  | "te"
  | "tg"
  | "th"
  | "tk"
  | "tr"
  | "tt"
  | "udm"
  | "uk"
  | "ur"
  | "uz"
  | "vi"
  | "zh-hans"
  | "zh-hant";
```

{% endtab %}

{% tab title="Unity" %}

```cpp
public enum NamiLanguageCode
    {
        AF,
        AR,
        AR_DZ,
        AST,
        AZ,
        BG,
        BE,
        BN,
        BR,
        BS,
        CA,
        CS,
        CY,
        DA,
        DE,
        DSB,
        EL,
        EN,
        EN_AU,
        EN_GB,
        EO,
        ES,
        ES_AR,
        ES_CO,
        ES_MX,
        ES_NI,
        ES_VE,
        ET,
        EU,
        FA,
        FI,
        FR,
        FY,
        GA,
        GD,
        GL,
        HE,
        HI,
        HR,
        HSB,
        HU,
        HY,
        IA,
        ID,
        IG,
        IO,
        IS_IS,
        IT,
        JA,
        KA,
        KAB,
        KK,
        KM,
        KN,
        KO,
        KY,
        LB,
        LT,
        LV,
        MK,
        ML,
        MN,
        MR,
        MY,
        NB,
        NE,
        NL,
        NN,
        OS,
        PA,
        PL,
        PT,
        PT_BR,
        RO,
        RU,
        SK,
        SL,
        SQ,
        SR,
        SR_LATN,
        SV,
        SW,
        TA,
        TE,
        TG,
        TH,
        TK,
        TR,
        TT,
        UDM,
        UK,
        UR,
        UZ,
        VI,
        ZH_HANS,
        ZH_HANT
    }
```

{% endtab %}
{% endtabs %}


# launch

Show a paywall or flow

#### Launch a campaign with the specified label

{% tabs %}
{% tab title="Swift" %}

```swift
NamiCampaignManager.launch(label: String)
```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
NamiCampaignManager.launch(activity: Activity, label: String)
```

{% endtab %}

{% tab title="Flutter" %}

```dart
NamiCampaignManager.launch(label: "onboarding");
```

{% endtab %}

{% tab title="React Native" %}

```javascript
NamiCampaignManager.launch('onboarding', (success, error) => {
  console.log('success', success);
  console.log('error', error);
});
```

{% endtab %}

{% tab title="Unity" %}

```cpp
NamiCampaignManager.Launch("onboarding");
```

{% endtab %}
{% endtabs %}

**Parameters**

* `label` - a string matching the label set in the Control Center

#### Launch a campaign with a result callback

This can be used to know if the launch succeeded or failed to raise a paywall.\
Additionally, you can use this to monitor for purchase change events to observe what the outcomes of any system purchase flows initiated from the campaign launch.

{% tabs %}
{% tab title="Swift" %}

```swift
NamiCampaignManager.launch(label: "a_label", launchHandler: { success, error in
   // callback with success (bool) or error (LaunchCampaignError)               
})
```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
NamiCampaignManager.launch(activity, "a_label") { result ->
    when (result) {
        is LaunchCampaignResult.Success -> {
          // success
        }
        is LaunchCampaignResult.Failure -> {
          // fail
            Log.d(LOG_TAG, "Launch Campaign Error -> ${result.error}")
        }
        is LaunchCampaignResult.PurchaseChanged -> {
            Log.d(
                LOG_TAG,
                "Launch Campaign Result - Purchase changed -> ${result.purchaseState}"
            )

            if (result.purchaseState == NamiPurchaseState.PURCHASED) {
                Log.d(
                    LOG_TAG,
                    "NamiPurchaseState - Purchased -> ${result.activePurchases}"
                )
            }
        }     
    }
}
```

{% endtab %}

{% tab title="Flutter" %}

```dart
// Launch the campaign, with a label, and use of an error handler
LaunchCampaignResult result;
result = await NamiCampaignManager.launch(label: "onboarding");
if (result.success) {
  print("Launch campaign - success");
} else {
  print("Launch campaign - error");
}
```

{% endtab %}

{% tab title="React Native" %}

```javascript
import {NamiCampaignManager, NamiCampaign} from 'react-native-nami-sdk';

NamiCampaignManager.launch(
  label,
  (successAction, error) => {
    console.log('successAction', successAction);
    console.log('error', error);
  });
```

{% endtab %}

{% tab title="Unity" %}

```cpp
// Launch a campaign with an error handler
var launchHandler = new LaunchHandler((isSuccess, errorMsg) =>
{
    // on launch
});
NamiCampaignManager.Launch("onboarding", launchHandler);
```

{% endtab %}
{% endtabs %}

#### Launch a campaign with paywall interaction callback

Use this to monitor user interactions with the paywall raised by this campaign launch. Returns `NamiPaywallAction` events and an optional `skuId` if relevant to the action.

{% tabs %}
{% tab title="Swift" %}

```swift
NamiCampaignManager.launch(label: label, launchHandler: { success, error in
        print("campaign launch - success \(success) or error \(error)")
    },
        paywallActionHandler: { paywallEvent in

            print("Campaign paywallActionHandler metadata: \n" +
                "campaignId: \(String(describing: paywallEvent.campaignId))\n" +
                "campaignName: \(String(describing: paywallEvent.campaignName))\n" +
                "campaignType: \(String(describing: paywallEvent.campaignType))\n" +
                "campaignLabel: \(String(describing: paywallEvent.campaignLabel))\n" +
                "campaignUrl: \(String(describing: paywallEvent.campaignUrl))\n" +
                "paywallId: \(String(describing: paywallEvent.paywallId))\n" +
                "paywallName: \(String(describing: paywallEvent.paywallName))\n" +
                "segmentId: \(String(describing: paywallEvent.segmentId))\n" +
                "externalSegmentId: \(String(describing: paywallEvent.externalSegmentId))\n" +
                "paywallLaunchContext: \(String(describing: paywallEvent.paywallLaunchContext))\n" +
                "deeplinkUrl: \(String(describing: paywallEvent.deeplinkUrl))\n")

    })
```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
// Launch the campaign with paywall interaction feedback handler
NamiCampaignManager.launch(activity, label, paywallActionCallback = { paywallEvent ->

    Log.d(
        LOG_TAG,
        "${paywallEvent.action}",
    )

    Log.d(
        LOG_TAG,
        "\tcampaignId ${paywallEvent.campaignId}\n" +
            "\tcampaignName ${paywallEvent.campaignName}\n" +
            "\tcampaignType ${paywallEvent.campaignType}\n" +
            "\tcampaignLabel ${paywallEvent.campaignLabel}\n" +
            "\tcampaignUrl ${paywallEvent.campaignUrl}\n" +
            "\tpaywallId ${paywallEvent.paywallId}\n" +
            "\tpaywallName ${paywallEvent.paywallName}\n" +
            "\tsegmentId ${paywallEvent.segmentId}\n" +
            "\texternalSegmentId ${paywallEvent.externalSegmentId}\n" +
            "\tdeepLinkUrl ${paywallEvent.deeplinkUrl}\n" +
            "\tselectedItemId ${paywallEvent.componentChange?.id}\n" +
            "\tselectedItemName ${paywallEvent.componentChange?.name}\n" +
            "\tsku ${paywallEvent.sku?.skuId}\n" +
            "\tpurchaseError ${paywallEvent.purchaseError}\n" +
            "\tpurchaseError ${paywallEvent.purchases}\n",

    )
}) { result ->
    when (result) {
        is LaunchCampaignResult.Success -> {
            Log.d(LOG_TAG, "Launch Campaign Success")
        }
        is LaunchCampaignResult.Failure -> {
            Log.d(LOG_TAG, "Launch Campaign Error -> ${result.error}")
        }
    }
               
```

{% endtab %}

{% tab title="Flutter" %}

```dart
// Launch the campaign, with a label, and use of an error handler
LaunchCampaignResult result;
result = await NamiCampaignManager.launch(
  label: "onboarding",
  onPaywallAction: (action, sku) {
      print("Paywall action $action");
});
if (result.success) {
  print("Launch campaign - success");
} else {
  print("Launch campaign - error");
}// Launch the campaign with paywall interaction callbacks
// - Android paywallActionHandler
var paywallActionHandler = new PaywallActionHandler((namiPaywallAction, sku) =>
{
    // on paywall action
});
// - iOS paywallActionHandler
var paywallActionHandler = new PaywallActionHandler((namiPaywallAction, sku, errorMsg, purchases) =>
{
    // on paywall action
});
NamiCampaignManager.Launch("onboarding", launchHandler, paywallActionHandler);
```

{% endtab %}

{% tab title="React Native" %}

```javascript
import {NamiCampaignManager, NamiCampaign} from 'react-native-nami-sdk';

NamiCampaignManager.launch(
  label,
  (successAction, error) => {
    console.log('successAction', successAction);
    console.log('error', error);
  },
  (
    action,
    skuId,
    purchaseError,
    purchases,
    campaignId,
    campaignLabel,
    paywallId,
  ) => {
    console.log('action', action);
    console.log('skuId', skuId);
    console.log('purchaseError', purchaseError);
    console.log('purchases', purchases);
    console.log('campaignId', campaignId);
    console.log('campaignLabel', campaignLabel);
    console.log('paywallId', paywallId);
  },
);
```

{% endtab %}

{% tab title="Unity" %}

```cpp
// Launch the campaign with paywall interaction callbacks
// - Android paywallActionHandler
var paywallActionHandler = new PaywallActionHandler((namiPaywallAction, sku) =>
{
    // on paywall action
});
// - iOS paywallActionHandler
var paywallActionHandler = new PaywallActionHandler((namiPaywallAction, sku, errorMsg, purchases) =>
{
    // on paywall action
});
NamiCampaignManager.Launch("onboarding", launchHandler, paywallActionHandler);
```

{% endtab %}
{% endtabs %}


# allCampaigns

A list of campaigns that are available to the device.

Get back a list of NamiCampaigns that are available to the device.

Campaigns are updated upon app start. You may also manually request an update via [refresh](/sdk-reference/namicampaignmanager/refresh).

{% tabs %}
{% tab title="Swift" %}

```swift
NamiCampaignManager.allCampaigns()
```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
NamiCampaignManager.allCampaigns()
```

{% endtab %}

{% tab title="Flutter" %}

```dart
import 'package:nami_flutter/campaign/nami_campaign.dart';
import 'package:nami_flutter/campaign/nami_campaign_manager.dart';

List<NamiCampaign> _campaigns = [];

NamiCampaignManager.allCampaigns().then((list) {
  setState(() {
    _campaigns = list;
  });
});
```

{% endtab %}

{% tab title="React Native" %}

```tsx
import {NamiCampaignManager, NamiCampaign} from 'react-native-nami-sdk';

const allCampaigns = await NamiCampaignManager.allCampaigns();
```

{% endtab %}

{% tab title="Unity" %}

```csharp
using NamiSDK;

var campaigns = NamiCampaignManager.AllCampaigns();
```

{% endtab %}
{% endtabs %}


# isCampaignAvailable

Returns a boolean if a matching campaign is available on the device.

{% tabs %}
{% tab title="Swift" %}

```swift
import NamiApple

// Returns true if a default campaign (one without a label) is available on the device
NamiCampaignManager.isCampaignAvailable()

// Returns true if a campaign matching the specified label is available on the device
NamiCampaignManager.isCampaignAvailable("a_label")
```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
// Returns true if a default campaign (one without a label) is available on the device
NamiCampaignManager.isCampaignAvailable()

// Returns true if a campaign matching the specified label is available on the device
NamiCampaignManager.isCampaignAvailable("a_label")
```

{% endtab %}

{% tab title="Flutter" %}

```dart
import 'package:nami_flutter/campaign/nami_campaign.dart';
import 'package:nami_flutter/campaign/nami_campaign_manager.dart';

// Check if a unlabeled campaign is available on device
bool available = await NamiCampaignManager.isCampaignAvailable();

// Check if a labeled campaign is available on device
bool available = await NamiCampaignManager.isCampaignAvailable(label: "a_label");
```

{% endtab %}

{% tab title="React Native" %}

```jsx
import {NamiCampaignManager, NamiCampaign} from 'react-native-nami-sdk';

const isCampaignAvailable = await NamiCampaignManager.isCampaignAvailable(
  label,
);
```

{% endtab %}
{% endtabs %}


# refresh

Manually request that available campaigns for the device be refreshed from the Nami service.

If a callback handler is registered with [registerAvailableCampaignsHandler](/sdk-reference/namicampaignmanager/registeravailablecampaignshandler), it will be triggered once the refresh is complete.

{% tabs %}
{% tab title="Swift" %}

```swift
import NamiApple

NamiCampaignManager.refresh()
```

{% endtab %}

{% tab %}

```kotlin
NamiCampaignManager.refresh()
```

{% endtab %}

{% tab title="Flutter" %}

```dart
import 'package:nami_flutter/campaign/nami_campaign.dart';
import 'package:nami_flutter/campaign/nami_campaign_manager.dart';

NamiCampaignManager.refresh();
```

{% endtab %}

{% tab title="React Native" %}

```jsx
import {NamiCampaignManager, NamiCampaign} from 'react-native-nami-sdk';

// Manually trigger a campaign refresh
NamiCampaignManager.refresh();
```

{% endtab %}
{% endtabs %}


# registerAvailableCampaignsHandler

Receive a callback whenever the SDK gets back the current list of available [NamiCampaign](/sdk-reference/namicampaignmanager/namicampaign) objects for the device. This list is personalized for the device by the Nami backend server based upon campaign filtering and priority rules.

{% tabs %}
{% tab title="Swift" %}

```swift
NamiCampaignManager.registerAvailableCampaignsHandler { campaigns in
}
```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
NamiCampaignManager.registerAvailableCampaignsHandler() { availableCampaigns ->
  
}
```

{% endtab %}

{% tab title="Flutter" %}

```dart
import 'package:nami_flutter/campaign/nami_campaign.dart';
import 'package:nami_flutter/campaign/nami_campaign_manager.dart';
List<NamiCampaign> _campaigns = [];

NamiCampaignManager.registerAvailableCampaignsHandler().listen((list) {
  setState(() {
    _campaigns = list;
  });
});
```

{% endtab %}

{% tab title="React Native" %}

```c
import {NamiCampaignManager, NamiCampaign} from 'react-native-nami-sdk';

useEffect(() => {
  const subscriptionRemover =
    NamiCampaignManager.registerAvailableCampaignsHandler(
      (availableCampaigns) => {
        console.log('availableCampaigns', availableCampaigns);
        setCampaigns(availableCampaigns);
      },
    );
  return () => {
    subscriptionRemover();
  };
}, []);
```

{% endtab %}
{% endtabs %}


# NamiCampaign

The campaign object represents the live campaigns configured in the Nami Control Center that are available to the device after all campaign filtering and ordering rules are applied.

{% tabs %}
{% tab title="Swift" %}

```swift
@objc public class NamiCampaign : NSObject, Codable, Identifiable {
    public var id: String { rule }
    public var rule: String
    public var segment: String
    public var paywall : String
    public var type: NamiCampaignRuleType = .unknown
    public var value: String?
}
```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
class NamiCampaign(
     val paywall: String,
     val segment: String,
     val type: NamiCampaignRuleType,
     val value: String?
)
```

{% endtab %}

{% tab title="Flutter" %}

```dart
class NamiCampaign {
  final String paywall;
  final String segment;
  final NamiCampaignRuleType type;
  final String? value;
}
```

{% endtab %}

{% tab title="React Native" %}

```jsx
export type NamiCampaign = {
  id: string;
  rule: string;
  segment: string;
  paywall: string;
  type: NamiCampaignRuleType;
  value?: string | null;
};
```

{% endtab %}

{% tab title="Unity" %}

```cpp
public class NamiCampaign
    {
        /// <summary> iOS only </summary>
        public string Id { get; private set; }

        /// <summary> iOS only </summary>
        public string Rule { get; private set; }

        public string Paywall { get; private set; }

        public string Segment { get; private set; }

        /// <summary> Android only </summary>
        public NamiCampaignRuleType Type { get; private set; }

        public string Value { get; private set; }
    }
```

{% endtab %}
{% endtabs %}


# NamiCampaignRuleType

Used by [NamiCampaign](/sdk-reference/namicampaignmanager/namicampaign) to indicate whether or not the campaign has a label or not.

{% tabs %}
{% tab title="Swift" %}

```swift
```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
enum class NamiCampaignRuleType { DEFAULT, LABEL }
```

{% endtab %}

{% tab title="Flutter" %}

```dart
enum NamiCampaignRuleType { DEFAULT, LABEL }
```

{% endtab %}

{% tab title="React Native" %}

```tsx
export enum NamiCampaignRuleType {
  DEFAULT = "default",
  LABEL = "label",
  UNKNOWN = "unknown",
}
```

{% endtab %}

{% tab title="Unity" %}

```cpp
public enum NamiCampaignRuleType
{
    Default,
    Label
}
```

{% endtab %}
{% endtabs %}


# LaunchCampaignError

If a campaign launch fails to raise a paywall, these are potential error types which are returned via an optional callback provided by [`NamiCampaignManager.launch`.](/sdk-reference/namicampaignmanager/launch)

{% tabs %}
{% tab title="Swift" %}

```swift
@objc enum LaunchCampaignError : Int {
    case DEFAULT_CAMPAIGN_NOT_FOUND = 0
    case LABELED_CAMPAIGN_NOT_FOUND = 1
    case CAMPAIGN_DATA_NOT_FOUND = 2
    case PAYWALL_ALREADY_DISPLAYED = 3
    case SDK_NOT_INITIALIZED = 4
    case PAYWALL_COULD_NOT_DISPLAY = 5
    case URL_CAMPAIGN_NOT_FOUND = 6
    case PRODUCT_DATA_NOT_FOUND = 7
    case PRODUCT_GROUPS_NOT_FOUND = 8
}
```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
enum class LaunchCampaignError : NamiError {
    SDK_NOT_INITIALIZED,
    DEFAULT_CAMPAIGN_NOT_FOUND,
    LABELED_CAMPAIGN_NOT_FOUND,
    PAYWALL_ALREADY_DISPLAYED,
    CAMPAIGN_DATA_NOT_FOUND
 }
```

{% endtab %}

{% tab title="Flutter" %}

```dart
enum LaunchCampaignError {
  SDK_NOT_INITIALIZED,
  DEFAULT_CAMPAIGN_NOT_FOUND,
  LABELED_CAMPAIGN_NOT_FOUND,
  PAYWALL_ALREADY_DISPLAYED,
  CAMPAIGN_DATA_NOT_FOUND
}
```

{% endtab %}

{% tab title="React Native" %}

```jsx
export enum LaunchCampaignError {
  DEFAULT_CAMPAIGN_NOT_FOUND = 0,
  LABELED_CAMPAIGN_NOT_FOUND = 1,
  CAMPAIGN_DATA_NOT_FOUND = 2,
  PAYWALL_ALREADY_DISPLAYED = 3,
  SDK_NOT_INITIALIZED = 4,
}
```

{% endtab %}

{% tab title="Unity" %}

```c
public enum LaunchCampaignError
{
    DefaultCampaignNotFound,
    LabeledCampaignNotFound,
    CampaignDataNotFound,
    PaywallAlreadyDisplayed,
    SDKNotInitialized
}
```

{% endtab %}
{% endtabs %}

* `SDK_NOT_INITIALIZED` - SDK must be initialized via \[Nami.configure] before launching a campaign
* `DEFAULT_CAMPAIGN_NOT_FOUND` - No live default campaign could be launched.
* `LABELED_CAMPAIGN_NOT_FOUND` - No live campaign could be launched for the requested label.
* `PAYWALL_ALREADY_DISPLAYED` - Cannot launch a campaign, because a paywall is currently on screen
* `CAMPAIGN_DATA_NOT_FOUND` - No campaign found
* `PAYWALL_COULD_NOT_DISPLAY` - Could not display the paywall
* `URL_CAMPAIGN_NOT_FOUND` - No live campaign for this deeplink URL was found
* `PRODUCT_DATA_NOT_FOUND`- No product data could be loaded from the app store
* `PRODUCT_GROUPS_NOT_FOUND` - Product groups passed into launch don't match what paywall expects


# CustomerJourneyState

Class representing the state of a customer's subscription journey.

{% tabs %}
{% tab title="Swift" %}

```swift
@objc public class CustomerJourneyState:NSObject, NSCoding, Codable {
  let formerSubscriber: Bool
  let inGracePeriod: Bool
  let inTrialPeriod: Bool
  let inIntroOfferPeriod: Bool
  let isCancelled : Bool
  let inPause : Bool
  let inAccountHold : Bool
}
```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
data class CustomerJourneyState(
    val formerSubscriber: Boolean,
    val inGracePeriod: Boolean,
    val inTrialPeriod: Boolean,
    val inIntroOfferPeriod: Boolean,
    val isCancelled: Boolean = false,
    val inPause: Boolean = false,
    val inAccountHold: Boolean = false
)
```

{% endtab %}

{% tab title="Flutter" %}

```dart
class CustomerJourneyState {
  final bool formerSubscriber;
  final bool inGracePeriod;
  final bool inTrialPeriod;
  final bool inIntroOfferPeriod;
  final bool isCancelled;
  final bool inPause;
  final bool inAccountHold;
}
```

{% endtab %}
{% endtabs %}

**Parameters**

* `formerSubscriber` - Boolean - indicates if the customer had subscribed in the past.
* `inGracePeriod` - Boolean - indicates the subscription has lapsed due to a payment failure where the platform is still trying to actively recover the payment method and the granted entitlements should still be active.
* `inTrialPeriod` - Boolean - indicates the customer is in a free trial.
* `inIntroOfferPeriod` - Boolean - indicates the customer is in an introductory offer subscription, where their current price is less than the eventual full price.
* `isCancelled` - Boolean - indicates if the customer used to be a subscriber and cancelled their subscription renewal
* `inPause` - Boolean - indicates if the customer's subscription is paused. **Android only**
* `inAccountHold` - Boolean - indicates if the subscription has lapsed due to a payment failure and the granted entitlements are no longer active


# isLoggedIn

Return if a user is currently logged into the device

Returns a boolean representing if there is a customer identifier current associated with the device. In other words, Nami believes the device is logged into to an account.

{% tabs %}
{% tab title="Swift" %}

```swift
let loggedIn = NamiCustomerManager.isLoggedIn()
```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
val loggedIn = NamiCustomerManager.isLoggedIn()
```

{% endtab %}

{% tab title="Flutter" %}

```dart
var loggedIn = NamiCustomerManager.isLoggedIn();
```

{% endtab %}

{% tab title="React Native" %}

```jsx
const checkIsLoggedIn = async () => {
  const isLoggedIn = await NamiCustomerManager.isLoggedIn();
  setIsUserLogin(isLoggedIn);
  console.log('isLoggedIn', isLoggedIn);
};
```

{% endtab %}

{% tab title="Unity" %}

```c
var isLoggedIn = NamiCustomerManager.IsLoggedIn;
```

{% endtab %}
{% endtabs %}


# journeyState

Returns the current state of a customer's subscription journey.

{% tabs %}
{% tab title="Swift" %}

```swift
static func journeyState() -> CustomerJourneyState?
```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
fun journeyState(): CustomerJourneyState?
```

{% endtab %}

{% tab title="Flutter" %}

```dart
static Future<CustomerJourneyState?> journeyState() async
```

{% endtab %}

{% tab title="React Native" %}

```javascript
export type CustomerJourneyState = {
  formerSubscriber: boolean;
  inGracePeriod: boolean;
  inTrialPeriod: boolean;
  inIntroOfferPeriod: boolean;
  isCancelled: boolean;
  inPause: boolean;
  inAccountHold: boolean;
};
```

{% endtab %}

{% tab title="Unity" %}

```c
public class CustomerJourneyState
{
    public bool FormerSubscriber { get; private set; }

    public bool InGracePeriod { get; private set; }

    public bool InTrialPeriod { get; private set; }

    public bool InIntroOfferPeriod { get; private set; }

    public bool IsCancelled { get; private set; }

    /// <summary> Android platforms only </summary>
    public bool InPause { get; private set; }

    public bool InAccountHold { get; private set; }
}
```

{% endtab %}
{% endtabs %}

Returns a [CustomerJourneyState](/sdk-reference/namicustomermanager/customerjourneystate) object.


# loggedInId

Return the unique customer identifier associated with the current device.

Returns a string of the external identifier that Nami has stored. Returns `null` if no id has been stored, including if a string was passed to [login](/sdk-reference/namicustomermanager/login) that was not valid.

{% tabs %}
{% tab title="Swift" %}

```swift
let customerId = NamiCustomerManager.loggedInId()
```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
val customerId = NamiCustomerManager.loggedInId()
```

{% endtab %}

{% tab title="Flutter" %}

```dart
var customerId = NamiCustomerManager.loggedInId();
```

{% endtab %}

{% tab title="React Native" %}

```jsx
const checkId = async () => {
  const loggedId = await NamiCustomerManager.loggedInId();
  const deviceId = await NamiCustomerManager.deviceId();
  setExternalId(loggedId);
  setDisplayedDeviceId(deviceId);
};
```

{% endtab %}

{% tab title="Unity" %}

```c
var loggedInId = NamiCustomerManager.LoggedInId;
```

{% endtab %}
{% endtabs %}


# login

Provide a customer id to link one or more devices to a known customer.

Provide a unique identifier that can be used to link different devices to the same customer in the Nami platform. This customer id will also be returned in any data sent from the Nami servers to your systems as well.

The ID sent to Nami must be a valid UUID or you may hash any other identifier with SHA256 and provide it in this call.

{% hint style="danger" %}
**Nami Will Not Accept PII as an Identifier**

Email addresses and usernames cannot be sent to Nami via this call. Nami only accepts data that is a valid numeric, UUID or a SHA256. Any other data will be rejected by the Nami server.
{% endhint %}

{% tabs %}
{% tab title="Swift" %}

```swift
NamiCustomerManager.login(withId: "123456")
```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
NamiCustomerManager.login("123456")
```

{% endtab %}

{% tab title="Flutter" %}

```dart
NamiCustomerManager.login(withId: "123456");
```

{% endtab %}

{% tab title="React Native" %}

```jsx
const onLoginPress = useCallback(() => {
  NamiCustomerManager.login(
    '123456',
    (success, error) => {
      console.log('success', success);
      console.log('error', error);
    },
  );
}, []);
```

{% endtab %}

{% tab %}

```c
NamiCustomerManager.Login("123456");
```

{% endtab %}
{% endtabs %}


# logout

Disassociate a device from a customer identifier.

Use this method to disconnect the association between a user's device and a customer identifier.\
For example, do this when the user logs out of their account within your app.

{% tabs %}
{% tab title="Swift" %}

```swift
NamiCustomerManager.logout()
```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
NamiCustomerManager.logout()
```

{% endtab %}

{% tab title="Flutter" %}

```dart
NamiCustomerManager.logout();
```

{% endtab %}

{% tab title="React Native" %}

```jsx
const onLogoutPress = useCallback(() => {
  NamiCustomerManager.logout((success, error) => {
    console.log('success', success);
    console.log('error', error);
  });
}, []);
```

{% endtab %}

{% tab title="Unity" %}

```c
NamiCustomerManager.Logout();
```

{% endtab %}
{% endtabs %}


# registerAccountStateHandler

Register a callback that will be called whenever [`NamiCustomerManager.login`](/sdk-reference/namicustomermanager/login) or [`NamiCustomerManager.logout`](/sdk-reference/namicustomermanager/logout) is called with results from those calls.

{% tabs %}
{% tab title="Swift" %}

```swift
NamiCustomerManager.registerAccountStateHandler { accountStateAction, success, error in
   if success {
       if accountStateAction == .login {
         // logged in
       } else if accountStateAction == .logout {
         // logged out
       }        
   } else {
     // an error occured
   }
}
```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
NamiCustomerManager.registerAccountStateHandler { accountStateAction, success, error ->
if (success) {
    if (accountStateAction == AccountStateAction.LOGIN) {
        Log.d(LOG_TAG, "User is logged in")
    } else if (accountStateAction == AccountStateAction.LOGOUT) {
        Log.d(LOG_TAG, "User is logged out")
    }
} else if (error != null) {
    if (accountStateAction == AccountStateAction.LOGIN) {
        Log.d(LOG_TAG, "There was an error logging in. Error - ${error}")
    } else if (accountStateAction == AccountStateAction.LOGOUT) {
        Log.d(LOG_TAG, "There was an error logging out. Error - ${error}")
    }
}
}
```

{% endtab %}

{% tab title="Flutter" %}

```dart
NamiCustomerManager.registerAccountStateHandler()
    .listen((accountState) {
  print("AccountStateHandler triggered");

  if (accountState.success) {
    if (accountState.accountStateAction == AccountStateAction.login) {
      print("Login success");
    } else
    if (accountState.accountStateAction == AccountStateAction.logout) {
      print("Logout success");
    }
  } else {
    if (accountState.accountStateAction == AccountStateAction.login) {
      print("Login error - ${accountState.error}");
    } else
    if (accountState.accountStateAction == AccountStateAction.logout) {
      print("Logout error - ${accountState.error}");
    }
  }
});
```

{% endtab %}

{% tab title="React Native" %}

```jsx
useEffect(() => {
  checkIsLoggedIn();
  const subscriptionAccountStateRemover =
    NamiCustomerManager.registerAccountStateHandler(
      (action, success, error) => {
        console.log('accountState', action, success, error);
        if (action === 'login' && success) {
          setIsUserLogin(success);
          checkId();
        }
        if (action === 'logout' && success) {
          setIsUserLogin(!success);
          checkId();
        }
      },
    );
  return () => {
    subscriptionAccountStateRemover();
  };
}, []);
```

{% endtab %}

{% tab title="Unity" %}

```c
NamiCustomerManager.RegisterAccountStateHandler(accountStateCallback);
```

{% endtab %}
{% endtabs %}


# registerJourneyStateHandler

Register a callback that will be made any time there's a change to the Journey State for the user. Note that Nami fetches journey state at the start of each session and this is the most likely time to see a change.

{% tabs %}
{% tab title="Swift" %}

```swift
NamiCustomerManager.registerJourneyStateHandler { journeyState in
    print("customer journey state")
    print("former subscriber: \(journeyState.formerSubscriber)")
    print("in grace period: \(journeyState.inGracePeriod)")
    print("in trial period: \(journeyState.inTrialPeriod)")
    print("in intro offer period: \(journeyState.inIntroOfferPeriod)")
    print("has cancelled subscription: \(journeyState.isCancelled)")
    print("in account hold: \(journeyState.inAccountHold)")
    print("in pause (Google Play): \(journeyState.inPause)")
}
```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
NamiCustomerManager.registerJourneyStateHandler { journeyState ->
    Log.d(LOG_TAG, "Customer journey state:")
    Log.d(LOG_TAG, "formerSubscriber ==> ${journeyState.formerSubscriber}")
    Log.d(LOG_TAG, "inGracePeriod ==> ${journeyState.inGracePeriod}")
    Log.d(LOG_TAG, "inIntroOfferPeriod ==> ${journeyState.inIntroOfferPeriod}")
    Log.d(LOG_TAG, "inTrialPeriod ==> ${journeyState.inTrialPeriod}")
    Log.d(LOG_TAG, "isCancelled ==> ${journeyState.isCancelled}")
    Log.d(LOG_TAG, "inPause ==> ${journeyState.inPause}")
    Log.d(LOG_TAG, "inAccountHold ==> ${journeyState.inAccountHold}")
}
```

{% endtab %}

{% tab title="Flutter" %}

```dart
NamiCustomerManager.registerJourneyStateHandler().listen((journeyState) {
  print("Customer Journey State);
  print("formerSubscriber ==> ${journeyState.formerSubscriber}");
  print("inGracePeriod ==> ${journeyState.inGracePeriod}");
  print("inIntroOfferPeriod ==> ${journeyState.inIntroOfferPeriod}");
  print("inTrialPeriod ==> ${journeyState.inTrialPeriod}");
  print("isCancelled ==> ${journeyState.isCancelled}");
  print("inPause ==> ${journeyState.inPause}");
  print("inAccountHold ==> ${journeyState.inAccountHold}");
});
```

{% endtab %}

{% tab title="React Native" %}

```javascript
import {NamiCustomerManager, CustomerJourneyState} from 'react-native-nami-sdk';

const getJourneyState = useCallback(async () => {
  const myJourneyState = await NamiCustomerManager.journeyState();
  console.log('myJourneyState', myJourneyState);
  setJourneyState(myJourneyState);
}, []);

useEffect(() => {
  getJourneyState();
  const subscriptionJourneyStateRemover =
    NamiCustomerManager.registerJourneyStateHandler((newJourneyState) => {
      console.log('newJourneyState', newJourneyState);
      setJourneyState(newJourneyState);
    });

  return () => {
    subscriptionJourneyStateRemover();
  };
}, [getJourneyState]);
```

{% endtab %}

{% tab title="Unity" %}

```c
NamiCustomerManager.RegisterJourneyStateHandler(journeyStateCallback);
```

{% endtab %}
{% endtabs %}


# setCustomerAttribute

Set an attribute in an on-device key/value store for use for paywall personalization uses cases.

{% tabs %}
{% tab title="Swift" %}

```swift
NamiCustomerManager.setCustomerAttribute("firstName", "Taylor")
```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
NamiCustomerManager.setCustomerAttribute("firstName", "Taylor")
```

{% endtab %}

{% tab title="Flutter" %}

```dart
NamiCustomerManager.setCustomerAttribute({"firstName": "Taylor"});
```

{% endtab %}

{% tab title="React Native" %}

```jsx
NamiCustomerManager.setCustomerAttribute('firstName', 'Taylor');
```

{% endtab %}
{% endtabs %}


# getCustomerAttribute

Get the current stored value, if available, for the provided key in the on-device customer key/value store.

{% tabs %}
{% tab title="Swift" %}

```swift
let firstName = NamiCustomerManager.getCustomerAttribute("firstName")
```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
val firstName = NamiCustomerManager.getCustomerAttribute("firstName")
```

{% endtab %}

{% tab title="Flutter" %}

```dart
NamiCustomerManager.getCustomerAttribute("firstName");
```

{% endtab %}

{% tab title="React Native" %}

```javascript
const firstName = await NamiCustomerManager.getCustomerAttribute('firstName);
```

{% endtab %}
{% endtabs %}


# clearCustomerAttribute

Remove a key from the on-device customer key/value store.

{% tabs %}
{% tab title="Swift" %}

```swift
NamiCustomerManager.clearCustomerAttribute("firstName")
```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
NamiCustomerManager.clearCustomerAttribute("firstName")
```

{% endtab %}

{% tab title="Flutter" %}

```dart
NamiCustomerManager.clearCustomerAttribute("firstName");                                         
```

{% endtab %}

{% tab title="React Native" %}

```jsx
NamiCustomerManager.clearCustomerAttribute('firstName');
```

{% endtab %}
{% endtabs %}


# clearAllCustomerAttributes

Clear all customer attributes in the on-device key/value store.

{% tabs %}
{% tab title="Swift" %}

```swift
NamiCustomerManager.clearAllCustomerAttributes("firstName")
```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
NamiCustomerManager.clearAllCustomerAttributes("firstName")
```

{% endtab %}

{% tab title="Flutter" %}

```dart
NamiCustomerManager.clearAllCustomerAttributes();
```

{% endtab %}

{% tab title="React Native" %}

```jsx
NamiCustomerManager.clearAllCustomerAttributes();
```

{% endtab %}
{% endtabs %}


# active

Retrieve all active entitlements for a user on the current device.

{% tabs %}
{% tab title="Swift" %}

```swift
NamiEntitlementManager.active() -> [NamiEntitlement]
```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
NamiEntitlementManager.active(): List<NamiEntitlement>
```

{% endtab %}

{% tab title="Flutter" %}

```dart
NamiEntitlementManager.active();
```

{% endtab %}

{% tab title="React Native" %}

```jsx
import {NamiEntitlementManager, NamiEntitlement} from 'react-native-nami-sdk';

const allEntitlements = await NamiEntitlementManager.active();
```

{% endtab %}

{% tab title="Unity" %}

```Text
// returns all active entitlements for a user on the current device

var activeEntitlements = NamiEntitlementManager.Active();
```

{% endtab %}
{% endtabs %}

**Returns**

Array of [NamiEntitlement](/sdk-reference/namientitlementmanager/namientitlement) objects for all entitlements the current device has access to.


# isEntitlementActive

Check if a single entitlement is currently active.

{% tabs %}
{% tab title="Swift" %}

```swift
NamiEntitlementManager.isEntitlementActive(_ referenceId: String ) -> Bool
```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
NamiEntitlementManager.isEntitlementActive(referenceId: String): Boolean
```

{% endtab %}

{% tab title="Flutter" %}

```dart
static Future<bool> isEntitlementActive(String referenceId)
```

{% endtab %}

{% tab title="React Native" %}
{% code overflow="wrap" %}

```javascript
import {NamiEntitlementManager, NamiEntitlement} from 'react-native-nami-sdk';

const isEntitlementActive = await NamiEntitlementManager.isEntitlementActive(referenceId);
```

{% endcode %}
{% endtab %}

{% tab title="Unity" %}

```c
NamiEntitlementManager.IsEntitlementActive(referenceId);
```

{% endtab %}
{% endtabs %}

**Parameters**

* `referenceId` - a string that is the entitlement reference ID from the Control Center.

**Returns**

`true` if active, `false` otherwise.


# NamiEntitlement

Object that contains data about an entitlement on the Nami Platform.

{% tabs %}
{% tab title="Swift" %}

```swift
public class NamiEntitlement : NSObject, Codable {
  var activePurchases : NamiPurchase
  var desc : String
  var name : String
  var namiId : String
  var purchasedSkus : [NamiSKU] = []
  var referenceId : String
  var relatedSkus : [NamiSKU] = []
}
```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
class NamiEntitlement(
    val name: String?,
    val desc: String? = null,
    val namiId: String?,
    val referenceId: String,
    val relatedSKUs: List<NamiSKU> = listOf(),
    val purchasedSKUs: List<NamiSKU> = listOf(),
    val activePurchases: List<NamiPurchase> = listOf()
)
```

{% endtab %}

{% tab title="Flutter" %}

```dart
class NamiEntitlement {
  final String? name;
  final String? desc;
  final String? namiId;
  final String referenceId;
  final List<NamiSKU> relatedSKUs;
  final List<NamiSKU> purchasedSKUs;
  final List<NamiPurchase> activePurchases;
}
```

{% endtab %}

{% tab title="React Native" %}

```tsx
export type NamiEntitlement = {
  activePurchases: NamiPurchase[];
  desc: string;
  name: string;
  namiId: string;
  purchasedSkus: NamiSKU[];
  referenceId: string;
  relatedSkus: NamiSKU[];
};
```

{% endtab %}

{% tab title="Unity" %}

```c
public class NamiEntitlement
{
    public List<NamiPurchase> ActivePurchases { get; private set; }
    public string Desc { get; private set; }
    public string Name { get; private set; }
    public string NamiId { get; private set; }
    public List<NamiSKU> PurchasedSKUs { get; private set; }
    public string ReferenceId { get; private set; }
    public List<NamiSKU> RelatedSKUs { get; private set; }
}
```

{% endtab %}
{% endtabs %}

**Parameters**

* `activePurchases` - a `NamiPurchase` object corresponding to the purchase that granted the entitlement. Will contain any general metadata know by the SDK. If the purchase was made on the current device, will contain additional platform-specific data.
* `desc` - the description for the entitlement, set in the Control Center.
* `name` - the name of the entitlement, set in the Control Center.
* `namiId` - an internal id used by Nami for the entitlement
* `purchasedSkus` - a list of [NamiSKU](ref:namisku) objects for the purchased in-app products that granted the entitlement. May contain some general metadata about the in-app purchase product when available. If the entitlement was purchased on device, this object will contain data about the in-app purchase product.
* `referenceId` - the unique id used to reference the entitlement, set in the Control Center
* `relatedSkus` - a list of [NamiSKU](ref:namisku) objects. This is the list of all known in-app purchase products that can grant this entitlement. Set in the Control Center.


# refresh

Manually trigger a refresh of the user's latest active entitlements from the Nami services.

{% tabs %}
{% tab title="Swift" %}

```swift
NamiEntitlementManager.refresh()
```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
NamiEntitlementManager.refresh(refreshCallBack: (List<NamiEntitlement>?) -> Unit)
```

{% endtab %}

{% tab title="Flutter" %}

```dart
static Future<List<NamiEntitlement>> refresh() async
```

{% endtab %}

{% tab title="React Native" %}

<pre class="language-tsx"><code class="lang-tsx"><strong>import {NamiEntitlementManager, NamiEntitlement} from 'react-native-nami-sdk';
</strong>
NamiEntitlementManager.refresh((newEntitlements) => {
  console.log('newEntitlements', newEntitlements);
});
</code></pre>

{% endtab %}

{% tab title="Unity" %}

```c
NamiEntitlementManager.Refresh(RefreshCallback);

void RefreshCallback(List<NamiEntitlement> entitlements)
{
    // on refresh
}
```

{% endtab %}
{% endtabs %}


# registerActiveEntitlementsHandler

Register a callback to react to a potential changes to the active entitlements for the user, whenever such state is fetched from the Nami service. This occurs during the course of the application lifecycle as well as when [refresh](/sdk-reference/namientitlementmanager/refresh) is called.

{% tabs %}
{% tab title="Swift" %}

```swift
NamiEntitlementManager.registerActiveEntitlementsHandler { (activeEntitlements: [NamiEntitlement]) in
  // respond to the current active entitlements for the user
}
```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
NamiEntitlementManager.registerActiveEntitlementsHandler { activeEntitlements ->
  // respond to the current active entitlements for the user
}
```

{% endtab %}

{% tab title="Flutter" %}

```dart
NamiEntitlementManager.registerActiveEntitlementsHandler()
    .listen((activeEntitlementHandlerData) {
});
```

{% endtab %}

{% tab title="React Native" %}

```jsx
import {NamiEntitlementManager, NamiEntitlement} from 'react-native-nami-sdk';

const subscriptionRemover =
  NamiEntitlementManager.registerActiveEntitlementsHandler(
    (activeEntitlements) => {
      console.log('activeEntitlements', activeEntitlements);
      setEntitlements(activeEntitlements);
    },
  );
return () => {
  subscriptionRemover();
};
```

{% endtab %}

{% tab title="Unity" %}

```c
NamiEntitlementManager.RegisterActiveEntitlementsHandler(activeEntitlementsCallback);
```

{% endtab %}
{% endtabs %}

**Returns**

* `activeEntitlements` - a list of the current entitlements active for the user and device.


# dismiss

Close a paywall if it is open

Use to close a Nami paywall programmatically if desired.

{% tabs %}
{% tab title="Swift" %}

```swift
NamiPaywallManager.dismiss(animated: Bool, completion: (Void)->Void)
```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
```

{% endtab %}

{% tab title="Flutter" %}

```Text
// coming soon
```

{% endtab %}

{% tab title="React Native" %}

```c
// coming soon
```

{% endtab %}

{% tab title="Unity" %}

```c
NamiPaywallManager.Dismiss();
```

{% endtab %}
{% endtabs %}

**Parameters**

* `animated`: Will animate the closing of the paywall if true.
* `completion`: Code to execute after paywall closure is fully complete.


# displayedViewController

{% hint style="info" %}
Apple-only method.
{% endhint %}

```swift
NamiPaywallManager.displayedViewController()
```

Returns the last raised Nami Paywall view controller. Will be `.none` if the paywall is closed.

### Handling VC Alerts

```swift
NamiPurchaseManager.registerRestorePurchasesHandler { state, newPurchases, oldPurchases, error in
            let presentAlertFromVC = NamiPaywallManager.displayedViewController()
                    
            switch state {
                case .started:
                    print("starting restoring purchases")
            case .finished:
                // additionally may want to check that there are more items in
                // newPurchases than oldPurchases
                if oldPurchases != newPurchases {
                    print("Found restored purchases")
                    presentAlertFromVC?.dismiss(animated: false)
                } else {
                    let alert = UIAlertController(title: "Restore Purchase", message: "No previous purchases to restore", preferredStyle: UIAlertController.Style.alert)
                    alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
                    presentAlertFromVC!.present(alert, animated: true, completion: nil)
                }
            case .error:
                print("error restoring purchases")
            default:
                print("unknown case")
            }
        }
```


# registerSignInHandler

Register a sign-in provider to handle your own sign-in logic

{% tabs %}
{% tab title="Swift" %}

```swift
NamiPaywallManager.registerSignInHandler { fromPaywallVC in
  // Add code to handle sign-in logic
}
```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
NamiPaywallManager.registerSignInHandler { context ->
  // Add code to handle sign-in logic
}
```

{% endtab %}

{% tab title="Flutter" %}

```c
// coming soon
```

{% endtab %}

{% tab title="React Native" %}

```jsx
useEffect(() => {
  const subscriptionSignInRemover =
  NamiPaywallManager.registerSignInHandler(() => {
    console.log('sign in');
  });
  return () => {
    subscriptionSignInRemover();
  };
```

{% endtab %}

{% tab title="Unity" %}

```c
NamiPaywallManager.RegisterSignInHandler(signInCallback);
```

{% endtab %}
{% endtabs %}

**Callback**

* (Apple-native only) `fromPaywallVC` : The paywall view controller from which the sign-in control was tapped by the user
* (Android-native only) `context` : The paywall context from which the sign-in control was tapped by the user


# registerCloseHandler

If this registered, paywall `close` buttons will call back to this handler for your own custom business logic instead of using the system default, which is to just dismiss the paywall.

{% tabs %}
{% tab title="Swift" %}

```swift
NamiPaywallManager.registerCloseHandler { paywall in
    if let paywallVC = paywall {
        paywallVC.dismiss(animated: true)
    }
}
```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
NamiPaywallManager.registerCloseHandler { paywall ->
	Log.d(LOG_TAG, "Paywall Close requested - implement custom logic here")
	paywall.finish()
}
```

{% endtab %}

{% tab title="Flutter" %}

```c
// coming soon
```

{% endtab %}

{% tab title="React Native" %}

```c
// coming soon
```

{% endtab %}

{% tab title="Unity" %}

```c
NamiPaywallManager.RegisterCloseHandler(CloseCallback);

void CloseCallback()
{
    // code, e.g.
    NamiPaywallManager.Dismiss();
}
```

{% endtab %}
{% endtabs %}


# registerBuySkuHandler

{% hint style="info" %}
**For Paywalls-only plans**

This method is for customers who have implemented their own in-app purchases or subscription code directly with the App Store, Google Play, etc. or who are using another third-party for subscription or purchase management.

Your Nami account needs to be on a Paywalls-only plan to use this interface. Contact <support@nami.ml> for details.
{% endhint %}

{% tabs %}
{% tab title="Swift" %}

```swift
NamiPaywallManager.registerBuySkuHandler { sku in
    print("Start the purchase flow for App Store product: \(sku.storeId)")
}
```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
NamiPaywallManager.registerBuySkuHandler { paywall, sku ->
    Log.d(LOG_TAG, "Start the purchase flow for Google Play/Amazon Appstore product: $skuRefId")
}
```

{% endtab %}

{% tab title="Flutter" %}

```
// Coming soon
```

{% endtab %}

{% tab title="React Native" %}

```jsx
NamiPaywallManager.registerBuySkuHandler((sku) => {
    // Start your purchase flow   
    console.log(
      'buy sku handler - start purchase flow for sku:',
      sku.skuId,
    );
}
```

{% endtab %}

{% tab title="Unity" %}

```c
NamiPaywallManager.RegisterBuySkuHandler(buySkuCallback);
```

{% endtab %}
{% endtabs %}

Registering with `NamiPaywallManager.registerBuySkuHandler` will provide a callback from a Nami paywall when the user has selected a sku and asked for the purchase flow to start.

It is you're responsible to listen to this handler's callback to start the purchase with the provided sku.

Once the purchase is successful, indicate it is complete by calling [buySkuComplete](/sdk-reference/namipaywallmanager/buyskucomplete) to close the paywall.


# registerDeeplinkActionHandler

Register a handler that calls back with a  when a paywall's Deeplink Button is invoked

{% tabs %}
{% tab title="Swift" %}

```swift
 NamiPaywallManager.registerDeeplinkActionHandler { destination in
      // Calls back with a string value as configured in the Paywall Creator
  }
```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
NamiPaywallManager.registerDeepLinkHandler { paywallActivity, destination ->
      // Calls back with destination value for Deeplink Button configured 
      // in the Paywall Creator
}
```

{% endtab %}

{% tab title="React Native" %}

```typescript
import {NamiPaywallManager} from 'react-native-nami-sdk';

const subscriptionDeeplinkRemover =
   NamiPaywallManager.registerDeeplinkActionHandler((destination) => {
     console.log('deeplink action ', destination);
   });
```

{% endtab %}

{% tab title="Roku" %}

```brightscript
' This is a condensed example. 
' See the full example in the Demo app:
'   https://github.com/namiml/nami-roku/blob/main/Demo/components/NamiDataSource.brs
'   https://github.com/namiml/nami-roku/blob/main/Demo/components/NamiDataSource.xml
sub init()
    setupLocals()
    initializeNamiSDKValues()
end sub

sub setupLocals()
    m.scene = m.top.getScene()
    m.namiPaywallManager = m.namiManager.namiPaywallManager
end sub

sub initializeNamiSDKValues()
    m.namiPaywallManager.callFunc("registerDeeplinkActionHandler", m.top)
end sub

function deeplinkActionHandlerCallback(url)
    ' deeplink url open process
    print "NamiDataSource : deeplinkActionHandlerCallback : deeplink url : " url
end function

```

{% endtab %}
{% endtabs %}


# buySkuComplete

{% hint style="info" %}
**For Paywalls-0nly Plans**

This method is for customers who have implemented their own in-app purchases or subscription code directly with the App Store, Google Play, etc. or who are using another third-party for subscription or purchase management.

Your Nami account needs to be on a Paywalls only plan to use this interface. Contact <support@nami.ml> for details.
{% endhint %}

{% tabs %}
{% tab title="Swift" %}

```swift
// StoreKit 2 Product & Transaction objects
NamiPaywallManager.buySkuComplete(sku: NamiSKU, product: Product, transaction: Transaction) 
                                  
// StoreKit 1 SKProduct & SKPaymentTransaction objects
NamiPaywallManager.buySkuComplete(sku: NamiSKU, product: SKProduct, transaction: SKPaymentTransaction)

// or pass in the individual data elements used by Nami, wrapped in a `NamiPurchaseSuccess` object
let purchaseSuccess = NamiPurchaseSuccess(product: sku, transactionID: transactionId, originalTransactionID: originalTransactionId, originalPurchaseDate: originalPurchaseDate, purchaseDate: purchaseDate, expiresDate: expirationDate, price: price, currencyCode: currency, locale: locale)
NamiPaywallManager.buySkuComplete(purchaseSuccess: purchaseSuccess)
```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
// paywall, and skuRefId were passed to you via NamiPurchaseManager.registerBuySkuHandler
// purchase is the purchase object from Google Play Billing
NamiPaywallManager.buySkuComplete(paywallActivity, purchase, sku)
  
  
// or provided a NamiPurchaseSuccess.Google or NamiPurchaseSuccess.Amazon object  
NamiPaywallManager.buySkuComplete(paywallActivity, purchaseSuccess)
```

{% endtab %}

{% tab title="Flutter" %}

```
// Coming Soon
```

{% endtab %}

{% tab title="React Native" %}

```jsx
// Once purchase flow is complete:    
if (Platform.OS === 'ios' || Platform.isTVOS) {
  NamiPaywallManager.buySkuCompleteApple({
    product: sku,
    transactionID: '12345',
    originalTransactionID: '12345',
    originalPurchaseDate: 1684823428,
    purchaseDate: 1684823428,
    price: '120',
    currencyCode: 'USD',
    locale: 'US',
  });
} else if (Platform.OS === 'android') {
  if (Platform.constants.Manufacturer === 'Amazon') {
    NamiPaywallManager.buySkuCompleteAmazon({
      product: sku,
      purchaseDate: 1684823428,
      purchaseSource: 'CAMPAIGN',
      receiptId: '12345',
      localizedPrice: '120',
      userId: '12345',
      marketplace: '12345',
    });
  } else {
    NamiPaywallManager.buySkuCompleteGooglePlay({
      product: sku,
      purchaseDate: 1684823428,
      purchaseSource: 'CAMPAIGN',
      purchaseToken:
        'jolbnkpmojnpnjecgmphbmkc.AO-J1OznE4AIzyUvKFe1RSVkxw4KEtv0WfyL_tkzozOqnlSvIPsyQJBphCN80gwIMaex4EMII95rFCZhMCbVPZDc-y_VVhQU5Ddua1dLn8zV7ms_tdwoDmE',
      orderId: 'GPA.3317-0284-9993-42221',
    });
  }
}
```

{% endtab %}

{% tab title="Unity" %}

```
// Coming soon
```

{% endtab %}
{% endtabs %}

Once your billing implementation has successfully processed a user's purchase, let the Nami SDK know by calling `NamiPaywallManager.buySkuComplete`. Once invoked, the paywall view will be closed.

To known when to start the purchase process, see [registerBuySkuHandler](/sdk-reference/namipaywallmanager/registerbuyskuhandler).


# NamiPurchaseSuccess

{% hint style="info" %}
**For Paywalls-0nly Plans**

This method is for customers who have implemented their own in-app purchases or subscription code directly with the App Store, Google Play, etc. or who are using another third-party for subscription or purchase management.

Your Nami account needs to be on a Paywalls only plan to use this interface. Contact <support@nami.ml> for details.
{% endhint %}

{% tabs %}
{% tab title="Swift" %}

```c
@objc public class NamiPurchaseSuccess: NSObject, Codable {
    let product: NamiSKU
    let transactionID: String
    let originalTransactionID: String
    let originalPurchaseDate: Date
    let expiresDate: Date?
    let purchaseDate: Date
    let price: Decimal
    let currencyCode: String
    let locale: Locale
    let purchaseSource: NamiPurchaseSource
}
```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
sealed class NamiPurchaseSuccess(
    open val product: NamiSKU,
    open val expiresDate: Date?,
    open val purchaseDate: Date,
    open val purchaseSource: NamiPurchaseSource,
    open val description: String?
) {
    data class GooglePlay(
        override val product: NamiSKU,
        override val expiresDate: Date?,
        override val purchaseDate: Date,
        override val purchaseSource: NamiPurchaseSource,
        override val description: String?,
        val orderId: String,
        val purchaseToken: String,
    ) : NamiPurchaseSuccess(product, expiresDate, purchaseDate, purchaseSource, description)

    data class Amazon(
        override val product: NamiSKU,
        override val expiresDate: Date?,
        override val purchaseDate: Date,
        override val purchaseSource: NamiPurchaseSource,
        override val description: String?,
        val receiptId: String,
        val localizedPrice: String,
        val userId: String,
        val marketplace: String
    ) : NamiPurchaseSuccess(product, expiresDate, purchaseDate, purchaseSource, description)
}
```

{% endtab %}

{% tab title="Flutter" %}

```c
// coming soon
```

{% endtab %}

{% tab title="React Native" %}

```jsx
export type PurchaseSuccessIos = {
  product: PurchaseSuccessProduct;
  transactionID: string;
  originalTransactionID: string;
  originalPurchaseDate: number;
  purchaseDate: number;
  expiresDate?: number;
  price: string;
  currencyCode: string;
  locale: string;
};

export type PurchaseSuccessGooglePlay = {
  product: PurchaseSuccessProduct;
  orderId: string;
  purchaseDate: number;
  expiresDate?: number;
  purchaseToken: string;
  purchaseSource: "CAMPAIGN" | "MARKETPLACE" | "UNKNOWN";
};

export type PurchaseSuccessAmazon = {
  product: PurchaseSuccessProduct;
  purchaseDate: number;
  expiresDate?: number;
  purchaseSource: "CAMPAIGN" | "MARKETPLACE" | "UNKNOWN";
  receiptId: string;
  localizedPrice: string;
  userId: string;
  marketplace: string;
};
```

{% endtab %}

{% tab title="Unity" %}

```c
// coming soon
```

{% endtab %}
{% endtabs %}


# NamiPaywallAction

{% tabs %}
{% tab title="Swift" %}

```swift
@objc public enum NamiPaywallAction : Int {
    case close_paywall = 0
    case restore_purchases = 1
    case sign_in = 2
    case buy_sku = 3
    case select_sku = 4
    case purchase_selected_sku = 5
    case purchase_success = 6
    case purchase_deferred = 7
    case purchase_failed = 8
    case purchase_cancelled = 9
    case purchase_unknown = 10
}
```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
enum class NamiPaywallAction {
    NAMI_CLOSE_PAYWALL,
    NAMI_RESTORE_PURCHASES,
    NAMI_SIGN_IN,
    NAMI_BUY_SKU,
    NAMI_SELECT_SKU,
    NAMI_PURCHASE_SELECTED_SKU,
    NAMI_PURCHASE_SUCCESS,
    NAMI_PURCHASE_CANCELLED,
    NAMI_PURCHASE_FAILED,
    NAMI_PURCHASE_PENDING,
    NAMI_PURCHASE_UNKNOWN
}
```

{% endtab %}

{% tab title="Flutter" %}

```c
// coming soon
```

{% endtab %}

{% tab title="React Native" %}

```javascript
export enum NamiPaywallAction {
  BUY_SKU = "BUY_SKU",
  SELECT_SKU = "SELECT_SKU",
  RESTORE_PURCHASES = "RESTORE_PURCHASES",
  SIGN_IN = "SIGN_IN",
  CLOSE_PAYWALL = "CLOSE_PAYWALL",
  SHOW_PAYWALL = "SHOW_PAYWALL",
  PURCHASE_SELECTED_SKU = "PURCHASE_SELECTED_SKU",
  PURCHASE_SUCCESS = "PURCHASE_SUCCESS",
  PURCHASE_FAILED = "PURCHASE_FAILED",
  PURCHASE_CANCELLED = "PURCHASE_CANCELLED",
  PURCHASE_PENDING = "PURCHASE_PENDING",
  PURCHASE_UNKNOWN = "PURCHASE_UNKNOWN",
  PURCHASE_DEFERRED = "PURCHASE_DEFERRED",
  SHOW_PAYWALL = "SHOW_PAYWALL",
}
```

{% endtab %}

{% tab title="Unity" %}

```c
public enum NamiPaywallAction
{
    ClosePaywall,
    RestorePurchases,
    SignIn,
    BuySku,
    SelectSku,
#if UNITY_IOS
    PurchaseSelectedSku,
    PurchaseSuccess,
    PurchaseDeferred,
    PurchaseFailed,
    PurchaseCancelled,
    PurchaseUnknown
#endif
}
```

{% endtab %}
{% endtabs %}

**Show Paywall** - the paywall is shown to the user

**Close Paywall**- the paywall is closed through the close control (if available), or by using the operating system to dismiss the view. For instance, through a hardware back button on Android or swiping the modal view away on iOS

**Restore Purchases** - the users invokes the paywall's restore purchases control

**Sign In** - the users invokes the paywall's sign in control for handling by the app developer

**Buy Sku** - the users starts the purchase flow by choosing a sku. For paywalls where product sku is a button that initiates the purchase flow.

**Select Sku** - the users selects a sku. For paywalls where the product skus are decoupled from the call to action button that initiates the purchase flow.

**Purchase Selected Sku** - the users starts the purchase flow from the selected sku. For paywalls where the product skus are decoupled from the call to action button that initiates the purchase flow.

**Purchase Success** - the purchase was successful. The paywall will be automatically closed. See `purchases` included on `paywallActionHandler` from `NamiCampaignManager.launch`

**Purchase Failed** - the purchase failed. See `purchaseError` included on `paywallActionHandler` from `NamiCampaignManager.launch`

**Purchase Cancelled** - the purchase flow was cancelled by the end user.

**Purchase Unknown** - an unknown purchase flow event was encountered

**Purchase Deferred** (Apple only) - the purchase was deferred.

**Purchase Pending** (Android only) - the purchase is pending.


# NamiSKUType

Enum defining types of SKUs

{% tabs %}
{% tab title="Swift" %}

```swift
@objc public enum NamiSKUType: Int, Codable {
  case unknown = 0
  case one_time_purchase
  case subscription
}
```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
@JsonClass(generateAdapter = false)
enum class NamiSKUType {
  @Json(name = "one_time_purchase")
  ONE_TIME_PURCHASE,

  @Json(name = "subscription")
  SUBSCRIPTION,

  @Json(name = "unknown")
  UNKNOWN
}
```

{% endtab %}

{% tab title="Flutter" %}

```dart
enum NamiPlatformType { one_time_purchase, subscription, unknown }
```

{% endtab %}

{% tab title="React Native" %}

```javascript
const NamiSKUType = {
  "one_time_purchase": "one_time_purchase",
  "subscription": "subscription",
  "unknown": "unknown"
}
```

{% endtab %}

{% tab title="Unity" %}

```c
public enum NamiSKUType
{
  Unknown,
  OneTimePurchase,
  Subscription
}
```

{% endtab %}
{% endtabs %}


# anySkuPurchased

Check if any of the passed in product SKU IDs have been purchased by the device.

{% tabs %}
{% tab title="Swift" %}

```swift
NamiPurchaseManager.anySkuPurchased(_ skuIds: [StoreID]) -> Bool
```

{% endtab %}

{% tab title="Kotlin" %}

```c
// coming soon
```

{% endtab %}

{% tab title="Flutter" %}

```Text
// coming soon
```

{% endtab %}

{% tab title="React Native" %}

```Text
// coming soon
```

{% endtab %}

{% tab title="Unity" %}

```Text
// coming soon
```

{% endtab %}
{% endtabs %}

**Arguments**

* (required) `skuIds`: An array of product SKU IDs to check for purchase status

**Returns**\
Boolean true if any of the product SKUs in the list have been purchased, or false otherwise.


# consumePurchasedSku

Mark a consumable IAP as processed so it can be purchased again.

{% tabs %}
{% tab title="Swift" %}

```swift
NamiPurchaseManager.consumePurchasedSku(skuId: StoreID)
```

{% endtab %}

{% tab title="Kotlin" %}

```Text
// coming soon
```

{% endtab %}

{% tab title="Flutter" %}

```Text
// coming soon
```

{% endtab %}

{% tab title="React Native" %}

```Text
// coming soon
```

{% endtab %}

{% tab title="Unity" %}

```Text
// coming soon
```

{% endtab %}
{% endtabs %}

**Parameters**

* `skuId` - the ID of the SKU to be consumed, can be a string, set in the Control Center.


# NamiPurchase

Object representing a purchase in the Nami Platform.

{% tabs %}
{% tab title="Swift" %}

```swift
public class NamiPurchase : NSObject, Codable {
    public var sku : NamiSKU,
    public var expires : Date?
    public var entitlementsGranted: [NamiEntitlement]
    public var transactionIdentifier : String?
    public var transaction : SKPaymentTransaction?
    public let skuId : StoreID
    public var purchaseInitiatedTimestamp: Date
}
```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
data class NamiPurchase( 
    val purchaseInitiatedTimestamp: Long = Date().time,
    val expires: Date? = null,
    val purchaseSource: NamiPurchaseSource,
    val skuId: String,
    val transactionIdentifier: String?,
    val purchaseToken: String?
 )
```

{% endtab %}

{% tab title="Flutter" %}

```dart
class NamiPurchase {
  final int purchaseInitiatedTimestamp;
  final DateTime? expires;
  final NamiPurchaseSource purchaseSource;
  final String skuId;
  final String? transactionIdentifier;
  final String? localizedDescription;
}
```

{% endtab %}

{% tab title="React Native" %}

```javascript
export type NamiPurchase = {
  sku?: NamiSKU;
  skuId: string;
  transactionIdentifier?: string;
  expires?: Date;
  purchaseInitiatedTimestamp: Date;
  purchaseSource?: "CAMPAIGN" | "MARKETPLACE" | "UNKNOWN";
};
```

{% endtab %}

{% tab title="Unity" %}

```c
public class NamiPurchase
{
    public long PurchaseInitiatedTimestamp { get; private set; }

    public DateTime Expires { get; private set; }

    /// <summary> Android platforms only </summary>
    public NamiPurchaseSource PurchaseSource { get; private set; }

    public string SkuId { get; private set; }

    public string TransactionIdentifier { get; private set; }

    /// <summary> Android platforms only </summary>
    public string PurchaseToken { get; private set; }

    /// <summary> Apple platforms only </summary>
    public NamiSKU Sku { get; private set; }

    /// <summary> Apple platforms only </summary>
    public List<NamiEntitlement> EntitlementsGranted { get; private set; }

    /// <summary> Apple platforms only </summary>
    public string Transaction { get; private set; }
}
```

{% endtab %}
{% endtabs %}

**Parameters**

Each App Platform provides data in NamiPurchase based upon what is available in the underlying store APIs.

**App Store**

* `sku` - a [NamiSKU](/sdk-reference/namipurchasemanager/namisku) object representing the in-app purchase product SKU the device purchased.
* `expires` - date the purchase expires if it is a subscription
* `entitlementGranted` - a [NamiEntitlement](/sdk-reference/namientitlementmanager/namientitlement) object for the entitlement granted by this purchase.
* `transactionIdentifier` - App Store ID for the transaction
* `transaction` - the StoreKit transaction object for the purchase
* `skuId` - the App Store reference ID of the purchased product SKU
* `purchaseInitiatedTimestamp` - The date and time when the purchase was initiated

**Google Play**

* `purchaseInitiatedTimestamp` - The date and time when the purchase was initiated
* `expires` - (bypass store only) Indicates when this purchase will cease
* `skuId` - the Google Play reference ID of the purchased product SKU
* `transactionIdentifier` - The purchase order ID record associated to this purchase
* `purchaseToken` - The purchase token associated to this purchase


# NamiPurchaseState

The different states a purchase can be in. Different platforms and frameworks may have different sets of states that they support.

{% tabs %}
{% tab title="Swift" %}

```swift
@objc public enum NamiPurchaseState: Int {
    case pending
    case purchased
    case consumed
    case resubscribed
    case unsubscribed
    case deferred
    case failed
    case cancelled
    case unknown
}
```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
enum class NamiPurchaseState {
    PURCHASED,
    FAILED,
    CANCELLED,
    PENDING,
    UNKNOWN
}
```

{% endtab %}

{% tab title="Flutter" %}

```dart
enum NamiPurchaseState {
  purchased,
  failed,
  cancelled,
  pending,
  unknown,
  deferred,
  resubscribed,
  unsubscribed,
  consumed
}
```

{% endtab %}

{% tab title="React Native" %}

```jsx
export enum NamiPurchaseState {
  PENDING = "pending",
  PURCHASED = "purchased",
  CONSUMED = "consumed",
  RESUBSCRIBED = "resubscribed",
  UNSUBSCRIBED = "unsubscribed",
  DEFERRED = "deferred",
  FAILED = "failed",
  CANCELLED = "cancelled",
  UNKNOWN = "unknown",
}
```

{% endtab %}

{% tab title="Unity" %}

```c
public enum NamiPurchaseState
{
    Pending,
    Purchased,
    Consumed,
    Resubscribed,
    Unsubscribed,
    Deferred,
    Failed,
    Cancelled,
    Unknown
}
```

{% endtab %}
{% endtabs %}


# NamiRestorePurchasesState

{% hint style="info" %}
**Apple SDK only**

This method is only available from the Nami SDK for Apple devices.
{% endhint %}

This object is specific to the Nami Apple SDK and Apple's process for restoring purchases. Each state is one that can be reacted to with .

{% tabs %}
{% tab title="Swift" %}

```swift
@objc public enum NamiRestorePurchasesState: Int {
  case started
  case finished
  case error
}
```

{% endtab %}

{% tab title="Flutter" %}

```Text
// Coming soon
```

{% endtab %}

{% tab title="React Native" %}

```Text
// Coming soon
```

{% endtab %}

{% tab title="Unity" %}

```
// Coming soon
```

{% endtab %}
{% endtabs %}


# NamiSKU

Object that contains all the data on a in-app purchase SKU for an App Platform.

{% tabs %}
{% tab title="Swift" %}

```swift
public class NamiSKU: NSObject, Codable {
    public var name : String
    public var skuId : String
    public var product : SKProduct?
    public var type : NamiSKUType
}
```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
data class NamiSKU internal constructor(
    val name: String,
    val skuId: String,
    val skuDetails: SkuDetails,
    val type: NamiSKUType,
)
```

{% endtab %}

{% tab title="Flutter" %}

```dart
class NamiSKU {
  final String? name;
  final String skuId;
  final NamiSKUType type;
}
```

{% endtab %}

{% tab title="React Native" %}

```jsx
export type NamiSKU = {
  name: string;
  skuId: string;
  product?: SKProduct;
  type: NamiSKUType;
};
```

{% endtab %}

{% tab title="Unity" %}

```c
public class NamiSKU
{
    public string Name { get; private set; }

    public string SkuId { get; private set; }

    /// <summary> GooglePlay only </summary>
    public string SkuDetails { get; private set; }

    /// <summary> Apple only </summary>
    public string Product { get; private set; }

    public NamiSKUType Type { get; private set; }
}
```

{% endtab %}
{% endtabs %}

**Parameters**

* `name` - The name of the product as set in the Nami Control Center
* `skuId` - The in-app purchase or subscription reference ID from the App Store or Google Play
* `product` - (Apple-only) additional product info from Apple StoreKit
* `skuDetails` - (Google Play-only) additional product info from Google Play Billing
* `type` - indicates subscription or one time purchase


# presentCodeRedemptionSheet

{% hint style="info" %}
**Apple Only**

This only works on Apple, for apps running iOS 14+
{% endhint %}

{% tabs %}
{% tab title="Swift" %}

```swift
NamiPurchaseManager.presentCodeRedemptionSheet()
```

{% endtab %}

{% tab title="Flutter" %}

```dart
// Coming soon
```

{% endtab %}

{% tab title="React Native" %}

```Text
// Coming soon
```

{% endtab %}

{% tab title="Unity" %}

```Text
NamiPurchaseManager.PresentCodeRedemptionSheet();
```

{% endtab %}
{% endtabs %}


# registerPurchasesChangedHandler

Register a callback that will be made anytime there is a change to purchases made on the device. This will be triggered when a purchase process is started and may have different states based on the particular store platform.

{% tabs %}
{% tab title="Swift" %}

```swift
NamiPurchaseManager.registerPurchasesChangedHandler { (purchases, purchaseState, error) in
	// process purchases data
}
```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
NamiPurchaseManager.registerPurchasesChangedHandler { purchases, purchaseState, error ->
  // process purchases change
}
```

{% endtab %}

{% tab title="Flutter" %}

```dart
NamiPurchaseManager.registerPurchasesChangedHandler()
    .listen((purchasesResponseHandlerData) {
    // process purchases change
});
```

{% endtab %}

{% tab title="React Native" %}

```Text
// Coming soon
```

{% endtab %}

{% tab title="Unity" %}

```c
NamiPurchaseManager.RegisterPurchasesChangedHandler(purchasesChangedCallback);
```

{% endtab %}
{% endtabs %}

**Returns**

* `purchases` - a list of the current purchases
* `purchaseState` - the state of the purchase, see [NamiPurchaseState](/sdk-reference/namipurchasemanager/namipurchasestate) for all options
* `error` - information about an error if one occurred, generated by the store platform making the purchase


# registerRestorePurchasesHandler

{% hint style="info" %}
**Apple Only**

This method is only available from the Nami SDK for Apple devices, or cross-platform SDKs being used on Apple devices.
{% endhint %}

For recommendations on where to present UI elements to your customers during a restore purchases process, see our [Restoring Purchases](doc:restoring-purchases) guide.

{% tabs %}
{% tab title="Swift" %}

```swift
NamiPurchaseManager.registerRestorePurchasesHandler { state, newPurchases, oldPurchases, error in
  // react to restore purchase process
}
```

{% endtab %}

{% tab title="Flutter" %}

```Text
// Coming soon
```

{% endtab %}

{% tab title="React Native" %}

```Text
// Coming soon
```

{% endtab %}

{% tab title="Unity" %}

```Text
NamiPurchaseManager.RegisterRestorePurchasesHandler(restorePurchasesCallback); // Apple only
```

{% endtab %}
{% endtabs %}

**Parameters**

Handler has the following parameters that return data:

* `state` - the [NamiRestorePurchasesState](/sdk-reference/namipurchasemanager/namirestorepurchasesstate), on React Native `stateDesc`
* `newPurchases` - a list of new purchases found that will be restored in the Restore Purchases process
* `oldPurchases` - a list of existing purchases already active on the device
* `error` - any error returned by the Restore Purchases process


# restorePurchases

Start the process to restore any purchases not currently active on the device.

{% hint style="info" %}
**Apple SDK only**

This method is only available from the Nami SDK for Apple devices, or cross-platform SDKs being used on Apple devices.
{% endhint %}

Restore replays all prior purchase transactions to determine which purchases are active. This function trigger an app store password prompt if called, so only call this at the request of the user.

Generally this is not needed if your Nami account supports purchase validation, as the receipt is checked every time the app comes to the foreground and can determine active purchases that way.

Learn more in our guide on [Restoring Purchases](doc:restoring-purchases) .

Activate the system restore purchases feature. Optionally calls back to a global `NamiRestorePurchasesStateHandler` handler with restore state if one is provided by\
`registerRestorePurchasesHandler`.

{% tabs %}
{% tab title="Swift" %}

```swift
NamiPurchaseManager.restorePurchases()
```

{% endtab %}

{% tab title="Flutter" %}

```Text
// Coming soon
```

{% endtab %}

{% tab title="React Native" %}

```Text
// Coming soon
```

{% endtab %}

{% tab title="Unity" %}

```Text
NamiPurchaseManager.RestorePurchases(); // Apple only
```

{% endtab %}
{% endtabs %}

Activate the system restore purchases feature and call back to the provided completion handler:

{% tabs %}
{% tab title="Swift" %}

```swift
NamiPurchaseManager.restorePurchases() { state, newPurchases, oldPurchases, error in
  // react to restore purchase process
}
```

{% endtab %}

{% tab title="Flutter" %}

```c
// coming soon
```

{% endtab %}

{% tab title="React Native" %}

```Text
// coming soon
```

{% endtab %}

{% tab title="Unity" %}

```c
NamiPurchaseManager.RestorePurchases(restorePurchasesCallback); // Apple only
```

{% endtab %}
{% endtabs %}

**Parameters**

* `state` - of the Restore purchase process
* `newPurchases` - array of all purchases that are active after restore purchase process ran
* `oldPurchases` - array of purchases that were active before the restore purchase process started
* `error` - error returned by the restore purchase process


# skuPurchased

Check if a specific product SKU has been purchased.

{% tabs %}
{% tab title="Swift" %}

```swift
public static func skuPurchased(_ skuId: StoreId) -> Bool
```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
fun isSKUIDPurchased(skuID: String): Boolean
```

{% endtab %}

{% tab title="Flutter" %}

```dart
static Future<bool> skuPurchased(String skuID)
```

{% endtab %}

{% tab title="React Native" %}

```Text
// coming soon
```

{% endtab %}

{% tab title="Unity" %}

```c
// coming soon
```

{% endtab %}
{% endtabs %}

**Parameters**

* `skuId` The id of a product SKU from the Control Center.

**Returns**\
True if the the `skuId` has been purchased, false otherwise.


# coreAction

Inform the SDK about an important action a user may take in your app.

{% tabs %}
{% tab title="Swift" %}

```swift
NamiMLManager.coreAction(label: "Shared Item")
```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
NamiMLManager.coreAction(label: String)
```

{% endtab %}

{% tab title="Flutter" %}

```dart
NamiMLManager.coreAction(String label);
```

{% endtab %}

{% tab title="React Native" %}

```javascript
NativeModules.NamiMLManagerBridge.coreActionWithLabel("Shared Item");
```

{% endtab %}
{% endtabs %}

**Arguments**

* (required) `label`: a string label used to identify the core user action

Used to indicate when a user performed an action in your app that is important in creating customer loyalty and engagement. These may include actions like liking or sharing, for example.


# enterCoreContent

Inform the SDK when a user starts consuming content that is core to your app experience

{% tabs %}
{% tab title="Swift" %}

```swift
NamiMLManager.enterCoreContent(label: String)
```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
NamiMLManager.enterCoreContent(label: String)
```

{% endtab %}

{% tab title="Flutter" %}

```cplusplus
// Use version that takes List<String> (see below)
```

{% endtab %}

{% tab title="React Native" %}

```javascript
NativeModules.NamiMLManagerBridge.enterCoreContentWithLabel(label: String);
```

{% endtab %}
{% endtabs %}

**Arguments**

* (required) `label`: String that describes the content being consumed. The same string must be used in both [enterCoreContent](/sdk-reference/namimlmanager/entercorecontent) and [exitCoreContent](/sdk-reference/namimlmanager/exitcorecontent) calls.

### Content with Hierarchies

If your content has a nested relationship between the tags, we provide a call that will allow you to inform Nami about that structure.

{% tabs %}
{% tab title="Swift" %}

```swift
NamiMLManager.enterCoreContent(labels: [String])
```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
NamiMLManager.enterCoreContent(labels: List<String>)
```

{% endtab %}

{% tab title="Flutter" %}

```dart
NamiMLManager.enterCoreContent(List<String> labels);
```

{% endtab %}

{% tab title="React Native" %}

```javascript
NativeModules.NamiMLManagerBridge.enterCoreContent(labels: [String])
```

{% endtab %}
{% endtabs %}

**Arguments**

* `labels` a list of strings where the list is ordered by the relationship of the content, such as \["video", "basketball", "michael jordan"].


# exitCoreContent

Inform the SDK when a user has finished consuming content that is core to your app experience.

{% tabs %}
{% tab title="Swift" %}

```swift
NamiMLManager.exitCoreContent(label: String)
```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
NamiMLManager.exitCoreContent(label: String)
```

{% endtab %}

{% tab title="Flutter" %}

```cplusplus
// Use version that takes List<String> (see below)
```

{% endtab %}

{% tab title="React Native" %}

```javascript
NativeModules.NamiMLManagerBridge.exitCoreContentWithLabel(String);
```

{% endtab %}
{% endtabs %}

**Arguments**

* (required) `label`: String that describes the nature of the content being consumed. The same string string must be used in both [enterCoreContent](/sdk-reference/namimlmanager/entercorecontent) and [exitCoreContent](/sdk-reference/namimlmanager/exitcorecontent) calls.

{% tabs %}
{% tab title="Swift" %}

```swift
NamiMLManager.exitCoreContent(labels: [String])
```

{% endtab %}

{% tab title="Java" %}

```java
NamiMLManager.exitCoreContent(List<String> labels);
```

{% endtab %}

{% tab title="Flutter" %}

```java
NamiMLManager.exitCoreContent(List<String> labels);
```

{% endtab %}
{% endtabs %}

**Arguments**

* (required) `labels`: A list of strings of different labels that describe the content that was consumed. Note the exact same list must be used in both the `enterCoreContent` and `exitCoreContent` calls to work correctly.


