Initiating a Single Instant Payment

Overview

To accept a Single Instant Payment, the customer must authorise it with the bank. The authorisation process is handled through Lean LinkSDK, which provides a secure, user-friendly interface for customers to select their bank, review payment details and confirm the transaction.

After authorisation, the customer will be redirected back to one of your whitelisted urls based on the authorisation outcome.

How it works

  1. Create a payment intent using Payment Intents API.

  2. Start the payment flow using LinkSDK.

  3. The customer selects their bank, reviews the payment details, and authorises it with bank.

  4. Handle a customer returning to your application with preconfigured urls.

  5. Use captureRedirect() to retrieve and display the payment result screen.

  6. Listen for payment state changes using the payment.created and payment.updated webhooks.


Creating a payment intent

The Payment intent is the contract between your backend and Lean to certify that you will request a payment from your customer of a specified amount and currency.

Create a Payment Intent using the Payment Intent API

curl -X POST 'https://sandbox.leantech.me/payments/v1/intents' \
  --header 'Content-Type: application/json' \
  --header 'Authorization: Bearer ...' \
  --data-raw '{
    "amount": 1000.50,
    "currency": "AED",
    "payment_destination_id": "DESTINATION_ID",
    "customer_id": "CUSTOMER_ID",
    "description": "YOUR_TRANSACTION_REFERENCE",
    "purpose_code": "FIS"
  }'
{
    "payment_intent_id": "c2f77a7d-fbd1-400a-b4e7-7079b6a87775",
    "customer_id": "26b69ba5-0447-45b6-be7d-376d6b432843",
    "amount": 1000.50,
    "currency": "AED",
    "description": "YOUR_TRANSACTION_REFERENCE",
    "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
    }
}

❗️

Return the payment_intent_id from this response to your frontend. It is required to initiate the payment using LinkSDK.


Triggering payment initiation

Use the LinkSDK checkout() function, to start the Single Instant Payment flow.

Pass the payment_intent_id returned from the previous step.

LeanV2.checkout({
    sandbox: true,
    app_token: "<your_application_id>",
    payment_intent_id: "<payment_intent_id>",
    success_redirect_url: "<url_to_redirect_on_success>",
    fail_redirect_url: "<url_to_redirect_on_failure>",
    access_token: "<customer_scoped_access_token>",
    risk_details: {} // omitted for brevity
})

📘

Risk Details Collection

Open Finance regulations require the collection of risk-related metadata to help prevent fraud. The risk_details object allows you to provide this information. See Risk Details for more information.


Bank selection, payment details and redirection

After initiating the payment, LinkSDK guides the customer through:

  • Selecting their bank
  • Reviewing payment details
  • Redirecting to their bank to authorise the payment

These steps are fully handled by LinkSDK and use CBUAE certified customer-facing screens.


📘

Screen Customisation

Due to Open Finance regulations, customer-facing screens in payment flow, must be certified and offer limited customisation.


LinkSDKs bank selection, payment details and redirect screens


During the authorisation the customer is being handed over from your application to the bank where they can perform payment authorisation. The customer will return to your application through a redirect url passed as a parameter to the checkout function.


📘

Using custom bank selection

Use Create your own bank list guide, if you want to provide a custom banks selection screen. Pass resulting bank_identifier to the checkout function to skip the default bank selection.


Capturing Redirects and displaying the result page

After the authorisation flow completes, Lean redirects the customer back to your configured redirect URL, appending query parameters that describe the payment outcome.

Capture Redirect Screen


To display the final result screen, call captureRedirect() and pass the parameters received in the redirect:

Lean.captureRedirect({
    app_token: "<your_app_id>",
    bank_identifier: "<from_query_param>",
    consent_id:"<from_query_param>",
    consent_attempt_id: "<from_query_param>",
    customer_id: "<from_query_param>",
    granular_status_code: "<from_query_param>",
    status_additional_info: "<from_query_param>",
    sandbox: true,
    access_token: "<customer_scoped_access_token>"   
})

Listening to payment state changes

Open Finance payments emit webhook events as the payment progresses.


{
  "type": "payment.created",
  "payload": {
    "id": "f672849b-b4f1-46b1-99cd-80e0bd24c6c0",
    "customer_id": "CUSTOMER_ID_RELATED_TO_PAYMENT",
    "intent_id": "INTENT_ID_RELATED_TO_PAYMENT",
    "status": "PENDING_WITH_BANK",
    "amount": 12.34,
    "currency": "AED",
    "iso_status": "PENDING",
    "payment_destination_id": "DESTINATION_ID_RELATED_TO_PAYMENT"
  },
  "message": "A payment object has been created.",
  "timestamp": "2025-12-17T13:59:32.008767568Z",
  "event_id": "7d1e3de6-fb8b-4480-8652-903c75b8b8c8"
}
{
  "type": "payment.updated",
  "payload": {
    "id": "f672849b-b4f1-46b1-99cd-80e0bd24c6c0",
    "customer_id": "CUSTOMER_ID_RELATED_TO_PAYMENT",
    "intent_id": "INTENT_ID_RELATED_TO_PAYMENT",
    "status": "PENDING_WITH_BANK",
    "amount": 12.34,
    "currency": "AED",
    "bank_transaction_reference": "528b2b3c-128a-4b51-b50e-31cfc6d7e01b",
    "iso_status": "ACCEPTED_SETTLEMENT_COMPLETED",
    "payment_destination_id": "DESTINATION_ID_RELATED_TO_PAYMENT"
  },
  "message": "A payment object has been updated.",
  "timestamp": "2025-12-17T14:00:00.731572845Z",
  "event_id": "bb93b16a-f1cd-486d-887e-b63492b4ebdd"
}

Configure webhook subscriptions in the Webhooks section of the Application Dashboard.


Webhooks panel in Application Dashboard