Migration guide: Payments API v1 to v3 - with Merchant Account

Everything you need to migrate from Payments v1 to the Payments API v3.

Scope of this document

Welcome to the TrueLayer v3 Payments migration guide.

This document provides information on the TrueLayer Payments v3 APIs and the migration process from the Payments v1 APIs to Payments v3 APIs.

🚧

Who this guide is for

This guide is for payments integrations that use a TrueLayer merchant account:

  • Pay-ins (deposits) into the merchant account using Payments v1 Legacy APIs
  • Payouts (withdrawals or refunds) from the merchant account with Payouts v1 Legacy APIs

Payments API v3 is the latest version of the TrueLayer Payments APIs and is a single interface to access all of TrueLayer's payments products in all supported geographies.

This includes:

In order to take advantage of these new features and ensure the best possible experience with our product, we strongly recommend that all users upgrade to this new version as soon as possible.

However, we understand that migrating to a new version can sometimes be a challenging process. That's why we've put together this guide to help you make the transition as smooth as possible.

We hope this guide will help you navigate the migration process and take full advantage of all the new features and improvements in the new version. If you have any questions or encounter any issues along the way, don't hesitate to reach out to our support team for assistance.

To summarise, the three benefits of v3 migrations are:

  • Out-of-the-box solutions (Mobile SDKs, hosted payment page, backend libraries) to support easier integration.
  • The same integration for all future coverage expansion and features for the next 3-5 years.
  • Building user interfaces to meet the differing requirements of European providers is complex. If you are interested in new geographies, we’ll reduce the barrier to entering these markets by extending the capabilities of our TrueLayer UI components.

Payments v3 APIs: introduction

🚧

Signing requests

It is now mandatory to sign all POST API requests, including both pay-ins and payouts. You must also include certain user data within payment creation requests.
Learn more about signing requests and get links to TrueLayer signing requests libraries.

🚧

Merchant Account ID

You can find your merchant_account_id in Console > Payments > Merchant Account or via the /merchant-accounts endpoint.

Learn more about merchant accounts.

Requirements for v3

When migrating from a previous version, it’s important to acknowledge new requirements and concepts introduced in Payments v3.

  • It is now mandatory to sign all POST API requests, including both pay-ins and payouts.
  • It is required to include additional user information within payment creation requests.
  • Pay-in creation and authorisation are now two distinct concepts and are handled in two separate steps.

Each of those concepts is explained here in more detail.

Signing requests and validation of the received webhooks signature

All Payments API v3 requests must be signed (including both pay-ins/deposits and payouts).

Payments request signing with v3 is explained in more detail in our docs, for both pay-ins and payouts.

See our guide on how to create certificates, upload them to Console, and use backend signing libraries to help out with the signing process. We strongly recommend using our signing libraries for easier integration.

We also provide backend signing libraries to verify the Tl-Signature of received webhooks. Check our docs about this.

Additional ‘User’ data for pay-in and payout requests

As a regulated Financial/Payment Institution we have a regulatory requirement to screen all in/out transactions from/to the merchant accounts against sanctions lists.

The requirement applies to all transactions by clients who are not fully regulated and authorised financial services in the UK or EU.

TrueLayer conducts sanction and AML screening on all transactions to and from your merchant account. We double-check transactions made by end-users whose name matches an individual on a sanction list.

If a transaction is flagged by sanction and/or AML screening we will issue a Request for Information (RFI) to collect additional information required for us to investigate.

To reduce the number of RFIs raised due to sanctions investigations, the end user's date of birth and address need to be included in the API request.

Pay-In: the User object

    "user":  
    {  
        "id": "f61c0ec7-0f83-414e-8e5f-aace86e0ed35",  
        "name": "Jonathan Sandbridge",  
        "email": "[email protected]",  
        "phone": "+44123456789",  
        "date_of_birth": "1992-11-28",  
        "address":  
        {  
            "address_line1": "1, Hardwick Street",  
           "address_line2": "Floor 1",  
            "city": "London",  
            "state": "London",  
            "zip": "EC1R 4RB",  
            "country_code": "GB"  
        }  
    }  
}

For each payment, you will be required to pass the following user information in the payment request:

Hash parameterDescription
Unique User IDRequired.

A unique identifier for the user. The field is optional. When left empty, represents a new user and a value will be generated by TrueLayer and returned in the response.

This should uniquely identify the user (must be in UUID format).
NameRequired for non-regulated customers.
Email addressRequired for non-regulated customers.
Phone numberRequired for non-regulated customers.
Date of birthRequired for non-regulated customers.
Physical addressRequired for non-regulated customers.

📘

Details of the end user who is making the payment are required. Whether or not all of these fields are required depends on the regulatory status of the customer initiating the payment. For detailed requirements, please confirm requirements with your Sales contact.

Integration options

TrueLayer offers different integration options for our Payments API v3 to suit your needs.

With Payments v3 pay-ins (deposits made into the merchant account), once the payment is created from the backend, there is a following step that consists in taking the end user to authorise the payment.

Basically, the payment creation is separated from the payment authorisation (that involves user bank selection and payment confirmation).

Coming from a v1 Payments integration, you might be leveraging the TrueLayer payment dialog pages.

Payment v3 also comes with desktop and mobile UX/UI components that can be used out of the box to implement the pay-in user flow for every supported provider and country.

Therefore, for payment authorisation steps, in general, we usually recommend using our embedded payment page (EPP) or the hosted payment page (HPP) as both will reduce the time and resources required since it is optimised for the best user experience.

Hosted Payment Page

1920

Image showing what the HPP interface looks like. There are two screenshots in the image, one showing the bank selection screen and the other showing the payment confirmation screen.

Docs

  • TrueLayer’s localised hosted browser solution for both mobile and desktop which can be used for the bank selection and payment confirmation page (including QR code handoff option for desktop to mobile app flow).
  • This is built to handle the nuance of bank and country requirements across UK & Europe for you. This will increase the speed and efficiency of your country rollout if you are looking into expanding open banking payments in Europe. For German banks that have embedded flow approval processes, the HPP, EPP or SDK must be used if you wish to have the coverage of these banks (due to European regulations).
  • This can be configured to match the look and feel of your own website or app environment so that the customer journey reflects your brand colours.

Embedded Payment Page (EPP)

Docs

  • The embedded payment page enables you to quickly and simply add instant bank payments to your website, with a prebuilt user interface that speeds up the integration process.
  • The EPP acts as a modal in your web page environment. It offers enhanced customization functionality, QR code authentication and built in localisation covering local languages and authentication flows for a range of European countries.
  • This is built to handle the nuance of bank and country requirements across UK & Europe for you. This will increase the speed and efficiency of your country rollout if you are looking into expanding Open Banking payment solutions in Europe. For German banks that have embedded flow approval processes, the HPP, EPP or SDK must be used if you wish to have the coverage of these banks (due to European regulations).

Mobile SDKs for Android, iOS and React Native

1920

Image of what the native screens look like on an Android device. There are two screenshots in the image, one shows the bank selection screen and the other shows the payment confirmation screen.

Docs

  • TrueLayer’s mobile SDK can be used to embed the bank selection and payment confirmation pages into your mobile app.
  • This can be configured to match the look and feel of your own mobile environment.

Direct API integration and keeping your custom white labelled frontend

In case you’ve done a completely white labelled frontend, you can still handle all the payment authorisation using TrueLayer APIs from the backend and keep your customised flow.

The next section in this guide will cover this case.

Please note that, as mentioned above, if you are going to operate eventually outside of the UK, you could have to handle more complex flows coming from additional bank-specific requirements (like banks with embedded flows). In this case we strongly recommend adopting our hosted payment pages or embedded payment pages. These will automatically handle all additional bank flow requirements out of the box.

TrueLayer Console and Payments V3

Console is our back office platform where you can find all the necessary credentials to start using our APIs in both sandbox and live environments. In Console, you can also check payments their statuses and run reports.

With Payments v3, the Payments section in Console includes sub-sections on:

  • settings
  • merchant account information (including available and historical balance)
  • UI customisation
  • the payments view, where you can track all transactions to and from your merchant account

Documentation quickstart guides and links

Get started with Payments v3

Try out the API endpoints with our Insomnia collection and use our Insomnia plugin for quickly signing requests. Follow the instructions in the page for how to setup Insomnia, import the TrueLayer signing plug-in and import the v3 collection.


Migrating from Payments v1 to v3

Introduction

With the Payments v1 APIs, you used TrueLayer payment dialogs to handle the bank selection screens, or pass the bank details (provider_id and sort_code-account_number) into the payment request calls.

With v3 this will still be possible. You can completely reuse your existing UX/UI flow, using a Direct API integration, or use one of TrueLayer UI and SDK components.

Payment token creation

Like with Payments v3 APIs, you will need to generate a Bearer access_token. This will be used to get info from your merchant account and to initiate API calls. Use your TrueLayer client_id and client_secret (found in your TrueLayer Console) to request an access_token from our auth server.

The /connect/token endpoint is the same. The scope must now be payments, which is used for both pay-ins (deposits) and payouts (withdrawals and refunds).

As with previous API versions, the generated access_token lasts for 1 hour and once expired, you need to generate a new one.

Example:

EnvironmentEndpoint
Livehttps\://auth.truelayer.com/connect/token
Sandboxhttps://auth.truelayer-sandbox.com/connect/token
curl -X POST  
    -d grant_type=client_credentials  
    -d client_id=${client_id}  
    -d client_secret=${client_secret}  
    -d scope=payments
https://auth.truelayer-sandbox.com/connect/token
{  
    "access_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6IjE0NTk4OUIwNTdDOUMzMzg0MDc4MDBBOEJBNkNCOUZFQjMzRTk1MTBSUzI1NiIsInR5cCI6ImF0K2p3dCIsIng1dCI6IkZGbUpzRmZKd3poQWVBQ291bXk1X3JNLWxSQSJ9.eyJuYmYiOjE2NjAyNDU0NzEsImV4cCI6MTY2MDI0OTA3MSwiaXNzIjoiaHR0cHM6Ly9hdXRoLnRydWVsYXllci1zYW5kYm94LmNvbSIsImF1ZCI6InBheW1lbnRzX2FwaSIsImNsaWVudF9pZCI6InNhbmRib3gtZGFyeWx0ZXN0LTc2YjkwOCIsImp0aSI6IkE0MTNERDhFOENENTJGQUQ5MjcwRTU3QjJCN0RFNjhFIiwiaWF0IjoxNjYwMjQ1NDcxLCJzY29wZSI6WyJwYXltZW50cyJdfQ.hV5Nuqi-X9PqNDOyVftnWZzHhuBIetsjM1zeK-64ZSJ9aTqPdwhqVGiM4zTqLEx0ZfT34MbUfY98cFu00X3SbgS4fV7_Mu2jV_5ofrLdlb_KoIFo82ZG5Y4SNd19vFI5sEIkYIL3KtYnvnjUwP4UZvxgl0siTg1K0kRqws8SqfeOwStgaHsBfYcTUi_w3Z5DSZTspR_G_FixOHGjTPFY48GPACO-wyfH5JZn_uMpARRUam-sadukUpe8yjxFrg1zQ8mqXBhuuBbk8PoG4DCkk5tY-lTjFx92P1NuElMP1RzvIJ_-1qDhdtnNJROLm09_D-l4YX1VIaxL29Wv9kudqQ",  
    "expires_in": 3600,  
    "scope": "payments",  
    "token_type": "Bearer"  
}

Merchant account

Docs

A merchant account is a bank account managed by TrueLayer on your behalf. As seen in the diagram above, the merchant account sits in the middle and enables the following flow of funds:

  • End-user payments from their bank account to the merchant account (Deposits)
  • Payments from the merchant account to the end user bank account (Payouts)
  • Funding of the merchant account from your corporate business account
  • Sweeping of funds from the merchant account to your corporate business account

Within the TrueLayer Console you will find the details to this bank account, including the merchant account holder name, account number, sort code, and IBAN. All payments coming into and out of this account will also be reflected in the TrueLayer Console.

Get Balances

Docs | API reference

Payments v3 endpoint | https://api.truelayer.com/merchant-accounts

The v3 response now includes more information, including sort_code and account_number (for UK currency) and the merchant account id, which is used to identify the merchant account to where closed-loop payouts are made, or where payouts are being sent from.

{  
    "items":  
    [  
        {  
            "id": "68e11e56-1062-4529-8cc7-e5c291948db7",  
            "currency": "GBP",  
            "account_identifiers":  
            [  
                {  
                    "type": "sort_code_account_number",  
                    "sort_code": "040668",  
                    "account_number": "00001719"  
                },  
                {  
                    "type": "iban",  
                    "iban": "GB71CLRB04066800001719"  
                }  
            ],  
            "available_balance_in_minor": 4039,  
            "current_balance_in_minor": 4039,  
            "account_holder_name": "Federico Casali"  
        },  
        {  
            "id": "dc75c4c0-85c9-489d-8394-09854f651d4e",  
            "currency": "EUR",  
            "account_identifiers":  
            [  
                {  
                    "type": "iban",  
                    "iban": "FR7630006000011234567890189"  
                }  
            ],  
            "available_balance_in_minor": 9835,  
            "current_balance_in_minor": 9835,  
            "account_holder_name": "Federico Casali"  
        }  
    ]  
}

Get Transactions

Docs | API reference

Payments v3 endpoint | https://api.truelayer.com/merchant-accounts

Set up Sweeping

Docs | API reference

To set up or change automated VRP sweeping settings, the endpoint is different, and the merchant account ID also needs to be passed as part of the endpoint URI.

Payments v3 endpoint | https://api.truelayer.com/merchant-accounts/<merchant_account_id>/sweeping

Pay-ins (Deposits)

Create deposits into the merchant account.

Docs | API reference

Step 1: Pay-In creation call

The Payments API call needs to be initiated from the backend, including the Bearer access_token we got in the previous step.

📘

Request signing

Learn more about request signing for Payments v3.

You can find your merchant_account_id in Console > Payments > Merchant Account or via GET /merchant-accounts

Using v1 APIs, you created a pay-in into your merchant account by making an API call request to the https://pay-api.truelayer.com/single-immediate-payments endpoint.


The two examples below show how to convert v1 payments creation calls to v3. There are two examples, one where the remitter information isn't passed, and one where it is passed.

See below an example of a payment creation call with v1 and its corresponding v3 version:

Here is an example where remitter data is also being passed in the request, and the corresponding v3 version:

As shown in the image above, the equivalent payment creation call can be made in v3, to the https://api.truelayer.com/payments endpoint.

v1 endpointv3 endpoint
https://pay-api.truelayer.com/single-immediate-paymentshttps://api.truelayer.com/payments

Then, the following changes in the request body should be applied (see the API reference for more information):

  • The beneficiary merchant account ID (where the money will be sent to) has now to be explicitly passed as the merchant_account_id value. The currency value needs to match with the merchant account currency. You can find the merchant_account_id value from the TrueLayer Console, under the Payments > Merchant Account page, or retrieving it from the /merchant-accounts endpoint.
  • user is now a dictionary object that is including multiple values, and represents the user authorizing the payment.
  • type needs to be specified as bank_transfer value.
  • In case you need to pass a remitter provider_id, it can be passed as part of the provider_selection object, where the type value has been passed as preselected (see example 2 above).

List of available parameters

API reference

FieldDescription
amount_in_minorThe amount in minor units. Minor units are the smallest units of a currency, depending on the number of decimals.

For example: EUR 1 = 100 cents
currencyMust be set to GBP or EUR.
payment_methodConfiguration options for the payment method.
payment_method.provider_selectionWhen set to user_selected, this allows the user to select their bank in the hosted payment page (use this option for first time deposits).
payment_method.provider_selection.filterConfiguration options to constrain which providers should be available during the provider_selection action.
payment_method.provider_selection.scheme_selectionConfiguration options to specify the type of scheme selection: instant_only Only allow providers that support instant payments.

Some EU providers may charge the remitter a fee for using instant payments. These providers are not returned in the provider selection action by default. To include them, you can set the allow_remitter_fee flag to true.

To enable your user to choose which payment scheme to use, set the scheme_selection object to user_selected.
payment_method.beneficiaryMust be set to external_account
payment_method.beneficiary.account_identifierIdentifies the destination account. In the case of EUR payments the identifier type is iban.
payment_method.beneficiary.account_holder_nameMust be the player’s legal name as registered.
payment_method.beneficiary.referenceReference that will appear in the player’s bank statement.
userThe user authorising the payment.
user.idA unique identifer for the user. Must be UUID format.
user.nameThis is the full legal name of your end user.
user.emailThe email address of your end user according to RFC 2822.
user.phoneThe phone number of your end user in formats recommended by ITU. The country calling code must be included and prefixed with a +.
user.date_of_birthThe date of birth of your end user, in YYYY-MM-DD format.
user.addressThe physical address of your end user.
user.address.address_line1The full street address including house number and street name.

Pattern: ^.{1,50}$
user.address.address_line2(Optional)

The full street address including house number and street name.

Pattern: ^.{1,50}$
user.address.cityName of the city / locality.

Pattern: ^.{1,50}$
user.address.stateName of the county / state. If not available pass the same value as in city.

Pattern: ^.{1,50}$
user.address.zipZip code or postal code.

Pattern: ^.{1,20}$
user.address.country_codeThe country code according to ISO-3166-1 alpha-2.
metadataOptional field for adding custom key-value data to a resource. This is saved on payment creation and returned on every payment retrieve.

This object can contain a maximum of 10 key-value pairs, each with a key with a maximum length of 40 characters and a non-null value with a maximum length of 500 characters.

With v1 you implemented payment flow using either the TrueLayer v1 payment dialog web page or building your own bank selection screen. These scenarios are both supported in v3.

In general, though, the recommended path is to benefit from the TrueLayer v3 out-of-the-box payment authorisation flows for handling the bank selection (like the Hosted Payment Page or the dedicated SDKs for iOS and Android), you can omit passing any remitter provider information in the payment creation call. See our docs page for more information.

With v1 APIs, after the payment creation request to https://pay-api.truelayer.com/single-immediate-payments, the API response includes a direct link to the provider specified in the request.

With Payments v3 APIs, instead, the https://api.truelayer.com/payments request creates a payment that still requires authorisation, and returns an object which includes the following:

{  
    "id": "e9931912-da0b-4aa7-8209-357741836691",  
    "user":  
    {  
        "id": "f61c0ec7-0f83-414e-8e5f-aace86e0ed35"  
    },  
    "resource_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzY29wZSI6InBheW1lbnQiLCJjbGllbnRfaWQiOiJzYW5kYm94LWRhcnlsdGVzdC03NmI5MDgiLCJqdGkiOiJlOTkzMTkxMi1kYTBiLTRhYTctODIwOS0zNTc3NDE4MzY2OTEiLCJuYmYiOjE2NjMxNzIwMzQsImV4cCI6MTY2MzE3MjkzNCwiaXNzIjoiaHR0cHM6Ly9hcGkudHJ1ZWxheWVyLXNhbmRib3guY29tIiwiYXVkIjoiaHR0cHM6Ly9hcGkudHJ1ZWxheWVyLXNhbmRib3guY29tIn0.yjQHGEASEJmvpl-PTxkngXWwVpzoWSWnuIQb_6bKaCU",  
"status": "authorization_required"  
}

Where:

  • id is the payment_id (or deposit_id)
  • user.id is the user.id being passed in the request. In case no user.id is passed in the request, TrueLayer will generate one and return it here.
  • resource_token is the token that should be used in the payment authorisation step only in the case you want to use TrueLayer UX/UI (HPP, EPP, SDK) for the Payment Authorisation flow.

📘

Resource tokens are valid for 15 minutes

After 15 minutes, the resource_token associated with the payment expires, causing the payment itself to fail.

The status of the payment will move to expired, instead of remaining in initiated indefinitely.

The payment has now been created and its status is authorization_required.


Migrating from a previous version

If you want to keep your custom provider selection flow, and continue to follow a logic where you are passing the remitter provider_id in the request, you can still do that as Payments V3 fully supports this.

You can continue to present white-labelled provider selection and consent pages to your users (and therefore, perform the payment creation API call after the provider has been selected and passed in the request).

If you are currently using a providers endpoint to fetch the provider_id, you can still keep this logic in your code. The remitter.provider_id value can be used for the payment_method.provider_selection.provider_id value, for payments from a “preselected” provider_id (which means from a specific provider).

However, you can create a pay-in (deposit) without specifying the provider_id the payment is coming from. Instead, the user selects their provider in the next step (see 'Select a provider for a payment' and the payment authorisation pages for web, mobile SDK or a white-labelled direct API integration).

So, if you would like to benefit from v3's out-of-the-box payment authorisation Web UI components or Mobile UI components for handling bank selection, you also won't need to pass any remitter provider information at the payment creation stage.

This also applies to payment scheme selection; you do not need to provide a specific scheme.id in the payment creation call. Instead, you can enable your user to select the payments rail they would like to use as part of the authorisation flow.


The bank selection screen: provider_selection.type = “user_selected:” vs “preselected”

As mentioned above, if you want to pass the provider_id in the request, in Payments V3 the provider_selection.type needs to be passed with the preselected value.

However is important here to acknowledge how with Payments V3 the Payment flow would work in case of using the user_selected value for provider_selection.type.

The concept is that in this case you would be first creating the payment, defining currency, amount and passing a filter object, that will determine which banks are going to be returned eventually in the authorization_flow subsequent step.

Basically, the difference is that you can skip providers endpoint calls ahead of creating the payment, and instead incorporate into the payment creation call the filters you would use to fetch the providers list, and then will either receive this list of providers in the /authorization-flow subsequent API call response (if integrating with a Direct API approach) or will receive this list of returned providers from the UI/UX component (like HPP, EPP, SDKs… [link]) used for the Authorization-flow step.

Let’s make an example.

In the following Payment creation call, see the filter object:

curl --request POST \
--url https://api.truelayer-sandbox.com/v3/payments \
--header 'Idempotency-Key: string' \
--header 'Tl-Signature: string' \
--header 'accept: application/json; charset=UTF-8' \
--header 'content-type: application/json; charset=UTF-8' \
--data '

{
    "currency": "GBP",
    "payment_method":
    {
        "type": "bank_transfer",
        "provider_selection":
        {
            "type": "user_selected",
            "filter":
            {
                "countries":
                [
                    "GB"
                ],
                "release_channel": "general_availability",
                "customer_segments":
                [
                    "retail"
                ]
            },
            "scheme_selection":
            {
                "type": "instant_only",
                "allow_remitter_fee": false
            }
        },
        "beneficiary":
        {
            "type": "merchant_account",
            "verification":
            {
                "type": "automated"
            },
            "merchant_account_id": "AB8FA060-3F1B-4AE8-9692-4AA3131020D0",
            "account_holder_name": "Ben Eficiary",
            "reference": "payment-ref"
        }
    },
    "user":
    {
        "id": "f9b48c9d-176b-46dd-b2da-fe1a2b77350c",
        "name": "Remi Terr",
        "email": "[email protected]",
        "phone": "+447777777777",
        "date_of_birth": "1990-01-31"
    },
    "amount_in_minor": 1
}

The filter object configured in this way will determine that (as an example) during the payment authorization, only UK banks (countries:[GB]) will be returned, and that will offer only payments instant and not subject to a fee.

Let’s then look now at the next step where the payment is authorised.

 Step 2: Payment Authorisation

Docs

In most circumstances, to authorise the payment, at this stage is recommended to use the TrueLayer UX/UI components (hosted payment page, embedded payment page, SDKs). This approach will result in being able to benefit from a series of advantages and better scalability in case of expanding into new geographies as TrueLayer UX/UI components evolve ensuring to support all possible different requirements from all supported providers (for example, additional screens in case of additional branches to be selected).

When expanding in the EU, integration efforts become more complex without using TrueLayer Hosted Payment Pages or SDKs. In some cases (for example, German banks using embedded flows), they are mandatory if you are operating with TrueLayer certificates (you are not regulated).

Coming from a Payments v1 integration, you may have been using the TrueLayer payment page dialogs to handle the bank selection screen and/or the payment consent screen. With v3, this is done by adopting a hosted payment page (or embedded payment page, or our native mobile SDK).

See how to handle the authorisation flow using TrueLayer's web components, and directly see our docs for our hosted payment page or embedded payment page. Alternatively, handle the authorisation flow using TrueLayer's mobile SDKs.

📘

For more advice on designing the best experience for your users, read our online UX/UI guidelines.

Direct API integration

In the case that you’d like to keep your current white labelled frontend and proceed with a Direct API integration, and handle payment authorisation using TrueLayer APIs from the backend, v3 fully supports this scenario and you can continue to present your custom bank selection and consent page to your users (and therefore, perform the payment creation API call after the provider has been selected and passed in the request).

  • Likewise, the /providers endpoint is used to fetch information about the provider_id and other info. You can still keep this logic in your code and the provider_id values can be used for the payment_method.provider_selection.provider_id value.
  • One thing to be kept in mind in this case, is that if you are passing the remitter provider_id, which, as mentioned above, and shown in the examples, in v3 is under payment_method.provider_selection.provider_id, you will also have to pass the relative provider payment scheme_id.
  • You can get the scheme_id either from the /providers endpoint, or after the first payment is settled into the merchant account, you can grab it from the payment_settled webhook, as explained in the sections ahead.
  • Once the Payment is created, you will have to make an additional API call to the /authorization-flow endpoint in order to start the authorisation flow for the payment (see the API specs for more information).

If you currently have implemented a customised white labelled frontend flow, want to keep and proceed with a Direct API integration, please get in touch directly with us.

Step 3: Consume webhooks and payment statuses

Once the payment authorisation process is completed, the user is redirected back to the return_uri. Now you just have to display indications to the user based on the payment status received via webhooks.

In Payments v3, these are the payment statuses to expect:

StatusDescriptionNotification Method
authorization_requiredThe payment has been created successfully and no further action has been taken.Status only via /GET /payments/{payment_id}
authorizingThe end user has started the authorization journey by interacting with the Hosted Payments Page or the client's UI and have not completed the journey yetStatus only via /GET /payments/{payment_id}
authorizedThe end user has completed the authorization journey and the payment has successfully completed its authorization flowStatus only via /GET /payments/{payment_id}
payment_executedTrueLayer has submitted the payment to the bank and the payment has been accepted successfully. The bank will now start processing the paymentStatus via /GET /payments/{payment_id}

Webhook sent to your endpoint
payment_settledThe payment has settled into the TrueLayer merchant account. This is a terminal status. Payment source details available.

When a payment settles in your TrueLayer merchant account, we confirm the bank details of the remitter account. In additionally to the bank details, we include a payment_source_id which identifies that particular bank account. This is a unique ID TrueLayer creates that refers to the bank account used to deposit.
Status via /GET /payments/{payment_id}

Webhook sent to your endpoint.
payment_failedThe payment has failed to transition to the next status. Within this notification, TrueLayer provides information about why the payment wasn't successful.

The failure reason is shared in the failure_reason field on the payment resource and the failure_stage field shares the payment status where the payment transitioned to payment_failed. This is a terminal status.
Status via /GET /payments/{payment_id}

Webhook sent to your endpoint.

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 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. If we continue to receive any other status codes than 2xx ones after retrying for 72 hours, we will discard the webhook. We apply this retry policy for payments, payment refunds, payouts, and mandates.

Pay-in webhook examples

🚧

We recommend that you use our signing libraries to verify the Tl-Signature of the received webhooks.

You must set your Webhook URI in Console to receive webhook notifications.

	{  
    "type": "payment_executed",  
    "event_version": 1,  
    "event_id": "ed5c3c60-6760-4830-86c3-bced4ce63f21",  
    "payment_id": "e9931912-da0b-4aa7-8209-357741836691",  
    "payment_method":  
    {  
        "type": "bank_transfer",  
        "provider_id": "mock-payments-gb-redirect",  
        "scheme_id": "faster_payments_service"  
    },  
    "executed_at": "2022-09-14T16:14:24.217Z",  
    "metadata":  
    {  
        "brand": "TL Casino"  
    }  
}
{  
    "type": "payment_settled",  
    "event_version": 1,  
    "event_id": "1d10e4e7-26a0-44b5-8f76-226ccf7e9c6c",  
    "payment_id": "e9931912-da0b-4aa7-8209-357741836691",  
    "payment_method":  
    {  
        "type": "bank_transfer",  
        "provider_id": "mock-payments-gb-redirect",  
        "scheme_id": "faster_payments_service"  
    },  
    "settled_at": "2022-09-14T16:14:26.958Z",  
    "payment_source":  
    {  
        "account_identifiers":  
        [  
            {  
                "type": "sort_code_account_number",  
                "sort_code": "040668",  
                "account_number": "00000871"  
            },  
            {  
                "type": "iban",  
                "iban": "GB75CLRB04066800000871"  
            }  
        ],  
        "id": "17a580e4-7d58-4f84-9b80-a649ba3982b9",  
        "account_holder_name": "JOHN SANDBRIDGE"  
    },  
    "user_id": "f61c0ec7-0f83-414e-8e5f-aace86e0ed35",  
    "metadata":  
    {  
        "brand": "TL Casino"  
    }  
}
{  
    "type": "payment_failed",  
    "event_version": 1,  
    "event_id": "8dfba42f-72db-4aa1-b573-e0602ca65506",  
    "payment_id": "09baadd0-499f-480f-a451-0ed6cd74593e",  
    "payment_method":  
    {  
        "type": "bank_transfer"  
    },  
    "failed_at": "2022-09-14T16:22:00.528Z",  
    "failure_stage": "authorizing",  
    "failure_reason": "canceled",  
    "metadata":  
    {  
        "brand": "TL Casino"  
    }  
}

Payouts introduction

The Payments API v3 supports two different types of payout:

  • Closed-loop
    When the payout is sent to a user which already made a deposit into the merchant account.
  • Open-loop
    When the payout is sent to a bank account that hasn't necessarily made a pay-in into the merchant account.

In addition, a dedicated Refunds API is available with Payments v3. This is specifically designed for issuing refunds of payments made to the merchant account. The amount refunded cannot exceed the original pay-in value.

Closed-Loop Payout

Docs | API reference

ProductEndpoint
Payouts v1https://payouts.truelayer.com/v1/payouts
Payments v3https://api.truelayer.com/payouts

To make a closed-loop payout in v3 you only need to specify a payment_source_id as the beneficiary, and add the user_id corresponding to the user that the money is going to.

This is returned in the payment_settled webhook as payment_source.id. The payment_source.id is a unique ID that TrueLayer creates, which corresponds to the original bank account the user deposited funds from.

The user_id must correspond to the user.id returned in the Pay-in creation response, which is also returned in the payment_settled status webhook. Therefore, this enables us to send funds back to the exact same bank account that was used for the deposit.

If you were using the legacy Payouts v1, the changes on the request params are:

v1 payoutPayments v3 closed-loop payout
beneficiary_namebeneficiary.payment_source.id
beneficiary_ibanbeneficiary.user_id
beneficiary_referencebeneficiary.reference
transaction_idNo longer required
Sender ‘merchant account’ was automatically retrieved based on the currency.A merchant_account_id, relating to the ID of the merchant account the payment will come from, has to be passed in the request.

This is an example of a Payments v3 closed-loop payout request to https://api.truelayer.com/payouts:

{  
    "merchant_account_id": "01829515-3525-4812-a6c0-6d9e195c947e",  
    "amount_in_minor": 1000,  
    "currency": "GBP",  
    "beneficiary":  
    {  
        "type": "payment_source",  
        "user_id": "4d9af4be-f75b-4ca7-be9b-b842bf7237c1",  
        "payment_source_id": "1c928e0e-6dc9-497c-8154-83dce43b2377",  
        "reference": "Payout0001"  
    },  
    "metadata":  
    {  
        "brand": "optional metadata"  
    },  
}

In this request:

  • beneficiary.payment_source_id is returned from the pay-in webhook (or GET status) once the payment has been settled.
  • beneficiary.user_id is the same user.id used for pay-in creation, and then also returned from the pay-in webhook (or GET status) once the payment has been settled.

This is an example of the Payments v3 response for this request:

{  
        "id": "5016c85d-de28-406d-9866-0a3ed85af3b1"  
}

See our Payments v3 closed-loop payout documentation for more details about Payments v3 closed-loop payouts.

Open-loop payout

Docs | API reference

ProductEndpoint
Payouts v1https://payouts.truelayer-sandbox.com/v1/payouts
Payments v3https://api.truelayer.com/payouts

With v3 payouts, you can still also make payouts to any supported bank account by using the beneficiary type external_account and submitting the relevant account details.

Note: With the Payouts API v1, you passed the beneficiary name and IBAN in the request, also for UK banks. With v3, if you are in the UK, you can now use sort_code and account_number as beneficiary account_identifier data.

Of course, you can still be using IBAN if you wish: set the account_identifier.type to iban, and include account_identifier.iban .

v1 payoutPayments v3 open-loop payout
beneficiary_namebeneficiary.account_holder_name
beneficiary_ibanEither:

beneficiary.account_identifier.sort_code
and
beneficiary.account_identifier.account_number

or

beneficiary.account_identifier.iban
beneficiary_referencebeneficiary.reference
transaction_idNo longer required
Sender merchant account automatically retrieved based on the currency.A merchant_account_id, relative to the ID of the Merchant Account from where the payment will come from, has to be passed in the request.

🚧

User details

As TrueLayer conducts sanction and AML screening on all transactions to and from your merchant account, and to reduce the number of RFIs raised due to sanctions investigation, the additional fields: address and date_of_birth must be included in the API request.

This is an example of a Payments v3 open-loop payout request to https://api.truelayer.com/payouts:

{  
    "merchant_account_id": "c6ba13f2-35ef-4556-a99e-a6afd6275044",  
    "amount_in_minor": 100,  
    "currency": "GBP",  
    "beneficiary":  
    {  
        "type": "external_account",  
        "reference": "Withdrawal",  
        "account_holder_name": "John Smith",  
        "account_identifier":  
        {  
            "type": "sort_code_account_number",  
            "sort_code": "<sort code>",  
            "account_number": "<account number>"  
        },  
        "date_of_birth": "1992-08-03",  
        "address":  
        {  
            "address_line1": "1 Hardwick St",  
            "address_line2": "Clerkenwell",  
            "city": "London",  
            "state": "London",  
            "zip": "EC1R 4RB",  
            "country_code": "GB"  
        }  
    },  
    "metadata":  
    {  
        "prop1": "value1",  
        "prop2": "value2"  
    }  
}

This is an example of the response to a successful request:

{  
        "id": "f5a6c87e-446a-4dcc-a91e-a74e3e4e0875"  
}

Refund

If you need to issue refunds, with Payments v3 a dedicated /payments/{id}/refunds endpoint is available to specifically make it easier to handle refunds.

Refunds with the Refunds API are basically closed-loop payouts. The differences are:

  • The maximum amount refundable is the pay-in amount being refunded.
  • The pay-in payment_id is the only piece of information required for the Create a refund API call.
  • It is possible to issue multiple refunds for the same pay-in.

Learn more about Refunds with the Payments API v3.

Visual summary of Payments v1 to v3 Closed-Loop + Refunds API and v3 webhook.

 Consume Payouts webhooks and payment statuses

StatusDescriptionNotification method
pendingThe payout has been created with TrueLayer's API but it has not yet been authorized and sent to the payment scheme for execution.Status only via
/GET /payouts/{payment_id}
authorizedThe payout has been created via TrueLayer's API and has been sent to the payment scheme for execution.Status only via
/GET /payouts/{payment_id}
payout_executedThe payout was executed. The payout amount has been deducted from your merchant account.Status via
/GET /payouts/{payment_id}

Webhook sent to your endpoint
payout_failedThe payout failed. The payout amount has not been deducted from your Merchant Account.Status via
/GET /payouts/{payment_id}

Webhook sent to your endpoint

Webhook examples (Payout)

🚧

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

You must set your Webhook URI in Console to recieve webhook notifications.

{  
    "type": "payout_executed",  
    "event_id": "1b712c55-6bc4-487c-8a5b-2107623fe3bf",  
    "event_version": 1,  
    "payout_id": "5016c85d-de28-406d-9866-0a3ed85af3b1",  
    "executed_at": "2022-09-14T16:39:50.593Z",  
    "beneficiary":  
    {  
        "type": "payment_source",  
        "user_id": "4d9af4be-f75b-4ca7-be9b-b842bf7237c1",  
        "payment_source_id": "1c928e0e-6dc9-497c-8154-83dce43b2377"  
    },  
    "metadata":  
    {  
        "brand": "TL Casino"  
    }  
}
{  
    "type": "payout_failed",  
    "event_id": "f8a144dc-a550-4681-844b-4de231ec3764",  
    "event_version": 1,  
    "payout_id": "f8a144dc-a550-4681-844b-4de231ec3764",  
    "failed_at": "2022-09-14T16:41:21.006718283Z",  
    "failure_reason": "insufficient_funds",  
    "beneficiary":  
    {  
        "type": "payment_source",  
        "user_id": "4d9af4be-f75b-4ca7-be9b-b842bf7237c1",  
        "payment_source_id": "1c928e0e-6dc9-497c-8154-83dce43b2377"  
    },  
    "metadata":  
    {  
        "brand": "TL Casino"  
    }  
}

Learn how to migrate from our legacy APIs to the Payments API v3.