At a high level, and common to all use cases, the technical integration steps are:
- Setting up the infrastructure and structuring the database for TrueLayer-related data.
- Creating the user authentication flow.
- Configuring the backend to use Data API.
Why it’s important
- Storing all the relevant and required customer end-user data.
- Adopting security measures.
The first step in the TrueLayer integration consists of structuring your Database
in a way to store all the required and relevant information. From a security perspective, it is important that all the API requests including tokens and client authentication keys stay in the backend and are not on client side. Encrypting keys and tokens is also always a good practice.
All database structures are different, and here we’ve given an example that might work well in the majority of cases. There is a Token_table which holds details of a given user’s consent which includes
refresh_token, expiry dates, and so on. For each consent, there may be multiple accounts that the user has given access to. The Accounts_table should hold details about a given account (for example, account number, sort code, account holder name and so on).
Finally, a given account will have multiple transactions that you may want to store. In the Transactions_table, you’ll store details about these transactions (amounts, description, dates, merchant names, classification/categorisation and so on).
For security, it's good practice to store encrypted values of your client keys (
client_secret) and encrypted values of user-associated tokens (
Make sure to also not access TrueLayer APIs calls from the frontend of your application, as well as for our CORS policy. You should always implement our functionality on the server-side of your application, to avoid exposing the client keys and tokens to the outside world.
The first step in the authentication process is to send the End user to the TrueLayer Authorisation Server via a properly formatted link (auth link).
The easiest way to build an auth link is in the TrueLayer Console, under the ‘Auth Link Builder’ section. From there you can:
- Pick the providers (banks) that you want to be displayed, among Open Banking and Challenger banks.
- Choose the permissions, which are the ‘scopes’ inside the auth link and eventually reflect the permissions the user will be prompted to accept in the UI.
- Choose the Redirect URI where the user will be redirected once the authentication process is complete. You must add the in the App Settings part of the TrueLayer Console.
The auth link will automatically be generated underneath the panel where you choose the providers, permissions and redirect URIs.
When the user goes through an auth link with TrueLayer’s UI, they will first be prompted to accept the permissions that correspond to the scopes in the auth link. Once they have accepted these permissions, they will then land on a bank selection screen, where they will pick the bank where the account they want to link is held. Once they’ve selected the bank, they will go through to that bank’s portal to authenticate.
Once the user has finished the authentication process in their bank, they will be taken to the redirect URI which will contain a code (and state, if you have added one) that you can exchange for the access and refresh tokens.
Many apps will want to display the UI of the authentication process as natively as possible, instead of using the customisable TrueLayer UI.
There are two screens that can potentially be done natively:
- Native bank selection screen:
If you are building a native bank selection screen, you will need to:
- Fetch a list of banks that TrueLayer supports, so that you know which banks to display to your users. You can do this on a regular basis (for instance, monthly) and then store in or update your database. Alternatively, you can fetch the list dynamically. You can fetch the current list of banks using the
/providersendpoint. You'll also find information about the country, supported scopes,
provider_idand logo files of each bank in the response.
- Create an auth link for each bank which is where the user should be sent when they choose that bank. You should pass an additional
provider_idparameter into each auth link you create that corresponds to the bank the user is selecting (for instance, the
provider_idfor Monzo is ob-monzo). You can find the
provider_idparameter means that the TrueLayer authorisation server will automatically skip the default bank selection screen and take the user straight through to the bank in question.
- Native permissions screen:
When a user is sent through a TrueLayer auth link, the first page they see is TrueLayer’s UI permissions screen. This screen prompts the user to accept the permissions (‘scopes’) that have been passed in the auth link.
Companies regulated by the FCA as an AISP (Account Information Services Provider) have the option to skip TrueLayer’s permissions screen. In this case, you will need to:
- Display your own permissions screen prior to the bank selection screen (where the auth links are).
- Ensure that the permissions the user is being asked to accept are the same as the ‘scopes’ in the auth links.
- Directly ask TrueLayer to whitelist your
client_id. You can either ask our Client Care team or one of the Integration Support team.
Companies without AISP status must use TrueLayer’s permissions screen.
The following is the description of the user flow once the authentication has
been completed on the provider (bank) side:
- User authenticates and selects the accounts to be linked.
- User is quickly directed to the TrueLayer auth server
auth.truelayer.com. Typically, at this stage, a blank browser page is opened and the
redirect_uri, as being set in the TrueLayer console, is being received (along with the associated
There are two choices at this stage that can be made regarding the implementation of the
redirect_uri can either be pointing at the backend of your application or directly redirecting the user to the desired application page.
In the first scenario, the
redirect_uri can point to your backend service. In this case, you'll have to:
- Get the code passed and use it to obtain and store the user tokens.
- Store and handle the
state, if being set and returned.
- Return a valid URI that would redirect the user to the desired landing page in your application (for mobile, this means returning a deep link to the desired app activity or controller, ideally as a valid iOS Universal Link or Android link).
In the second scenario, the
redirect_uri can directly be returned to your user. In this case, you would have to:
- Configure the redirect_uri as the link to the desired landing page in your application (for mobile, this means returning a deep link to the desired app activity or controller, ideally as a valid iOS Universal Link or Android link).
- Have the client to pass the
codeto the backend, which they need to obtain and store the user tokens.
- Store and pass the
stateto the backend, if it's being set and returned.
The user will have to transition from a web page to the customer mobile app. In this case, the recommendation is to use Universal Links for iOS.
The reason behind the above recommendation is related to the fact that in iOS, using the Universal Link, the native pop-up prompting the user to click to be redirected to the mobile app won’t be displayed and will instead automatically redirect the user.
After the user has returned to your application, you should query the state of the payment to see if it was successful.
state is an optional value that can be passed in the
Its value is returned as a parameter (with the
code and the
scope) alongside the
redirect_uri once your user has authenticated with their provider.
state can contain pretty much any data value you would like to be passed through the authentication flow.
Usually, its purpose is to have a field that can be used for reconciliation of users within the authentication flow after re-consenting. This helps maintain state between the request and the callback.
For example, the
userID and any other data could be passed within the state to identify the user or to validate or sign the request (such as by passing a JWT encoded signature token).
Any value returned will be included in the URL, Therefore we recommend encoding the state (for example, in base64) to make sure there are no characters that invalidate the URL.
Due to OB regulations, users are required to re-consent after 90 days.
The consent is associated with the Provider, therefore a user will have
to re-consent on all the accounts associated with a specific provider. Still, there are some recommendations we can provide in order to make it less painful for the users.
- Proactively inform the user
After a user authenticates, is a good practice to keep track of the date/time of the user authentication by recording the timestamp and associate it with the other user consent information on your backend (User Unique ID, Tokens, Credentials_ID, Provider_ID...).
You can create a job on your end that checks this date/time on your userbase.
When the 90 days are approaching, you can display some alert to the user (eg. Push Notifications or other means, based on how your app is structured) informing them that they soon need to re-consent for that Provider.
Given that in the current bank flows, the user will be prompted to choose which bank accounts they want to link, it is important to tell them to select the same accounts that are currently linked. This will avoid any confusion on the user’s end and also in your DB.
Regarding the /me endpoint, we return the consent expiration date (
consent_ expires_at) directly from the bank.
However, banks are not required to provide this data, and therefore we do not recommend relying on it. This data could not be returned and/or we can not be 100% sure that is also necessarily reflecting the 90 days SCA requirement.
- Pass the
provider_idon the re-consent
When asking the user to re-consent, the provider name will most likely now be
To ease the friction, the
auth_uri from there can directly pass the
provider_id which would directly send the user to the provider auth page skipping any kind of bank selection screen.
- What’s next
TrueLayer is currently working to support a dedicated provider endpoint for providing an easier experience with less friction, but at the moment the only option is to send the user to the initial consent flow.
The differences with the standard authentication flow could be provider dependent.
Check out our blog post on introduction to token management concepts.
The aim of the authentication process is to obtain an access token which gives you the ability to access data from the user’s bank account.
Given that the access token is short-lived (up to 60 minutes), another aim is to obtain a refresh token which can renew the access token going forward (necessary for pulling data over a longer period than the initial access token’s lifetime).
Access tokens: An access token is required to access a user’s bank account information. It represents the authorisation the user has given to access their data.
The access token is short-lived. Its lifetime is up to 60 minutes, depending on the bank token lifetime. When generating an access token, its lifetime will always be returned in the
expires_infield of the response. Make sure to check whether an access token has expired before attempting to use it to fetch data.
If the access token has expired, it will be necessary to generate a new one. This is done by using the refresh token, which is returned in the response along with the access token (unless you have disabled offline_access). The new access token will have a different value to the previous one.
It's possible to perform any of the API requests with just a valid
access_token. Once the access_token expires, it needs to be renewed by using the
Refresh tokens: The refresh token is required to renew the access token.
The refresh token has the same lifetime as the user’s consent, which is 90 days, and maintains a fixed value. However, throughout this period, if the refresh token is not used for a 30 day period, it will expire.
Therefore, it is important to ensure the refresh token is used at some point within any given 30 day period if you intend to access the user’s account information on an ongoing basis, otherwise the refresh token, and so the user’s consent, will have expired. In that case, the only way to proceed is ask the user to re-consent.
Every time the refresh_token is being used to get a new access_token, its 30 days validity period would renew, until the 90 days expiration associated to the consent is reached.
For example, let’s say User A authenticates now on Day 0. Company X receives an access token and refresh token that are a representation of that user’s consent. Company X immediately fetches the balance and one month of transactions using the access token. This is successful because the access token is still valid.
The next day, Day 1, Company X wants to fetch User A’s latest balance and transactions. They try to use the access token they used yesterday. This is unsuccessful because the access token has expired. So Company X uses the refresh token to generate a new access token, and then tries to fetch the data. Success!
For some reason, Company X then doesn’t need the balance and transactions data until Day 35. They forget to use the refresh token during the intervening period. As a result, when they try to use the refresh token to renew the access token, they get an error. Unfortunately for Company X, the refresh token has expired due to no use over a 30 day period. They have no choice but to re-authenticate User A.
In conclusion, keep track of the expiry date-times of the access and refresh tokens, and depending on the use case, refresh these when necessary.
To avoid the pitfalls of the previous example, it is important to store tokens and their expiry dates in a robust way.
How the access token validity is being set
refresh_token are generated with the following expiration logic:
access_token: 1 hour, if the provider's
access_tokenhas a validity of more than 1 hour. 5 minutes less than the provider's
access_tokenin case it has a validity or less than an hour, for example, if it was thirty minutes, then TrueLayer's
access_tokenwould have twenty-five minutes validity.
refresh_token: Thirty days. Every time the
refresh_tokenis used, it's renewed for another thirty days, until the relevant expiration date is reached. A
refresh_tokenis persistent. This means that the value of the token does not change when you refresh it.
Due to Open Banking regulations, some providers require that transactions older than 3 months must be retrieved in a short time period immediately after the user gives consent and authenticates with the bank.
This time window typically ranges within 5 to 45 minutes. During this time historical transactions can be retrieved. After that, only 90 days of transactions are available.
ο First 5-45 mins = 6 years of historical transactions ο 45 mins+ = 90 days of historical transactions
A list of providers and details for each can be found here:
When requesting more than 3 months after the time window expires, the call would fail with an access_denied error and no partial data would be returned.
It is also recommended to paginate any historical transactions call, especially when requesting more than a year timespan. This minimises the chance of a large API call failing.
3 to 6 months are usually the recommended timespans for each transactions call.
You can make TrueLayer API calls both synchronously and asynchronously.
- Async is in general preferred as it mitigates issues that are beyond the control of TrueLayer.
- TrueLayer automatically implements a retry mechanism for asynchronous calls, thus removing the need for you to write your own error and retry logic.
- The Data API supports asynchronous requests on all endpoints.
Best for retrieving small amounts of data
Best for retrieving large amounts of data
You must handle your own error/retry logic
All error/retry logic is handled by TrueLayer
Marginally quicker response
Marginally slower response
Marginally quicker initial set-up
Marginally slower initial set-up
You cannot use the
To perform a request in Async mode, pass a query parameter async=true and a results_uri parameter that will contain the results of your request once they are available. After making an asynchronous API call, you can poll the results_uri and wait for completion.
To avoid polling, you can pass a webhook_uri parameter to receive a real-time notification via HTTP POST (Webhook) when the request is completed.
Please note that even if webhook_uri is passed the results will not be part of the HTTP POST payload but must be fetched at results_uri.
When the results are ready, they will be available to fetch at the results_uri. The query will return one of the following status messages:
The query is waiting to run.
The query is currently running.
The query has successfully returned results.
The query has failed to retrieve the results.
Therefore, a good practice, would be to query for the status of the request and only fetch the results only in case of a successful status. For more information on asynchronous calls, see Asynchronous calls and webhooks.
Synchronous calls are typically those calls that need to be fast and retrieving a small amount of data. They are usually something similar to a user opening the app and checking the balance right away or pulling only the last few transactions in the recent past.
Asynchronous calls are those usually pulling more data, that aren’t necessarily very much time-sensitive. A background call to fetch all transactions in a long period of time or any other call that would prefer reliability over time to respond.
Updated 21 days ago