Migration guide: Payments v1 to v3 with merchant accounts
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:
- Pay-ins
- Closed-loop payouts
- Open-loop payouts
- Webhooks for payment statuses
- Automatic funds sweeping with VRP
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
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.
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 parameter | Description |
---|---|
Unique User ID | Required. 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). |
Name | Required for non-regulated customers. |
Email address | Required for non-regulated customers. |
Phone number | Required for non-regulated customers. |
Date of birth | Required for non-regulated customers. |
Physical address | Required 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
Learn more about the hosted payment page.
- 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)
Learn more about the embedded payment page.
- 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
Learn more about TrueLayer's mobile SDKs.
- 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.
When you open an app in Console, the tab menu includes sub-sections for:
- Payments, which displays a table of pay-ins to and payouts from your merchant account, and the ability to issue refunds.
- Settings, such as webhook and redirect URIs, and your client ID and secret.
- Merchant Account information, including available and historical balances.
- UI customisation options for the HPP, EPP, and more.
Documentation quickstart guides and links
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:
Environment | Endpoint |
---|---|
Live | https\://auth.truelayer.com/connect/token |
Sandbox | https://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
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
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
Payments v3 endpoint | https://api.truelayer.com/merchant-accounts
Set up Sweeping
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.
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 endpoint | v3 endpoint |
---|---|
https://pay-api.truelayer.com/single-immediate-payments | https://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. Thecurrency
value needs to match with the merchant account currency. You can find themerchant_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 asbank_transfer
value.- In case you need to pass a remitter
provider_id
, it can be passed as part of theprovider_selection
object, where thetype
value has been passed aspreselected
(see example 2 above).
List of available parameters
Field | Description |
---|---|
amount_in_minor | The 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 |
currency | Must be set to GBP or EUR. |
payment_method | Configuration options for the payment method. |
payment_method.provider_selection | When 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.filter | Configuration options to constrain which providers should be available during the provider_selection action. |
payment_method.provider_selection.scheme_selection | Configuration 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.beneficiary | Must be set to external_account |
payment_method.beneficiary.account_identifier | Identifies the destination account. In the case of EUR payments the identifier type is iban . |
payment_method.beneficiary.account_holder_name | Must be the player’s legal name as registered. |
payment_method.beneficiary.reference | Reference that will appear in the player’s bank statement. |
user | The user authorising the payment. |
user.id | A unique identifer for the user. Must be UUID format. |
user.name | This is the full legal name of your end user. |
user.email | The email address of your end user according to RFC 2822. |
user.phone | The 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_birth | The date of birth of your end user, in YYYY-MM-DD format. |
user.address | The physical address of your end user. |
user.address.address_line1 | The 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.city | Name of the city / locality. Pattern: ^.{1,50}$ |
user.address.state | Name of the county / state. If not available pass the same value as in city .Pattern: ^.{1,50}$ |
user.address.zip | Zip code or postal code. Pattern: ^.{1,20}$ |
user.address.country_code | The country code according to ISO-3166-1 alpha-2. |
metadata | Optional 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 thepayment_id
(ordeposit_id
)user.id
is theuser.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 ininitiated
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 V2 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). Alternatively, you can use the V3 providers endpoint, /v3/payment-providers/search
, to get the list of provider IDs.
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": "remi.terr@aol.com",
"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
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 authorisation UIs, and 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 theprovider_id
and other info. You can still keep this logic in your code and theprovider_id
values can be used for thepayment_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 underpayment_method.provider_selection.provider_id
, you will also have to pass the relative provider paymentscheme_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:
Status | Description | Notification Method |
---|---|---|
authorization_required | The payment has been created successfully and no further action has been taken. | Status only via /GET /payments/{payment_id} |
authorizing | The 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 yet | Status only via /GET /payments/{payment_id} |
authorized | The end user has completed the authorization journey and the payment has successfully completed its authorization flow | Status only via /GET /payments/{payment_id} |
payment_executed | TrueLayer has submitted the payment to the bank and the payment has been accepted successfully. The bank will now start processing the payment | Status via /GET /payments/{payment_id} Webhook sent to your endpoint |
payment_settled | The 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_failed | The 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.
This block contains examples of the webhooks you receive for executed, settled and failed payments:
{
"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
Product | Endpoint |
---|---|
Payouts v1 | https://payouts.truelayer.com/v1/payouts |
Payments v3 | https://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 payout | Payments v3 closed-loop payout |
---|---|
beneficiary_name | beneficiary.payment_source.id |
beneficiary_iban | beneficiary.user_id |
beneficiary_reference | beneficiary.reference |
transaction_id | No 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 sameuser.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
Product | Endpoint |
---|---|
Payouts v1 | https://payouts.truelayer-sandbox.com/v1/payouts |
Payments v3 | https://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 payout | Payments v3 open-loop payout |
---|---|
beneficiary_name | beneficiary.account_holder_name |
beneficiary_iban | Either:beneficiary.account_identifier.sort_code and beneficiary.account_identifier.account_number or beneficiary.account_identifier.iban |
beneficiary_reference | beneficiary.reference |
transaction_id | No 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
anddate_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
Status | Description | Notification method |
---|---|---|
pending | The 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} |
authorized | The 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_executed | The 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_failed | The 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.
This block contains examples of the webhooks you receive for executed and failed payouts.
{
"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.
Updated 3 months ago