Tapaya
Integration GuideMobile SDK Integration

Mobile SDK Integration

Integrate the Tapaya Accept SDK into your mobile application.

The Tapaya Accept SDK for Android provides a robust, secure, and easy-to-use toolkit for embedding payment processing directly into your Android application. Designed with modern Android development practices in mind, it supports Kotlin Coroutines, lifecycle-aware components, and a clean API surface.

Installation

Add the Tapaya Accept SDK dependency to your module-level build.gradle file.

dependencies {
    implementation("com.tapaya:accept:1.4.2")
}

Initialization

The Accept singleton is the entry point for all SDK functionality. Initialize it once (typically in your Application class), then authenticate separately with a merchant token.

Step 1: Initialize

// Sandbox is the default (isProduction = false)
Accept.initialize(context = this)

// Target production explicitly
Accept.initialize(context = this, isProduction = true)

// Or drive it from your build type
Accept.initialize(context = this, isProduction = !BuildConfig.DEBUG)

Step 2: Authenticate

Call Accept.auth.authenticate() after initialization to log in a merchant with a token obtained from your backend. It is a suspend function and throws an AcceptException on failure. On success, Accept.state transitions to SdkState.Authenticated.

// suspend; call from a coroutine
try {
    val merchantToken = myBackendApi.getMerchantToken()
    Accept.auth.authenticate(merchantToken)
    // Accept.state now emits SdkState.Authenticated
} catch (e: AcceptException) {
    // handle authentication failure
}

You can observe Accept.state (a StateFlow<SdkState>) to react to lifecycle changes — Idle → Initialized → Authenticated.

Core Concepts

The Accept object exposes the SDK through a small set of surfaces:

SurfacePurpose
Accept.authAuthenticate a merchant session.
Accept.merchantMerchant profile, config, onboarding status.
Accept.paymentsCreate and manage card payments.
Accept.pluginTerminal (plugin app) install and activation.
Accept.sdkSDK-level config (e.g. minimum amounts).
Accept.stateStateFlow<SdkState> lifecycle.

Taking a Payment

Call Accept.payments.pay() with the amount (in the currency's minor unit) and an ISO 4217 currency code. It returns a Flow<PaymentEvent>; collect it to observe progress and the terminal outcome. pay() never throws — failures arrive as PaymentEvent.CreationFailed.

Payment Flow

Accept.payments.pay(amount = 15000, currency = "CZK") // 150.00 Kč
    .collect { event ->
        when (event) {
            PaymentEvent.Creating -> Log.d("pay", "creating")
            is PaymentEvent.Created -> Log.d("pay", "created ${event.paymentToken}")
            PaymentEvent.Launched -> Log.d("pay", "launched")
            is PaymentEvent.Result -> Log.d("pay", event.payResult.toString())
            is PaymentEvent.CreationFailed -> Log.e("pay", event.cause.toString())
        }
    }

The terminal PaymentEvent.Result carries a PayResultSuccess(paymentToken), Declined, Canceled, or Failed(reason). Query a payment later with Accept.payments.status(paymentToken) or stop it with Accept.payments.cancel(paymentToken).

Plugin App

Every card payment hands off to Tapaya Terminal, the Tapaya plugin app; it is always required, there is no card payment path that skips it. Check whether it is installed, then activate the terminal, or open the store listing so the merchant can install it.

Plugin App

if (Accept.plugin.isInstalled()) {
    // suspend; returns ActivateTerminalResult (Success / Canceled / Failed)
    Accept.plugin.activateTerminal()
} else {
    Accept.plugin.install() // opens the store listing
}

Read the plugin's current state with Accept.plugin.status(), or sign the merchant out of the plugin with Accept.plugin.logout().

Permissions

Card payments require the host app to hold location permission (ACCESS_FINE_LOCATION). The SDK does not request it for you — grant it with the standard Android permission APIs before calling pay().

class PaymentActivity : AppCompatActivity() {
    private val requestLocation = registerForActivityResult(
        ActivityResultContracts.RequestPermission()
    ) { granted ->
        if (granted) launchPaymentFlow() else showPermissionRationale()
    }

    fun startPayment() {
        requestLocation.launch(Manifest.permission.ACCESS_FINE_LOCATION)
    }
}

If location is missing or cannot be resolved when pay() runs, the flow emits PaymentEvent.CreationFailed with LocationPermissionRequired, LocationUnavailable, or LocationTimeout as the cause.

Error Handling

Every checked failure is a subclass of the sealed AcceptException. Suspend calls (authenticate, merchant.*, payments.status/cancel, plugin.activateTerminal/status/logout, clear) throw one on failure. payments.pay() is the exception: it never throws and instead reports failures as PaymentEvent.CreationFailed(cause).

Exception Types

ExceptionDescription
Lifecycle
NotInitializedA call needs Accept.initialize() first.
NotAuthenticatedA call needs Accept.auth.authenticate() first.
SessionExpiredAuthenticated session expired; re-authenticate.
UnknownEnvironment(key)Environment key not recognized (internal initialize overload).
Payments
PaymentInProgressA previous pay() is still awaiting a result.
CurrencyNotAvailableForMerchant(code)Currency not configured for the merchant.
UnsupportedCurrency(code)Currency not recognized by the SDK.
AmountBelowMinimum(minimum, currency)Amount below the configured minimum.
PaymentCreationFailed(cause)Any other failure while creating a payment.
PaymentNotFoundstatus()/cancel() token unknown to the backend.
Location
LocationPermissionRequiredHost app lacks location permission.
LocationUnavailableNo provider could produce a location fix.
LocationTimeoutLocation fix not resolved in time.
Plugin / Terminal
PluginUnavailablePlugin app not installed, or its service could not be bound.
PluginTimeoutPlugin did not respond in time.
ActivationInProgressA previous activateTerminal() is still awaiting a result.
PluginAlreadyAuthenticatedPlugin already authenticated for this merchant.
PluginMerchantMismatchPlugin authenticated under a different merchant; call plugin.logout() first.
MerchantOnboardingIncomplete(state)Merchant has not finished onboarding.
System
NoInternetConnectionDevice has no network connectivity.
Unknown(cause)Any failure the SDK does not recognize as one of its own.

Result vs. exception

A payment that reaches the terminal but does not succeed is not an exception — it arrives as PaymentEvent.Result carrying PayResult.Declined, Canceled, or Failed(reason). Likewise, terminal activation reports ActivateTerminalResult.Failed(reason).

Handling Exceptions

Wrap suspend calls in a try-catch; branch on specific cases or catch AcceptException broadly.

try {
    val status = Accept.payments.status(paymentToken)
} catch (e: SessionExpired) {
    // Re-authenticate
} catch (e: NoInternetConnection) {
    // Ask the user to check connectivity
} catch (e: AcceptException) {
    // Handle any other SDK error
    Log.e("Payment", "Error: ${e.message}")
}

Logging

Enable debug logging during development to troubleshoot issues.

Accept.setDebugLoggingEnabled(true)

Logging Out

Clear all locally persisted SDK state (auth token, device id, cached config) and reset Accept.state to SdkState.Idle. Call this on user logout.

Accept.clear() // suspend

The Tapaya Accept SDK for React Native is a robust, secure, and easy-to-use toolkit that lets you embed payment processing directly into your React Native application. Built to integrate seamlessly with the React Native ecosystem, it offers a clean API, reliable performance, and a developer-friendly experience across platforms.

Installation

Install NPM Package

Add the dependency to your project.

npm i @tapayadot/accept-react-native

Register the plugin in your app.json.

app.json
"plugins": [
    [
        "@tapayadot/accept-react-native"
    ]
]

Before first Expo run

Run npx expo prebuild --clean to generate the native bindings before building your app.

Initialization

The AcceptSDK object is the entry point for all SDK functionality. Call initialize() once at app launch.

import AcceptSDK from '@tapayadot/accept-react-native';

// set true for testing environment
await AcceptSDK.initialize(true);

Authentication

After initialization, authenticate the merchant using a token obtained from your backend.

const merchantToken = await myBackend.login();
await AcceptSDK.authenticate(merchantToken);

Core Concepts

Payment Interface

Tapaya Terminal Required

Card payments always hand off to Tapaya Terminal, the Tapaya companion app; there is no card payment path that skips it. Use AcceptSDK.isCompanionAppInstalled() to check, and AcceptSDK.presentCompanionAppSheet() to prompt installation if needed.

The SDK exposes payment methods through the AcceptSDK.payments object.

MethodDescriptionUse Case
startCardPaymentNFC Card ReaderContactless EMV payments.

Example of starting a card payment:

import AcceptSDK, { Currency, CardPaymentIntent } from '@tapayadot/accept-react-native';

const paymentIntent: CardPaymentIntent = {
    paymentIntentId: Crypto.randomUUID(),
    amount: 10000, // 100.00 CZK
    requestedCurrency: Currency.CZK,
};

try {
    const result = await AcceptSDK.payments.startCardPayment(
        paymentIntent,
        (status) => {
            console.log("Payment Status Update:", status);
        },
        (message, exception) => {
            console.error("Payment Error:", message, exception);
        }
    );
    console.log("Payment Successful:", result);
} catch (error) {
    console.error("Payment Failed:", error);
}

Permissions

Processing payments, especially contactless card payments, requires specific permissions (like Location).

const granted = await AcceptSDK.requestLocationPermission();

if (granted) {
    // Proceed with payment
} else {
    // Show rationale
}

Error Handling

The SDK returns errors through the error callback in payment methods. The error code is an enum AcceptSDKError.

Error CodeNameDescription
1UninitializedSDK is not initialized.
2ServiceStartingService is starting.
3ServiceInitializationService initialization failed.
4TokenInitializationErrorError initializing token.
5InitializationGeneral initialization error.
6LoginExpiredLogin session expired.
7InitializeWithoutDataInitialized without necessary data.
8LocationPermissionLocation permission missing.
9LocationDisabledLocation services disabled.
10NFCDisabledNFC is disabled.
11NotDebuggableApp is not debuggable.
12DebuggableNotDemoDebuggable app in non-demo mode.
13ReaderNotFoundCard reader not found.
14ReaderNotReadyYetReader is not ready.
15ReaderBadConnectionBad connection to reader.
16OfflineDevice is offline.
17InitializeTransactionTransaction initialization failed.
18FinalizeTransactionTransaction finalization failed.
19OperationTimeoutOperation timed out.
20PaymentNotFoundPayment not found.
21ServerErrorServer error occurred.
22ClientErrorClient error occurred.
23OnboardingOnboarding error.
24DuplicatedOnboardingOnboarding duplicated.
25MissingKYBDetailsMissing KYB details.
26LocationNotFoundLocation not found.
27LocationIdNotFoundLocation ID not found.
28UnknownUnknown error.
29UnknownMessageUnknown error message.
30CancellationOperation cancelled.

Other Operations

Get Status

Check the current status of the SDK.

const status = await AcceptSDK.getStatus();

Get Transaction Info

Retrieve information about a specific payment intent.

const result = await AcceptSDK.getPaymentStatus("payment_intent_id");

Log Out

Clear the current session.

await AcceptSDK.logOut();

On this page