Make a payment [Payments V1]

This section describes how to set up, execute, and monitor the 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.

about configuring single immediate payments, and also testing your integration.

Single immediate payments

To set up, execute and monitor payments:

  1. Build a provider selection
  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 provider selection screen is where your user chooses the provider they want to pay with.

The /providers endpoint:

  • returns a list of which providers are active
  • provides the assets you need to build a provider selection screen, such as logos and icons

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


Each available bank returned has the following fields.

idstringThe provider ID to send us in the create payment request.
logostringThe address of the logo asset in SVG form.
iconstringThe address of the icon asset in SVG form.
displayable_namestringA human-readable name for the provider.
main_bg_colorstringThe hex code of the colour in the background of the logo.
supports_app_to_appboolIf true, this means the user will be redirected to their mobile banking app if they are using their mobile phone. /n/n If false, the user authenticates in their browser.
divisionsstring arrayAn array that includes all divisions that are available on this provider. For example, retail and business would indicate you can use this provider to access both retail and business accounts.
stepsarrayThis array includes any extra steps in the authentication flow required to send your end user through with some banks. The results of these steps will be used in your request to create a payment.

We do not recommend that you store the information from the /providers endpoint locally. This is because TrueLayer occasionally updates the response returned by the endpoint.

Structure of the steps parameter

titlestringYesUser-friendly name for this method within the provider.
fieldsarrayYesArray of input fields.
fields.typestringYesInput field type. Can be a single choice input or a free input.
fields.is_sensitivebooleanNoFor free input values, is set to true if a field requires the user to input sensitive information (like a password).
fields.valuesarrayNoFor single choice input, an array of values.
fields.values.valuestringNoFor single choice input, input field value.
fields.values.display_namestringNoFor single choice input, a user-friendly name for this input field value.
fields.validationsarrayNoFor free input values, an array of RegEx validation rules that need to be satisfied to consider the input valid.
fields.allowed_charactersstringNoFor Free Input Values, character ranges allowed. Can be alphanumeric or numeric.
fields.idstringYesUnique id for this field within the method.
fields.display_namestringYesUser-friendly name for this field within the method.
fields.help_textstringYesInput help text for the end user.
fields.mandatorybooleanYesIndicates whether the field is required.

Create a payment

This method includes the following fields:

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 beneficiary account (your account) if the account is a UK account (see below for EU).
beneficiary_account_numberstringMandatoryThe account number of the beneficiary 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 user's bank statement. Note: this can only be 18 characters or less.
beneficiary_namestringMandatoryThe name on the beneficiary 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 provider your user has chosen. If this isn't specified, the user will be sent to TrueLayer to choose their provider in the UK. For providers 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 that the payment is being made from, and 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 that the payment is being made from, and if the account is a UK account (see below for EU). This may be an AML requirement.
remitter_iban stringConditionalIf you are making payments in Central European countries, this is a compulsory field.
direct_bank_linkboolOptional / ConditionalIf set to true, a URI directly from the bank will be returned. Note: If using this, you will skip all TrueLayer optimisation. Conversion may be lower on desktop. You must specify the 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": ""
}' \

The request will return a simp_id: store this. Once they are authorised, 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": "",
      "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": "",
      "status": "new"

Adapting an existing integration for EU payments

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

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

Redirecting a user to authenticate

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 to their bank.

Handle the user returning to your application

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

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.

The header has the following fields:

X-TL-Webhook-TimestamptimestampThe time that the webhook was sent to you. It should look like this: 2020-05-18T10:17:47Z
Tl-SignaturestringJSON web signature with a detached payload of the form {HEADER}..{SIGNATURE}
X-Tl-SignaturestringThis is legacy JWS. Verification using Tl-Signature is preferred.

The body has the following fields:

event_typestringDescribes the event. In this case, the event will be single_immediate_payment_status_changed.
event_bodyobjectContains both the payment_id as a string and the status as a string.
Tl-Signature: "detached..jws"
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 successfully delivered when we receive a success status code (2xx) from your webhook URI.

If we receive any other status code (for instance, if 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 for up to 72 hours.

Validate the received webhook signature

We recommend developers to use our signing libraries to verify the Tl-Signature of the webhooks they receive.

E.g. Java com.truelayer.truelayer-signing


Poll 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 are 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: TrueLayer has successfully submitted the payment to the bank and the bank has confirmed it as accepted. This does not mean that the payment will settle in the creditor’s account.

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.



After a payment has been executed, it may take some time for it to be settled — but for transactions executed via Faster Payments, this normally happens very quickly.

curl -H "Authorization: Bearer ${access_token}" \

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}" \

Testing guidelines

Before testing with live accounts, we recommend that you test your integration in sandbox.

When you transition to live testing in the production environment:

  • Ensure you change all URIs to end with instead of
  • 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: Make sure that you have stored your production client_secret since you last reset it.
  • Have two live bank accounts that you own to hand: one to make payments from, and one to make payments into. The payer bank account must be from one of the supported providers listed here

Bank account limits

Providers set their own limits on how much money can be transferred using online banking. These also apply to their open banking payment APIs.

(click tab “Payment limits and timeframes”)
Bank of Scotland
(click tab FAQs)
Royal Bank of Scotland
HSBCFrom : “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”
Danske Bank (see table on page 4 referencing Open Banking payment limits)
AIB (Allied Irish Bank)
First Trust Bank

Velocity Limits

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

Banks don't publish these limits, since fraudsters might take advantage of this information. Therefore, when testing:

  • Do not make too many 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 UI. If this happens, you need to contact the bank’s support team to unblock the account.