---
updatedAt: 2026-08-31T16:22:48.000Z
agentTools:
  projectIndex: https://docs.ecartpay.com/llms.txt
---

# SDK Tap To Phone

# Ecart Pay Android SDK - Tap to Phone

Accept in-person card payments in your Android app using Tap to Phone technology. Enable your users to accept contactless payments by simply tapping the card on the device — no additional hardware required.

***

## Prerequisites

| Requirement    | Minimum Version                       |
| -------------- | ------------------------------------- |
| Android SDK    | `minSdk 24` (Android 7.0)             |
| Android Studio | Hedgehog or later                     |
| Device         | NFC-enabled with Tap to Phone support |

> ⚠️ **Important**: The SDK requires a physical device with NFC support. Testing on emulators is not possible.

***

## Get Your Credentials

To integrate the SDK, you need a pair of API keys specifically for Tap to Phone.

### Steps to obtain credentials

1. Log in to [Ecart Pay](https://ecartpay.com)
2. In the sidebar menu, navigate to **Integrations**
3. Select **Dev Tools**
4. Click on **Credentials**
5. Create new API Keys selecting the type **SDK Tap To Phone**
6. Securely save your `Public ID` and `Private ID`

> 💡 **Tip**: You can create separate credentials for Sandbox (testing) and Production environments.

> ⚠️ **Warning**: Your `Private ID` is confidential. **Never share it** or include it in publicly visible code.

***

## Installation

Add the Ecart Pay SDK to your project using Maven Central:

```groovy
// build.gradle (app module)
dependencies {
    implementation 'com.ecartpay:tap-to-phone-sdk:1.0.1'
}
```

Make sure Maven Central is included in your repositories:

```groovy
// settings.gradle
dependencyResolutionManagement {
    repositories {
        google()
        mavenCentral()
    }
}
```

***

## Initial Setup

Initialize the SDK once, preferably in your `Application` class:

```kotlin
class MyApplication : Application() {
    override fun onCreate() {
        super.onCreate()
        
        EcartPaySDK.initialize(
            context = this,
            config = EcartPayConfig(
                publicId = "pk_live_your_public_id",
                privateId = "sk_live_your_private_id",
                environment = Environment.PRODUCTION
            )
        )
    }
}
```

### Available Environments

| Environment              | Use Case                | Base URL               |
| ------------------------ | ----------------------- | ---------------------- |
| `Environment.SANDBOX`    | Testing and development | `sandbox.ecartpay.com` |
| `Environment.PRODUCTION` | Live transactions       | `ecartpay.com`         |

***

## Quick Start

### Set Up the Device (Recommended)

The `setupDevice()` method executes the entire setup process in a single call:

1. **Registers** the device with Ecart Pay servers
2. **Enrolls** the device with the payment provider (CyberSource)

```kotlin
EcartPaySDK.instance().setupDevice(activity = this) { result ->
    when (result) {
        is SetupResult.Ready -> {
            // ✅ Device ready to process payments
            Log.d("EcartPay", "Setup complete: ${result.deviceId}")
            enableChargeButton()
        }
        
        is SetupResult.TapToPayReadyRequired -> {
            // ⚠️ "Tap to Pay Ready" app installation required
            showInstallationDialog()
        }
        
        is SetupResult.Cancelled -> {
            // ℹ️ User cancelled the process
            Log.i("EcartPay", "Setup cancelled")
        }
        
        is SetupResult.RegistrationFailed -> {
            // ❌ Registration error
            Log.e("EcartPay", "Error: ${result.code} - ${result.message}")
            showError("Could not register device")
        }
        
        is SetupResult.EnrollmentFailed -> {
            // ❌ Registration succeeded but enrollment failed
            Log.e("EcartPay", "Enrollment error: ${result.message}")
            showError("Could not complete setup")
        }
    }
}
```

### Install Tap to Pay Ready

When the SDK reports `TapToPayReadyRequired`, prompt the user to install the Visa companion app:

```kotlin
private fun showInstallationDialog() {
    AlertDialog.Builder(this)
        .setTitle("Installation Required")
        .setMessage("To accept card payments, you need to install Visa's \"Tap to Pay Ready\" application.")
        .setPositiveButton("Install") { _, _ ->
            EcartPaySDK.instance().openTapToPayReadyPlayStore()
        }
        .setNegativeButton("Cancel", null)
        .show()
}
```

***

## Process a Payment

Once the device is set up, you can process payments in different ways:

### Option A: Direct Charge (Simple Amount)

Ideal for quick charges where you don't need itemized products:

```kotlin
val request = PaymentRequest(
    amount = 150.00,
    currency = "MXN",
    email = "customer@email.com",
    reference = "SALE-001"
)

EcartPaySDK.instance().startPayment(activity = this, request = request) { result ->
    when (result) {
        is PaymentResult.Approved -> {
            // ✅ Payment successful
            showReceipt(
                orderId = result.orderId,
                transactionId = result.transactionId,
                amount = result.amount,
                card = result.maskedCardNumber
            )
        }
        
        is PaymentResult.Declined -> {
            // ❌ Payment declined
            showError("Payment declined: ${result.reason}")
        }
        
        is PaymentResult.Cancelled -> {
            // ℹ️ User cancelled
            Log.i("EcartPay", "Payment cancelled")
        }
        
        is PaymentResult.Error -> {
            // ❌ Technical error
            Log.e("EcartPay", "Error: ${result.code} - ${result.message}")
            showError("An error occurred while processing the payment")
        }
    }
}
```

### Option B: Itemized Charge

For sales with detailed products, useful for receipts and inventory:

```kotlin
val request = PaymentRequest(
    currency = "MXN",
    email = "customer@email.com",
    firstName = "John",
    lastName = "Doe",
    phone = "5512345678",
    items = listOf(
        OrderItem(name = "Product A", price = 99.00, quantity = 2),
        OrderItem(name = "Product B", price = 150.00, quantity = 1)
    )
)

EcartPaySDK.instance().startPayment(activity = this, request = request) { result ->
    // Handle result...
}
```

### Option C: Complete Charge (with Shipping)

For e-commerce with physical products:

```kotlin
val request = PaymentRequest(
    currency = "MXN",
    email = "customer@email.com",
    firstName = "Jane",
    lastName = "Smith",
    phone = "5598765432",
    reference = "ORDER-2024-001",
    referenceId = "ORD-12345",
    notifyUrl = "https://your-server.com/webhooks/ecartpay",
    items = listOf(
        OrderItem(name = "Smartphone XYZ", price = 8999.00, quantity = 1)
    ),
    shippingAddress = ShippingAddress(
        firstName = "Jane",
        lastName = "Smith",
        address1 = "123 Main Street",
        address2 = "Apt 4B",
        city = "Mexico City",
        postalCode = "06600",
        countryCode = "MX",
        stateCode = "CDMX",
        phone = "5598765432"
    ),
    shippingItems = listOf(
        ShippingItem(
            name = "Express Shipping",
            amount = 150.00,
            carrier = "FEDEX"
        )
    )
)
```

***

## Field Reference

### PaymentRequest

| Field             | Type                  | Required         | Description                               |
| ----------------- | --------------------- | ---------------- | ----------------------------------------- |
| `amount`          | `Double?`             | When no `items`  | Total amount to charge                    |
| `currency`        | `String`              | Yes              | Currency: `"MXN"` or `"USD"`              |
| `email`           | `String?`             | No               | Customer email                            |
| `phone`           | `String?`             | No               | Customer phone                            |
| `firstName`       | `String?`             | No               | Customer first name                       |
| `lastName`        | `String?`             | No               | Customer last name                        |
| `reference`       | `String?`             | No               | Internal reference (e.g., invoice number) |
| `referenceId`     | `String?`             | No               | External ID from your system              |
| `notifyUrl`       | `String?`             | No               | Webhook notification URL                  |
| `items`           | `List<OrderItem>?`    | When no `amount` | List of products                          |
| `shippingItems`   | `List<ShippingItem>?` | No               | Shipping options                          |
| `shippingAddress` | `ShippingAddress?`    | No               | Delivery address                          |

### OrderItem

| Field      | Type     | Required | Description      |
| ---------- | -------- | -------- | ---------------- |
| `name`     | `String` | Yes      | Product name     |
| `price`    | `Double` | Yes      | Unit price (> 0) |
| `quantity` | `Int`    | Yes      | Quantity (≥ 1)   |

### ShippingItem

| Field            | Type      | Required | Description                        |
| ---------------- | --------- | -------- | ---------------------------------- |
| `name`           | `String`  | Yes      | Shipping method name               |
| `amount`         | `Double`  | Yes      | Cost (can be 0)                    |
| `carrier`        | `String`  | Yes      | Carrier (e.g., `"FEDEX"`, `"DHL"`) |
| `trackingNumber` | `String?` | No       | Tracking number                    |

### ShippingAddress

| Field         | Type      | Required | Description                     |
| ------------- | --------- | -------- | ------------------------------- |
| `firstName`   | `String?` | Yes\*    | Recipient first name            |
| `lastName`    | `String?` | No       | Recipient last name             |
| `address1`    | `String?` | Yes\*    | Primary address                 |
| `address2`    | `String?` | No       | Secondary address               |
| `address3`    | `String?` | No       | Additional address              |
| `city`        | `String?` | No       | City                            |
| `postalCode`  | `String?` | No       | Postal code                     |
| `countryCode` | `String?` | Yes\*    | ISO country code (e.g., `"MX"`) |
| `countryName` | `String?` | No       | Country name                    |
| `stateCode`   | `String?` | No       | State code                      |
| `stateName`   | `String?` | No       | State name                      |
| `phone`       | `String?` | No       | Contact phone                   |
| `reference`   | `String?` | No       | Delivery instructions           |

\*Required by backend when `shippingAddress` is included

***

## Advanced Integration

### Step-by-Step Setup

If you need more control over the flow (e.g., to show different UI states for each step), you can use the individual methods:

#### Step 1: Register the Device

```kotlin
EcartPaySDK.instance().registerDevice { result ->
    when (result) {
        is RegistrationResult.Success -> {
            Log.d("EcartPay", "Device registered: ${result.deviceId}")
            // Continue with enrollment
        }
        is RegistrationResult.Failure -> {
            Log.e("EcartPay", "Error: ${result.code} - ${result.message}")
        }
    }
}
```

#### Step 2: Enroll the Device

```kotlin
EcartPaySDK.instance().enrollDevice(activity = this) { result ->
    when (result) {
        is EnrollmentResult.Enrolled -> {
            Log.d("EcartPay", "Enrollment complete")
        }
        EnrollmentResult.TapToPayReadyRequired -> {
            // Show installation dialog
        }
        EnrollmentResult.Cancelled -> {
            Log.i("EcartPay", "Enrollment cancelled")
        }
        is EnrollmentResult.Failure -> {
            Log.e("EcartPay", "Error: ${result.code} - ${result.message}")
        }
    }
}
```

### Check Device Status

```kotlin
val sdk = EcartPaySDK.instance()

// Is registered?
val isRegistered = sdk.isDeviceRegistered
val deviceId = sdk.deviceId

// Has provider credentials?
val hasCredentials = sdk.hasProviderCredentials

// Is enrolled?
val isEnrolled = sdk.isEnrollmentPersisted

// Is Tap to Pay Ready installed?
val isAppInstalled = sdk.isTapToPayReadyInstalled()
```

### Reset the Device

To clear all local configuration (useful when signing out):

```kotlin
EcartPaySDK.instance().reset()
```

***

## Network Monitoring (Debug)

For debugging, you can observe all HTTP requests:

```kotlin
EcartPaySDK.instance().setNetworkListener(object : NetworkListener {
    override fun onRequest(method: String, url: String, body: String?) {
        Log.d("HTTP", "→ $method $url")
        body?.let { Log.d("HTTP", it) }
    }

    override fun onResponse(method: String, url: String, statusCode: Int, body: String) {
        Log.d("HTTP", "← $method $url [$statusCode]")
    }

    override fun onError(method: String, url: String, error: Throwable) {
        Log.e("HTTP", "✕ $method $url - ${error.message}")
    }
})

// Disable when done
EcartPaySDK.instance().setNetworkListener(null)
```

***

## Error Handling

| Code                           | Description            | Solution                                   |
| ------------------------------ | ---------------------- | ------------------------------------------ |
| `NOT_REGISTERED`               | Device not registered  | Call `setupDevice()` or `registerDevice()` |
| `NOT_ENROLLED`                 | Device not enrolled    | Call `setupDevice()` or `enrollDevice()`   |
| `TAP_TO_PAY_READY_REQUIRED`    | Visa app not installed | Use `openTapToPayReadyPlayStore()`         |
| `MISSING_PROVIDER_CREDENTIALS` | Incomplete credentials | Contact Ecart Pay support                  |
| `API_401`                      | Invalid credentials    | Verify your `publicId` and `privateId`     |
| `API_400`                      | Invalid request data   | Check `PaymentRequest` fields              |

***

## ProGuard / R8

If you use code shrinking, the SDK includes its own ProGuard rules. No additional configuration is required.

***

## Sample Application

A complete sample application demonstrating all SDK features is available on GitHub:

* 📱 **Repository**: [ecartpay-sdk-app-example](https://github.com/envia-ep/ecartpay-sdk-app-example)

The sample app includes:

* Device registration and enrollment
* Multiple payment scenarios (direct, itemized, with shipping)
* Error handling examples
* UI best practices

***

## Support

Have questions or issues with integration?

* 📧 Email: <support@ecartpay.com>
* 📖 Documentation: [docs.ecartpay.com](https://docs.ecartpay.com)
* 💬 Live Chat: Available in the Ecart Pay dashboard