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:
| Surface | Purpose |
|---|---|
Accept.auth | Authenticate a merchant session. |
Accept.merchant | Merchant profile, config, onboarding status. |
Accept.payments | Create and manage card payments. |
Accept.plugin | Terminal (plugin app) install and activation. |
Accept.sdk | SDK-level config (e.g. minimum amounts). |
Accept.state | StateFlow<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.
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 PayResult — Success(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.
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
| Exception | Description |
|---|---|
| Lifecycle | |
NotInitialized | A call needs Accept.initialize() first. |
NotAuthenticated | A call needs Accept.auth.authenticate() first. |
SessionExpired | Authenticated session expired; re-authenticate. |
UnknownEnvironment(key) | Environment key not recognized (internal initialize overload). |
| Payments | |
PaymentInProgress | A 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. |
PaymentNotFound | status()/cancel() token unknown to the backend. |
| Location | |
LocationPermissionRequired | Host app lacks location permission. |
LocationUnavailable | No provider could produce a location fix. |
LocationTimeout | Location fix not resolved in time. |
| Plugin / Terminal | |
PluginUnavailable | Plugin app not installed, or its service could not be bound. |
PluginTimeout | Plugin did not respond in time. |
ActivationInProgress | A previous activateTerminal() is still awaiting a result. |
PluginAlreadyAuthenticated | Plugin already authenticated for this merchant. |
PluginMerchantMismatch | Plugin authenticated under a different merchant; call plugin.logout() first. |
MerchantOnboardingIncomplete(state) | Merchant has not finished onboarding. |
| System | |
NoInternetConnection | Device 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() // suspendThe 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-nativeRegister the plugin in your 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.
| Method | Description | Use Case |
|---|---|---|
startCardPayment | NFC Card Reader | Contactless 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 Code | Name | Description |
|---|---|---|
| 1 | Uninitialized | SDK is not initialized. |
| 2 | ServiceStarting | Service is starting. |
| 3 | ServiceInitialization | Service initialization failed. |
| 4 | TokenInitializationError | Error initializing token. |
| 5 | Initialization | General initialization error. |
| 6 | LoginExpired | Login session expired. |
| 7 | InitializeWithoutData | Initialized without necessary data. |
| 8 | LocationPermission | Location permission missing. |
| 9 | LocationDisabled | Location services disabled. |
| 10 | NFCDisabled | NFC is disabled. |
| 11 | NotDebuggable | App is not debuggable. |
| 12 | DebuggableNotDemo | Debuggable app in non-demo mode. |
| 13 | ReaderNotFound | Card reader not found. |
| 14 | ReaderNotReadyYet | Reader is not ready. |
| 15 | ReaderBadConnection | Bad connection to reader. |
| 16 | Offline | Device is offline. |
| 17 | InitializeTransaction | Transaction initialization failed. |
| 18 | FinalizeTransaction | Transaction finalization failed. |
| 19 | OperationTimeout | Operation timed out. |
| 20 | PaymentNotFound | Payment not found. |
| 21 | ServerError | Server error occurred. |
| 22 | ClientError | Client error occurred. |
| 23 | Onboarding | Onboarding error. |
| 24 | DuplicatedOnboarding | Onboarding duplicated. |
| 25 | MissingKYBDetails | Missing KYB details. |
| 26 | LocationNotFound | Location not found. |
| 27 | LocationIdNotFound | Location ID not found. |
| 28 | Unknown | Unknown error. |
| 29 | UnknownMessage | Unknown error message. |
| 30 | Cancellation | Operation 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();