Changelog

How to integrate with Android SDK

Follow the guide to set-up Android SDK integration

Required Flow

Before starting the integration with our Android SDK, it is important to understand the overall flow of requests coming from the SDK to Dapi's system. In addition to setting up the Android SDK, you will also need to configure a backend server. The purpose of the backend server is to provide an extra layer of security and allow you to confirm the information on your backend if required by your use case.

330

Flow with the Android SDK.

Setting-up App Backend Server (Node.js)

If you are not interested in setting up the server using Node.js, you can refer to the Server set-up for SDKs and follow any quickstart instructions for a different language.

Install npm libraries in your project

npm i @dapi-co/dapi-node
npm i express
npm i cors

Save the following file as server.js. You might need to install the other dependencies if they don't already exist on your machine.

var express = require('express')
const DapiApp = require('@dapi-co/dapi-node')
var cors = require('cors')

const app = express()
const port = 8060 // default port to listen
app.use(cors())
app.use(express.json())

const dapi = new DapiApp.default({
  appSecret: 'YOUR_APP_SECRET',
})

// define a route handler for the sdk
app.post('/dapi', async (req, res) => {

  try {
    
    const dapiResponse = await dapi.handleSDKDapiRequests(req.body, req.headers)
    res.send(dapiResponse)

  } catch (error) {

    //Handle Network Errors
    console.dir(error)
  }
})

// start the Express server
app.listen(port, () => {
  console.log(`server started at http://localhost:${port}`)
})

In the directory of server.js use the following command to run the server:

node server.js

Once the server is running successfully, also make sure to add the App Server URL to the Dapi Dashboard. In this way, the SDK will automatically know where to send its requests to.

If you followed the above NodeJS and Express example the App Server URL value is http://localhost:8060/dapi.

1836

After adding App Server URL on Dapi Dashboard

You are now all set to start your Android integration!

Android SDK Example

Clone this repository, run the application and see Dapi in action.

Android SDK Configuration

Install SDK

Open Gradle Scripts | build.gradle (Module: app) and do the following:

  1. Add the following to the dependencies {} section of your build.gradle (module: app) file to compile the latest version of the Connect SDK:
implementation "co.dapi:connect:2.26.0"
  1. Save and close build.gradle (Module: app).

  2. Build your project. Now you can start the SDK

Start SDK

  1. Open your application class file and import Dapi there
import co.dapi.connect.core.base.Dapi
import co.dapi.connect.core.base.Dapi;
  1. Start the SDK with your configuration in onCreate method
val configurations = DapiConfigurations(
    environment = DapiEnvironment.PRODUCTION, //Or DapiEnvironment.SANDBOX for testing
    countries = arrayOf("AE", "EG", "JO", "US"), 
    extraBody = hashMapOf(Pair("key1", "value1"), Pair("key2", "value2")), //Body added to all requests
    extraQueryParameters = hashMapOf(Pair("key1", "value1"), Pair("key2", "value2")), //Query parameters added to all requests
    extraHeaderFields = hashMapOf(Pair("key1", "value1"), Pair("key2", "value2")) // Header fields added to all requests
)

Dapi.start(
	application = this,
	appKey = "ABC",
	clientUserID = "JohnDoe",
	configurations = configurations,
	onSuccess = {
	},
	onFailure = { error ->
		
	}
)
DapiConfigurations configurations = new DapiConfigurations();
configurations.setEnvironment(DapiEnvironment.PRODUCTION);
configurations.setCountries(new String[]{"AE", "EG", "JO", "US"});

Dapi.start(this, "ABC", "JohnDoe", configurations, () -> {
    return null;
}, error -> {
    return null;
});

In case you get App config not found error double check your applicationId is the same as the bundleID you set on the dashboard.

  1. Open your build.gradle file
  2. Copy the value of applicationId
1474
  1. Open your app in the dashboard
  2. Go to App Settings -> Bundle IDs
  3. Click on the + icon, paste the copied value and click Submit
1388

Destroy SDK

Clean up all the SDK's resources

Parameters
Method does not receive any parameter.

Example

Dapi.destroy()

Create Bank Connection

Let's now create a connection object. A connection represents a user's connection to a bank. So if they authenticate and login, through Dapi, to 2 banks there will be 2 connections.
Since you don't know yet which bank the user will choose, you will just display the connect page. The user has to then pick the bank and enter their credentials.

Dapi.presentConnect()
Dapi.presentConnect();
762

Bank selection

748

Credentials

Implement DapiConnectCallback to handle a successful or a failed connection attempt.

Dapi.connectCallback = object : DapiConnectCallback {
    override fun onConnectionSuccessful(result: DapiConnectResult.Success) {
        
    }

    override fun onConnectionFailure(result: DapiConnectResult.Error) {
        
    }

    override fun onBankRequest(result: DapiConnectResult.BankRequest) {
        
    }

    override fun onDismissed() {
        
    }
}
Dapi.setConnectListener(new OnDapiConnectListener() {
    @Override
    public void onConnectionSuccessful(@NonNull DapiConnection connection) {

    }

    @Override
    public void onConnectionFailure(@NonNull DapiError error, @NonNull String bankID) {

    }

    @Override
    public void onBankRequest(@NonNull String bankName, @NonNull String iban) {

    }

    @Override
    public void onDismissed() {

    }
});

That's it. You can now try to run your app on the emulator and call the presentConnect function and see Dapi in action!

Create Sandbox User

You can create users for sandbox environment to test your integration with Dapi instead of connecting your real accounts

Navigate to Dashboard -> Apps -> Your App -> Sandbox -> Create a Sandbox User

Enter the following details and click Submit.

  • Sandbox Bank: select a bank from the dropdown list
  • Sandbox Username : username of your choice
  • Sandbox Password : password of your choice
1384

In order to add accounts to a sandbox user, click the NEW button on the Accounts column and provide the following information:

  • Acount Name: user's account name (You can see it on the Account Information dialog when you click an account from the Sandbox Users table.)
  • Account Number: user's account number (You can see it on the Account Information dialog)
  • IBAN: user's IBAN (You can see it on the Account Information dialog)
  • Account Type: choose a value from the dropdown
  • Balance: set a starting balance for the account
  • Currency: choose the currency for the account from the dropdown
1388

Get Cached Connections

When you authenticate and login through Dapi, a DapiConnection object is created and stored in the local cache containing information about your connection to the bank, so that you don't have to authenticate and login again every time you open the app.

Dapi.getConnections() returns the list of connections in cache.

Dapi.getConnections({ connections -> 
    if (connections.isNotEmpty()) {
        val connection = connections.first()
        val accounts = connection.accounts //cached accounts. gets updated by connection.getAccounts() call
        val cards = connection.cards //cached cards. gets updated by connection.getCards() call
        val clientUserID = connection.clientUserID
        val userID = connection.userID
        val bankId = connection.bankId
        val swiftCode = connection.swiftCode
        val country = connection.country
        val name = connection.name
        val fullName = connection.fullName
        val fullLogoPng = connection.fullLogoPng
        val halfLogoPng = connection.halfLogoPng
        val miniLogoPng = connection.miniLogoPng
        val accessCode = connection.accessCode
        val connectionID = connection.connectionID
        val tokenID = connection.tokenID
        val color = connection.color
    }
}, { error ->
    
})
Dapi.getConnections((connections) -> {
    DapiConnection connection = connections.get(0);
    List<DapiAccountsResponse.DapiAccount> accounts = connection.getAccounts(); //cached accounts. gets updated by connection.getAccounts(onSuccess, onFailure) call
    List<DapiCardsResponse.DapiCard> cards = connection.getCards(); //cached cards. gets updated by connection.getCards(onSuccess, onFailure) call
    String clientUserID = connection.getClientUserID();
    String userID = connection.getUserID();
    String bankId = connection.getBankId();
    String swiftCode = connection.getSwiftCode();
    String country = connection.getCountry();
    String name = connection.getName();
    String fullName = connection.getFullName();
    String fullLogoPng = connection.getFullLogoPng();
    String halfLogoPng = connection.getHalfLogoPng();
    String miniLogoPng = connection.getMiniLogoPng();
    String accessCode = connection.getAccessCode();
    String connectionID = connection.getConnectionID();
    String tokenID = connection.getTokenID();
    Map<String, String> color = connection.getColor();
    return null;
}, (error) -> {
    return null;
});

Dismiss Connect

Closes the presented Connect UI

Parameters

Method does not receive any parameter.

Example

Dapi.dismissConnect()

Get Parameters

A method for obtaining the connection parameters

Parameters

Method does not receive any parameter.

Example

connection.getParameters({ parameters ->
    
}, { error ->
    
})

Create Connection

Add a new connection based on connection parameters.

Parameters

ParameterDescription
jsonConnectionParametersDapiConnection's parameters, can be obtained using connection.getParameters()

Example

DapiConnection.create(parameters, { connection ->
    
}, { error ->
    
})

Android SDK Reference

Payment Endpoints

createTransfer()

A method for creating a transfer. Can be used to make a payment:

  • from the user's account to your own account
  • from the user's account to another external account

So in a nutshell, you can send money from an account to an account with a specific amount.All 3 variables are optional.

Parameters

📘

Note

Behavior of the SDK depends on the parameters that will be set.

ParameterDescription
toBeneficiaryIf you are accepting a transfer into your own company's account, you don't need to set the parameter. You can simply add one in your dashboard under your app. The toBeneficiary will automatically be set to that account.
fromAccountAccount from where the amount must be transferred. If you don't set a from account, SDK will simply display a popup screen for your user to pick the account from our UI.
If you do provide a from object, this screen won't be displayed.
amountAmount to be transferred. If you don't set an amount SDK will display a screen with a numpad screen for your user to enter the amount in.
remarkA message associated with the transfer.

Implement DapiTransferCallback to handle a successful or a failed transfer attempt.

Dapi.transferCallback = object : DapiTransferCallback {

    override fun onTransferSuccess(result: DapiTransferResult.Success) {
        
    }

    override fun onTransferFailure(result: DapiTransferResult.Error) {
        
    }
    
    override fun willTransferAmount(result: DapiTransferResult.PreTransfer) {
        
    }

    override fun onUiDismissed() {
        
    }
}
Dapi.setTransferListener(new OnDapiTransferListener() {
    @Override
    public void willTransferAmount(double amount, @NonNull DapiAccountsResponse.DapiAccount senderAccount) {

    }

    @Override
    public void onTransferSuccess(@NonNull DapiAccountsResponse.DapiAccount account, double amount, @Nullable String reference, @Nullable String operationID) {

    }

    @Override
    public void onTransferFailure(@Nullable DapiAccountsResponse.DapiAccount account, @NonNull DapiError error) {

    }

    @Override
    public void onUiDismissed() {

    }
});

Example - When toBeneficiary Is Not Specified

Here we will pick the first account in the connection object. Remember, a bank connection might have several accounts, so the accounts object is a list. You will need to pick which account you're sending from.

connection.createTransfer(
    fromAccount = connection.accounts?.first(),
    amount = amount
)
connection.createTransfer(connection.getAccounts().get(0), null, amount);

Example - When toBeneficiary Is Specified

We first need to create a new Object called Beneficiary. We will then need to set a few details about the bank account we're sending the money to.

val lineAddress = LinesAddress()
lineAddress.line1 = "baniyas road"
lineAddress.line2 = "dubai"
lineAddress.line3 = "united arab emirates"

val beneficiary = DapiBeneficiary(

address = lineAddress,
accountNumber = "0959040184901",
name = "John Doe",
nickname = "John ENBD",
bankName = "Emirates NBD Bank PJSC",
swiftCode = "EBILAEAD",
iban = "AE140260000959040184901",
country = "AE",
branchAddress = "Baniyas Road Deira PO Box 777 Dubai UAE",
branchName = "Emirates NBD Bank PJSC",
phoneNumber = "+0585859206"

)

connection.createTransfer(
	fromAccount = connection.accounts?.first(),
	toBeneficiary = beneficiary,
	amount = amount
)
LinesAddress lineAddress = new LinesAddress();
lineAddress.setLine1("baniyas road");
lineAddress.setLine2("dubai");
lineAddress.setLine3("united arab emirates");

DapiBeneficiary beneficiary = new DapiBeneficiary(
        lineAddress,
        "0959040184901",
        "John Doe",
        "Emirates NBD Bank PJSC",
        "EBILAEAD",
        "AE140260000959040184901",
        "UNITED ARAB EMIRATES",
        "Baniyas Road Deira PO Box 777 Dubai UAE",
        "Emirates NBD Bank PJSC",
        "+0585859206"
);

connection.createTransfer(connection.getAccounts().get(0), beneficiary, amount);

Example - When fromAccount Is Not Specified

connection.createTransfer(
    amount = amount
)
connection.createTransfer(null, null, amount);

The SDK shows UI for the user to select an account to send money from

762

Account Selection Screen

Example - When amount Is Not Specified

connection.createTransfer(
    fromAccount = connection.accounts?.first(),
)
connection.createTransfer(connection.getAccounts().get(0));

The SDK shows UI for the user to enter the amount to send

752

Amount Screen

Example - No arguments

connection.createTransfer()
connection.createTransfer();

The SDK shows UI for the user to select an account to send money from then navigate to the amount screen to enter the amount to send

762 752

createTransferToExistingBeneficiary()

A method for sending money to an existing beneficiary.

Parameters

ParameterDescription
fromAccountAccount from where the amount must be transferred.
toBeneficiaryIDThe id of the beneficiary to which the money must be transferred. Obtain by connection.getBeneficiaries()
amountAmount to be transferred

Example

connection.getBeneficiaries({ beneficiariesResponse ->
    connection.createTransferToExistingBeneficiary(
        fromAccount = connection.accounts!!.first(),
        toBeneficiaryID = beneficiariesResponse.beneficiaries!!.first().id,
        amount = amount,
    )
}, { error ->

})
connection.getBeneficiaries((beneficiariesResponse) -> {
    connection.createTransferToExistingBeneficiary(
            connection.getAccounts().get(0),
            beneficiariesResponse.getBeneficiaries().get(0).getId(),
            amount
    );
    return null;
}, (error) -> {
    return null;
});

🚧

Beneficiary Not Activated error on Sandbox

This error occurs If you make a transfer on Sandbox to wrong or random beneficiary details, instead you should make the beneficiary details to be of another sandbox user.

To get the beneficiary details of a sandbox user you can do the following:

1- Open your app on the dashboard and navigate to the Sandbox tab. You'll see the Sandbox Users table.
2- Click an account from the Accounts column.
3- A pop up shows up containing beneficiary details.

1380

Sandbox Account Beneficiary details

createBeneficiary()

A method for adding a new beneficiary

Parameters

ParameterDescription
beneficiaryInformation of the beneficiary to add.

Example

val lineAddress = LinesAddress()
lineAddress.line1 = "baniyas road"
lineAddress.line2 = "dubai"
lineAddress.line3 = "united arab emirates"

val beneficiary = DapiBeneficiary(

address = lineAddress,
accountNumber = "0959040184901",
name = "John Doe",
nickaname = "John Doe ENBD",
bankName = "Emirates NBD Bank PJSC",
swiftCode = "EBILAEAD",
iban = "AE140260000959040184901",
country = "AE",
branchAddress = "Baniyas Road Deira PO Box 777 Dubai UAE",
branchName = "Emirates NBD Bank PJSC",
phoneNumber = "+0585859206"

)

connection.createBeneficiary(
    beneficiary = beneficiary,
    onSuccess = { createBeneficiaryResponse ->

    },
    onFailure = { error ->
                    
    }
)
LinesAddress lineAddress = new LinesAddress();
lineAddress.setLine1("baniyas road");
lineAddress.setLine2("dubai");
lineAddress.setLine3("united arab emirates");

DapiBeneficiary beneficiary = new DapiBeneficiary(
        lineAddress,
        "0959040184901",
        "John Doe",
        "Emirates NBD Bank PJSC",
        "EBILAEAD",
        "AE140260000959040184901",
        "UNITED ARAB EMIRATES",
        "Baniyas Road Deira PO Box 777 Dubai UAE",
        "Emirates NBD Bank PJSC",
        "+0585859206"
);

connection.createBeneficiary(beneficiary, (createBeneficiaryResponse) -> {
    return null;
}, (error) -> {
    return null;
});

getBeneficiaries()

A method for obtaining registered beneficiaries

Parameters

Method does not receive any parameter.

Example

connection.getBeneficiaries({ beneficiariesResponse ->
                    
}, { error ->
                    
})
connection.getBeneficiaries((beneficiariesResponse) -> {
    return null;
}, (error) -> {
    return null;
});

Metadata Endpoints

getAccountsMetaData()

A method for obtaining bank account metadata

Parameters

Method does not receive any parameter.

Example

connection.getAccountsMetaData({ accountsMetaDataResponse ->
                    
}, { error ->
                    
})
connection.getAccountsMetaData((accountsMetaDataResponse) -> {
    return null;
}, (error) -> {
    return null;
});

Data Endpoints

getAccounts()

A method for obtaining and displaying bank accounts of the user

Parameters

Method does not receive any parameter.

Example

connection.getAccounts(
	onSuccess = { accounts ->  
                      
	}, 
	onFailure = { error -> 
                            
})
connection.getAccounts((accounts) -> {
    return null;
}, (error) -> {
    return null;
});

getIdentity()

Get the identity information that has been confirmed by the bank.

These are the identity details that you will get. Not all banks provide all this data. So we will provide as much of it as possible.

Parameters
Method does not receive any parameter.

Example

connection.getIdentity(
	onSuccess = { identity ->  
                        
	}, onFailure = { error ->
                        
})
connection.getIdentity((identity) -> {
    return null;
}, (error) -> {
    return null;
});

getCards()

A method for obtaining and displaying bank cards of the user

Parameters
Method does not receive any parameter.

Example

connection.getCards(
        onSuccess = {

        }, onFailure = {

})
connection.getCards((cards) -> {
    return null;
}, (error) -> {
    return null;
});

Account - getTransactions()

A method for obtaining and displaying transactions created from users bank accounts. The list will not be filtered. In other words, this will display all the transactions performed by the user from the specified account (not filtered by app).

Parameters

ParameterDescription
accountAccount from where the transaction was performed
fromDateStart date of transactions history range
toDateEnd date of transactions history range

Example

connection.getTransactions(
	account = connection.accounts!!.first(),
	fromDate = Date(),
	toDate = Date(),
	onSuccess = { transactions -> 

	},
	onFailure = { error -> 

	})
connection.getTransactions(connection.getAccounts().get(0), new Date(), new Date(), (transactions) -> {
    return null;
}, (error) -> {
    return null;
});

Card - getTransactions()

A method for obtaining and displaying transactions created from a card. The list will not be filtered. In other words, this will display all the transactions performed by the user from the specified account (not filtered by app).

Parameters

ParameterDescription
cardCard from where the transaction was performed
fromDateStart date of transactions history range
toDateEnd date of transactions history range

Example

connection.getTransactions(
	card = connection.cards!!.first(),
	fromDate = Date(),
	toDate = Date(),
	onSuccess = { transactions -> 

	},
	onFailure = { error -> 

	})
connection.getTransactions(connection.getCards().get(0), new Date(), new Date(), (transactions) -> {
    return null;
}, (error) -> {
    return null;
});

Enable Network Logging

Enable network logging to get full information on the requests happening inside the SDK.

  1. Open AndroidManifest.xml.
  2. Add the following code.
<application
     android:icon="@mipmap/ic_launcher"
     android:label="@string/app_name"
     android:roundIcon="@mipmap/ic_launcher_round"
     .
	 .
	 .>

      <!--enable logger-->
      <meta-data
          	android:name="co.dapi.networkLoggingEnabled"
            android:value="true" />
</application>

Launch in Production Checklist

This section highlights best practices and recommendations to help you achieve the best user experience with Dapi integration.

👍

ClientUserID configuration

ClientUserID is used to distinguish between different users on the same device. The value for ClientUserID needs to be set by you. We recommend setting clientUserID to your actual user ID that you use to distinguish between users. You should update the clientUserID once the user logs out and another user logs in.

Why? clientUserID is used to keep track of the bank connections in the cache.

👍

INVALID_CREDENTIALS or INVALID_CONNECTION

When receiving this error, the bank account should be connected again. Depending on your flow, you can do one or multiple of those steps:

  • Delete the connection connection.delete({}, {})
  • Prompt the user with Connect screen call Dapi.presentConnect() to reconnect the bank account. User selects the bank and logs in again.
  • Prompt the user with the same bank login screen Dapi.presentConnect(bankID) to reconnect the bank account. User can log in again to the same bank that was connected before and skips the bank choosing stage.

Why? This error indicates that the user has updated their online banking credentials. This means that also the linked bank account details should be updated. If your application continues to use outdated details, it may result in blocking the user's banking account.

To reproduce this error on Sandbox to test your implementation you can do the following:

1- Login to your sandbox account
2- Open your app on the dashboard and navigate to the Sandbox tab. You'll see the Sandbox Users table.
3- Delete the account you're currently logged in to.
4- Go back to the Dapi SDK and make any API call and it will return this error

2692

Delete Sandbox Account

👍

Bank IDs

If your logic is relying on bankIDs, then note that sandbox and production bankIDs are different. For example, ADCB:

  • Sandbox: DAPIBANK_AE_ADCB
  • Production: ADCBAEAA

👍

Do you have internal timeouts?

Do you usually have a default timeout for the requests going out of your application or server? It is possible that resolving a request with the bank can take longer. Dapi has an internal timeout at 2 minutes for any request.

Having a shorter timeout on your end can result in it occasional 504 errors.

👍

Proguard rules

Follow the below example to make sure that your own Proguard rules are not deforming Dapi's data types/

-keep class co.dapi.connect.data.endpoint_models.** { *; }
-keep class co.dapi.connect.data.models.** { *; }
-keep class co.dapi.connect.core.base.**{ *; }
-keep class co.dapi.connect.core.callbacks.DapiConnectCallback { *; }
-keep class co.dapi.connect.core.callbacks.DapiTransferCallback { *; }
-keep class co.dapi.connect.core.callbacks.DapiTransferResult { *; }
-keep class co.dapi.connect.core.callbacks.DapiConnectResult { *; }

Additional checklist for Payment API

👍

Special characters

Please double-check that you are only passing in alpha-numeric values in the beneficiary information. Including special characters in any of the fields will result in errors later on.

👍

BENEFICIARY_COOL_DOWN_PERIOD

Make sure you have handled the beneficiary cooldown period. Receiving this error means that beneficiary activation will take time from the bank side and the user must wait for the cooldown period to end before attempting the transfer again.

The exact time taken varies based on the user's bank. You can get the time take for the beneficiary to be active for any bank by using getAccountsMetaData API. You can for example use it to schedule a notification for the user to send money again when the beneficiary is activated.

Production Access

Once you have completed the above checklist here are the 2 simple steps to move your application from Sandbox to Production.

1. AppKey Permissions

Contact the Dapi team to give your existing appKey the permission to make calls in our Production environment.

2. Change the environment variable to DapiEnvironment.PRODUCTION

val configurations = DapiConfigurations(
    environment = DapiEnvironment.PRODUCTION, //used to be  DapiEnvironment.SANDBOX
    countries = arrayOf("AE", "EG", "JO", "US"), 
    extraBody = hashMapOf(Pair("key1", "value1"), Pair("key2", "value2")), //Body added to all requests
    extraQueryParameters = hashMapOf(Pair("key1", "value1"), Pair("key2", "value2")), //Query parameters added to all requests
    extraHeaderFields = hashMapOf(Pair("key1", "value1"), Pair("key2", "value2")) // Header fields added to all requests
)

Congratulations, you are all set with your Dapi integration!