Single immediate payments

This section describes how to setup, execute, and monitor progress of a Single Immediate Payment.

A single immediate payment is a one time payment, executed immediately, that requires the user to authenticate with their bank.

Below are instructions for how to:

  1. Build a provider selection screen for your users to select their bank
  2. Create a payment
  3. Redirect a user to authenticate
  4. Handle the user returning to your application
  5. Poll for payment status

Build a provider selection screen

The providers endpoint serves two purposes:

  1. Tells you which banks are active, if a bank isn't listed then we have deactivated it temporarily until its service is returned.
  2. Gives you the assets to build out a selection screen, for example, logos and icons.

When querying the endpoint, specify capability in the query string as SingleImmediatePayment.

Each bank available will have the following fields:

FieldTypeDescription
idstringThis is the provider ID that you will send us in the create payment request.
logostringThis is the address of the logo asset in SVG form.
iconstringThis is the address of the icon asset in SVG form.
displayable_namestringThis is a readable name for the provider.
main_bg_colorstringThis is a hexacode color that matches the background of the logo.
supports_app_to_appboolThis indicates whether the user will be redirected to the mobile banking app if using their mobile phone. In cases where this is false, the user authenticate in their browser.
divisionsstring arrayThis array includes all divisions that are available on this provider, for example, retail and business would indicate you can use this single provider to access both retail and business accounts.
stepsarrayThis array includes any extra steps in the authentication flow that you are required to send your end user through with some banks. The results of these steps will be used in your create payment request.

We recommend you query this endpoint every single time you make a payment as we will remove banks that are not currently available.

• The steps parameter structure

FieldTypeDescription
titlestringFriendly name for this method within the provider
fieldsarrayArray of input fields
fields.typestringInput field type. Can be a Single Choice Input or a Free Input
fields.is_sensitivebooleanOPTIONAL: For Free Input Values, is set to true for sensitive information like passwords
fields.valuesarrayOPTIONAL: For Single Choice Input, an array of values
fields.values.valuestringOPTIONAL: For Single Choice Input, input field value
fields.values.display_namestringOPTIONAL: For Single Choice Input, friendly name for this input field value
fields.validationsarrayOPTIONAL: For Free Input Values, an array of RegEx validation rules that need to be satisfied to consider the input valid
fields.allowed_charactersstringOPTIONAL: For Free Input Values, character ranges allowed. can be alphanumeric or numeric
fields.idstringUnique id for this field within the method
fields.display_namestringFriendly name for this field within the method
fields.help_textstringInput help text for the end user
fields.mandatorybooleanIndicates whether the field is required
https://pay-api.truelayer.com/providers?capability=SingleImmediatePayment
{
  "results":[
    {
      "id":"ob-sandbox-natwest",
      "logo":"example.com",
      "icon":"example.com",
      "displayable_name":"Natwest Sandbox",
      "main_bg_color":"#eee",
      "supports_app_to_app":false,
      "divisions":["retail"]
    }
  ]
}

Create a payment

This method includes the following fields:

FieldTypeMandatory/OptionalDescription
amountintMandatoryThe amount of money you are requesting in pennies.
currencystringMandatoryThe currency code of the payment in three characters. For example, GBP or EUR.
beneficiary_referencestringMandatoryThe reference that will appear on your bank statement. Note: this can only be 18 characters or less.
beneficiary_sort_codestringMandatoryThe sort code of the receiving account (your account) if the account is a UK account (see below for EU).
beneficiary_account_numberstringMandatoryThe account number of the receiving account (your account) if the account is a UK account (see below for EU).
beneficiary_iban stringConditionalIf making payments in Central European countries the beneficiary IBAN is a compulsory field and replaces the account number and sort code.
remitter_referencestringMandatoryThe reference that will appear on the sender's bank statement. Note: this can only be 18 characters or less.
beneficiary_namestringMandatoryThe name on the receiving account.
redirect_uristringMandatoryThe URL we will redirect the user to after authorising the payment.
remitter_provider_idstringOptional / ConditionalThe ID from the providers endpoint of the bank your user has chosen. If this isn't specified the user will be sent to TrueLayer to choose their bank in the UK. For banks outside of the UK, you will need to set this.
remitter_account_numberstringOptionalThe account number of the payer, specify this if you want to lock the account from which the payment is being made if the account is a UK account (see below for EU). This may be an AML requirement.
remitter_sort_codestringOptionalThe sort code of the payer, specify this if you want to lock the account from which the payment is being made if the account is a UK account (see below for EU). This may be an AML requirement.
remitter_iban stringConditionalIf making payments in Central European countries the remitter IBAN is a compulsory field.
direct_bank_linkboolOptional / ConditionalIf set to true, you will be returned a URI directly from the bank. !WARNING! If using this, you will skip all TrueLayer optimisation and conversion may be lower on desktop. You must specify remitter_provider_id for this request to succeed. This is a required field for European Banks.
webhook_uristringOptionalAn address to send payment webhooks to with the status of your payment. This has to be https.
auth_inputs dictionaryConditionalIf the providers endpoint returns you required steps you will need to list them and their answers here. For example, banks in France require you to specify the branch name.
curl -X POST \
     -H "Authorization: Bearer ${access_token}" \
     --data '{
  "amount": 120000,
  "currency": "GBP",
  "remitter_provider_id": "ob-bank",
  "remitter_name": "Mike Smith",
  "remitter_sort_code": "987654",
  "remitter_account_number": "98765432",
  "remitter_reference": "FS-1000001",
  "beneficiary_name": "Financial Services Ltd",
  "beneficiary_sort_code": "234567",
  "beneficiary_account_number": "23456789"
  "beneficiary_reference": "FinServ-1a2b3c4d",
  "redirect_uri": "https://client.app.com/payment_redirect"
}' \
https://pay-api.truelayer.com/single-immediate-payments

The request will return a simp_id that you should store as, after authorisation, the user will be redirected to your redirect_uri with this appended as payment_id.

Use the auth_uri to redirect your user to authorise the payment.

{
  "results": [
    {
      "simp_id": "44708581-1967-4120-8f6a-1e532f1bf52a",
      "auth_uri": "https://example.com",
      "created_at": "2018-10-01T17:00:00.0000000+00:00",
      "amount": 120000,
      "currency": "GBP",
      "remitter_provider_id": "ob-bank",
      "remitter_name": "Mike Smith",
      "remitter_sort_code": "987654",
      "remitter_account_number": "98765432",
      "remitter_reference": "FS-1000001",
      "beneficiary_name": "Financial Services Ltd",
      "beneficiary_sort_code": "234567",
      "beneficiary_account_number": "23456789",
      "beneficiary_reference": "FinServ-1a2b3c4d",
      "redirect_uri": "https://client.app.com/payment_redirect",
      "status": "new"
    }
  ]
}

 Adapting an existing integration for EU payments (Private beta)

If you've already implemented the payments API and would now like to use our European payment capability, here are some key considerations to help you transition:

  1. Instead of account numbers and sort codes, you need to use our IBAN fields.
  2. Both the remitter and beneficiary IBANs are compulsory fields to create a payment with a European Bank in Euros.
  3. You'll need to change the currency code to EUR.
  4. European banks can only pay to European bank accounts.
  5. Some banks have additional steps required (these appear on their provider in the providers endpoint result you get back) and you'll need to complete these steps before creating the payment and pre-fill the auth_inputs field.
  6. The remitter provider ID is a compulsory field.
  7. direct_bank_link is a compulsory field.

Redirecting your user to the bank

After creating the payment, you need to redirect the user to the auth_uri.

If you did not specify the remitter_provider_id your user will be redirected to the TrueLayer Provider Selection screen and from there on to their bank.

Handling a returning user

Once the payment is authorised, the user will return to your redirect_uri. The URL will include a payment_id query parameter containing the simp_id from the payment creation response.

https://client.app.com/payment_redirect?payment_id=a55f2e12-55ef-410c-9341-628033a62dc3

Managing payment status with webhooks

When the status of a payment changes, we send a single_immediate_payment_status_changed event to the uri that you specified when creating the payment.

In the header you will see the following fields:

FieldTypeDescription
X-TL-SignatureJWS Tokena signature in the form of a JWS token that you can use to validate that the request came from us. Instructions for validating this can be found below.
X-TL-Webhook-Timestamptimestamptime that the webhook was sent to you. This will be in the following format 2020-05-18T10:17:47Z

In the body you will see the following fields:

FieldTypeDescription
event_typestringdescribing which event is detailed. In this case the event will be single_immediate_payment_status_changed
event_bodyobjectcontaining both the payment_id as a string and the status as a string
X-TL-Signature:  "a JWS token"

X-TL-Webhook-Timestamp: 2020-05-18T10:17:52Z

{
  "event_type": "single_immediate_payment_status_changed",
  "event_body": {
    "payment_id": "77a75df0-af60-4785-8e91-809ac77ca8e3",
    "status": "executed"
  }
}

Webhook Retry Policy

We consider a webhook as having been successfully delivered when we receive a success status code (2xx) from your webhook URI.

If we receive any other status code (for example, your API is temporarily unavailable), we will start retrying.
Our retry policy is jittered exponential backoff: we will immediately perform some fast retries and then start waiting increasingly longer; we will keep retrying until 24 hours has passed since the first attempt.

Validating the webhook signature

The value of the X-TL-Signature header contains a JSON Web Signature (JWS) with a detached payload. It takes the form {HEADER}..{SIGNATURE}.

The JWS header contains the following values:

FieldTypeDescription
algstringThe algorithm used to sign the webhook. We currently use the RS256 algorithm.
jkustringThe URI of the JSON Web Key Set (JWKS), a hosted page where a list of public keys owned by TrueLayer can be found.
kidstringThe ID of the key used to sign the webhook, used to retrieve the correct key from the JWKS.

The steps for verifying the signature are as follows:

  1. Verify the jku field in the token header matches the expected value (below). If not, the signature should be rejected as invalid.
    • Sandbox: https://pay-api.truelayer-sandbox.com/.well-known/jwks.json
    • Production: https://pay-api.truelayer.com/.well-known/jwks.json
  2. Use the jku value to retrieve the JWKS. This may be cached for some time, but if verification fails the JWKS must be re-retrieved to ensure that all keys are up to date. Keys may be rotated or revoked at any time by TrueLayer.
  3. Retrieve the relevant public key by using the kid to look up the relevant value from the JWKS.
  4. Reconstruct the signature payload. This is of the form: {"Content-Type":"<value-of-content-type-header>","X-TL-Webhook-Timestamp":"<value-of-timestamp-header>","body":"<webhook-request-body>"}.
  5. Use a JWT library to verify the JWS headers combined with the reconstructed payload matches the signature provided in the token. The algorithm used to verify the signature must be that declared in the alg header of the JWS.

You can find code samples for signature validation in our GitHub.

Polling for payment status

The application can poll the payment resource to see if the status has been modified. This allows the application to know if the payment was successful or not.

Note that if the remitter was specified, remitter details will also be included in the response.

The payment resource may exist in different states according to the progress of the transaction:

  • new: The payment resource has been created, but the payer has not yet authorised the payment. The initial API response will always have this status if the API call is successful.
  • authorised: The payer has successfully authorised the payment using the bank portal, but the payment has not yet been submitted for execution.
  • cancelled: The payer has cancelled the payment using the bank portal. This may also happen for some bank UIs if the payer clicks the “Back” button in their browser. This is a terminal state.
  • failed: The bank has failed to initiate a payment session, this happens after a bank has been selected but before redirecting the user to the bank UI. This is a terminal state.
  • rejected: The payer authorised the payment, but the bank rejected it after this. This is a terminal state.
  • submitted: TrueLayer has successfully submitted the authorised payment initiation request to the bank API.
  • executed: The funds have left the remitter’s account and will arrive in the beneficiary’s account. This is a terminal state.

The submitted and executed states are very close; in fact a bank may respond to the payment submission indicating the payment has already been executed. However, it is also possible for a payment to be queued within the bank for a short period of time; in that case, the payment status will initially be submitted, and then may be updated to executed after polling for a status check.

Note that after a payment has been executed, it may take some time for it to be settled, although for transactions executed via Faster Payments, this normally happens very quickly.

curl -H "Authorization: Bearer ${access_token}" \
https://pay-api.truelayer.com/single-immediate-payments/a55f2e12-55ef-410c-9341-628033a62dc3
{
  "results": [
    {
      "simp_id": "c45d38a6-2384-49aa-98ab-60134a50a5d7",
      "created_at": "2018-10-01T16:00:00.0000000+00:00",
      "amount": 350,
      "currency": "GBP",
      "beneficiary_reference": "ecommerce-12345",
      "beneficiary_name": "Ecommerce Shop",
      "beneficiary_sort_code": "102030",
      "beneficiary_account_number": "88881234",
      "remitter_reference": "ECOM-12345-ABCD",
      "redirect_uri": "http://www.ecommerce.com/redirect",
      "remitter_provider_id": "ob-lloyds",
      "status": "executed"
    }
  ]
}

To see all known states of your payment and trace your payment with the timestamps, add /statuses to the end of the request.

curl -H "Authorization: Bearer ${access_token}" \
https://pay-api.truelayer.com/single-immediate-payments/a55f2e12-55ef-410c-9341-628033a62dc3/statuses
{
    "results": [
        {
            "status": "New",
            "date": "2020-04-08T21:53:35.364038"
        },
        {
            "status": "Authorised",
            "date": "2020-04-08T21:54:17.690429"
        },
        {
            "status": "Submitted",
            "date": "2020-04-08T21:54:18.546706"
        },
        {
            "status": "Executed",
            "date": "2020-04-08T21:54:28.063325"
        },
        {
            "status": "Executed",
            "date": "2020-04-08T21:54:28.2761"
        }
    ],
    "status": "queued"
}

Testing Guidelines

The following guidelines aim to provide practical guidance while testing the integration.

Before testing with live accounts, we recommend that you test your integration with the sandbox. The Payments Quick Start provides instructions on how to access the sandbox APIs.

When you transition to live testing in the production environment:

  1. Make sure you change all URIs to end with truelayer.com instead of truelayer-sandbox.com
  2. Change from using your sandbox client_id_ and client_secret to your production client_id and client_secret. You can find your production client_id here: https://console.truelayer.com/settings/Application (you should have saved your production client_secret when you last reset it, or when you created your production account)
  3. Have a live bank account to hand which you own to make payments from, as well as one to make payments into. The payer (or remitter) bank account must be from one of the supported providers listed here

Bank Account Limits

Each bank has its own limits on how much money can be transferred using online banking, which also apply to their open banking payment APIs.

BankDetails
Lloydshttps://www.lloydsbank.com/online-banking/benefits-online-banking/view-pay-your-bills.asp#tab-row-5
Halifaxhttps://www.halifax.co.uk/bankaccounts/help-guidance/online-banking-help/fasterpayments/
(click tab “Payment limits and timeframes”)
Bank of Scotlandhttps://www.bankofscotland.co.uk/helpcentre/internet-banking/faster-payments/
(click tab FAQs)
Royal Bank of Scotlandhttps://www.supportcentre-rbs.co.uk/Searchable/997053272/What-are-the-payment-limits.htm
NatWesthttps://supportcentre.natwest.com/Searchable/913208362/What-are-the-payment-limits.htm
Ulsterhttps://supportcentre.ulsterbank.co.uk/Searchable/997054072/What-are-the-payment-limits.htm
Barclayshttps://www.barclays.co.uk/current-accounts/online-payment-limits/
HSBCFrom https://www.hsbc.co.uk/1/2/linklaunch/contactandsupport : “You can make payments of up to £25,000, per day via Online Banking if the funds are available, for larger amounts, you would need to visit an HSBC Branch with Identification and there may be a charge”
Santanderhttps://www.santandercb.co.uk/contact-support/connect-helpcentre/making-payments/standard-domestic-payments-faster-payments
Nationwidehttps://www.nationwide.co.uk/support/support-articles/important-information/faster-payments#xtab:payment-limits
Danske Bankhttps://danskebank.co.uk/SiteCollectionDocuments/personal/payment-table-personal.pdf (see table on page 4 referencing Open Banking payment limits)
Post Office Bank (Bank of Ireland)https://www.postoffice.co.uk/current-account-faqs (see item “How much money can I send?”
AIB (Allied Irish Bank)https://aibgb.co.uk/ways-to-bank/online-banking/transaction-limit-information
First Trust Bankhttps://firsttrustbank.co.uk/ways-to-bank/transaction-limit-information
Starlinghttps://www.starlingbank.com/paymentservices/
Monzohttp://fasterpayments.org.uk/monzo
Revoluthttps://www.revolut.com/help/exploring-revolut/sending-money/sending-money-to-a-bank-account/what-are-the-transfer-limits/
TSBhttps://www.tsb.co.uk/business/payment-services/faster-payments/
Tescohttps://yourcommunity.tescobank.com/t5/Help-Support/Faster-payments-and-daily-withdrawal-limits/td-p/11580

Velocity Limits

All banks have controls in place to protect their end users from fraudulent withdrawals. One type of control is a velocity limit, which allows only a certain number of payments, or a maximum aggregate payment amount, per time period, for example, one hour, one day, and so on.

Banks will not publish these limits, as the information could be taken advantage of by fraudsters. Therefore, when testing:

  • Do not make an excessive number of payments from the same account within a short time period.
  • If it is not possible to make a successful payment, this will be visible in the bank’s authorisation user interface. At this point, it will be necessary to contact the specific bank’s end user support team to get the account unblocked.

Did this page help you?