Getting Started with Payments

Lean Payments API illustration

Overview

This guide will help you to get set up making payments between a customer and your default bank account. For advanced usage such as routing funds to different accounts, please see the Multi-Beneficiary and P2P guides respectively.

How does the Payments API work?

The Payment flow can be roughly broken down into four stages:

  1. Create a Payment Destination and Customer.
  2. Create an authorisation link (beneficiary) between their account and your account. This step can involve a cool down period dependent on the bank a user has connected.
  3. Create a 'contract' between Lean and your Application for the value you want to transfer between accounts, this is called a Payment Intent.
  4. Initiate Payment, your user confirms the amount they want to transfer from their account to your account and the payment is processed.

Create a Payment Destination

What is a Destination?

A Destination is a bank account that you want your customer to be able transfer money into.

Create a new Destination

Call the Destinations endpoint in the Payments API to create a new Destination resource:

Call

bash

curl -X POST 'https://sandbox.leantech.me/payments/v1/destinations' \
--header 'Content-Type: application/json' \
--header 'lean-app-token: YOUR_APP_TOKEN' \
--data-raw '{
"display_name": "Acme USD Account",
"name": "Acme Inc.",
"bank_identifier": "ENBD_UAE",
"address": "",
"city": "",
"country": "",
"account_number": "",
"iban": ""
}'

Response

bash

{
"id": "266733cc-6f46-4e87-af7e-9bb46b99601d"
"display_name": "Acme USD Account",
"name": "Acme Inc.",
"bank_identifier": "ENBD_UAE",
"address": "",
"city": "",
"country": "",
"account_number": "",
"iban": ""
}

You should store the ID of this Destination resource - as it will be used to determine where you route customer funds to in later stages.

Fetch a list of all destinations

If you would like to retrieve a list of all created Destinations in your application, you can make a GET request to the Destinations endpoint.

bash

GET https://sandbox.leantech.me/payments/v1/destinations

Create a Customer

In order to start fetching data, you first need to create a Customer resource. This creates a relationship between your application, user and all the services they consume within Lean into a single object.

To create a Customer, call the /customers/v1 endpoint with a reference to your app_user_id. You should save the returned customer_id against your user table for future reference.

Please note: app_user_id has a unique constraint, but does not need to map directly to the id of the user in your database, for example you could pass prod_usr_1246 as the app_user_id, so that you can identify that the Customer is a user of your production database. In this case, you should save both the customer_id and app_user_id against your user table for later retrieval and mapping.

Call

bash

curl -X POST 'https://sandbox.leantech.me/customers/v1/' \
--header 'Content-Type: application/json' \
--header 'lean-app-token: YOUR_APP_TOKEN' \
--data-raw '{
"app_user_id": "IDENTIFIER_FOR_CUSTOMER"
}'

Response

json

{
app_user_id: "IDENTIFIER_FOR_CUSTOMER",
customer_id: "f08fb010-878f-407a-9ac2-a7840fb56185"
}

Create a Payment Source

In order for your customer to be able to make a payment, first they need to authorise their bank to transfer funds from their account to your account. This is known in their bank account as a 'Beneficiary'.

For some banks, creating a beneficiary can have a cool-down period of up to 24 hours, which is why we have separated the flow into two distinct parts so that users can complete future initiations without having to enter passwords and wait for cool-down periods.

Please note: Setting up payments does not require actually making a payment from your end-user, in order to make functionality available as soon as possible to your customer, you can create a Payment Source during initial onboarding.

Creating the Payment Source

On your Front-end, make a .createPaymentSource() call to the LinkSDK to guide your user through the process of creating a beneficiary. For further information on integrating the LinkSDK into your platform please see the LinkSDK integration documentation at https://docs.leantech.me/link-sdk. For the purposes of this guide we will be using Javascript as the language being used by the front-end.

javascript

// page.html
<button onClick={() => cps(...params)}>Set up payments</button>
// script.js
function cps(customer_id) {
Lean.createPaymentSource({
app_token: "YOUR_APP_TOKEN",
customer_id: customer_id,
payment_destination_id: "266733cc-6f46-4e87-af7e-9bb46b99601d"
})
}

When a customer completes the LinkSDK - please note, no details are shared directly from the SDK to your front-end. A Success, Error or Cancelled message can be returned from the SDK via a callback (depending on the platform you're integrating with, this is handled differently) in the following format:

json

{
"status": "SUCCESS",
"method": "CREATE_PAYMENT_SOURCE",
"message": "Customer created Payment Source successfully"
}

The details of your newly created entity will instead be sent via a webhook to your backend services. Your front-end should therefore handle the success by making a call to your backend to refresh the data.

Payment Source webhooks

When a customer creates a Payment Source using the LinkSDK, your backend will receive two webhooks, one payment_source.created and one payment_source.beneficiary.created webhook.

For the purpose of this guide, please respond to the payment_source.beneficiary.created webhook with a 200 response and ignore it.

The payment_source.created webhook will look like this:

json

{
"type": "payment_source.created",
"payload": {
"id": "d8d7a9b3-c401-49f6-81a4-386d8398aa2c",
"customer_id": "6db94cb7-3a02-4a57-a03a-e2a92ce86406",
"status": "AWAITING_BENEFICIARY_COOL_OFF",
"bank_identifier": "ENBD_UAE",
"bank_name" : "Emirates NBD"
},
"message": "A payment source was preauthorized by your customer.",
"timestamp": "2020-07-31T07:11:39.862804Z"
}

The key component here is the AWAITING_BENEFICIARY_COOL_OFF status. This status indicates that there is a cool down period before the account is chargeable. If the status is ACTIVE your customer can make a payment immediately.

Fetch the Payment Source

Using the id in the payload from the webhook, fetch the newly created Payment Source and save it to your database:

bash

curl -X GET 'sandbox.leantech.me/customers/v1/<customer_id>/payment-sources/<payment_source_id>' \
--header 'Content-Type: application/json' \
--header 'lean-app-token: YOUR_APP_TOKEN'

Returns

json

{
"id": "d8d7a9b3-c401-49f6-81a4-386d8398aa2c",
"customer_id": "6db94cb7-3a02-4a57-a03a-e2a92ce86406",
"app_id": "2c9280887230f322017231b408cf0007",
"bank_identifier": "ENBD_UAE",
"beneficiaries": [
{
"id": "26891A75-9406-4E06-97BA-F4D6DA664F3C",
"payment_destination_id": "266733cc-6f46-4e87-af7e-9bb46b99601d"
"status": "AWAITING_BENEFICIARY_COOL_OFF",
"beneficiary_cool_off_expiry": "2021-02-13T13:20:57.674299Z"
}
]
"accounts": [
{
"id": "9acde98e-9d19-495d-934c-b2ff966262c8",
"account_id": "aaadbc4e-96a4-420f-ba01-597fa63502ee",
"account_name": "CURRENT ACCOUNT",
"account_number": "1015528734001",
"iban": "AE340260001015528734001",
"balance": 35681.15,
"currency": "AED",
"balance_last_updated": "2021-02-12T13:20:23.83922Z"
}, {
"id": "1457d23a-c1f8-4aee-bc6f-2a253b2e617f",
"account_id": "69f22112-e95d-427e-8bd1-eb58b4db60ba",
"account_name": "CURRENCY PASSPORT SAVINGS AC",
"account_number": "0315528734002",
"iban": "AE790260000315528734002",
"balance": 80871.00,
"currency": "USD",
"balance_last_updated": "2021-02-12T13:20:57.370659Z"
}
]
}

Send a notification when your Customer's Payment Source becomes active

When a Payment Source switches from AWAITING_BENEFICIARY_COOL_OFF to ACTIVE another webhook is sent to your server, notifying you that an update has been made.

You can use this webhook to drive Push Notifications to bring your customer back into your application to complete a purchase or top up an account.

json

{
"type": "payment_source.updated",
"payload": {
"id": "d8d7a9b3-c401-49f6-81a4-386d8398aa2c",
"customer_id": "6db94cb7-3a02-4a57-a03a-e2a92ce86406",
"status": "ACTIVE",
"bank_identifier": "ENBD_UAE",
"bank_name" : "Emirates NBD"
},
"message": "A payment source has been updated.",
"timestamp": "2020-07-31T07:11:39.862804Z"
}

Create a Payment Intent

Now that your user has a Payment Source - the next step is to create a Payment Intent.

A payment intent

When your user clicks transfer a call to your backend should be initiated expecting a payment_intent_id as the response.

javascript

onClick={() => callMyApi(amount, currency, customer_id, payment_destination_id)}

Create the Payment Intent

Call

bash

curl -X POST 'https://sandbox.leantech.me/payments/v1/intents' \
--header 'Content-Type: application/json' \
--header 'lean-app-token: YOUR_APP_TOKEN' \
--data-raw '{
"amount": 1000,
"currency": "USD",
"payment_destination_id": "266733cc-6f46-4e87-af7e-9bb46b99601d",
"customer_id": "CUSTOMER_ID"
}'

Response

json

{
"payment_intent_id": "9dafc6f5-37e8-4f72-aa0b-5323c0935c5f",
"customer_id": "6bc2336a-6d74-4e59-a492-65313423a8f8",
"amount": 1000.00,
"currency": "AED",
"payments": [],
"payment_destination": {
"id": "XXXXXX-c568-40d7-8710-3e330dXXXXXX",
"bank_identifier": "HSBC_UAE",
"name": "XXXXXX",
"iban": "AEXXXXXXXXXXXXXXXX",
"display_name": "XXXXXXX",
"account_number": "XXXXXXXX",
"swift_code": "BBMEAEAD",
"status": "CONFIRMED",
"address": "1234 1234",
"country": "ARE",
"city": "Dubai",
"default": true
}
}

You should take the payment_intent_id received in the response and return back to your front-end to initiate the payment.


Initiate a Payment

Once an initiation has been completed, you will receive a payment.created webhook to your Webhook URL:

json

{
"payload": {
"id": "81f686b5-0cf3-4ee1-9250-9f8dae030a1d",
"customer_id": "e52d8b7e-7c4d-40af-b851-90ab5c061028",
"intent_id": "88f73a6d-f017-4fc6-85bf-2cc2804c2a4a",
"status": "ACCEPTED_BY_BANK",
"amount": 10.12,
"currency": "AED"
},
"type": "payment.created",
"message": "A payment object has been created.",
"timestamp": "2021-03-24T12:50:47.521324Z"
}

Payment Initiations can have three final statuses on the Lean platform.

REJECTED_BY_BANK / FAILED: The bank rejected the payment initiation. This could be for a number of reasons such as insufficient balance to complete the transaction, or a connectivity failure.

PENDING_WITH_BANK: The bank accepted the initiation, but didn’t provide a transaction reference number. Pending payments may be processed by the bank at a future date and require manual reconciliation.

ACCEPTED_BY_BANK: The bank accepted the initiation and provided a transaction reference number. Transactions that are ACCEPTED_BY_BANK should not be treated as completed payments until the funds have been reconciled in your account. There are a rare number of circumstances when a delay may occur between a bank accepting a payment and the funds reaching your account and/or circumstances which may cause the payment to fail. For example, a bank may request additional KYC checks or there may be insufficient funds available for the transaction after the bank transfer fees are applied. We recommend that funds are reconciled in your account before making them available to the customer.