React Native

Overview

Bring secure Telr payments to your React Native app fast. Our plug-in launches the checkout flow, manages the payment steps behind the scenes, and returns a clear success or failure result, so your team ships quicker and supports less.

Requirements

  • React Native ≥ 0.75
  • iOS: iOS 14+, Xcode 15+, Swift 5.9+
  • Android: minSdk 24+, targetSdk 34, Kotlin 1.9+
  • Your backend must return two URLs taken directly from the createOrder API response:
    • tokenUrl — value of _links.auth.href
    • orderUrl — value of _links.self.href

Installation

Install the package in your React Native app:

npm install @telrsdk/rn-telr-sdk
# or
yarn add @telrsdk/rn-telr-sdk

Platform Setup

iOS

  1. Ensure your ios/Podfile targets iOS 15.1 or newer and has New Architecture enabled for the best performance.

Minimal example:

platform :ios, '15.1'

require_relative '../node_modules/react-native/scripts/react_native_pods'
require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules'

target 'YourApp' do
  config = use_native_modules!

  use_react_native!(
    :path => config[:reactNativePath],
    :new_arch_enabled => true
  )

  use_frameworks! :linkage => :static
end
  1. Install pods with New Architecture enabled:
cd ios && RCT_NEW_ARCH_ENABLED=1 pod install

If CocoaPods cannot find the TelrSDK pod, make sure you have access to Telr's podspec source as provided by Telr and that your Podfile declares the appropriate source entries. Then run pod repo update and re-install.

Android

No additional setup required

Usage

import TelrPayments, {
  TelrInitResult,
  TelrResult,
  TelrStatus,
  ConfigureOptions,
} from '@telrsdk/rn-telr-sdk';

async function checkout() {
  // 1) Initialize
  const init: TelrInitResult = await TelrPayments.initialize();
  if (!init.success) {
    // Show a friendly message; you may allow retry
    console.warn('Telr SDK initialization failed', init.error);
    return;
  }

  // 2) Fetch tokenUrl/orderUrl from your backend
  const { tokenUrl, orderUrl } = await fetch('/api/checkout')
    .then(r => r.json());

  // 3) Present native payment UI
  const result: TelrResult = await TelrPayments.presentPayment({
    tokenUrl,
    orderUrl,
  });

  // 4) Handle result
  switch (result.status) {
    case TelrStatus.Succeeded:
      // Optional: submit transactionId or metadata to your backend
      console.log('Payment successful');
      break;
    case TelrStatus.Canceled:
      console.log('Payment canceled by user');
      break;
    case TelrStatus.Failed:
      console.log('Payment failed', result.errorCode, result.message);
      break;
  }
}

API Reference

  • presentPayment(tokenURL: string, orderURL: string): Promise<PaymentResponse>
    • Presents the Telr payment UI modally (full screen) on iOS.
    • Resolves with { success: boolean; message: string } when the flow completes.

Types

type PaymentResponse = { success: boolean; message: string };

Notes

  • The payment view is presented full-screen using UIKit/SwiftUI under the hood and dismissed automatically when a result is available.
  • Make sure your tokenURL and orderURL are accessible from the device/simulator and use HTTPS.

Troubleshooting

  • TurboModule 'TelrSDK' is null or undefined

    • Ensure New Architecture is enabled (:new_arch_enabled => true in Podfile, or RCT_NEW_ARCH_ENABLED=1 when installing pods) and re-run pod install.
  • CocoaPods cannot find TelrSDK

    • Ensure your Podfile includes Telr's private spec repo or the correct pod source as provided by Telr, then run pod repo update and pod install.
  • Build fails due to iOS version

    • Ensure your app targets platform :ios, '15.1' or newer.

Add Card Flow

Use launchAddCardActivity when you want to verify and save a new card (without immediate checkout capture).

Merchant-side flow

  1. Merchant backend creates a VERIFY order.

  2. Merchant backend returns tokenUrl + orderUrl to the app.

  3. App opens SDK add-card sheet with those URLs.

  4. SDK handles card entry, 3DS, and completion callback.

  5. On success callback, app stores the saved card details and payment reference for future use.

Example

import com.telr.android.payment.sdk.Core
import com.telr.android.payment.sdk.data.sdk.PaymentRequest
import com.telr.android.payment.sdk.data.sdk.SDKAddCardResult

val paymentRequest = PaymentRequest(
    tokenUrl = addCardTokenUrl,
    orderUrl = addCardOrderUrl
)

Core.getInstance().launchAddCardActivity(this, paymentRequest) { result ->
    when (result.paymentStatus) {
        PaymentStatus.SUCCESS -> {
            // result.ref — payment reference from the VERIFY transaction (store for saved-card payments)
            // result.maskedName — masked cardholder name (store for SDKSavedCardInput)
            // result.savedCards — list of saved card details (token, maskedCard, expiry, scheme)
            val cards = result.savedCards
            val paymentRef = result.ref
        }
        PaymentStatus.CANCELLED -> { /* user cancelled */ }
        PaymentStatus.PENDING -> { /* order status being confirmed */ }
        PaymentStatus.FAILURE -> {
            // result.message contains the error description
            // result.errorCode contains the SDK error code (nullable)
        }
    }
}

SDKAddCardResult

@Parcelize
data class SDKAddCardResult(
    val paymentStatus: PaymentStatus,
    val message: String,
    val errorCode: String? = null,
    val ref: String? = null,             // payment reference for CONT transactions
    val savedCards: List<SDKSavedCardInput>? = null,
    val maskedName: String? = null       // e.g. "J*** D**"
) : Parcelable

Pay with Saved Card Flow

UselaunchSavedCardPaymentActivitywhen a customer selects a saved card and CVV re-entry and/or 3DS is required (typically for higher-value transactions per your risk policy).

📘

For low-value or recurring transactions, your backend can process the saved card silently usingclass: CONTwith the payment reference from the add-card flow — no CVV or user interaction needed. UselaunchSavedCardPaymentActivity(ECOM) when your risk policy requires CVV re-entry or 3DS authentication.

Merchant-side flow

  1. Merchant backend creates a SALE order.

  2. Merchant backend returns tokenUrl + orderUrl to the app.

  3. App opens the SDK saved-card sheet with those URLs and the saved card details.

  4. SDK displays the masked card (read-only) and prompts for CVV only.

  5. SDK handles payment, 3DS, and calls the completion callback.

Example

import com.telr.android.payment.sdk.Core
import com.telr.android.payment.sdk.data.sdk.SDKSavedCardInput
import com.telr.android.payment.sdk.data.sdk.SavedCardPaymentLaunchRequest
import com.telr.android.payment.sdk.data.sdk.PaymentStatus

val savedCard = SDKSavedCardInput(
    token = "card_token_here",
    maskedCard = "**** 1111",     // from add-card flow
    expiry = "12/30",
    scheme = "VISA",
    maskedName = "J*** D**"       // optional, shown on the sheet
)

val launchRequest = SavedCardPaymentLaunchRequest(
    tokenUrl = checkoutTokenUrl,
    orderUrl = checkoutOrderUrl,
    savedCard = savedCard
)

Core.getInstance().launchSavedCardPaymentActivity(this, launchRequest) { result ->
    when (result.paymentStatus) {
        PaymentStatus.SUCCESS -> handleSuccess()
        PaymentStatus.CANCELLED -> handleCancelled()
        else -> handleFailure(result.sdkError?.description)
    }
}

SDKSavedCardInput

@Parcelize
data class SDKSavedCardInput(
    val token: String,           // card token from add-card flow
    val maskedCard: String,      // e.g. "**** 1111"
    val expiry: String,          // e.g. "12/30"
    val scheme: String,          // e.g. "VISA"
    val maskedName: String? = null // optional, e.g. "J*** D**"
) : Parcelable

SavedCardPaymentLaunchRequest

@Parcelize
data class SavedCardPaymentLaunchRequest(
    val tokenUrl: String,
    val orderUrl: String,
    val savedCard: SDKSavedCardInput
) : Parcelable

Pay with Card Flow

UselaunchPayWithCardActivitywhen you want to collect card details and process an immediate payment (e.g., gift card purchases) without saving the card.

Merchant-side flow

  1. Merchant backend creates a SALE order.

  2. Merchant backend returns tokenUrl + orderUrl to the app.

  3. App opens SDK pay-with-card sheet with those URLs.

  4. SDK handles card entry, BIN lookup (including international card blocking), 3DS, and completion callback.

  5. On success callback, the payment is complete.

Example

import com.telr.android.payment.sdk.Core
import com.telr.android.payment.sdk.data.sdk.PaymentRequest
import com.telr.android.payment.sdk.data.sdk.PaymentStatus

val paymentRequest = PaymentRequest(
    tokenUrl = checkoutTokenUrl,
    orderUrl = checkoutOrderUrl
)

Core.getInstance().launchPayWithCardActivity(this, paymentRequest) { result ->
    when (result.paymentStatus) {
        PaymentStatus.SUCCESS -> handleSuccess()
        PaymentStatus.CANCELLED -> handleCancelled()
        else -> handleFailure(result.sdkError?.description)
    }
}

Error Handling

SDK Result

Results are delivered via the callback from launchPaymentActivity:

import com.telr.android.payment.sdk.data.sdk.SDKResult
import com.telr.android.payment.sdk.data.sdk.PaymentStatus

// SDKResult(paymentStatus: PaymentStatus, sdkError: SDKError?)
  • PaymentStatus.SUCCESS
  • PaymentStatus.FAILURE
  • PaymentStatus.CANCELLED

SDK Errors

Common error codes returned in SDKResult.sdkError:

  • E001: Context must be a ComponentActivity
  • E002: Unable to register for Activity Result (init must run on app load)
  • E003: SDK not initialised (call Core.init() first)
  • E004: Unable to fetch result from Payment Intent
  • E005: Missing/invalid auth/order parameters
  • E006: Authentication failed/expired
  • E007: Fetch order failed (invalid order or node)
  • E008: Make payment API failed or session expired
  • E009: Unable to get 3DS validation status
  • E010: Unable to get 3DS URL

Handle errors by showing user‑friendly messages and optionally retrying where appropriate.

Internationalization

  • The SDK UI strings include English; Arabic is supported for RTL layout alignment when configured by your app’s locale.
  • The SDK follows the host app locale and supports RTL mirroring.

Troubleshooting

Common Issues

  1. Core.init() returns FAILED

    • Ensure you pass a ComponentActivity instance
    • Call init before launching payment
  2. Network or Timeout errors

    • Verify tokenUrl and orderUrl
    • Check device connectivity and SSL configuration
  3. Payment not processing

    • Confirm your backend endpoints return valid token/order responses
    • Ensure the order links include allowed operations and methods
  4. 3DS challenge not returning

    • Check if the device can reach the ACS URL
    • Verify threeDs links in the order are valid

Debugging Tips

  • Log the SDKResult and sdkError for diagnostics.
  • Use your app’s network logger or proxy to inspect traffic to your backend.

API Reference

Core

object Core {
    fun getInstance(): Core
    fun init(context: Context): SDKInitResult // context must be a ComponentActivity
    fun launchPaymentActivity(
        context: Context,
        paymentRequest: PaymentRequest,
        callback: (SDKResult) -> Unit
    )
}

PaymentRequest

@Parcelize
data class PaymentRequest(
    val tokenUrl: String,
    val orderUrl: String
) : Parcelable

SDKInitResult

enum class InitStatus { SUCCESS, FAILED }

data class SDKInitResult(
    val initStatus: InitStatus,
    val sdkError: SDKError? = null
)

SDKResult

@Parcelize
data class SDKResult(
    val paymentStatus: PaymentStatus,
    val sdkError: SDKError?
) : Parcelable

PaymentStatus

enum class PaymentStatus { SUCCESS, FAILURE, CANCELLED }

Order and Amount (server response models)

data class Amount(val value: Double, val currency: String)

enum class OrderStatus { PENDING, AUTHORISED, PAID, CANCELLED, DECLINED }

Additional models include allowed payment methods, links, and 3DS details.