Making payments

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

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

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

Create the Payment Intent


curl -X POST '' \
    --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", //this param is optional; if not sent, the default payment destination will be used
        "customer_id": "CUSTOMER_ID",
        "description": "YOUR_TRANSACTION_REFERENCE" //optional



The description maximum length on Lean's side is 32 characters. However, we recommend to have it as short as possible and without any special characters!

‼️ It's important to note that some banks only allow 12 characters for the reference. So if you want the description to be passed as it is and avoid having it trimmed, you need to restrict it to 12 characters on your side !!


    "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": "LEANMB1",
        "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:

  "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.

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.

Testing Different Payment Responses

In order to test failed payments using your sandbox account/test users, please refer to the below details:

StatusAmountCurrencyAdditional Details
PENDING_WITH_BANK12.34AEDInitiation successful - happy path
FAILED34.56AEDThis would return a generic failure message
FAILEDBig amounts, i.e: 300000AEDThis would return an insufficient funds message within the status_additional_info field
ACCEPTED_BY_BANKAny valid amountAny valid currencyInitiation successful - happy path