# Android SDK

import { Aside } from "@astrojs/starlight/components";
import Image from "@components/content/Image.astro";

This documentation provides a step-by-step guide for SumUp's native Android SDK, which enables you to integrate SumUp's proprietary card terminals and payment platform to accept credit and debit card payments (including VISA, MasterCard, American Express, and more). The SDK communicates with card terminals via Bluetooth (BLE 4.0).

During checkout, the SDK guides users through each payment step with appropriate screens. It also provides terminal setup and cardholder signature verification interfaces. The checkout result is returned with relevant transaction data for your records.

Sensitive card data is never passed to or stored on the merchant's phone. All data is encrypted by the card terminal, which complies with top industry standards (PCI, EMV I & II, Visa, MasterCard, Amex).

<Aside>
  SumUp also provides the [Android Tap to Pay SDK](/terminal-payments/sdks/android-ttp) as a separate package for handling tap-to-pay payments via smartphone.
</Aside>

## At a Glance

|                        |                                                      |
| ---------------------- | ---------------------------------------------------- |
| **Platform**           | Android                                              |
| **Languages**          | Java, Kotlin                                         |
| **Readers**            | Solo, Solo Lite, Air, 3G, PIN+                       |
| **Distribution**       | Maven (`com.sumup:merchant-sdk`)                     |
| **Source and samples** | [GitHub](https://github.com/sumup/sumup-android-sdk) |

## Prerequisites

- Registered for a merchant account via SumUp's [country websites](https://sumup.com/) or use a [sandbox merchant account](/terminal-payments/quickstart/#sandbox-merchant-account)
- A supported SumUp card reader: Solo, Solo Lite, Air, 3G, or PIN+
- An [Affiliate Key](/tools/authorization/affiliate-keys/) linked to your Android application ID
- Access to the [Android SDK repository](https://github.com/sumup/sumup-android-sdk)

## Requirements

| Requirement           | Minimum |
| --------------------- | ------- |
| `minSdkVersion`       | 26      |
| `targetSdkVersion`    | 35      |
| Android Gradle Plugin | 8.8.0   |
| Kotlin                | 1.9.0   |
| Java                  | 17      |

## Sandbox Merchant Account

Use the shared [Quickstart sandbox setup](/terminal-payments/quickstart/#sandbox-merchant-account) to create and test with a sandbox merchant account before integrating the Android SDK.

## Compatibility

Starting with firmware version 1.0.1.84, Air card readers with serial numbers starting with 108, 109 or later require SDK version 4.0.0 and later. Please update to the latest SDK version if you need to support these readers.

For store-and-forward payments when connectivity is unavailable, see [Offline Transactions](/terminal-payments/sdks/offline-transactions/).

## Integrate the Android SDK

You can use the sample app provided in the repository as a reference.

### Adding Dependencies

1. Add the SumUp maven repository to your Gradle project dependencies build file:

   ```groovy
   allprojects {
     repositories {
         maven { url 'https://maven.sumup.com/releases' }
     }
   }
   ```

2. Add the SDK dependency to your app module build file:

   ```groovy
   implementation 'com.sumup:merchant-sdk:7.0.0'
   ```

3. Sync your project.

### Initializing SumUp Components

Initialize the SumUp components in your app:

```java
public class SampleApplication extends Application {

  @Override
  public void onCreate() {
    super.onCreate();
    SumUpState.init(this);
  }
}
```

### Logging Merchant In and Out

Before calling any features of the Android SDK, a registered SumUp merchant account needs to be logged in. Log in by supplying your Affiliate Key ([create one](/tools/authorization/affiliate-keys) if necessary):

```java
SumUpLogin sumupLogin = SumUpLogin.builder(mAffiliateKey).build();
SumUpAPI.openLoginActivity(MainActivity.this, sumupLogin, 1);
```

<Image alt="Login screen" src="/img/guides/android_sdk_login.png" width="40%" />

<Aside>
  It is also possible to login an account with a token, without the user entering their SumUp login credentials in the SDK. Please refer to section [Transparent Authentication](#transparent-authentication)
</Aside>

To log Merchant out, call:

```java
SumUpAPI.logout();
```

### Making Payments

After logging in, start accepting card payments. If no account is logged in, an error `ERROR_NOT_LOGGED_IN` is returned.

Once logged in, you can start using the Android SDK to accept card payments. If no account is logged in, `SumUpAPI.Response.ResultCode.ERROR_NOT_LOGGED_IN` will be returned.

```java
    SumUpPayment payment = SumUpPayment.builder()
            // mandatory parameters
            .total(new BigDecimal("1.12")) // minimum 1.00
            .currency(SumUpPayment.Currency.EUR)
            // optional: to be used only if the card reader supports the feature, what can be checked with `SumUpApi.isTipOnCardReaderAvailable()`
            .tipOnCardReader()
        // optional: include a tip amount in addition to the total, ignored if `tipOnCardReader()` is present
        .tip(new BigDecimal("0.10"))
            // optional: add details
            .title("Taxi Ride")
            .receiptEmail("customer@mail.com")
            .receiptSMS("+3531234567890")
            // optional: Add metadata
            .addAdditionalInfo("AccountId", "taxi0334")
            .addAdditionalInfo("From", "Paris")
            .addAdditionalInfo("To", "Berlin")
            // optional: foreign transaction ID, must be unique!
            .foreignTransactionId(UUID.randomUUID().toString())  // can not exceed 128 chars
        // optional: skip the success screen
        .skipSuccessScreen()
        // optional: time out for the success screen
        .successScreenTimeout(3)
        // optional: skip the failed screen
            .skipFailedScreen()
            .build();

    SumUpAPI.checkout(MainActivity.this, payment, 2);
```

<Image
  alt="Payment screen"
  src="/img/guides/android_sdk_payment.png"
  width="40%"
/>

### Handling Payment Result

Override `onActivityResult` to handle payment results:

```java
   @Override
   protected void onActivityResult(int requestCode, int resultCode, Intent data) {
      if (requestCode == 2 && data != null) {
         // Handle the response here
      }
   }
```

### Connecting Reader

## Additional Features

### Response Fields

Several response fields are available when the callback activity is called:

| Property                                           | Type                                                   | Description / Possible Values                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| -------------------------------------------------- | ------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **SumUpAPI.Response.RESULT_CODE**                  | int                                                    | Possible Values:<br/>- SUCCESSFUL = 1<br/>- ERROR_TRANSACTION_FAILED = 2<br/>- ERROR_GEOLOCATION_REQUIRED = 3<br/>- ERROR_INVALID_PARAM = 4<br/>- ERROR_INVALID_TOKEN = 5<br/>- ERROR_NO_CONNECTIVITY = 6<br/>- ERROR_PERMISSION_DENIED = 7<br/>- ERROR_NOT_LOGGED_IN = 8<br/>- ERROR_DUPLICATE_FOREIGN_TX_ID = 9<br/>- ERROR_INVALID_AFFILIATE_KEY = 10<br/>- ERROR_ALREADY_LOGGED_IN = 11<br/>- ERROR_INVALID_AMOUNT_DECIMALS = 12<br/>- ERROR_API_LEVEL_TOO_LOW = 13<br/>- ERROR_CARD_READER_SETTINGS_OFF = 14<br/>- ERROR_UNKNOWN_TRANSACTION_STATUS = 15 |
| **SumUpAPI.Response.MESSAGE**                      | String                                                 | A human readable message describing the result of the payment                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| **SumUpAPI.Response.TX_CODE**                      | String                                                 | The transaction code associated with the payment                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
| **SumUpAPI.Response.TX_INFO**                      | Parcelable (com.sumup.merchant.Models.TransactionInfo) | Transaction info object containing information about the transaction:<br/>- Transaction Code<br/>- Merchant Code<br/>- Amount (including tip amount and VAT)<br/>- Tip amount<br/>- VAT<br/>- Currency (e.g. EUR)<br/>- Payment Status (PENDING \| SUCCESSFUL \| CANCELLED \| FAILED)<br/>- Payment Type (CASH \| POS \| ECOM \| UNKNOWN \| RECURRING \| BITCOIN \| BALANCE)<br/>- Entry Mode (e.g. CHIP)<br/>- Number of Installments<br/>- Card Type (e.g. MASTERCARD)<br/>- Last four digits of the card<br/>- Product information                         |
| **SumUpAPI.Response.RECEIPT_SENT**                 | boolean                                                | true if a receipt was issued to the customer, false otherwise                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| **SumUpAPI.Response.CARD_READER_MODEL**            | String                                                 | The model of the card reader used for the transaction                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| **SumUpAPI.Response.CARD_READER_FIRMWARE_VERSION** | String                                                 | The firmware version of the card reader used for the transaction                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |

The response flags are provided within the Bundle that is passed back to the callback activity:

```java
 	int resultCode = getIntent().getExtras().getInt(SumUpAPI.Response.RESULT_CODE);
```

### Card Reader Page

When a merchant is logged in, you can open this activity to access all the settings and options related to the card reader.

- Connect to new readers.
- View the reader attributes when previously connected i.e. Battery percentage, Serial number, Last three digits of serial number, Software version.
- Connect to the last saved reader if it is inactive.
- Update firmware of the reader if available.
- Visual illustration of the saved reader with its current connectivity status and name.

```java
 	SumUpAPI.openCardReaderPage(MainActivity.this, 4);
```

<Image
  alt="Card Reader Page"
  src="/img/guides/android_sdk_reader_view.png"
  width="40%"
/>

### Preparing the SumUp Card Terminal for Checkout

`prepareForCheckout()` offers the possibility to connect the card reader ahead of initiating the checkout which speeds up the overall checkout time.

To call this method, user needs to be logged in with a SumUp account and their card reader should already be setup. Next, call `prepareForCheckout()` before initiating a checkout.

```java
SumUpAPI.prepareForCheckout()
```

> Note: Air and Solo card readers remain connected via BLE after each transaction while `prepareForCheckout()` is used when the card reader becomes disconnected (e.g. the reader is out of range, the host app looses focus, or the reader is turned off).

### Additional Checkout Parameters

When setting up the `SumUpPayment` object, the following optional parameters can be included:

#### Tip Amount

A tip amount can be processed in addition to the `total` using the `tip` parameter. The tip amount will then be shown during the checkout process and be included in the response. Please note that a tip amount cannot be changed during/after the checkout.

##### Tip on Card Reader

This allows the customer to add a tip directly on the card reader, rather than prompting for a tip amount on the Android device.

A tip amount can be prompted directly in the card reader by using `tipOnCardReader` parameter, if the card reader supports tipping. See the [tipOnCardReader payment example](https://github.com/sumup/sumup-android-sdk#4-make-a-payment) for this field.

<Aside>
Not all card readers support this feature. To find out if the feature is supported for the last-saved card reader, you should always check `SumUpApi.isTipOnCardReaderAvailable()`. You must handle this case yourself in order to avoid no tip from being prompted.

Please also note that if both `tip` and `tipOnCardReader` are called then only `tipOnCardReader` amount will be considered during checkout if available.
</Aside>

#### Timeout on Success Screen

Use `.successScreenTimeout(int seconds)` to configure how long the success screen is displayed. The screen will automatically dismiss after the specified duration if the user has not closed it manually. The value must be greater than 0.

#### Retry Policy Configuration

The `configureRetryPolicy()` feature allows you to set custom retry parameters for transaction result retrieval, using `pollingInterval`, `maxWaitingTime`, and `disableBackButton`.

- Parameters: Both `pollingInterval` and `maxWaitingTime` should be provided in milliseconds, with default values of 2000 ms and 60000 ms, respectively. Setting `disableBackButton` to true disables the back button during retries.
- Timeout: If `maxWaitingTime` elapses with no result, the SDK returns `SumUpAPI.ResultCode.ERROR_UNKNOWN_TRANSACTION_STATUS`. Pressing the back button (if enabled) during retries will also trigger this error.
- Adjustments: If `pollingInterval` exceeds `maxWaitingTime`, `maxWaitingTime` will automatically be adjusted to match. Negative values for either parameter default to 0.
- Default: If `configureRetryPolicy()` is not used, the SDK defaults to returning `SumUpAPI.ResultCode.ERROR_TRANSACTION_FAILED`.

##### Querying the Transaction Status

When using the SumUp payment as shown below:

```java
SumupPayment.builder()
...
.foreignTransactionId(UUID.randomUUID().toString())
.configureRetryPolicy(2000, 60000, true)
.build();
```

If there are connectivity issues and the transaction status can not be retrieved, the API will return `ERROR_UNKNOWN_TRANSACTION_STATUS`. In such cases, you can query the transaction status by calling [SumUp transaction status API](https://developer.sumup.com/api/transactions/get) using the specified `foreignTransactionId`.

#### Transaction Identifier

The `foreignTransactionID` identifier will be associated with the transaction and can be used to retrieve details related to the transaction. See [API documentation](https://developer.sumup.com/rest-api/#tag/Transactions) for details. Please make sure that this ID is unique within the scope of the SumUp merchant account and sub-accounts. It must not be longer than 128 characters.
The foreignTransactionID is available when the callback activity is called: `SumUpAPI.Param.FOREIGN_TRANSACTION_ID`

#### Skip Success Screen

To skip the success screen shown at the end of a successful transaction, the `skipSuccessScreen` parameter can be used. When using this parameter, your application is responsible for displaying the transaction result to the customer. In combination with the Receipts API your application can also send your own receipts, see [API documentation](https://developer.sumup.com/rest-api/#tag/Receipts) for details. Please note success screens will still be shown when using the SumUp Air Lite readers.

#### Skip Failed Screen

To skip the failed screen shown at the end of a failed transaction, the `skipFailedScreen` parameter can be used. When using this parameter, your application is responsible for displaying the transaction result to the customer. Please note failed screens will still be shown when using the SumUp Air Lite readers.

### Transparent Authentication

To authenticate an account without the user typing in their SumUp credentials each time, you can generate an access token using the OAuth 2.0 authorization code flow and use it to transparently log in to the Android SDK.

```java
SumUpLogin sumupLogin = SumUpLogin.builder(mAffiliateKey).accessToken("MY_ACCESS_TOKEN").build();
SumUpAPI.openLoginActivity(MainActivity.this, sumupLogin, 1);
```

For information about how to obtain a token, please see the [Authorization Documentation](/tools/authorization/).

If the token is invalid, `SumUpAPI.Response.ResultCode.ERROR_INVALID_TOKEN` is returned.

### Retrieve Data of the Active Merchant Account

If a merchant account is currently logged in, it is possible to retrieve the data for this account.

```java
	if (!SumUpAPI.isLoggedIn()) {
		// no merchant account currently logged in
	} else {
		Merchant currentMerchant = SumUpAPI.getCurrentMerchant();
	}
```

### Retrieve Connected Card Reader's Data

You can check the connection status and retrieve details about the saved card reader using the following methods:

- **`isCardReaderConnected()`**: Returns a `boolean` indicating whether a card reader is currently connected.
- **`getSavedCardReaderDetails()`**: Returns an object containing the reader's serial number, type, and last known battery percentage.

#### Supported Reader Types

The reader type returned by `getSavedCardReaderDetails()` will be one of the following constants:

- `SOLO`
- `SOLO_LITE`
- `AIR`
- `THREE_G`
- `PIN_PLUS`
- `UNKNOWN` — returned only if the SDK encounters an issue and cannot identify the reader type.

<Aside>
  The `lastKnownBatteryPercentage` is **not** real-time. It reflects the battery level recorded during the last transaction. As a result, this value may not match the current battery level exactly if the reader has been idle or charged since the last payment.
</Aside>

### Enable ProGuard

```groovy
   buildTypes {
        release {
            // All ProGuard rules required by the SumUp SDK are packaged with the library
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android.txt')
        }
    }
```

### Use Google Location Services

The SDK supports Google Location Services, to improve location accuracy and reduce power consumption.

In order to use it you need to add the dependency in `build.gradle` file

```groovy
implementation "com.google.android.gms:play-services-location:19.0.1"
```

If the GLS dependency is not added to the project or Google Play Services are not installed on the mobile device, the Android SDK will determine the location with the default Location Service provided by Android.

<Aside>
  Using GLS version 19.0.1 is recommended.
</Aside>

## Sample App

SumUp provides a sample app which implements main SDK components. You can find the app under [App directory](https://github.com/sumup/sumup-android-sdk/tree/master/app) of the repository.

## Out of Scope

The following functions are handled by the [SumUp APIs](/api/):

- [Refunds](/api/transactions/refund/)
- [Transaction history](/api/transactions/list/)
- [Receipts](/api/receipts/get/)
- [Account management](/api/merchant/)
- [Online Payments](/online-payments/)

## Community

- **Questions?** Get in contact with our integration team by sending an email to
  <a href="mailto:integration@sumup.com">integration@sumup.com</a>.
- **Found a bug?** [Open an issue](https://github.com/sumup/sumup-android-sdk/issues/new).
  Please provide as much information as possible.

## Changelog

See the [SumUp Changelog](/changelog/) for updates.

## License

See [SumUp Android SDK License](https://github.com/sumup/sumup-android-sdk/blob/master/LICENSE.md).