Android Native SDK Integration

Accept payments in android app


Integrate Durianpay Checkout with your android app to start accepting online payments from your customers. Durianpay supports a slew of payment methods such as bank transfers/VA, credit and debit cards, e-wallets (OVO, DANA, LinkAja) and others. Our checkout library provides all the essential features for integrating Durianpay Checkout with the client-side of your application.

Please note that this document only talks about android integration.

Preparation

  1. Create a Durianpay account

    If you haven't done it already, click here to sign up. Sign up for Durianpay account here to retrieve API keys for Sandbox environment and to test integrations end-to-end.

  2. Generate API Keys

    Retrieve Sandbox API keys that will be used in next section(s) It is okay to have only the sandbox key for now. If you have live key, you can use it too.

  3. Have access to the Durianpay android SDK depending your implementation requirement - *.aar (for Java and Kotlin both codebases). Put the aar sdk file in libs/ folder.

Sample Durianpay SDK filename id.durianpay.android:durianpaysdk:<version>@aar

Steps Overview

Step 1: Setting up Android sdk

Add the following lines in project level android/build.gradle file to add a repository to get the android sdk:

# Previous version of Android Studio 
allprojects {
    repositories {
        maven { url 'https://jitpack.io' }
    }
}
# For Android Studio Arctic Fox or latest add the repository in your settings.graddle instead
dependencyResolutionManagement {
    repositories {
        ...
        maven { url 'https://jitpack.io' }
    }
}

In your app build.gradle file, add the following dependency:

dependencies {
    implementation 'com.github.durianpay:android-sdk:v1.5.3'
}

Step 2: Add implementations to your Activity Class

Add CheckoutResultListener implementation to your Activity class as follows

class Activity extends AppCompatActivity implements CheckoutResultListener {
    ...
}

Step3: Create an order/token from the server

Use following endpoint to create an order

/orders
server.js
var options = {
  amount: "20000",
  currency: "IDR",
  order_ref_id: "order2314",              // optional, your order reference
  customer: {
    customer_ref_id: "cust_001",          // optional, your customer reference
    given_name: "Imam Sugiarto",
    email: "imam.sugiarto@koss.info",     // mandatory
    mobile: "08972638003",
    address: {                            // mandatory for BNPL
        receiver_name: "Jude Casper",
        receiver_phone: "8987654321",
        label: "Judes Address",
        address_line_1: "Cambridge layout",
        address_line_2: "Apartment #786",
        city: "Bangalore",
        region: "Jogupalya",
        country: "Indonesia",
        postal_code: "560008",
        landmark: "Kota Jakarta Selatan"
    }
  },
  items: [
    {
        "name": "LED Television",
        "qty": 1,
        "price": "925001.55",
        "logo": "/static/tv_image.jpg"
    }
  ]
};
// Create Orders 
dpay.orders.create(options).then(resp => {
    console.log(resp);
    // order_id = resp.order_id;
})
.catch(error => {
    console.log(error.err + ' | ' + JSON.stringify(error.data));
});
Response
// Sample response
{
  "id": "ord_A31sd3AwAgItmmXdp",
  "customer_id": "cus_rX2ABaMbZJ0050",
  "amount": "20000",
  "currency": "IDR",
  "payment_option": "full_payment",
  "status": "started",
  "order_ref_id": "order2314",
  "address_id": 3863,
  "created_at": "2021-08-04T06:06:37.849813Z",
  "updated_at": "2021-08-04T06:06:37.849813Z",
  "metadata": {},
  "access_token": "adsyoi12sdASd123ASX@qqsda231",
  ...
}

Read more: Learn more about Orders API.

Step 4: Pass Context, options with orderID and CheckoutListener to Durianpay Checkout

Create a data class DCheckoutOptions with below variables where either customer_id or (customer_name and customer email) can be used. amount and paymentType are optional variables which are necessary only for an installment type of payment. The paymentType can have the values full_payment or installment which can be passed according to the type of payment. Default value is full_payment.

DCheckoutOptions options = new DCheckoutOptions();
options.setEnvironment("production");
options.setLocale("en");
options.setSiteName("Movie Ticket);
options.setCustomerId("cus_Das2XXXXXXXXX");
options.setCustomerEmail("mario@supermario.net");
options.setCustomerGivenName("John Doe");
options.setOrderId("ord_HdmXXXXXXXXX");
options.setAccessToken("d59XXXXXXXXXXXX");
options.setCurrency("IDR");  
options.setAmount("25000");  
options.setPaymentType("full_payment");                  //optional
options.setLabel("home");                                //optional 
options.setCustomerAddressLine1("ramnagar, kayembedu");  //optional
options.setCustomerCity("chennai");                      //optional
options.setCustomerCountry("india");                     //optional
options.setCustomerRegion("asia");                       //optional
options.setCustomerPostalCode("523323");                 //optional
options.setReceiverName("dhanraj");                      //optional
options.setReceiverPhone("8999998999");                  //optional
options.setCustomerMobile("8939983823");                 //optional
options.setLandmark("avenue east");                      //optional
options.setDarkMode(true)                                //optional (Set to true to enable dark mode. This is available for Android 10 and above only. For Android 9 and below, using this field will not throw errors, but dark mode will not be enabled)

Pass the data class to Durianpay checkout as shown below where the third parameter is the CheckoutResultListener -

Durianpay.getInstance(this).checkout(checkoutOptions, this);

Step5: Handle callbacks payment success and failures

The methods implemented from the CheckoutResultListener will be onSuccess(), onFailure() and onClose() which have to be handled as:

/* Sample response
{
    "type":"success",
    "response": {
        ...
        "payment_id":"pay_XXXXXXXX",
        "payment_metadata":{},
        "payment_method_used":"none",
        "order_id":"ord_XXXXXXX",
        "amount":"15000.00",
        "currency":"IDR",
        ...
    }
}
*/

@Override
public void onSuccess(DPaymentSuccess s) {
    Log.d("callbackSuccess", s.getResponse?.getPaymentId.toString());
    Toast.makeText(this, "Payment Success", Toast.LENGTH_SHORT).show();
}

@Override
public void onFailure(DPaymentFailed s) {
    Log.d("callbackFailure", s?.getResponse?.getPaymentId.toString());
    Toast.makeText(this, "Payment Failed", Toast.LENGTH_SHORT).show();
}

@Override
public void onClose(String s) {
    Toast.makeText(this, "Payment closed before completion", Toast.LENGTH_SHORT).show();
}

Step6: Webhooks / Store fields on your servers (Optional)

Whenever certain transaction actions occur on your Durianpay Checkout integration, we trigger events which your application can listen to. This is where webhooks come in. A webhook is a URL on your server where we send payloads for such events. For example, if you implement webhooks, once a payment is successful, we will immediately notify your server with a payment.completed event. Here is a list of events we can send to your webhook URL.

You can specify your webhook URL on your dashboard (or through your dedicated Customer success manager) where we would send POST requests to whenever an event occurs.

Valid events

payment.completed payment.failed, payment.cancelled, order.created, order.completed

payment.completed
{  
  "event": "payment.completed",
  "data":{  
    "id": "pay_dAS123ad123Asd",
    "signature": "9e892f199d026d06a56669e658a56f264610431d24e8b4d07f7bd46f6d5062d2",
    "order_id": "ord_XXXXXXXXX",
    "amount": "10000",
    "currency": IDR,
    "paid_at": "2016-09-30T21:10:19.000Z",
    "created_at":"2016-09-30T21:09:56.000Z",
    "metadata": {
      "key": "value"
    },
}

Step7: Verify signature on your server side (Optional)

You will get payment_id through webhook callback (if configured). You should ideally try to validate the payment and store the details in your server/database against the order/transaction accordingly.

First, you need to get verification signature from Durianpay which would have been provided to you in your webhook callback.

{  
  "event": "payment.completed",
  "data":{  
    "id": "pay_dAS123ad123Asd",
    "signature": "9e892f199d026d06a56669e658a56f264610431d24e8b4d07f7bd46f6d5062d2",    ...
}

If you didn't receive it for any reason, you can call payment status check API from your server/backend which will respond back with signature if status of payment is completed.

/payments/:id/status
"status": "completed",
"is_completed": true,
"signature": "9e892f199d026d06a56669e658a56f264610431d24e8b4d07f7bd46f6d5062d2"

This signature is computed by us using payment_id, amount and your secret key. You need to create the hash on your server/backend where you have all these elements and match with the signature provided by us.

Sample code for signature generation

// Function to generate the signature for verification of payment
//use appropriate key if it is a sandbox order please use dp_test key and if it is a live order then use dp_live key
func GenerateSignature(paymentID string, amount string, accessKey string) (generatedSignature string) {
  //message passed includes payment_id + “|” + amount. Amount is in “15000.00” format
  secretData := paymentID + "|" + amount
  // Create a new HMAC by defining the hash type and the key (as byte array)
  h := hmac.New(sha256.New, []byte(accessKey))
  // Write Data to it
  h.Write([]byte(secretData))
  // Get result and encode as hexadecimal string
  generatedSignature = hex.EncodeToString(h.Sum(nil))
  return
}

Test Integration

Test payments

You can use following test payment credentials to test payments.

Verify Payment status

Through Dashboard

  1. Log into the Dashboard and navigate to Payments in sidebar.
  2. Check if a payment_id has been generated. If no payment_id has been generated, it means that the transaction has failed (and didn't even initiate from user's end)
Durian Dashboard 1

Through APIs

Use following endpoint to do status check on a payment (Read more about Payment Status Check API)

/payments/:id/status
curl -u <YOUR_SECRET_KEY> \
-X GET https://api.durianpay.id/v1/payments/pay_B14sdfwAdmmSDF24a/status \
-H "content-type: application/json"'
Response
{
    "data": {
        "status": "completed",
        "is_completed": true,
        "signature": "9e892f199d026d06a56669e658a56f264610431d24e8b4d07f7bd46f6d5062d2"
    }
}

Accept LIVE payments

After testing the flow of funds end-to-end in sandbox mode, you can switch to the live mode and start accepting payments from your customers. However, make sure that you swap the test API keys with the live keys.

  1. Log into Dashboard and switch to Live mode on the sidebar menu.
  2. Navigate to Settings → API Keys to access your API key for live mode.
  3. Replace the sandbox API key with the Live Key in the Checkout code and start accepting real-time payments.