Introduction
Overview
TrueLayer allows applications to connect securely with their End user’s bank, in order to either read their financial data, gain insight into their income and spending patterns, or initiate payments:
- Data API - instant access to financial data
- Payments API - instant payment initiation
- PayDirect API - instant verification, deposits, and withdrawals
- Verification API - account holder name verification
Our products provide an unified interface between multiple financial institutions and third party applications over a common RESTful API.
Getting Started
Getting started with the Data API
- Sign-up and obtain your
client_id
andclient_secret
. You will need to register at least oneredirect_uri
. - Create an Authentication Link to authenticate your End users
- Obtain an
access_token
following the End user Authentication oAuth 2.0 flow - Use the Data API to retrieve End user’s personal information, account numbers and transaction data.
Getting started with the Payments API
- Sign-up in the sandbox environment and obtain your
client_id
andclient_secret
. You will need to register at least oneredirect_uri
. - Create a client credentials grant to get a token to call the API.
- Use the Payments API to create a new payment resource, and follow the redirect URI to navigate to a bank payment consent flow.
Getting started with the PayDirect API
- Sign up in the sandbox environment and obtain your
client_id
andclient_secret
. You will need to register at least oneredirect_uri
. - Go to the PayDirect section of the sandbox console.
- Select the request access button and wait for the email confirmation.
- Configure your
webhook_uri
and public certificate in the settings. - Create a client credentials grant to get a token to call the API.
- Use the PayDirect API to create deposits and withdrawals, and verify account ownership.
Getting started with the Verification API
- Choose the providers you want to integrate with. Verification API is avaliable in the UK, France, Germany, and Spain in public beta.
- Implement the authentication flow detailed in the Connecting an account guide and:
- Set the
scopes
field to["info", "accounts"]
only. - Set the
providers
field according to your needs.
- Set the
- Contact Support with your
client_id
so that we can enable your access. - Generate an auth link and whitelist your redirect uri’s in the App Settings in the console.
- Generate an access token.
- Use the postman collection to make a request to the API.
Access methods
TrueLayer uses dedicated PSD2 APIs for all available banks. We also use public proprietary APIs when available. For example, Monzo/First-direct. The authentication is managed by the bank.
API Authentication
To call any TrueLayer APIs which require authentication, it’s necessary to first request the creation of an access token. Requests to authenticated APIs which do not include a valid access token will be rejected.
To create an access token, you will need your client_id
and client_secret
. These values can be found in the Console here: https://console.truelayer.com/settings/Application
Data API
When creating an access token for the Data API, you will also need to provide a code which represents the authorisation provided by your user.
See Data API Authentication for more details.
Payments API
Request access token
To create an access token for the Payments API, you simply need to provide the client_id
and client_secret
and request the payments
scope.
Request
curl -X POST \
-d grant_type=client_credentials \
-d client_id=${client_id} \
-d client_secret=${client_secret} \
-d scope=payments \
https://auth.truelayer.com/connect/token
Response
{
"access_token": "JWT-ACCESS-TOKEN-HERE",
"expires_in": 3600,
"token_type": "Bearer"
}
Use access token
Once you have the access_token
from the response, this can be included in Payments API requests as a Bearer token in the Authorization header. Here’s an example with other fields removed for clarity:
Request
curl -X POST \
-H "Authorization: Bearer ${access_token}" \
--data '{...}' \
https://pay-api.truelayer.com/single-immediate-payments
Data types
General
All of the responses returned by TrueLayer APIs are in JSON format. The description of the data types encoded in a JSON response is below.
Type | Description |
---|---|
string |
A UTF-8 string |
datetime |
An ISO8601 encoded date time |
boolean |
true or false |
number |
A float number |
ISO20022 Text Fields
The Payments API constrains some fields to be limited to ISO 20022 text format. These fields are typically used for names and references in bank payment requests.
Valid characters for such a text field include:
a-z
A-Z
0-9
/ – ? : ( ) . , ‘ +
space
Any other characters included will result in a validation error.
API response structure
All responses are JSON encoded.
Success
Success response
{
"results": [
{
"hello": "world"
}
]
}
Field name | Type | Description |
---|---|---|
results |
array | An array of objects |
Error
Error response
{
"error": "internal_error",
"error_description": "Well, this is embarrassing!",
"error_details": {
"detail_key": "detail value"
}
}
Field name | Type | Description |
---|---|---|
error |
string | An error code for classification. eg: internal_error |
error_description |
string | When possible, extra details about the specific error |
error_details |
object | Additional key/value error details if available |
Error codes
The following error codes can be returned with the associated HTTP status for both the Data and Payments API.
Auth (OAuth2) API Errors
HTTP Status | Description | Error | Retry | How to handle |
---|---|---|---|---|
200 |
Success | |||
400 |
The request is missing a required parameter | invalid_request |
No | Check that your API request is correct and that contains all the required parameters |
400 |
The client is not authorized to request an authorization token | unauthorized_client |
No | Check your client id/secret/redirect_url |
400 |
Client authentication failed (e.g., unknown client, no client authentication included, or unsupported authentication method) | invalid_client |
No | Check your client id/secret/redirect_url |
400 |
The resource owner or authorization server denied the request | access_denied |
Yes | Retry later |
400 |
The authorization server does not support obtaining an authorization code using this method | unsupported_response_type |
No | Check that your API request is correct |
400 |
The requested scope is invalid, unknown, or malformed | invalid_scope |
No | Check the scopes that you are requesting |
400 |
The server encountered an unexpected condition that prevented it from fulfilling the request | server_error |
Yes | Retry later |
400 |
The authorization server is currently unable to handle the request due to a temporary overloading or maintenance | temporarily_unavailable |
Yes | Retry later |
400 |
The provided authorization grant or refresh token is invalid, expired, revoked, does not match the redirection URI used in the authorization request, or was issued to another client | invalid_grant |
No | Ask the user to reconnect their account. This most often occurs when a user’s 90 days of consent to access their account has expired. It can also be caused by some rare network errors which can cause a user’s bank tokens to be made invalid. Either way, the user must reconnect their account. |
400 |
The authorization grant type is not supported by the authorization server | unsupported_grant_type |
No | Check that your API request is correct |
401 |
This error can occur in two instances: 1. When the access_token used to retrieve data is malformed, or 2. if the access_token has expired. Please refer to the returned error_description to confirm which issue has occured. |
invalid_token |
No | For malformed tokens, please check the token being used is sent without unintended manipulation. For an expired access_token , try renewing the access_token . If error remains, a new access_token will be required. |
429 |
There are too many concurrent refresh requests for a given refresh token. | too_many_requests |
Yes | Implement a suitable backoff strategy. Where possible, try to wait for the completion of a previous refresh request for the same token before retrying. |
Providers
TrueLayer uses the term providers
to refer to Banks, ASPSPs, or other institutions we connect to.
Each provider has a provider_id
which is immutable.
Examples: ob-lloyds
, oauth-starling
, xs2a-db
.
Provider Release Channels
We allow our customers to get early access to providers we are working on, for both our Data and Payments products.
Provider release stages
Private Beta | Public Beta | Live | |
---|---|---|---|
Definition | We have a functional connector that has been proven to work with live traffic, and we may have known issues.We do not commit to our standard SLA’s when using these providers. | We have a functional connector that has been proven to work with live traffic, and we may have known issues, but they are only minor. We do not commit to our standard SLA’s when using these providers. | We are comfortable the connector is functional to TrueLayer’s standards. We commit to maintaining these providers based on our standard SLA’s. |
Availability | Open to specific clients who express an interest in specific providers. | Open to all TrueLayer clients. | Open to all TrueLayer clients. |
Access | Please contact your Customer Success Manager to join. | Please contact our sales team to join. | Everyone, including people testing our API, can use these providers. |
Full list of providers
To see the full list of live providers via API, you can use this endpoint: https://auth.truelayer.com/api/providers
Check our Banking Index to learn more about the readiness and capabilities of banks
Providers and authorisation steps
If you are creating your own bank selection page, you may need to collect additional information from the end-user during the authorisation flow. This additional information is documented in the form of steps
in the Providers API response for all providers that require them. You can find more information on how to send us the end-user’s response to these steps
as Auth Inputs
on our Direct Bank Authentication section. If you are using TrueLayer’s Auth Dialog, TrueLayer will handle this process for you.
The steps
parameter structure
Field | Type | Description |
---|---|---|
title | string | Friendly name for this method within the provider |
fields | array | Array of input fields |
fields.type | string | Input field type. Can be a Single Choice Input or a Free Input |
fields.is_sensitive | boolean | OPTIONAL: For Free Input Values, is set to true for sensitive information like passwords |
fields.values | array | OPTIONAL: For Single Choice Input, an array of values |
fields.values.value | string | OPTIONAL: For Single Choice Input, input field value |
fields.values.display_name | string | OPTIONAL: For Single Choice Input, friendly name for this input field value |
fields.validations | array | OPTIONAL: For Free Input Values, an array of RegEx validation rules that need to be satisfied to consider the input valid |
fields.allowed_characters | string | OPTIONAL: For Free Input Values, character ranges allowed. can be alphanumeric or numeric |
fields.id | string | Unique id for this field within the method |
fields.display_name | string | Friendly name for this field within the method |
fields.help_text | string | Input help text for the end user |
fields.mandatory | boolean | Indicates whether the field is required |
Accessing beta providers
Once approved for the programme, Beta connectors will be enabled for your client_id
only.
You can view the providers you have access to in two ways:
- Via your Console. You must be logged into the correct account to view them.
- Via the Providers API. You must pass your client_id in the providers URL following this pattern:
https://auth.truelayer.com/api/providers?clientId=your-client_id
Sandbox
We provide a sandbox environment where you can test your integration without requiring live bank accounts. All account data and transactions are completely segregated from the production environment.
The sandbox environment provides the console to manage your account, the Data API, the Payments API, the PayDirect API, the Verification API, and the Payouts API.
When you create an account on our console, you’ll get access to our sandbox environment. You can go to our live environment by switching the toggle on the top menu bar.
Note that the sandbox does not include a full bank simulation with consistent bank accounts, it is only intended to facilitate API testing.
For details on how to integrate to the Payments API using the sandbox, please see the Payments Quick Start.
User logins and TrueLayer platform accounts
Your login to the TrueLayer platform is either via single-sign-on (e.g. Google or Github accounts), or with email address and password. When you create your login for the first time, you will navigate through our registration wizard, then your TrueLayer platform account will be created.
Sandbox accounts and production accounts
Your sandbox environment has its own client_id
and client_secret
; these may be used to create access tokens to call the Data or Payments API. To differentiate it from production accounts, your sandbox account client_id
will always have the prefix sandbox-. It will not be possible to add this prefix to a production account client_id
.
Sandbox account information can only be used with sandbox API endpoints: - sandbox client credentials cannot be used to create a production access token - sandbox access tokens cannot be used to call production API endpoints
The production environment has no access to the sandbox environment. Resources created in the sandbox cannot be accessed via production APIs, for example, if a payment is created in the sandbox, an attempt to GET the payment resource in the production environment will return a 404 response. Similarly, when the Data API is used to retrieve banking data within the sandbox environment, this data will not be accessible from within the production environment.
Sandbox API endpoints
API endpoints for the sandbox are the same as in production, but instead of ending with the domain truelayer.com, they all end with the domain truelayer-sandbox.com.
Sandbox Bank Accounts
For Payments, we have integrated into an actual bank sandbox environment to facilitate end-to-end testing of the API and the associated user journeys. This provides the ability to navigate through a bank’s payment consent journey while testing the Payments API.
For Data, we currently support testing of our API in the sandbox environment with Mock Bank.
Data API v1
Overview
The TrueLayer Data API is a single interface to access identity, accounts, transactions and balance data for all integrated banks.
Available data
The Data API allows you to access the following data for a connected account:
- Account: account holder name, account number, IBAN etc.
- Credit card: card network, last four digits, name on card etc.
- Transactions: description, amount, category, merchant name etc
- Balances: current, available etc.
- Regular payments: standing orders and direct debits
Coverage
We offer the Data API in the UK and Ireland in general availability. Our APIs are in public beta in France, Italy and Spain. More countries coming soon!
Authentication flow
We offer a ready-made UX flow for you to easily let users connect their bank accounts to your application, or you can build your own fully custom flow on top of our API.
If you are regulated, you have 2 options for your auth flow:
- Use our ready-made user journey
- Fully customise your own
Non-regulated customers must use TrueLayer’s flow, which is customisable to fit seamlessly into your application.
Authentication features:
- Auth Link & Direct Bank Authentication: initiate user journey to connect a bank
- Auth Dialog: customisable front-end user experience
- Reauthentication: easy reconnection of lapsed account connections
- Auth journey analytics: understand how far users make it through the authentication journey (private beta)
To get support for the Data API:
Data API Quick Start
You can connect with our Data API and retrieve bank data in a few quick steps - here’s how it works:
- After signing up to our Console, generate an Authentication Link. This link provides a simple user interface for your users to connect their bank accounts.
- Through that interface, you or your users can log into a real bank account (or our Mock Bank account), and obtain an
access_token
. Then, you can use thisaccess_token
to access user data (accounts, transactions, balances, etc.) via our API.
It’s that simple! Want to see it in action? Try our demo application Piggy Bank to see a working example of a TrueLayer integration.
Or try it yourself! We have made Postman collections available for both our Live and Sandbox environments.
Sandbox Postman Collection
Step 1 - Sign Up
- Sign up to the TrueLayer Console to get your Sandbox
client_id
andclient_secret
. - Install Postman and download our Sandbox Postman collection. It contains sample requests so that you can quickly retrieve data, and generate code snippets in various languages of your choice. It also has our Sandbox environment endpoints preconfigured.
Step 2 - Authorise a User
Create a Sandbox Auth Link to authenticate users via the Auth Link Builder in our Console. This Auth Link provides an easy user interface to demo connecting to our Mock Bank.
How to build your Sandbox Auth Link:
- Select the set of Permissions to include in the Authentication link. These permissions will limit the endpoints of Data API that your application will be able to access.
- You must also choose a Redirect URI where the user will be redirected after authenticating.
- Make sure the
Mock
provider is enabled so that you can use our Mock Bank user credentials for testing. - Next, click the test button to open the generated Sandbox Auth Link and connect to Mock Bank.
- Select Mock Bank and use a set of our Mock Bank credentials (eg. “john”/”doe”) in order to obtain a code.
Step 3 - Obtain an Access Token
Use the Postman Exchange Code
request within the Authentication
folder in order to exchange the generated code
into an access_token
. To do so:
- Add the missing required variables : Sandbox
client_id
and Sandboxclient_secret
(found in the Console) as well as thecode
(generated in Step 2).
- Send the request and retrieve a response containing an
access_token
andrefresh_token
.
Step 4 - Access Data
With the acquired access_token
, run any of the requests in the Data API
folder in the Sandbox Postman collection to retrieve account numbers, transaction data or personal information.
For example: the List all accounts
request within the Data API
folder will retrieve all account information within the given set of credentials. For a list of all the endpoints supported, see the full Data API reference.
Now you’re retrieving mock bank data!
Live Postman Collection
Step 1 - Sign Up
- Sign up to the TrueLayer Console to get your
client_id
andclient_secret
. - Install Postman and download our Live Postman collection. It contains sample requests so that you can quickly retrieve data, and generate code snippets in various languages of your choice.
Step 2 - Authorise a User
Create an Auth Link to authenticate users via the Auth Link Builder in our Console. This Auth Link provides an easy user interface for your users to choose their bank accounts.
How to build your Auth Link:
- Select the set of Permissions to include in the Authentication link. These permissions will limit the endpoints of Data API that your application will be able to access.
- You must also choose a Redirect URI where the user will be redirected after authenticating.
- Enable the providers you want to to make available.
- Next, click “Test” to open the generated link and connect a bank.
- Select a Live Bank and you will be redirected to the Bank’s Open banking Consent screen to Authenticate in order to obtain a code.
Step 3 - Obtain an Access Token
Use the Postman Exchange Code
request within the Authentication
folder in order to exchange the generated code
into an access_token
. To do so:
- Add the missing required variables :
client_id
andclient_secret
(found in the Console) as well as thecode
(generated in Step 2). - Send the request and retrieve a response containing an
access_token
andrefresh_token
.
Step 4 - Access Data
With the acquired access_token
, run any of the requests in the Data API
folder in the Postman collection to retrieve account numbers, transaction data or personal information.
For example: the List all accounts
request within the Data API
folder will retrieve all account information within the given set of credentials. For a list of all the endpoints supported, see the full Data API reference.
Now you’re retrieving live bank data!
What’s next
- See the rest of our documentation for instructions on how to use all of our features.
- Check out our Data API Quickstart sample app.
Data Guides
This section will contain the Guide sub-sections for the Data API.
Data Definitions
Definition | Description |
---|---|
Account | A financial account with a Provider |
Authorization Server | The secure service hosted by TrueLayer that allows End users to authenticate with their Provider credentials. It also offers API endpoints to obtain and renew access_token |
Client | An application implementing this API |
End user | An application’s user and the owner of an account |
Data API | The API that provides access to End users’s financial data |
Permissions | A set of permissions the End user grant to the Client to access data on their behalf |
Provider | A supported bank or other financial institution |
Credentials | A set of identifiers and secrets the End user uses to access their accounts with a Provider |
Data API Authentication
To authenticate, the single-use code
obtained at the redirect_uri
will need to be exchanged for a short-lived access_token
.
The access_token
can be used to access all Data API endpoints allowed by the given set the permissions.
To see how to exchange the code for the access token: Exchange code for access_token
To see how to renew an access token: Renew the access_token
The Data API supports one access method for authentication: Access Methods
The Data API authentication via Regulated APIs works like this:
End User Authentication
The first step in the authentication process is to redirect the End user with a properly formatted link to TrueLayer Authorization Server.
If the provider used for the authentication is already known, it can be supplied with an optional provider_id
parameter, in order to skip the selection.
Request
https://auth.truelayer.com/\
?response_type=code\
&response_mode=form_post\
&client_id=${client_id}\
&redirect_uri=${redirect_uri}\
&scope=${scope}\
&state=${state}
Authentication Link: The End user’s browser is redirected to TrueLayer’s Authorization Server using a link that includes the application’s client_id
, redirect_uri
(already authorized for the Client) and a scope
parameter defining the Permissions requested to the End user. A state
argument is optional but is strongly recommended (helps reconcile requests that by their nature are stateless).
You can build your Authentication Link in the console as shown below.
End user log-in: The End user selects a Provider and authenticates securely on the TrueLayer authorization server using their Provider credentials.
Code Redirect: End user’s browser is redirected to the
redirect_uri
controlled by the Client with acode
, the requestedscope
and the optionalstate
Exchange
code
withaccess_token
: The application exchanges thecode
received with a short-livedaccess_token
(and optionally arefresh_token
if the scopeoffline_access
was requested) making a HTTP POST to the TrueLayer authorization server including the applicationclient_id
,client_secret
andredirect_uri
Access Data API: The application can use the obtained
access_token
to access data on behalf of the End user. AnAuthorization
header must be provided to access any endpoint of the Data APIRenew the access_token: After the short-lived
access_token
expires (1 hour by default or provider specified) a newaccess_token
can be obtained using therefresh_token
Auth Dialog
TrueLayer Auth Dialog is the end user facing interface that permits you to connect to your user’s bank account.
Its purpose is to guide the end users through the process of sharing their banking data by providing a login experience that is simple and compliant with FCA policies, GDPR and PSD2.
The Auth Dialog will handle credential validation, different authentication methods and error handling for all the banks we support, so you don’t have to. It works across all modern browsers and devices.
UI Customisation
On the Scale plan and the Enterprise plan, you can also customise parts of the Auth Dialog including colours, some copy elements, setting a cancelation_uri
or a link to your FAQs directly from our Console.
Flow Customisation
The Auth Dialog flow can also be customised depending on your needs:
- Full Flow - You just add a button on your App, we do the rest.
- Skip Bank - Start your journey with your own bank selection page.
- Skip Consent - Create your own custom consent page.
- Login only - Skip both Bank and Consent page, and use our Login.
Async Requests
We recommend using Data API asynchronously. Asynchronous access mitigates issues that are beyond the control of TrueLayer and removes the need for you to write your own error and retry logic as is it handled seamlessly.
You can make an asynchronous API call by passing a query parameter async=true
for any potentially long operation (For ex. fetching multiple years of transactions) and be returned with a results_uri
that will contain the results of your request once they are available. The Data API supports asynchronous requests on all endpoints.
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
.
Make Asynchronous API calls
Request
curl -H "Authorization: Bearer ${access_token}" \
"https://api.truelayer.com/data/v1/accounts/${account_id}?async=true&webhook_uri=${uri}"
Response
{
"results_uri": "https://api.truelayer.com/data/v1/results/b1bc9472-3c21-44ed-ade2-2e932c41ee64",
"status": "Queued",
"task_id": "b1bc9472-3c21-44ed-ade2-2e932c41ee64"
}
If a query parameter async=true
is passed, the Data API immediately returns a response containing the results_uri
, status
and task_id
, which can be used to track the status of the call. 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:
Status | Description |
---|---|
Queued |
The query is waiting to run |
Running |
The query is currently running |
Succeeded |
The query has successfully returned results |
Failed |
The query is has failed to retrieve the query results |
Parameters
Field | Type | Description |
---|---|---|
async |
boolean | If true the request is handled asynchronously |
webhook_uri |
URI | The URI where notification of completion will be sent via HTTP POST |
Webhook Callback Payload
Webhook payload
{
"request_timestamp" : "0001-01-01T00:00:00Z",
"request_uri" : "https://api.truelayer.com/api/v1.0/accounts/1234/transactions?from=2017-01-01&to=2017-12-01",
"credentials_id": "6L7RxyPKX0THy1tw93PB4V+8DB+KjnX9Pxa451yXPu0=",
"task_id": "e1245d07-d846-42df-86d8-99b08b430a0",
"status": "Succeeded | Failed",
"results_uri": "https://api.truelayer.com/data/v1/results/e1245d07-d846-42df-86d8-99b08b430a0/",
"error_description": "Error | null",
"error": "Error | null"
}
When an asynchronous request is completed, this payload will be sent to the webhook_uri
via HTTP POST
.
Field | Type | Description |
---|---|---|
request_timestamp |
datetime | The time of the original request |
request_uri |
string | The URI of the original request |
credentials_id |
string | Unique string identifying a set of End user’s credentials used to access a Provider |
task_id |
string | A unique ID associated with the task |
status |
string | Succedeed or Failed |
results_uri |
string | The URI where results can be fetched from when available. |
error |
string | An error code |
error_description |
string | Extra details about the error |
Webhook Retry Policy
We consider a webhook as having been successfully delivered when we receive a success status code (2xx) from the webhook_uri
.
If we receive any other status code like 5xx or 408 (e.g. 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 retry for a maximum of 6 times.
Fetch the results
Request
curl -H "Authorization: Bearer ${access_token}" \
"https://api.truelayer.com/data/v1/results/${task_id}
To fetch results from results_uri
you will need to authenticate with a valid access_token
corresponding to the credentials_id
of the original request.
Transaction Categorisation
transaction_category
identifies the type of a transaction for both account and card transactions. The supported set of categories is consistent across all providers.
These are the supported set of transaction categories:
Type | Description |
---|---|
ATM |
Deposit or withdrawal of funds using an ATM (Automated Teller Machine) |
BILL_PAYMENT |
Payment of a bill |
CASH |
Cash deposited over the branch counter or using a Cash & Deposit Machines |
CASHBACK |
An option retailers offer to withdraw cash while making a debit card purchase |
CHEQUE |
A document ordering the payment of money from a bank account to another person or organization |
CORRECTION |
Correction of a transaction error |
CREDIT |
Funds added to your account |
DIRECT_DEBIT |
An automatic withdrawal of funds initiated by a third party at regular intervals |
DIVIDEND |
A payment to your account from shares you hold |
FEE_CHARGE |
Fees or charges in relation to a transaction |
INTEREST |
Credit or debit associated with interest earned or incurred |
OTHER |
Miscellaneous credit or debit |
PURCHASE |
A payment made with your debit or credit card |
STANDING_ORDER |
A payment instructed by the account-holder to a third party at regular intervals |
TRANSFER |
Transfer of money between accounts |
DEBIT |
Funds taken out from your account, uncategorised by the bank |
UNKNOWN |
No classification of transaction category known |
Transaction Classification
transaction_classification
returns detailed category information for account and card transactions.
This field, along with merchant_name
, is currently supported for banks in UK, Ireland and France; we attempt to classify transactions from banks in unsupported countries with the classification system used for UK trasactions, but accuracy may be lower in this case.
Our classification system is built around purchase-related transactions; for this reason transactions with transaction_category
equal to CREDIT
are currently not supported.
It is possible that some transactions may not receive a category/subcategory classification. Additionally, the category/subcategory classification for a given transaction may change over time, as we improve our systems.
[
{
"classification_category": "Uncategorized",
"sub_classification_categories": [
"Cash & ATM",
"Check"
]
},
{
"classification_category": "Entertainment",
"sub_classification_categories": [
"Arts",
"Music",
"Dating",
"Movies & DVDs",
"Newspaper & Magazines",
"Social Club",
"Sport",
"Games"
]
},
{
"classification_category": "Education",
"sub_classification_categories": [
"Tuition",
"Student Loan",
"Books & Supplies"
]
},
{
"classification_category": "Shopping",
"sub_classification_categories": [
"Pets",
"Groceries",
"General",
"Clothing",
"Home",
"Books",
"Electronics & Software",
"Hobbies",
"Sporting Goods"
]
},
{
"classification_category": "Personal Care",
"sub_classification_categories": [
"Hair",
"Laundry",
"Beauty",
"Spa & Massage"
]
},
{
"classification_category": "Health & Fitness",
"sub_classification_categories": [
"Dentist",
"Doctor",
"Eye care",
"Pharmacy",
"Gym",
"Pets",
"Sports"
]
},
{
"classification_category": "Food & Dining",
"sub_classification_categories": [
"Catering",
"Coffee shops",
"Delivery",
"Fast Food",
"Restaurants",
"Bars"
]
},
{
"classification_category": "Gifts & Donations",
"sub_classification_categories": [
"Gift",
"Charity"
]
},
{
"classification_category": "Investments",
"sub_classification_categories": [
"Equities",
"Bonds",
"Bank products",
"Retirement",
"Annuities",
"Real-estate"
]
},
{
"classification_category": "Bills and Utilities",
"sub_classification_categories": [
"Television",
"Home Phone",
"Internet",
"Mobile Phone",
"Utilities"
]
},
{
"classification_category": "Auto & Transport",
"sub_classification_categories": [
"Auto Insurance",
"Auto Payment",
"Parking",
"Public transport",
"Service & Auto Parts",
"Taxi",
"Gas & Fuel"
]
},
{
"classification_category": "Travel",
"sub_classification_categories": [
"Air Travel",
"Hotel",
"Rental Car & Taxi",
"Vacation"
]
},
{
"classification_category": "Fees & Charges",
"sub_classification_categories": [
"Service Fee",
"Late Fee",
"Finance Charge",
"ATM Fee",
"Bank Fee",
"Commissions"
]
},
{
"classification_category": "Business Services",
"sub_classification_categories": [
"Advertising",
"Financial Services",
"Office Supplies",
"Printing",
"Shipping",
"Legal"
]
},
{
"classification_category": "Personal Services",
"sub_classification_categories": [
"Advisory and Consulting",
"Financial Services",
"Lawyer",
"Repairs & Maintenance"
]
},
{
"classification_category": "Taxes",
"sub_classification_categories": [
"Federal Tax",
"State Tax",
"Local Tax",
"Sales Tax",
"Property Tax"
]
},
{
"classification_category": "Gambling",
"sub_classification_categories": [
"Betting",
"Lottery",
"Casino"
]
},
{
"classification_category": "Home",
"sub_classification_categories": [
"Rent",
"Mortgage",
"Secured loans",
"Pension and insurances",
"Pension payments",
"Life insurance",
"Buildings and contents insurance",
"Health insurance"
]
}
]
Category | Subcategory |
---|---|
Uncategorized |
Cash & ATM |
Check | |
Entertainment |
Arts |
Music | |
Dating | |
Movies & DVDs | |
Newspaper & Magazines | |
Social Club | |
Sport | |
Games | |
Education |
Tuition |
Student Loan | |
Books & Supplies | |
Shopping |
Pets |
Groceries | |
General | |
Clothing | |
Home | |
Books | |
Electronics & Software | |
Hobbies | |
Sporting Goods | |
Personal Care |
Hair |
Laundry | |
Beauty | |
Spa & Massage | |
Health & Fitness |
Dentist |
Doctor | |
Eye care | |
Pharmacy | |
Gym | |
Pets | |
Sports | |
Food & Dining |
Catering |
Coffee shops | |
Delivery | |
Fast Food | |
Restaurants | |
Bars | |
Gifts & Donations |
Gift |
Charity | |
Investments |
Equities |
Bonds | |
Bank products | |
Retirement | |
Annuities | |
Real-estate | |
Bills and Utilities |
Television |
Home Phone | |
Internet | |
Mobile Phone | |
Utilities | |
Auto & Transport |
Auto Insurance |
Auto Payment | |
Parking | |
Public transport | |
Service & Auto Parts | |
Taxi | |
Gas & Fuel | |
Travel |
Air Travel |
Hotel | |
Rental Car & Taxi | |
Vacation | |
Fees & Charges |
Service Fee |
Late Fee | |
Finance Charge | |
ATM Fee | |
Bank Fee | |
Commissions | |
Business Services |
Advertising |
Financial Services | |
Office Supplies | |
Printing | |
Shipping | |
Legal | |
Personal Services |
Advisory and Consulting |
Financial Services | |
Lawyer | |
Repairs & Maintenance | |
Taxes |
Federal Tax |
State Tax | |
Local Tax | |
Sales Tax | |
Property Tax | |
Gambling |
Betting |
Lottery | |
Casino | |
Home |
Rent |
Mortgage | |
Secured loans | |
Pension and insurances |
Pension payments |
Life insurance | |
Buildings and contents insurance | |
Health insurance |
Batch endpoint
Setup
# Get a valid access token and export it as an environment variable:
export ACCESS_TOKEN=your-access-token
# Set up a request bin on https://requestbin.com/ - you will use it to receive our webhook
# Put the request body in a JSON file, e.g. `batch_request.json`:
echo '{
"from": "2020-01-01",
"to": "2020-07-01",
"pending": true,
"balance": true,
"webhook_uri": "https://your-webhook-uri.com/"
}' > batch_request.json
The batch endpoint reduces integration complexity in case where you want to retrie transaction histories and balances for all accounts and cards belonging to a user.
You can try out the batch endpoint immediately using our mock
bank in sandbox - check the API reference.
Fetching lots of data with the batch endpoint
- Submit a POST request
curl --header "Content-Type: application/json" \
--header "Authorization: Bearer ${ACCESS_TOKEN}" \
--request POST \
--data @batch_request.json \
https://api.truelayer.com/data/v1/batch/transactions
# repsonse
{
"results_uri": "https://api.truelayer.com/data/v1/batch/results/8e35198d-f488-4e7d-8f41-991c8ace45f2",
"status": "Queued",
"task_id": "8e35198d-f488-4e7d-8f41-991c8ace45f2"
}
- Await a single webhook
# Example of a successful webhook payload
{
"request_timestamp" : "0001-01-01T00:00:00Z",
"request_uri" : "https://api.truelayer.com/",
"results_uri": "https://api.truelayer.com/data/v1/results/e1245d07-d846-42df-86d8-99b08b430a0",
"credentials_id": "6L7RxyPKX0THy1tw93PB4V+8DB+KjnX9Pxa451yXPu0=",
"task_id": "e1245d07-d846-42df-86d8-99b08b430a0",
"status": "succeeded",
}
- GET results
curl --header "Authorization: Bearer ${ACCESS_TOKEN}" \
https://api.truelayer.com/data/v1/results/e1245d07-d846-42df-86d8-99b08b430a0
# response
{
"request": {
"from": "2018-09-28T00:00:00",
"to": "2020-11-19T11:40:26.481103"
},
"results": {
"accounts": [{
"account_id": "12b48043fa864c798484a9cdd7cf196a",
"transactions": [{...}],
"pending_transactions": [{...}],
"balance": {...}
}],
"cards": [{
"account_id": "9e56cad7d782649e768df41751532824",
"transactions": [{...}],
"pending_transactions": [{...}],
"balance": {...}
}]
},
"status": "Succeeded",
"task_id": "8e35198d-f488-4e7d-8f41-991c8ace45f2"
}
If a user chooses to link multiple cards or accounts from a single provider, you can access transaction, pending transaction and balance data for all these linked accounts in a single asynchronous call to the batch endpoint.
Accessing data via the batch endpoint is a three step process
- Submit a POST request to batch endpoint specifying access token and transaction time period;
- Await a single webhook notifying you that the job is complete;
- GET results from the
results_uri
specified in the webhook payload, using the access token.
Data API reference
The Data API provides endpoints to retrieve personal information, account numbers and transaction data. All endpoints require authorization using access_token
.
Only one concurrent request per access token is allowed in the synchronous API, if a concurrent request is made a 409 request_conflict
error is returned.
Identifiers
Identifier name | Description | Confidentiality | Lifetime |
---|---|---|---|
access_token |
A short-lived JWT token used to access data on behalf of the End user | Secret | provider-specific (usually 1 hour) |
client_id |
A unique string identifying a Client | Public | Forever |
client_secret |
A secret key used to authenticate a Client | Secret | Forever (until rotated) |
code |
A one-time code that can be exchanged for an access_token |
Secret | Single use |
credentials_id |
Unique string identifying a set of End user’s credentials used to access a Provider | Public | Forever |
provider_id |
A unique string identifying a Provider | Public | Forever |
redirect_uri |
A URI controlled by the Client where one-time code is posted during authentication |
Public | Forever |
refresh_token |
A long-lived code used to obtain a new access_token |
Secret | Single use |
Common headers
The following request and response headers are supported by our endpoints available at https://api.truelayer.com
Request Headers
Header | Value |
---|---|
Authorization |
Bearer <ACCESS_TOKEN> |
X-Client-Correlation-Id |
Optional client-set correlation Id. We do not return this in response headers |
X-PSU-IP |
The PSU’s IP address to be passed on to the bank in order to avoid rate limiting. (see End-user IP Address) |
Response Headers
Header | Value |
---|---|
X-TL-Correlation-Id |
Unique Id per request - we recommend logging this and always sharing it with our client-care team when opening incident tickets |
X-Credentials-Id |
CredentialsId of the access token used |
X-Request-Id |
Not recommended: X-TL-Correlation-Id should be used instead |
Cache-Control |
max-age=n where n number of seconds |
Content-Encoding |
gzip |
Content-Type |
application/json; charset=utf-8 |
Date |
Date and time the message was sent |
Last-Modified |
Indicates the date and time a resource was last modified |
Content-Security-Policy |
default-src 'none'; frame-ancestors 'none'; |
X-Content-Type-Options |
nosniff |
X-Frame-Options |
deny |
X-XSS-Protection |
1; mode=block |
Referrer-Policy |
no-referrer |
Permissions
An Authentication Link must include a set of permissions in the scope
parameter that your Client is requesting on behalf of the End user. These permissions (or scopes) limit what endpoints the Client will be authorized to access in the Data API.
Scope | Description | API endpoint |
---|---|---|
info |
Allows access to End user’s identity information held by the Provider | /data/v1/info |
accounts |
Allows access to End user’s account numbers and details | /data/v1/accounts , /data/v1/accounts/${account_id} |
accounts + balance |
Allows access to End user’s account balances | /data/v1/accounts/${account_id}/balance |
accounts + transactions |
Allows access to End user’s account transactions | /data/v1/accounts/${account_id}/transactions |
accounts + transactions + balance |
Allows access to End user’s account transactions along with running balance | /data/v1/accounts/${account_id}/transactions |
cards |
Allows access to End user’s card numbers and details | /data/v1/cards , /data/v1/cards/${account_id} |
cards + balance |
Allows access to End user’s card balances | /data/v1/cards/${account_id}/balance |
cards + transactions |
Allows access to End user’s card transactions | /data/v1/cards/${account_id}/transactions |
cards + transactions + balance |
Allows access to End user’s card transactions along with running balance | /data/v1/cards/${account_id}/transactions |
offline_access |
Allows access to End user’s data after the short-lived access_token expires. When this permission is granted a refresh_token will be returned |
refresh_token |
direct_debits |
Allows access to End user’s direct debits. Open Banking providers only | /data/v1/accounts/${account_id}/direct_debits |
standing_orders |
Allows access to End user’s standing orders. Open Banking providers only | /data/v1/accounts/${account_id}/standing_orders |
Auth link
Request
https://auth.truelayer.com/\
?response_type=code\
&response_mode=form_post\
&client_id=${client_id}\
&redirect_uri=${redirect_uri}\
&scope=${scope}\
&state=${state}
The first step in the authentication process is to redirect the End user with a properly formatted link to TrueLayer Authorization Server.
If the provider used for the authentication is already known, it can be supplied with an optional provider_id
parameter in order to skip the selection.
Note that even if you include a provider_id
parameter, the intended provider must still be included in the parameter providers
. For example, if you use provider_id=ob-lloyds
, under providers you must include either uk-ob-all
or ob-lloyds
.
Clients with regulatory permission to collect user consent themselves (for example, an AISP license from the Financial Conduct Authority in the UK), can use the Direct Bank Authentication process as an alternative to Auth Link.
Generate Auth Link
To easily generate your Auth Link you can use the Auth Link Builder in our Console.
Parameters
Parameter | Description |
---|---|
client_id |
Your client unique identifier |
redirect_uri |
Must exactly match one of the registered redirect_uri for your Client |
state |
An opaque value used by the Client to maintain state between the request and callback. |
scope |
Space-separated list of requested permissions. Please see Permissions |
response_type |
MUST be: "code" |
providers |
OPTIONAL. Space-separated list of providers to include. If not provided, will default to the TrueLayer default list, which is providers=uk-oauth-all uk-ob-all. |
provider_id |
OPTIONAL. If supplied provider selection will be skipped. |
response_mode |
OPTIONAL. if set to "form_post" the code will be submitted via form POST instead of a query string encoded redirect. |
disable_providers |
OPTIONAL. Space-separated list of provider ids to be hidden in the authentication dialog |
language_id |
OPTIONAL. Choose the language for Auth Dialog. If not specified, Auth Dialog defaults to English. Supported values: en (English), es (Spanish), it (Italian), fr (French), de (German), zh_CN (Chinese - Simplified). |
tracking_id |
OPTIONAL. Allows you to query how far the user got in the authentication flow. See Auth Journey Analytics |
v |
OPTIONAL. Beta Feature. Use v=2 to activate the new, Beta version of TrueLayer’s Auth Dialog for that session. Contact us for more information. |
To enable Mock Bank, our fictitious bank for testing, include provider uk-cs-mock
. See Mock Users.
Once submitted, this will start a regular OAuth2 authorization_code flow. Optionally, you may choose to use a PKCE flow which is a more secure option for mobile and javascript based implementations.
Optional PKCE flow
PKCE requires a code_verifier
. This is a cryptographically random string using the characters A-Z, a-z, 0-9, and the punctuation characters -._~ (hyphen, period, underscore, and tilde), between 43 and 128 characters long.
The code_verifier
is held on to by the client and passed on a back channel during final code exchange. To initiate PKCE flow, during the auth-link phase, the following parameters must be supplied
Parameter | Description |
---|---|
code_challenge |
Base64Url encoded string of the SHA256 hash of the code_verifier . |
code_challenge_method |
“S256” |
Request
# This value will be sent on code exchange
code_verifier=$(head /dev/urandom | tr -dc A-Za-z0-9 | head -c 64 ; echo '')
# the `code_challenge` hash *must* be derived from
# the binary representation of the `code_verifier`.
# It *must* be Base64Url encoded
code_challenge=$(printf %s "${code_verifier}" | openssl dgst -sha256 -binary | base64 | sed 's/+/-/g; s/\//_/g; s/=//g';)
https://auth.truelayer.com/\
?response_type=code\
&response_mode=form_post\
&client_id=${client_id}\
&redirect_uri=${redirect_uri}\
&scope=${scope}\
&state=${state}\
&code_challenge=${code_challenge}\
&code_challenge_method=S256
Provider Format
For including under the providers
or disable_providers
parameters in the Auth Link, Provider IDs have the format CountryCode-AccessMethod-BankIdentifier
. For example: ob-lloyds
, uk-oauth-starling
. Some BankIdentifier can contain information specific to the bank; e.g. ob-lloyds-business
for Business users of Lloyds Bank.
The list of providers
can include a list of individual, country-specific providers (e.g. uk-ob-hsbc-business
, uk-oauth-starling
), or you can use an aggregated label to include all banks from a country (uk-ob-all
, ie-ob-all
), or all countries for a given bank (all-ob-revolut
).
To include new banks that TrueLayer releases as soon as they are available, use “all” for “Bank Identifier” in your provider flag for a given country and access method. For instance, “uk-ob-all” will include all Open Banking banks in the UK, including new ones when they are released.
To enable Mock Bank, our fictitious bank for testing, include provider uk-cs-mock
.
Backwards Compatibility
We are backwards compatible with our legacy provider_id
schema. This means that in the UK, we would accept provider_id
’s without the uk-
prefix. In the example provided above, we would also therefore accept ob-lloyds-business
.
Direct Bank Authentication
Request
curl -X POST -H "Content-Type: application/json" \
-d '{
"response_type":"code",
"client_id":"${client_id}",
"redirect_uri":"${redirect_uri}",
"scope":"${scopes}",
"state":"${state}",
"consent_id":"${consent_id}",
"provider_id":"${provider_id}"
}' \
https://auth.truelayer.com/v1/authuri
Response
{
"result": "https://example.com",
"success": true
}
Direct Bank Authentication is an alternative authorisation flow which can be used by regulated clients (those with permission to capture user consent themselves, for example anyone with AISP permission from the Financial Conduct Authority in the UK). In this flow, you can retrieve from TrueLayer a link directly to the bank - send your user to this link where they can approve access to their bank account.
Anyone can test Direct Bank Authentication in our sandbox environment. Contact us to confirm your regulatory status in order to use it in production.
Parameters
Field | Type | Description |
---|---|---|
response_type |
string | "code" |
client_id |
string | TrueLayer client_id |
redirect_uri |
string | A valid redirect_uri for your TrueLayer client_id (set in your Console) |
state |
string | OPTIONAL. An opaque value used by the Client to maintain state between the request and callback |
scope |
string | Space delimited list of desired TrueLayer scopes |
consent_id |
string | Identifier to indicate the client has captured the user’s consent themselves. Any alphanumeric string allowed. Should be unique to track that the user has given consent. |
provider_id |
string | Intended provider. See our Providers API to look up a provider_id. |
auth_inputs |
array | OPTIONAL. For banks that require extra inputs before the user is directed to the bank, those values are specified here. Our Providers API specifies which providers require these extra inputs (steps ) and lists possible values if available. The possible input types are described here. The auth_inputs field requires specifying the input and the value, for example: "auth_inputs":{"branch-name": "stet-credit-agricole-alpes-provence"} |
code_challenge |
string | OPTIONAL. PKCE code challenge |
code_challenge_method |
string | MANDATORY "S256" only if code_challenge is supplied |
response_mode |
string | OPTIONAL. "form_post" |
tracking_id |
string | OPTIONAL. Allows you to query how far the user got in the authentication flow. See Auth Journey Analytics. |
Response
We will return a link for the user to follow to authenticate with their bank.
Parameter | Description |
---|---|
result | A link to the bank for the user to follow |
success | Returned only with successful responses, as true |
The user will then follow the link to their bank’s app or website to approve sharing of data, after which they will be sent through the Code redirect.
Reauthentication flow
Request
curl --request POST --header 'Content-Type: application/json' \
--data '{
"response_type":"code",
"refresh_token":"${refresh_token}",
"redirect_uri":"${redirect_uri}"
}' \
https://auth.truelayer.com/v1/reauthuri
Response
{
"result": "https://example.com",
"success": true
}
UK only: Reauthentication is currently only supported for UK providers. Ireland and other European providers are not supported.
Most European banks require that end-users who are sharing account details grant permission for data sharing every 90 days.
For these banks, access to your user’s bank accounts will no longer be available 90 days after they initially connect their account. When this happens, the TrueLayer /connect/token
endpoint will return a 400 invalid_grant
error when you try to refresh your tokens, and if you try to fetch data using an access_token
TrueLayer will return a 403 access_denied
error.
The reauthentication flow provides a simple path for the user to follow to reconnect their account, providing a shorter user journey compared to setting up their account for the first time.
To initiate the reauthentication flow, call the reauth endpoint with a refresh_token
for the user you would like to re-authenticate. We will return a link to the bank for the user to follow. You can have the user go through this flow either before or after their original connection expires (for example, you may prefer to have users reconnect their accounts a week before the connection expires, which would reset the expiration to 90 days from the time of reauthentication).
Users can use the reauthentication flow for up to 90 days after their associated refresh_token
expires. (The expiration time varies based on the underlying bank but in general you will have at least 90 days after their connection has expired in which to use the reauthentication flow). After that time has elapsed, reauthentication is no longer possible and the user should go through the first-time authentication flow instead.
Parameters
Field | Type | Description |
---|---|---|
redirect_uri |
string | A valid redirect_uri for your TrueLayer client_id (set in your Console) |
response_type |
string | "code" |
refresh_token |
string | refresh token for the PSU you wish to re-authenticate |
state |
string | OPTIONAL. An opaque value used by the Client to maintain state between the request and callback |
code_challenge |
string | OPTIONAL. PKCE code challenge |
code_challenge_method |
string | MANDATORY "S256" only if code_challenge is supplied |
response_mode |
string | OPTIONAL. "form_post" |
Response
We will return a link for the user to follow to reauthenticate with their bank.
Parameter | Description |
---|---|
result | A link to the bank for the user to follow |
success | Returned only with successful responses, as true |
The user will then follow the link to their bank’s app or website, approve continued sharing of data, and will be returned to you at the specified redirect_uri
with a code
to swap for access and refresh tokens, just as in the first-time user authentication flow.
Note that reauth is intended for a user to reconnect their existing accounts, but for some banks it is possible for the user to select a different set of accounts (for example, from sharing a current
account and a savings
account at first to just sharing the current
account after reauthenticating). Some, but not all, banks require the user to choose exactly the same set of accounts that they had shared previously, but because not all banks enforce this requirement it is possible the list will change.
To safeguard against the reauthentication flow being used by the wrong user, if the user chooses to share a completely different set of accounts (with no overlap with their previous selection), you will receive a 500 internal_server_error
when trying to access their bank data. If you expect the user to choose a new set of accounts, have them connect their accounts as if they are a new user, not by using the reauthentication flow.
Auth journey analytics
The Auth Journey Analytics API allows you to track the progress of your users through Auth Dialog. Simply include a tracking_id
for that user or session when you initiate the authentication flow, and later you can look up which events were completed for the flow (or flows) that had that tracking_id
.
Add a tracking_id to your Auth Link
Include a parameter for a tracking_id
in your Auth Link. You can make this ID distinct per session or repeat it for multiple different sessions (for example, you could use the same ID for every session for the same user).
You can also include a tracking_id
parameter when using Direct Bank Authentication.
Retrieve tracked events
Access Token Request
curl -d grant_type=client_credentials \
-d client_id=$CLIENT_ID \
-d client_secret=$CLIENT_SECRET \
-d scope=tracking \
"https://auth.truelayer.com/connect/token"
Access Token Response
{
"access_token": "eyJhbG...",
"expires_in": 3600,
"scope": "tracking",
"token_type": "Bearer"
}
Request
curl -H "Authorization: Bearer eyJhbG..." \
"https://client-tracking.truelayer.com/v1/tracked-events?tracking_id=$TRACKING_ID"
Response
{"results": [
{
"name": "dialog_started",
"time": "2020-01-01T00:01:40.0000001Z",
"flow_id": "auth-2ba09237-af3b-4c5f-bdb9-71f385cf8739",
"reauth": false // appears only for reauthentication flows
},
{
"name": "consent_granted",
"time": "2020-01-01T00:01:55Z",
"flow_id": "auth-2ba09237-af3b-4c5f-bdb9-71f385cf8739",
"reauth": false // appears only for reauthentication flows
},
{
"name": "provider_selected",
"time": "2020-01-01T00:01:58Z",
"flow_id": "auth-2ba09237-af3b-4c5f-bdb9-71f385cf8739",
"provider_id": "ob-barclays",
"reauth": false // appears only for reauthentication flows
},
{
"name": "provider_auth_started",
"time": "2020-01-01T00:02:04Z",
"flow_id": "auth-2ba09237-af3b-4c5f-bdb9-71f385cf8739",
"reauth": false,
"provider_id": "ob-barclays"
},
{
"name": "provider_authorized",
"time": "2020-01-01T00:02:08Z",
"flow_id": "auth-2ba09237-af3b-4c5f-bdb9-71f385cf8739",
"credentials_id": "GUoLgKmIvr3Jpb2rRtgJJF/77ixGUxD626nFTJgqCZs=",
"consent_id": "7b1aaee1-9e26-453e-b116-b38251206f24",
"provider_id": "ob-barclays",
"reauth": false,
},
{
"name": "code_exchanged",
"time": "2020-01-01T00:02:24Z",
"flow_id": "auth-2ba09237-af3b-4c5f-bdb9-71f385cf8739",
"credentials_id": "GUoLgKmIvr3Jpb2rRtgJJF/77ixGUxD626nFTJgqCZs=",
"consent_id": "7b1aaee1-9e26-453e-b116-b38251206f24",
"reauth": false,
"provider_id": "ob-barclays"
}
]}
A scope=tracking
access token is required to fetch the tracked events. These are provided by auth.truelayer.com.
Call our API endpoint with that tracking_id to retrieve the events associated with the ID.
Mock users
These credentials can be used with the mock
bank for testing normal behaviour and errors.
Username | Password | Behaviour |
---|---|---|
"john" |
"doe" |
Working normally with fake data.* |
"error.account_permanently_locked" |
"error" |
Any endpoint will fail with account_permanently_locked |
"error.account_temporarily_locked" |
"error" |
Any endpoint will fail with account_temporarily_locked |
"error.internal_error" |
"error" |
Any endpoint will fail with internal_error |
"error.provider_error" |
"error" |
Any endpoint will fail with provider_error |
"error.user_input_required" |
"error" |
Any endpoint will fail with user_input_required |
"error.wrong_credentials" |
"error" |
Any endpoint will fail with wrong_credentials |
*Multiple user accounts can be tested with the following username/password combinations: john1/doe1
, john2/doe2
, up to john100/doe100
.
Code redirect
Request
code=${code}&scope=${scope}&state=${state}
End user’s browser is redirected to perform an HTTP GET (or HTTP POST in case response_mode
has been set to "form_post"
) to the redirect_uri
controlled by the Client with the following parameters:
Parameters
Parameter | Description |
---|---|
code |
A one-time code that can be exchanged with an access_token . The code has a lifetime of 5 minutes. |
state |
An opaque value used by the Client to maintain state between the request and callback. |
scope |
Space-separated list of granted permissions. Please see Permissions |
error |
If the user doesn’t grant the request scopes the redirect will contain an error parameter with value access_denied |
Exchange code with access token
Request
curl -X POST \
-d grant_type=authorization_code \
-d client_id=${client_id} \
-d client_secret=${client_secret} \
-d redirect_uri=${redirect_uri} \
-d code=${code} \
-d code_verifier=${code_verifier} ## Only if using PKCE flow
https://auth.truelayer.com/connect/token
Response
{
"access_token": "JWT-ACCESS-TOKEN-HERE",
"expires_in": "JWT-EXPIRY-TIME",
"token_type": "Bearer",
"refresh_token": "REFRESH-TOKEN-HERE"
}
After a code
is obtained by the Client via redirect it can be exchanged for a short-lived access_token
Parameters
Parameter | Description |
---|---|
client_id |
Your unique client identifier |
client_secret |
Your client secret |
code |
one-time code obtained via the redirect |
grant_type |
Must be: "authorization_code" |
redirect_uri |
Must match the registered redirect_uri that was used to authorize access to the account. |
code_verifier |
Required only if using PKCE flow. Must be the code_verifier used to generate the code_challenge |
Response
The Authorization server will respond with JSON
Parameter | Description |
---|---|
access_token |
A short-lived JWT token used to access data on behalf of the End user |
expire_in |
access_token validity in seconds. Default is 1 hour or specified by provider. |
refresh_token |
A long-lived code used to obtain a new access_token when expired. It will be returned only if the scope offline_access was requested |
token_type |
Must be: Bearer |
Renew the access_token
Request
curl -X POST \
-d grant_type=refresh_token \
-d client_id=${client_id} \
-d client_secret=${client_secret} \
-d refresh_token=${refresh_token} \
https://auth.truelayer.com/connect/token
Response
{
"access_token": "JWT-ACCESS-TOKEN-HERE",
"expires_in": "JWT-EXPIRY-TIME",
"token_type": "Bearer",
"refresh_token": "REFRESH-TOKEN-HERE"
}
After the short-lived access_token
expires (1 hour by default) a new access_token
can be requested using a refresh_token
Parameters
Parameter | Description |
---|---|
grant_type |
Must be: "refresh_token" |
client_id |
Your unique client identifier |
client_secret |
Your client secret |
refresh_token |
The refresh_token |
Response
Parameter | Description |
---|---|
access_token |
A short-lived JWT token used to access data on behalf of the End user |
expire_in |
access_token validity in seconds. Default is 1 hour |
refresh_token |
The refresh_token just used in the request |
token_type |
Must be: Bearer |
Delete encrypted credentials
Request
curl -X DELETE -H "Authorization: Bearer ${access_token}" \
https://auth.truelayer.com/api/delete
This endpoint will revoke the access associated with the access token used for the request.
Submit access token for debug
Request
curl -X POST -H "Content-Type: application/json" \
-d '{"access_token": "ACCESS-TOKEN-HERE"}' https://auth.truelayer.com/api/debug
Response
{
"credentials_id": "SSwF1CgQMLOs0qratFpybzF7uJ3hxwppiw1C4s+rT4I=",
"debug_id": "mock|U1N3RjFDZ1FNTE9zMHFyYXRGcHliekY3dUozaHh3cHBpdzFDNHMrYXk0ST0",
"provider_id": "mock"
}
DELETE /api/debug
Content-Type: application/json
{"access_token": "ACCESS-TOKEN-HERE"}
curl -X DELETE -H "Content-Type: application/json" \
-d '{"access_token": "ACCESS-TOKEN-HERE"}' https://auth.truelayer.com/api/debug
{
"credentials_id": "SSwF1CgQMLOs0qratFpybzF7uJ3hxwppiw1C4s+rT4I=",
"debug_id": "mock|U1N3RjFDZ1FNTE9zMHFyYXRGcHliekY3dUozaHh3cHBpdzFDNHMrYXk0ST0",
"provider_id": "mock"
}
This endpoint will return a debug_id
that will allow TrueLayer to debug a particular issue.
You can delete the credentials from the endpoint in two ways:
Remove the credentials completely using the delete endpoint found here or
remove just the debug credentials using the /debug
endpoint.
Response
Parameter | Description |
---|---|
credentials_id |
Unique TrueLayer credential ID |
debug_id |
Computed TrueLayer key |
provider_id |
Unique TrueLayer provider ID |
List of supported providers
Request
curl https://auth.truelayer.com/api/providers
Response
{
"display_name": "RBS Scotland",
"logo_url": "https://auth.truelayer.com/img/banks/banks-icons/rbs-digital-icon.svg",
"provider_id": "rbs-digital",
"scopes": [
"info",
"accounts",
"transactions",
"balance",
"cards",
"offline_access"
],
"country": "uk"
}
This endpoint returns the list of supported providers:
The endpoint returns all providers in production, from every country. When TrueLayer adds new providers they will automatically be returned by this endpoint.
clientId
is an optional query parameter. If you include your TrueLayer Client ID, the endpoint will return all providers that your account has access to, including providers that are currently in beta:
- https://auth.truelayer.com/api/providers?clientId=YOUR_CLIENT_ID
Response
Parameter | Description |
---|---|
provider_id |
Unique TrueLayer provider ID |
display_name |
Human friendly provider name |
logo_url |
URL to the provider’s logo as used by TrueLayer |
scopes |
List of Permissions supported by the provider |
country |
Country where the provider is available |
Retrieve access_token
metadata
Request
curl -H "Authorization: Bearer ${access_token}" \
https://api.truelayer.com/data/v1/me
Response
{
"results": [
{
"client_id": "test",
"credentials_id": "6L7RxyPKX0THy1tw93PB4V+8DB+KjnX9Pxa451yXPu0=",
"consent_status": "Authorised",
"consent_status_updated_at": "2020-05-24T15:44:40.077Z",
"consent_created_at": "2020-05-24T14:44:40.077Z",
"consent_expires_at": "2020-08-24T14:44:40.077Z",
"provider": {
"display_name": "Lloyds Bank",
"logo_uri": "https://auth.truelayer.com/img/banks/banks-icons/lloyds-icon.svg",
"provider_id": "lloyds"
},
"scopes": [
"info",
"accounts",
"balance",
"transactions",
"cards",
"offline_access"
],
"privacy_policy": "Feb2019"
}
]
}
Returns access_token
metadata.
Response
Field | Type | Description | Auth Method |
---|---|---|---|
client_id |
string | Your unique client identifier | All |
credentials_id |
string | Unique identifier of the set of credentials | All |
consent_status |
string | Consent status. Possible responses: Rejected , Authorised , Revoked or AwaitingAuthorisation |
OB |
consent_status_updated_at |
string | OPTIONAL (returned if available). Consent status update date | OB |
consent_created_at |
string | OPTIONAL (returned if available). Consent creation date | OB |
consent_expires_at |
string | OPTIONAL (returned if available). Consent expiration date | OB |
provider.display_name |
string | Display name for the Provider | All |
provider.logo_uri |
string | URI for the Provider logo | All |
provider.provider_id |
string | Unique identifier for the Provider | All |
scopes |
array | Permission intersection for the End user and Provider | All |
privacy_policy |
string | The version of TrueLayer’s Privacy Policy that the owner of the set of credentials has given consent to | All |
Retrieve identity information
Request
curl -H "Authorization: Bearer ${access_token}" \
https://api.truelayer.com/data/v1/info
Response
{
"results": [
{
"full_name": "John Doe",
"update_timestamp": "2020-11-19T09:30:00Z"
}
]
}
Returns End user’s identity information held by the Provider. This can include name, address, emails, phone numbers and the user’s banking branch identifier.
When implementing this endpoint for UK accounts, the end user’s data should be requested within five minutes of the consent grant, and stored if necessary for your use case. Provider implementations of this endpoint differ due to varying interpretations of Article 10 of PSD2’s Regulatory Technical Standards on Strong Customer Authentication. If the data becomes unavailable, we will return an “sca_exceeded” error message.
Response
Field | Type | Description |
---|---|---|
update_timestamp |
datetime | last time the data has been updated from the provider |
full_name |
string | Full name of the End user |
branch_id |
string | OPTIONAL Identifier of the end user’s banking branch (only returned for some French accounts) |
emails[...] |
Array of strings | OPTIONAL. Email addresses (if none available returns empty array) |
phones[...] |
Array of strings | OPTIONAL. Phone numbers (if none available returns empty array) |
NOTE: Most of the providers will only return the full_name
List all accounts
Request
curl -H "Authorization: Bearer ${access_token}" \
https://api.truelayer.com/data/v1/accounts
Response
{
"results": [
{
"update_timestamp": "2017-02-07T17:29:24.740802Z",
"account_id": "f1234560abf9f57287637624def390871",
"account_type": "TRANSACTION",
"display_name": "Club Lloyds",
"currency": "GBP",
"account_number": {
"iban": "GB35LOYD12345678901234",
"number": "12345678",
"sort_code": "12-34-56",
"swift_bic": "LOYDGB2L"
},
"provider": {
"provider_id": "lloyds"
}
},
{
"update_timestamp": "2017-02-07T17:29:24.740802Z",
"account_id": "f1234560abf9f57287637624def390872",
"account_type": "SAVINGS",
"display_name": "Club Lloyds",
"currency": "GBP",
"account_number": {
"iban": "GB35LOYD12345678901235",
"number": "12345679",
"sort_code": "12-34-57",
"swift_bic": "LOYDGB2L"
},
"provider": {
"provider_id": "lloyds"
}
}
]
}
Returns all End user’s
accounts and associated data
Response
Field | Type | Description |
---|---|---|
account_id |
string | Unique identifier of the account |
account_type |
string | Type of the account |
account_number.iban |
string | OPTIONAL. ISO 13616-1:2007 international bank number |
account_number.number |
string | OPTIONAL (only returned for UK accounts). Bank account number |
account_number.sort_code |
string | OPTIONAL (only returned for UK accounts). United Kingdom SORT code |
account_number.swift_bic |
string | ISO 9362:2009 Business Identifier Codes |
currency |
string | ISO 4217 alpha-3 currency code of the account |
display_name |
string | Human-readable name of the account |
update_timestamp |
datetime | Last update time of the account information |
provider.display_name |
string | Deprecated. Display name for the Provider. |
provider.logo_uri |
string | Deprecated. URI for the Provider logo |
provider.provider_id |
string | Unique identifier for the Provider |
Provider attributes display_name
, logo_uri
are deprecated.
The details about the providers are available on a separate end point. https://auth.truelayer.com/api/providers
Account types
These account types are currently supported and can be returned as account_type
Type | Description |
---|---|
TRANSACTION |
A transaction account is a checking account or current account |
SAVINGS |
A savings account is an interest-bearing deposit account |
BUSINESS_TRANSACTION |
A transaction account for a business |
BUSINESS_SAVINGS |
A savings account for a business |
Retrieve an account
Request
curl -H "Authorization: Bearer ${access_token}" \
https://api.truelayer.com/data/v1/accounts/${account_id}
Response
{
"results": [
{
"update_timestamp": "2017-02-07T17:29:24.740802Z",
"account_id": "f1234560abf9f57287637624def390871",
"account_type": "TRANSACTION",
"display_name": "Club Lloyds",
"currency": "GBP",
"account_number": {
"iban": "GB35LOYD12345678901234",
"number": "12345678",
"sort_code": "12-34-56"
},
"provider": {
"provider_id": "lloyds"
}
}
]
}
Returns data associated with the specified account_id
Response
Field | Type | Description |
---|---|---|
account_id |
string | Unique identifier of the account |
account_type |
string | Type of the account |
account_number.iban |
string | OPTIONAL (not returned by internal savings accounts on credential sharing). ISO 13616-1:2007 international bank number |
account_number.number |
string | OPTIONAL (only returned for UK accounts). Bank account number |
account_number.sort_code |
string | OPTIONAL (only returned for UK accounts). United Kingdom SORT code |
account_number.swift_bic |
string | ISO 9362:2009 Business Identifier Codes |
account_number.routing_number |
string | OPTIONAL (only returned for US-based accounts). Routing transit number |
currency |
string | ISO 4217 alpha-3 currency code of the account |
display_name |
string | Human-readable name of the account |
update_timestamp |
datetime | Last update time of the account information |
provider.display_name |
string | Deprecated. Display name for the Provider |
provider.logo_uri |
string | Deprecated. URI for the Provider logo |
provider.provider_id |
string | Unique identifier for the Provider |
Provider attributes display_name
, logo_uri
are deprecated.
The details about the providers are available on a separate end point. https://auth.truelayer.com/api/providers
Account types
These account types are currently supported and can be returned as account_type
Type | Description |
---|---|
TRANSACTION |
A transaction account is a checking account or current account |
SAVINGS |
A savings account is an interest-bearing deposit account |
BUSINESS_TRANSACTION |
A transaction account for a business |
BUSINESS_SAVINGS |
A savings account for a business |
Swift BIC
If swift_bic
is not supported, one of the below values will be returned.
Value | Description |
---|---|
NOT_SUPPORTED_BY_GEO |
Swift BIC is not supported in the geographical location |
NOT_SUPPORTED_BY_PROVIDER |
Swift BIC is not supported by the provider |
Retrieve account balance
Request
curl -H "Authorization: Bearer ${access_token}" \
https://api.truelayer.com/data/v1/accounts/${account_id}/balance
Response
{
"results": [
{
"currency": "GBP",
"available": 2150.8,
"current": 1161.2,
"overdraft": 1000,
"update_timestamp": "2017-02-07T17:33:30.001222Z"
}
]
}
Returns balance information for the specified account_id
Response
Field | Type | Description |
---|---|---|
currency |
string | ISO 4217 alpha-3 currency code |
available |
number | OPTIONAL. The amount of funds available to the account holder. This takes into account any pending transactions and includes any overdraft facility. |
current |
number | The amount of funds within the account. This does not include any pending transactions. |
overdraft |
number | OPTIONAL. Pre-arranged overdraft limit. Available for all “TRANSACTION” and “BUSINESS_TRANSACTION” account types. See Account Types |
update_timestamp |
datetime | OPTIONAL (if applicable). Last update time |
For payments accounts (current and some savings), a negative balance amount represents funds owed to the provider from the account holder, such as an overdraft. A positive balance amount represents funds that are available to spend.
In the example on the right, the account has a current balance of £1161.20, a £1000.00 overdraft facillity and has £11.60 spent in pending transactions. Therefore, available
is calculated as 2150.80 = 1161.20 + 1000.00 - 11.60
.
Retrieve account transactions
Request
curl -H "Authorization: Bearer ${access_token}" \
"https://api.truelayer.com/data/v1/accounts/${account_id}/transactions?from=${from}&to=${to}"
Response
{
"results": [
{
"transaction_id": "03c333979b729315545816aaa365c33f",
"normalised_provider_transaction_id": "txn-ajdifh38fheu5hgue",
"provider_transaction_id": "9882ks-00js",
"timestamp": "2018-03-06T00:00:00",
"description": "GOOGLE PLAY STORE",
"amount": -2.99,
"currency": "GBP",
"transaction_type": "DEBIT",
"transaction_category": "PURCHASE",
"transaction_classification": [
"Entertainment",
"Games"
],
"merchant_name": "Google play",
"running_balance": {
"amount": 1238.60,
"currency": "GBP"
},
"meta": {
"provider_transaction_category": "DEB"
}
},
{
"transaction_id": "3484333edb2078e77cf2ed58f1dec11e",
"normalised_provider_transaction_id": "txn-2jdh8whf8w9rh3udh",
"provider_transaction_id": "33b5555724",
"timestamp": "2018-02-18T00:00:00",
"description": "PAYPAL EBAY",
"amount": -25.25,
"currency": "GBP",
"transaction_type": "DEBIT",
"transaction_category": "PURCHASE",
"transaction_classification": [
"Shopping",
"General"
],
"merchant_name": "Ebay",
"meta": {
"provider_transaction_category": "DEB"
}
}
]
}
Returns transaction data for the specified account_id.
Parameters
Field | Type | Description |
---|---|---|
from |
datetime | OPTIONAL. Returns transactions posted on or after this date. Default value is date as of the API request minus 88 days |
to |
datetime | OPTIONAL. Returns transactions up to and including this date. Default value is date as of the API request |
Response
Field | Type | Description |
---|---|---|
transaction_id |
string | Unique identifier of the transaction in a request. It may change between requests. |
normalised_provider_transaction_id |
string | OPTIONAL TrueLayer’s recommended identifier of the transaction in a request. It will not change between requests. |
provider_transaction_id |
string | OPTIONAL Provider’s identifier of the transaction in a request. The format of this string will vary across providers. |
timestamp |
datetime | Date the transaction was posted on the account |
description |
string | Original description of the transaction as reported by the Provider |
transaction_type |
string | Type of the transaction |
transaction_category |
string | Category of the transaction |
transaction_classification |
array | Classification of the transaction (array can be empty if classification has not been successfully assigned) |
merchant_name |
string | OPTIONAL (if merchant has been identified). Name of the merchant |
amount |
number | Amount of the transaction |
currency |
string | ISO 4217 alpha-3 currency code |
meta |
object | A collection of additional Provider specific transaction metadata |
running_balance.amount |
number | OPTIONAL. If available, contains the running balance |
running_balance.currency |
string | OPTIONAL. If available, contains the running balance currency - ISO 4217 alpha-3 currency code |
For payment accounts (current and some savings), a positive transaction amount represents the addition of funds to the account, for example an incoming bank transfer. A negative transaction amount indicates the flow of funds out of an account, such as a shop purchase.
A negative running balance amount represents funds owed to the provider from the account holder, such as an overdraft. A positive running balance amount represents funds that are available to spend.
Transaction types
transaction_type
can have one of the below value
Value | Description |
---|---|
CREDIT |
Indicates an incoming fund |
DEBIT |
Indicates an outgoing fund |
Retrieve account pending transactions
Request
curl -H "Authorization: Bearer ${access_token}" \
"https://api.truelayer.com/data/v1/accounts/${account_id}/transactions/pending"
Response
{
"results": [
{
"transaction_id": "03c333979b729315545816aaa365c33f",
"normalised_provider_transaction_id": "txn-ajdifh38fheu5hgue",
"provider_transaction_id": "9882ks-00js",
"timestamp": "2018-11-18T00:00:00",
"description": "GOOGLE PLAY STORE",
"amount": -2.99,
"currency": "GBP",
"transaction_type": "DEBIT",
"transaction_category": "PURCHASE",
"transaction_classification": [
"Entertainment",
"Games"
],
"merchant_name": "Google play",
"running_balance": {
"amount": 1238.60,
"currency": "GBP"
},
"meta": {
"provider_transaction_category": "DEB"
}
},
{
"transaction_id": "3484333edb2078e77cf2ed58f1dec11e",
"normalised_provider_transaction_id": "txn-2jdh8whf8w9rh3udh",
"provider_transaction_id": "33b5555724",
"timestamp": "2018-11-18T00:00:00",
"description": "PAYPAL EBAY",
"amount": -25.25,
"currency": "GBP",
"transaction_type": "DEBIT",
"transaction_category": "PURCHASE",
"transaction_classification": [
"Shopping",
"General"
],
"merchant_name": "Ebay",
"meta": {
"provider_transaction_category": "DEB"
}
}
]
}
Returns pending transaction data for the specified account_id.
Response
Field | Type | Description |
---|---|---|
transaction_id |
string | Unique identifier of the transaction in a request. It may change between requests. |
normalised_provider_transaction_id |
string | OPTIONAL TrueLayer’s recommended identifier of the transaction in a request. It will not change between requests. |
provider_transaction_id |
string | OPTIONAL Provider’s identifier of the transaction in a request. The format of this string will vary across providers. |
timestamp |
datetime | Date the transaction was posted on the account |
description |
string | Original description of the transaction as reported by the Provider |
transaction_type |
string | Type of the transaction |
transaction_category |
string | Category of the transaction |
transaction_classification |
array | Classification of the transaction (array can be empty if classification has not been successfully assigned) |
merchant_name |
string | OPTIONAL (if merchant has been identified). Name of the merchant |
amount |
number | Amount of the transaction |
currency |
string | ISO 4217 alpha-3 currency code |
meta |
object | A collection of additional Provider specific transaction metadata |
running_balance.amount |
number | OPTIONAL. If available, contains the running balance |
running_balance.currency |
string | OPTIONAL. If available, contains the running balance currency - ISO 4217 alpha-3 currency code |
For payment accounts (current and some savings), a positive transaction amount represents the addition of funds to the account, for example an incoming bank transfer. A negative transaction amount indicates the flow of funds out of an account, such as a shop purchase.
A negative running balance amount represents funds owed to the provider from the account holder, such as an overdraft. A positive running balance amount represents funds that are available to spend.
Transaction types
transaction_type
can have one of the below value
Value | Description |
---|---|
CREDIT |
Indicates an incoming fund |
DEBIT |
Indicates an outgoing fund |
Retrieve direct debits
Request
curl -H "Authorization: Bearer ${access_token}" \
"https://api.truelayer.com/data/v1/accounts/${account_id}/direct_debits"
Response
{
"results": [{
"direct_debit_id": "004ea8ce16b6ff57090b7bf8c7b483a1",
"timestamp": "2019-07-19T17:28:37.798+01:00",
"name": "EE",
"status": "Active",
"previous_payment_timestamp": "2018-09-17T00:00:00+01:00",
"previous_payment_amount": 25.0,
"currency": "GBP",
"meta": {
"provider_mandate_identification": "6",
"provider_account_id": "1000000000000000001"
}
}, {
"direct_debit_id": "8e5dfbc5b4d66c8aff248e9ca6440c55",
"timestamp": "2019-07-19T17:28:37.805+01:00",
"name": "PAYPAL",
"status": "Active",
"previous_payment_timestamp": "2019-07-18T00:00:00+01:00",
"previous_payment_amount": 4.99,
"currency": "GBP",
"meta": {
"provider_mandate_identification": "9",
"provider_account_id": "1000000000000000001"
}
}, {
"direct_debit_id": "72699309c9be1226e46e5257fb24133f",
"timestamp": "2019-07-19T17:28:37.805+01:00",
"name": "BT INTERNET",
"status": "Active",
"previous_payment_timestamp": "2018-09-18T00:00:00+01:00",
"previous_payment_amount": 16.99,
"currency": "GBP",
"meta": {
"provider_mandate_identification": "7",
"provider_account_id": "1000000000000000001"
}
}],
"status": "Succeeded"
}
Returns direct debit data for the specified account_id.
When implementing this endpoint, the end user’s data should be requested within five minutes of the consent grant, and stored if necessary for your use case. Provider implementations of this endpoint differ due to varying interpretations of Article 10 of PSD2’s Regulatory Technical Standards on Strong Customer Authentication. If the data becomes unavailable, we will return an “sca_exceeded” error message.
Response
Field | Type | Description |
---|---|---|
direct_debit_id |
string | Unique identifier of the direct debit in a request. It may change between requests. |
timestamp |
datetime | Date and time the request was made |
name |
string | Name of the service or user returned by the Provider |
status |
string | OPTIONAL. This can either be Active or Inactive |
previous_payment_timestamp |
datetime | OPTIONAL. Date of the latest payment |
previous_payment_amount |
string | OPTIONAL. Amount of the latest payment |
currency |
string | OPTIONAL. ISO 4217 alpha-3 currency code |
meta |
object | A collection of additional Provider specific transaction metadata |
Retrieve standing orders
Request
curl -H "Authorization: Bearer ${access_token}" \
"https://api.truelayer.com/data/v1/accounts/${account_id}/standing_orders"
Response
{
"results": [
{
"frequency": "IntrvlMnthDay:01:26",
"status": "Active",
"timestamp": "2019-07-24T11:29:47.414+00:00",
"currency": "GBP",
"meta": {
"provider_account_id": "12345ca1-18fd-4e6b-891e-0597cac6bb8c"
},
"next_payment_date": "2019-07-26T00:00:00+00:00",
"next_payment_amount": 500.0,
"first_payment_date": "2019-06-26T00:00:00+00:00",
"first_payment_amount": 0.0,
"final_payment_date": "9999-12-31T00:00:00+00:00",
"final_payment_amount": 0.0,
"reference": "Savings"
},
{
"frequency": "IntrvlMnthDay:01:30",
"status": "Active",
"timestamp": "2019-07-24T11:29:47.416+00:00",
"currency": "GBP",
"meta": {
"provider_account_id": "12345ca1-18fd-4e6b-891e-0597cac6bb8c"
},
"next_payment_date": "2019-07-30T00:00:00+00:00",
"next_payment_amount": 500.0,
"first_payment_date": "2019-01-01T00:00:00+00:00",
"first_payment_amount": 0.0,
"final_payment_date": "9999-12-31T00:00:00+00:00",
"final_payment_amount": 0.0,
"payee": "JOHN DOE",
"reference": "MONZO"
}
],
"status": "Succeeded"
}
Returns standing order data for the specified account_id.
When implementing this endpoint, the end user’s data should be requested within five minutes of the consent grant, and stored if necessary for your use case. Provider implementations of this endpoint differ due to varying interpretations of Article 10 of PSD2’s Regulatory Technical Standards on Strong Customer Authentication. If the data becomes unavailable, we will return an “sca_exceeded” error message.
Response
Field | Type | Description |
---|---|---|
frequency |
string | Frequency of the standing order. Possible values: EvryDay - every day, EvryWorkgDay - every working day, IntrvlDay:XX - every XX calendar day, IntrvlMnthDay:XX:YY - every XXth month on the YYth day of the month, IntrvlWkDay:XX:YY - every XXth week, on the YYth day of the week, QtrDay - quarterly - , WkInMnthDay:XX:YY -every month, on the XXth week of the month and on the YYth day of the week. |
status |
string | OPTIONAL. This can either be Active or Inactive |
timestamp |
datetime | Date and time the request was made |
currency |
string | ISO 4217 alpha-3 currency code |
meta |
object | A collection of additional Provider specific transaction metadata |
next_payment_date |
datetime | OPTIONAL. The date on which the next payment for the standing order schedule will be made. |
next_payment_amount |
string | OPTIONAL. Amount of the next payment for the standing order |
first_payment_date |
datetime | OPTIONAL. The date on which the first payment for the standing order schedule will be or was made. |
first_payment_amount |
string | OPTIONAL. Amount of the first payment for the standing order |
final_payment_date |
datetime | OPTIONAL. The date on which the next payment for a Standing Order schedule will be made. |
final_payment_amount |
string | OPTIONAL. Amount of the last payment for the standing order |
reference |
string | OPTIONAL. Reference of the standing order set by the user |
payee |
datetime | OPTIONAL. Payee of the standing order set by the user |
List all cards
Request
curl -H "Authorization: Bearer ${access_token}" \
https://api.truelayer.com/data/v1/cards
Response
{
"results": [
{
"account_id": "f7b093437032c216d4350b7d442b9c5ccc0e9f19",
"card_network": "VISA",
"card_type": "CREDIT",
"currency": "GBP",
"display_name": "Club Credit Card",
"partial_card_number": "0044",
"name_on_card": "A. N. Other",
"valid_from": "2017-01",
"valid_to": "2018-01",
"update_timestamp": "2017-02-07T17:29:24.740802Z",
"provider": {
"provider_id": "lloyds"
}
},
{
"account_id": "ad86fb1c213245b6b6594895068973efca5f9367",
"card_network": "MASTERCARD",
"card_type": "CHARGE",
"currency": "GBP",
"display_name": "Club Charge Card",
"partial_card_number": "0055",
"name_on_card": "A. N. Other",
"valid_from": "2017-01",
"valid_to": "2018-01",
"update_timestamp": "2017-02-07T17:29:24.740802Z",
"provider": {
"provider_id": "lloyds"
}
}
]
}
Returns all End user’s
cards and associated data
Response
Field | Type | Description |
---|---|---|
account_id |
string | Unique identifier of the account |
card_network |
string | Processing network (eg. VISA) |
card_type |
string | Type of card (eg. Credit) |
currency |
string | ISO 4217 alpha-3 currency code of the account |
display_name |
string | Human-readable name of the account |
partial_card_number |
string | Last 4 digits of the card |
name_on_card |
string | OPTIONAL. If available, the name on the card |
valid_from |
string | OPTIONAL. If available, the valid from date |
valid_to |
string | OPTIONAL. If available, the valid to date |
update_timestamp |
datetime | Last update time of the card information |
provider.display_name |
string | Deprecated. Display name for the Provider |
provider.logo_uri |
string | Deprecated. URI for the Provider logo |
provider.provider_id |
string | Unique identifier for the Provider |
Provider attributes display_name
, logo_uri
are deprecated.
The details about the providers are available on a separate end point. https://auth.truelayer.com/api/providers
Supported card networks
These card networks are currently supported and can be returned as card_network
Type | Description |
---|---|
AMEX |
Processing network is American Express |
MASTERCARD |
Processing network is Mastercard |
VISA |
Processing network is VISA |
NOT_SUPPORTED_BY_GEO |
Processing network is not supported in the geographical location |
NOT_SUPPORTED_BY_PROVIDER |
Processing network is not supported by the provider |
Retrieve a card
Request
curl -H "Authorization: Bearer ${access_token}" \
https://api.truelayer.com/data/v1/cards/${account_id}
Response
{
"results": [
{
"account_id": "f7b093437032c216d4350b7d442b9c5ccc0e9f19",
"card_network": "VISA",
"card_type": "CREDIT",
"currency": "GBP",
"display_name": "Club Credit Card",
"partial_card_number": "0044",
"name_on_card": "A. N. Other",
"valid_from": "2017-01",
"valid_to": "2018-01",
"update_timestamp": "2017-02-07T17:29:24.740802Z",
"provider": {
"provider_id": "lloyds"
}
}
]
}
Returns a End user’s
card and associated data
Response
Field | Type | Description |
---|---|---|
account_id |
string | Unique identifier of the account |
card_network |
string | Processing network (eg. VISA) |
card_type |
string | Type of card (eg. Credit) |
currency |
string | ISO 4217 alpha-3 currency code of the account |
display_name |
string | Human-readable name of the account |
partial_card_number |
string | Last 4 digits of the card |
name_on_card |
string | OPTIONAL. If available, the name on the card |
valid_from |
string | OPTIONAL. If available, the valid from date |
valid_to |
string | OPTIONAL. If available, the valid to date |
update_timestamp |
datetime | Last update time of the card information |
provider.display_name |
string | Deprecated. Display name for the Provider |
provider.logo_uri |
string | Deprecated. URI for the Provider logo |
provider.provider_id |
string | Unique identifier for the Provider |
Provider attributes display_name
, logo_uri
are deprecated.
The details about the providers are available on a separate end point. https://auth.truelayer.com/api/providers
Retrieve card balance
Request
curl -H "Authorization: Bearer ${access_token}" \
https://api.truelayer.com/data/v1/cards/${account_id}/balance
Response
{
"results": [
{
"available": 3279.0,
"currency": "GBP",
"current": 20.0,
"credit_limit": 3300,
"last_statement_balance": 420.0,
"last_statement_date": "2017-01-28",
"payment_due": 5.0,
"payment_due_date": "2017-02-24",
"update_timestamp": "2017-02-247T17:29:24.740802Z"
}
]
}
Returns card balance information for the specified account_id
Response
Field | Type | Description |
---|---|---|
available |
number | OPTIONAL. The amount available to the card holder. This takes into account any pending transactions and credit limit. |
currency |
string | ISO 4217 alpha-3 currency code |
current |
number | The amount of expenditure on the card. This does not include any pending transactions. |
credit_limit |
number | OPTIONAL. Card credit limit |
last_statement_balance |
number | OPTIONAL. Card balance at time of last statement, if available |
last_statement_date |
string | OPTIONAL. Date of last statement, if available |
payment_due |
number | OPTIONAL. Minimum amount required by due date |
payment_due_date |
number | OPTIONAL. Date by which payment due should be remitted |
update_timestamp |
datetime | Last update time |
A negative available
amount means the card’s credit limit has been exceeded. A positive available
amount represents the credit available to the card holder.
A positive current
amount represents money owed to the provider from the card holder. Conversely (and far less common), a negative current
amount represents money owed to the card holder from the provider.
Retrieve card transactions
Request
curl -H "Authorization: Bearer ${access_token}" \
"https://api.truelayer.com/data/v1/cards/${account_id}/transactions?from=${from}&to=${to}"
Response
{
"results": [
{
"transaction_id": "a15d8156569ba848d84c07c34d291bca",
"normalised_provider_transaction_id": "txn-a15d8156569ba848d",
"provider_transaction_id": "33b5555724",
"timestamp": "2018-01-16T00:00:00+00:00",
"amount": 24.25,
"currency": "GBP",
"description": "SAINSBURYS SMRKT STORE 128",
"transaction_type": "DEBIT",
"transaction_category": "PURCHASE",
"running_balance": {
"amount": 1238.60,
"currency": "GBP"
},
"meta": {
"cardNumber": "1234********5678",
"location": "INTERNET"
}
},
{
"transaction_id": "af4d5470cc7ad6a83a02335ab8053481",
"normalised_provider_transaction_id": "txn-af4d5470cc7ad6a83",
"provider_transaction_id": "33b5555724",
"timestamp": "2018-03-19T00:00:00",
"amount": 46.82,
"currency": "GBP",
"description": "TALKTALK TELECOM",
"transaction_type": "DEBIT",
"transaction_category": "PURCHASE",
"meta":{
"provider_transaction_category": "DEB",
"cardNumber": "1234********5678",
"location": "INTERNET"
}
}
]
}
Returns card transaction data for the specified account_id.
Parameters
Field | Type | Description |
---|---|---|
from |
datetime | OPTIONAL. Returns transactions posted on or after from date. Default value is date as of the API request minus 88 days |
to |
datetime | OPTIONAL. Returns transactions up to and including this date. Default value is date as of the API request |
Response
Field | Type | Description |
---|---|---|
transaction_id |
string | Unique identifier of the transaction in a request. It may change between requests. |
normalised_provider_transaction_id |
string | OPTIONAL TrueLayer’s recommended identifier of the transaction in a request. It will not change between requests. |
provider_transaction_id |
string | OPTIONAL Provider’s identifier of the transaction in a request. The format of this string will vary across providers. |
timestamp |
datetime | Date the transaction was posted on the account |
description |
string | Original description of the transaction as reported by the Provider |
transaction_type |
string | Type of the transaction |
transaction_category |
string | Category of the transaction |
transaction_classification |
array | Classification of the transaction (array can be empty if classification has not been successfully assigned) |
merchant_name |
string | OPTIONAL (if merchant has been identified). Name of the merchant |
amount |
number | Amount of the transaction |
currency |
string | ISO 4217 alpha-3 currency code |
meta |
object | A collection of additional Provider specific transaction metadata |
running_balance.amount |
number | OPTIONAL. If available, contains the running balance |
running_balance.currency |
string | OPTIONAL. If available, contains the running balance currency - ISO 4217 alpha-3 currency code |
A positive transaction amount
reflects the flow of funds out of a card, such as a purchase. A negative amount
indicates the flow of funds into the card, for example a refund.
A positive running balance amount
represents money owed to the provider from the card holder. Conversely (and far less common), a negative running balance amount
represents money owed to the card holder from the provider.
Transaction types
transaction_type
can have one of the below value
Value | Description |
---|---|
CREDIT |
Indicates an incoming fund |
DEBIT |
Indicates an outgoing fund |
Retrieve card pending transactions
Request
curl -H "Authorization: Bearer ${access_token}" \
"https://api.truelayer.com/data/v1/cards/${account_id}/transactions/pending"
Response
{
"results": [
{
"transaction_id": "a15d8156569ba848d84c07c34d291bca",
"normalised_provider_transaction_id": "txn-a15d8156569ba848d",
"provider_transaction_id": "33b5555724",
"timestamp": "2018-01-16T00:00:00+00:00",
"amount": 24.25,
"currency": "GBP",
"description": "SAINSBURYS SMRKT STORE 128",
"transaction_type": "DEBIT",
"transaction_category": "PURCHASE",
"running_balance": {
"amount": 1238.60,
"currency": "GBP"
},
"meta": {
"cardNumber": "1234********5678",
"location": "INTERNET"
}
},
{
"transaction_id": "af4d5470cc7ad6a83a02335ab8053481",
"normalised_provider_transaction_id": "txn-af4d5470cc7ad6a83",
"provider_transaction_id": "33b5555724",
"timestamp": "2018-03-19T00:00:00",
"amount": 46.82,
"currency": "GBP",
"description": "TALKTALK TELECOM",
"transaction_type": "DEBIT",
"transaction_category": "PURCHASE",
"meta":{
"provider_transaction_category": "DEB",
"cardNumber": "1234********5678",
"location": "INTERNET"
}
}
]
}
Returns card pending transaction data for the specified account_id.
Response
Field | Type | Description |
---|---|---|
transaction_id |
string | Unique identifier of the transaction in a request. It may change between requests. |
normalised_provider_transaction_id |
string | OPTIONAL TrueLayer’s recommended identifier of the transaction in a request. It will not change between requests. |
provider_transaction_id |
string | OPTIONAL Provider’s identifier of the transaction in a request. The format of this string will vary across providers. |
timestamp |
datetime | Date the transaction was posted on the account |
description |
string | Original description of the transaction as reported by the Provider |
transaction_type |
string | Type of the transaction |
transaction_category |
string | Category of the transaction |
transaction_classification |
array | Classification of the transaction (array can be empty if classification has not been successfully assigned) |
merchant_name |
string | OPTIONAL (if merchant has been identified). Name of the merchant |
amount |
number | Amount of the transaction |
currency |
string | ISO 4217 alpha-3 currency code |
meta |
object | A collection of additional Provider specific transaction metadata |
running_balance.amount |
number | OPTIONAL. If available, contains the running balance |
running_balance.currency |
string | OPTIONAL. If available, contains the running balance currency - ISO 4217 alpha-3 currency code |
A positive transaction amount
reflects the flow of funds out of a card, such as a purchase. A negative amount
indicates the flow of funds into the card, for example a refund.
A positive running balance amount
represents money owed to the provider from the card holder. Conversely (and far less common), a negative running balance amount
represents money owed to the card holder from the provider.
Transaction types
transaction_type
can have one of the below value
Value | Description |
---|---|
CREDIT |
Indicates an incoming fund |
DEBIT |
Indicates an outgoing fund |
Retrieve cards and accounts transactions with a single call
Enqueueing a batch task
You can retrieve all card and account transactions with a single API call using our batch endpoint.
Batch calls are asynchronous: in the response you will find a results_uri
where you can fetch
the transactions once the batch task is complete.
If you specify a webhook_uri
you will receive a webhook notification when the status of your task changes. Possible status values are Succeeded
or Failed
.
You can retrieve cards and accounts transactions once the task is complete using our /batch/results
endpoint.
Request - Endpoint
POST /data/v1/batch/transactions
Request - Headers
Header | Value |
---|---|
Content-Type |
application/json |
Authorization |
Bearer <ACCESS_TOKEN> |
Request - Body
Request
# Put the request body in a JSON file, e.g. `batch_request.json`:
echo '{
"from": "2020-01-01",
"to": "2020-07-01",
"pending": true,
"balance": true,
"webhook_uri": "https://your-webhook-uri.com/"
}' > batch_request.json
curl -X POST -d @request.json \
-H "Authorization: Bearer ${access_token}" \
-H "Content-Type:application/json" \
https://api.truelayer.com/data/v1/batch/transactions
Field | Required | Example | Description |
---|---|---|---|
from |
Yes | 2019-01-07 or2019-01-07T10:00:00 |
An ISO8601 encoded date or datetime that specifies the lower limit of the time window you want to fetch transactions for. |
to |
Yes | 2019-05-07 or 2019-05-07T17:00:00 |
An ISO8601 encoded date or datetime that specifies the upper limit of the time window you want to fetch transactions for. |
webhook_uri |
No | https://app.api.example.com/ |
The endpoint that will receive our notification webhook. The webhook will be fired as a POST request - query parameters are allowed. |
pending |
No | true |
If set, also the pending transactions will be included in the response (if not specified it defaults to false ).If the provider doesn’t support pending transactions, they won’t be included in the response. |
balance |
No | true |
If set, the balance will also be returned for each account and/or card. |
account_ids_whitelist |
No | ["32828340fa4c", "3100e17de12145"] |
A JSON array of account/card ids to be whitelisted - only accounts with the corresponding id’s will be returned in the batch response. When set in the request body at least one id must be provided. If a whitelisted account is not found, the batch call will fail. |
Response
Response
{
"results_uri": "https://api.truelayer.com/data/v1/batch/results/8e35198d-f488-4e7d-8f41-991c8ace45f2",
"status": "Queued",
"task_id": "8e35198d-f488-4e7d-8f41-991c8ace45f2"
}
Field | Type | Description |
---|---|---|
results_uri |
string |
The URI where results can be fetched from when available. |
status |
string |
The request outcome. If successful, Queued . |
task_id |
string |
A unique ID associated with the task |
Webhook notification for a batch call
Webhook payload
{
"request_timestamp" : "2020-11-19T09:30:00Z",
"request_uri" : "https://api.truelayer.com/",
"results_uri": "https://api.truelayer.com/data/v1/results/e1245d07-d846-42df-86d8-99b08b430a0",
"credentials_id": "6L7RxyPKX0THy1tw93PB4V+8DB+KjnX9Pxa451yXPu0=",
"task_id": "e1245d07-d846-42df-86d8-99b08b430a0",
"status": "succeeded",
}
When a batch task is completed, this payload will be sent to the webhook_uri
specified in
the batch request via HTTP POST
.
Field | Type | Description |
---|---|---|
request_timestamp |
datetime |
The ISO8601 encoded datetime specified in the original request |
request_uri |
string |
The URI of the original request |
credentials_id |
string |
Unique string identifying a set of End user’s credentials used to access a Provider |
task_id |
string |
A unique ID associated with the task |
status |
string |
Succeeded or Failed |
results_uri |
string |
The URI where results can be fetched from when available. |
Webhook Retry Policy
We consider a webhook as having been successfully delivered when we receive a success status code (2xx) from the webhook_uri
.
If we receive any other status codes like 5xx or 408 (e.g. 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 retry for a maximum of 6 times.
Retrieve batch results - Success case
If the batch job was successful, you can use the results_uri
specified in the webhook payload to fetch your transactions.
Request
curl -H "Authorization: Bearer ${access_token}" \
https://api.truelayer.com/data/v1/batch/results/0cf3fca2-e64e-4a35-8280-7c5bd7b5dc43
Response
{
"status": "Succeeded",
"task_id": "0cf3fca2-e64e-4a35-8280-7c5bd7b5dc43",
"request": {
"from": "2019-05-10T00:00:00",
"to": "2019-05-20T00:00:00"
},
"results": {
"accounts": [
{
"account_id": "a467e5319ddc9ad99846465bd6f0127e",
"transactions": [
{
"timestamp": "2019-05-10T00:00:00",
"description": "EDF ENERGY",
"transaction_type": "DEBIT",
"transaction_category": "UNKNOWN",
"transaction_classification": [
"Bills and Utilities",
"Utilities"
],
"merchant_name": "EDF ENERGY",
"amount": -24.5,
"currency": "GBP",
"transaction_id": "1647dc2acf12438d8c348a379b85814a"
},
{
"timestamp": "2019-05-20T00:00:00",
"description": "REGENDA REDWING",
"transaction_type": "DEBIT",
"transaction_category": "UNKNOWN",
"transaction_classification": [
"Investments",
"Real-estate"
],
"merchant_name": "REDWING LIVING",
"amount": -150,
"currency": "GBP",
"transaction_id": "7cfc04c0f5c4c39a3e168b76ec607799"
}
],
"pending_transactions": [
{
"transaction_id": "a15d8156569ba848d84c07c34d291bca",
"normalised_provider_transaction_id": "txn-a15d8156569ba848d",
"provider_transaction_id": "33b5555724",
"timestamp": "2019-05-20T00:00:00",
"amount": 24.25,
"currency": "GBP",
"description": "SAINSBURYS SMRKT STORE 128",
"transaction_type": "DEBIT",
"transaction_category": "PURCHASE",
"running_balance": {
"amount": 1238.6,
"currency": "GBP"
},
"meta": {
"cardNumber": "1234********5678",
"location": "INTERNET"
}
},
{
"transaction_id": "af4d5470cc7ad6a83a02335ab8053481",
"normalised_provider_transaction_id": "txn-af4d5470cc7ad6a83",
"provider_transaction_id": "33b5555724",
"timestamp": "2019-05-20T00:00:00",
"amount": 46.82,
"currency": "GBP",
"description": "TALKTALK TELECOM",
"transaction_type": "DEBIT",
"transaction_category": "PURCHASE",
"meta": {
"provider_transaction_category": "DEB",
"cardNumber": "1234********5678",
"location": "INTERNET"
}
}
],
"balance": {
"currency": "GBP",
"available": 200.12,
"current": 200.12,
"overdraft": 0,
"update_timestamp": "2019-05-20T00:00:00"
}
},
{
"account_id": "9586f94c8b253dc83807171339ea5da9",
"transactions": [
{
"timestamp": "2019-05-10T00:00:00",
"description": "EDF ENERGY",
"transaction_type": "DEBIT",
"transaction_category": "UNKNOWN",
"transaction_classification": [
"Bills and Utilities",
"Utilities"
],
"merchant_name": "EDF ENERGY",
"amount": -24.5,
"currency": "GBP",
"transaction_id": "f80d0229693f61fcb6c1fb79f2c61af4"
},
{
"timestamp": "2019-05-20T00:00:00",
"description": "REGENDA REDWING",
"transaction_type": "DEBIT",
"transaction_category": "UNKNOWN",
"transaction_classification": [
"Investments",
"Real-estate"
],
"merchant_name": "REDWING LIVING",
"amount": -150,
"currency": "GBP",
"transaction_id": "bdf8979b2d9c80ad1db2053c2e18a483"
}
],
"pending_transactions": [],
"balance": {
"currency": "GBP",
"available": 50.08,
"current": 50.08,
"overdraft": 0,
"update_timestamp": "2019-05-20T00:00:00"
}
}
],
"cards": [
{
"account_id": "8901414c1e40d6beb24dfe45f39f3912",
"transactions": [
{
"timestamp": "2019-05-10T00:00:00",
"description": "EDF ENERGY",
"transaction_type": "CREDIT",
"transaction_category": "UNKNOWN",
"transaction_classification": [
"Bills and Utilities",
"Utilities"
],
"merchant_name": "EDF ENERGY",
"amount": -24.5,
"currency": "GBP",
"transaction_id": "646a9145784840eb911fef6278fbc4e5"
},
{
"timestamp": "2019-05-20T00:00:00",
"description": "REGENDA REDWING",
"transaction_type": "CREDIT",
"transaction_category": "UNKNOWN",
"transaction_classification": [
"Investments",
"Real-estate"
],
"merchant_name": "REDWING LIVING",
"amount": -150,
"currency": "GBP",
"transaction_id": "27d48b9c7d943c285e870bceba5b033b"
}
],
"balance": {
"available": 3279.0,
"currency": "GBP",
"current": 20.0,
"credit_limit": 3300,
"last_statement_balance": 420.0,
"last_statement_date": "2019-04-30",
"payment_due": 5.0,
"payment_due_date": "2019-05-20",
"update_timestamp": "2019-05-107T17:29:24.740802Z"
}
},
{
"account_id": "afb594831dacd544563b20be7c362a51",
"transactions": [
{
"timestamp": "2019-05-10T00:00:00",
"description": "EDF ENERGY",
"transaction_type": "CREDIT",
"transaction_category": "UNKNOWN",
"transaction_classification": [
"Bills and Utilities",
"Utilities"
],
"merchant_name": "EDF ENERGY",
"amount": -24.5,
"currency": "GBP",
"transaction_id": "cc96f312d45f2c96d9464e69873d6a04"
},
{
"timestamp": "2019-05-20T00:00:00",
"description": "REGENDA REDWING",
"transaction_type": "CREDIT",
"transaction_category": "UNKNOWN",
"transaction_classification": [
"Investments",
"Real-estate"
],
"merchant_name": "REDWING LIVING",
"amount": -150,
"currency": "GBP",
"transaction_id": "da5c341e2b790bb3bcfd0235829df37c"
}
],
"balance": {
"available": 510.0,
"currency": "GBP",
"current": 200.0,
"credit_limit": 710,
"last_statement_balance": 420.0,
"last_statement_date": "2019-04-30",
"payment_due": 10.0,
"payment_due_date": "2019-05-20",
"update_timestamp": "2019-05-107T17:29:24.740802Z"
}
}
]
}
}
Request - Endpoint
GET /data/v1/batch/results/<your-task-id>
Request - Headers
Header | Value |
---|---|
Authorization |
Bearer <ACCESS_TOKEN> |
Response
The schema of the response retrieved from results_uri
has the following top-level structure:
Field | Type | Description |
---|---|---|
results |
BatchResult |
A BatchResult object. See below for its schema. |
request |
BatchRequest |
An object containing the parameters used for the request. See below for its schema. |
task_id |
string |
A unique ID associated with the task. |
status |
string |
The request outcome. If successful, Succeeded . |
BatchRequest
has the following structure:
Field | Type | Description |
---|---|---|
from |
datetime |
The ISO8601 encoded date time passed as from query parameter in the original batch endpoint request. |
to |
datetime |
The ISO8601 encoded date time passed as to query parameter in the original batch endpoint request. |
BatchResult
has the following structure:
Field | Type | Description |
---|---|---|
cards |
Asset list |
A list of Asset objects, one for each card associated to the credential set the token belongs to. See below for their schema. |
accounts |
Asset list |
A list of Asset objects, one for each account associated to the credential set the token belongs to. See below for their schema. |
Asset
has the following structure:
Field | Type | Description |
---|---|---|
account_id |
string |
A unique ID associated with the card or the account (the same that would be returned if using /cards or /accounts ) |
transactions |
object list |
The list of transactions associated with the account or card for the specified time window. |
pending_transactions |
object list |
The list of the pending transactions associated with the account or card (if there are no pending transactions this field will contain an empty list). |
balance |
object object |
The account balance of the account or card. |
Each element in the transactions
array has the same schema of a transaction returned from /accounts/{account_id}/transactions
or /cards/{account_id}/transactions
.
Each element in the pending_transactions
array has the same schema of a transaction returned from /accounts/{account_id}/transactions/pending
or /cards/{account_id}/transactions/pending
.
The returned balance has the same schema as a balance returned from /accounts/{account_id}/balance
or /cards/{account_id}/balance
.
Retrieve batch results - Failure case
If the batch task was unsuccessful, you can use the results_uri
specified in the webhook payload
to retrieve useful information on what went wrong.
The response contains the details of each failed sub_task
.
Request
curl -H "Authorization: Bearer ${access_token}" \
https://api.truelayer.com/data/v1/batch/results/0cf3fca2-e64e-4a35-8280-7c5bd7b5dc43
Response
{
"status": "Failed",
"error_details_list": [
{
"sub_task_id": "d734dbf4-92a8-4d15-96e2-25f3571139ed",
"status_code": 404,
"error": "not_found",
"error_description": "Unable to find one or more whitelisted asset ids",
"sub_task_type": "BatchRequest"
}
]
}
Request - Endpoint
GET /data/v1/batch/results/<your-task-id>
Request - Headers
Header | Value |
---|---|
Authorization |
Bearer <ACCESS_TOKEN> |
Response
Field | Type | Description |
---|---|---|
status |
string |
Status of the batch request (Failed ) |
error_details_list |
ErrorDetails list |
A list of ErrorDetails containing details on the failure reason for each failed sub_task |
ErrorDetails
has the following structure:
Field | Type | Description |
---|---|---|
sub_task_id |
string |
Id of the failed sub task |
status_code |
int |
Failure status code of the sub task |
error |
string |
Failure error code of the sub task. One of: bad_request , internal_server_error , unauthorized , not_found , forbidden |
error_description |
string |
Failure error description of the sub task |
sub_task_type |
string |
Type of the failed sub task. One of: Cards , Accounts , AccountTransactions , CardTransactions , AccountPendingTransactions , CardPendingTransactions ) |
End-user IP Address
EU banks limit the number of requests that can be made to their API if the request is not initiated by the end-user. These are documented as 429
errors here. In order to avoid this rate limit, you can include the end-user’s IP address in your requests to the Data API as follows.
Field | Type | Description |
---|---|---|
X-PSU-IP |
string | The PSU’s IP address to be passed on to the bank in order to avoid rate limiting. |
Data API errors
The following error codes can be returned with the associated HTTP status.
HTTP Status | Description | Error Code | Retry | How to handle |
---|---|---|---|---|
200 |
Success | |||
400 |
The supplied parameters are not valid. | validation_error |
Yes | There’s a problem with the request. Read the error message which explains what’s wrong with the request specifically. |
400 |
Invalid date range provided. | invalid_date_range |
No | Change the from and to parameters. Check here for bank-specific requirements: https://truelayer.zendesk.com/hc/en-us/articles/360003168153-How-far-back-can-I-pull-transactions- |
400 |
The provider has been deprecated. | deprecated_provider |
No | The provider has been deprecated. It is no longer supported. |
401 |
The credentials or token are no longer valid | unauthorized |
No | Refresh your access token. The access token may be invalid or expired. You can check for more details in the error description. |
401 |
The token is no longer valid | invalid_token |
No | Refresh your access token. The access token may be invalid or expired. You can check for more details in the error description. |
403 |
Access to a specific resource has been denied. | access_denied |
No | Ask the user to reconnect their account. This error is returned when the access to their account is no longer valid, either because it expired or because the user revoked it themselves. |
403 |
The provided credentials encryption key is invalid. | invalid_credentials_key |
||
403 |
SCA exemption has expired. This resource is protected and should be accessed shortly after PSU Authentication. In order to access this resource, please have the PSU re-authenticate. | sca_exceeded |
No | The access to that specific endpoint has expired. For example, for some European banks you may only access the /info endpoint, or transanctions older than 90 days, during the 5 minutes after the user first grants access. Access to other data (balances, recent transactions) should still be working. |
404 |
The requested account cannot be found. | account_not_found |
No | Check the accountId parameter used within your request. Confirm this matches an accountId returned from /accounts endpoint. |
429 |
Provider rate limit exceeded. | provider_too_many_requests |
Yes | Include the X-PSU-IP header or retry later. Requests exceed the bank’s rate limit. |
429 |
Maximum number of requests per user allowed by provider exceeded. | provider_request_limit_exceeded |
Yes | Include the X-PSU-IP header or retry later. The bank has a regulatory limit on how often the account can be accessed (for example, many European banks have a limit of 4 requests for a given user per endpoint per day, unless the user has initiated the request). |
500 |
Internal server error. | internal_server_error |
Yes | Retry later. |
501 |
Feature not supported by the provider. | endpoint_not_supported |
No | Check supported endpoints for each provider via our Help Desk FAQ. |
503 |
The provider service is unavailable. | provider_error |
Yes | Retry later - the bank is currently undergoing maintenance. |
503 |
The connector service is currently overloaded. | connector_overload |
Yes | Retry later - TrueLayer is currently overloaded. |
503 |
The provider service is unavailable. | temporarily_unavailable |
Yes | Retry later - the bank is experiencing unexpected downtime. |
504 |
The provider service timed out. | provider_timeout |
Yes | Retry later - the bank is experiencing issues. |
504 |
The connector service timed out. | connector_timeout |
Yes | Retry later - TrueLayer is experiencing a transient issue. |
Data API Changelog
November 23, 2020
- New providers: Polish and lithuanian banks now in public beta
- Removed feature: The batch endpoint (private beta) no longer supports storing previously fetched data
October 29, 2020
- New feature: An improved auth dialog is now in private beta. User journey is simpler, mobile optimised and has a better conversion rate. Request private beta access here
- New feature: You can now return users straight to your app once they’ve connected their bank account. Feature in provate beta. Request private beta access here
- New feature: Identify pain points in the authentication flow with the Auth journey analytics API (in private beta). Request private beta access here
- New providers: Polish banks now avilable in private beta. Request private beta access here
- Removed feature: Deprecated the
provider.logo_uri
andprovider.display_name
fields incards
andaccounts
Data API payloads. Values are still returned, but their correctness is no longer guaranteed. We recommend the Providers API for accuracte information about providers
September 25, 2020
- New feature: Transaction classification now available in Ireland and France
- New feature: Organisation owners can now create multiple applications within a single account (only available in LIVE environment)
- New providers: Increased bank coverage available in Germany. Head to the console to enable these banks
- New providers: Lithuanian banks now in private beta. Request private beta access here
August 27th, 2020
- New providers: expanded coverage for Italian banks. Enable these in the console
May 21, 2020
- Added more information on advised implementations of SCA Protected endpoints
August 1, 2019
- Updated response:
running_balance
now available on transactions from supported providers
June 20, 2019
- Updated response:
consent_status
,consent_status_updated_at
andconsent_created_at
available in the /me endpoint
June 19, 2019
- New Provider: OB-Revolut (provider_id:
ob-revolut
) available - New Feature: OB-HSBC (provider_id:
ob-hsbc
) supports/info
endpoint
May 24, 2019
- Updated response:
consent_expires_at
available in the /me endpoint
May 21, 2019
- New Feature:
ob-lloyds
,ob-bos
andob-halifax
supports savings accounts - New Feature:
ob-rbs
,ob-natwest
supports savings accounts and credit cards - New Provider: OB-HSBC Business (provider_id:
ob-hsbc-business
) now available
March 29, 2019
- New Feature:
disable_providers
query parameter takes a list of provider ids to be hidden in the authentication dialog - New Provider: OB-Nationwide
Payments API v1
Payments API Overview
The TrueLayer Platform is integrated to UK and EU banks which offer Payment Initiation APIs. We provide a single public API that enables you to make payment requests to all integrated UK banks and some European banks.
If you are interested in offering payments in Europe, you can integrate with Payment API v2 as a private beta tester to get access to the full coverage of our integrated banks.
To use our Payments API, you need to:
- Create a TrueLayer account using the Console.
- Contact sales for access to the Payments API.
Payments API: Contents
In this section of the documentation you will find:
- A Quick Start to get you up and running with the Payments API immediately
- A guide to integrating the Payments API to your application
- A changelog with a history of changes made to the API
Payments API Quick Start
Use our Payments API to make a single immediate payment in just a few quick steps - here’s how it works:
- After signing up to our Console, make a note of the
client_id
and theclient_secret
. These credentials allow you to obtain anaccess_token
. - Using that token, set up a single immediate payment, specifying recipient and amount.
- We’ll provide you with an authorisation link, which provides a simple interface for you to select the bank to make the payment from and complete the payment.
It’s that simple! To see it in action, use our Sandbox Postman collection to start making payments in just a few minutes, following the steps below.
If you want to use Postman with your production account, please download this Postman collection instead (this has production URIs instead of sandbox URIs).
Set Up
- Sign up to the TrueLayer Console to get your
client_id
andclient_secret
. - Install Postman and download our Postman collection. It contains sample requests so that you can start making payments, and generate code snippets in various languages of your choice.
Step 1 - Obtain an Access Token
- Open the first step in the Postman collection and click the
Body
tab. - Replace
CLIENT_ID
andCLIENT_SECRET
with your own values obtained in Step 1. - Click the
Send
button to forward the request to our server. - In response you’ll receive an
access_token
, which you can copy into your clipboard.
Step 2 - Create a Single Immediate Payment
- Now open the second step in the postman collection and click the
Authorization
tab. - Replace the token value
ACCESS-TOKEN-HERE
with the value obtained in the previous step. - Now click on
Body
and replace the values with the actual payment details. Make sureredirect_uri
is one of the URIs that has been whitelisted in the TrueLayer Console. - Click the blue
Send
button to forward the request to our server. - Open the
auth_uri
in a browser to complete the payment.
Step 3 - Get Payment Status
- Now open the third step in the Postman collection and click the
Authorization
tab. - Replace the token value
ACCESS-TOKEN-HERE
with the value obtained in Step 1. - Replace
PAYMENT-ID-HERE
in the URI with the value ofsimp_id
obtained in Step 2. - Click the
Send
button to forward the request to our server. We will return the status for this payment.
Congratulations, you made your first payment!
What’s next
- Check out our full documentation for more details on how to use our Payments API.
Payments API Guide
Note that all API endpoint URIs in this section are for the production environment. If you wish to follow this guide using the sandbox environment, please ensure that you change the endpoint domain from truelayer.com
to truelayer-sandbox.com
. You can also find all the sandbox endpoints in our Sandbox Postman collection.
Integration Checklist
Below are two checklists, one is for using the TrueLayer UI to initiate payments and the other is for whitelabeling our service inside your own application. For the best user experience and the highest conversion rate, we recommend you integrate into your own UI.
For the simplest guide to getting integrated as fast as possible, see a blog post we have published here.
Using your own UI
- Use our providers endpoint to build a ‘Provider Selection screen’ for the user to choose their bank. (all assets are supplied)
- Obtain a client credentials grant from the authentication server
- Create a new Single Immediate Payment, specifying the bank the user wants to use
- Redirect the user to the URI specified in the API response
- Handle the redirect back from the bank on the redirect_uri you set in the console.
- Poll our Get Info endpoint until you see a final status.
Please note, if you are unregulated as a PISP and you wish to use your own UI, you are required to add the following disclaimer on the screen where you confirm the payment details with the user:
By clicking next you are permitting TrueLayer to initiate a payment from your bank account. You also agree to TrueLayer end-user terms and privacy policy
For full guidance, please refer to our support post here or reach out to our support team for further information.
Using our UI
- Obtain a client credentials grant from the authentication server
- Create a new Single Immediate Payment
- Redirect the user to the URI specified in the API response
- Handle the redirect back from the bank on the redirect_uri you set in the console.
- Poll our Get Info endpoint until you see a final status.
Getting Setup
Using the Sandbox
To use the sandbox, all you have to do is replace truelayer.com with truelayer-sandbox.com in your requests. Remember to use the right credentials for the sandbox.
In the sandbox, you will have access to banks that have a sandbox environment. With these banks you can send a fake payment that will behave like a real one.
Finding your Client ID and Secret
To authenticate to our API you will need to use your Client ID and Secret for the environment you are using (Live or Sandbox). Both can be found in the console.
The client ID can be found in the settings page. If you don’t have your client secret, you can generate a new one here.
To upgrade your account to the live environment, you will need to give our sales team your Client ID. In the sandbox area of the console follow these steps:
- Navigate to the payments tab
- Click 'Go to live env’
- Navigate to the settings tab
- Copy the client ID field
Adding a redirect_uri
Once the user has authenticated with their bank, we will redirect them back to your application. Add this URI to the console so that we can validate it when you create a payment.
Add the redirect to the settings page, you can add as many as you like.
Common concepts to familiarise yourself with
Concept | Description |
---|---|
Provider selection | This refers to a selection screen used by your users to select their bank. You can build your own with the providers endpoint available for each payment type. |
Redirect URI | The redirect uri that you send us will be used to the send the user home after authorising their payment with the bank. This URI can’t have any parameters associated with it. We will add a query parameter with the payment ID. |
Beneficiary | This refers to the bank account receiving the funds. This is most commonly you. |
Remitter | This refers to the bank account making the payment. This is most commonly your user. |
How to present this payment method to your users
The only requirement for your user interface is that you should not embed the payment flow as a frame within a larger frameset. Most banks will not accept their flow running this way and will block the user from continuing. However, running as a webview should not be a problem if you wish to initiate the payment from within a mobile application.
When presenting the end user with the option to use this payment method, we recommend you label the option as “Pay with Bank” rather than mentioning TrueLayer or Open Banking. This increases user trust and confidence in using the service.
Authentication
Request
curl -X POST \
-d grant_type=client_credentials \
-d client_id=${client_id} \
-d client_secret=${client_secret} \
-d scope=payments \
https://auth.truelayer.com/connect/token
Response
{
"access_token": "JWT-ACCESS-TOKEN-HERE",
"expires_in": 3600,
"token_type": "Bearer"
}
Use our authentication server to obtain a client credentials grant. You will need to use this on your requests to the Payments API.
Unlike our Data API, this grant doesn’t represent a user, but a client creating the payment.
Single Immediate Payment
This section describes how to setup, execute, and monitor progress of a Single Immediate Payment.
A single immediate payment is a one time payment, executed immediately, that requires the user to authenticate with their bank.
Below are instructions for how to:
- Build a provider selection screen for your users to select their bank
- Create a payment
- Redirect a user to authenticate
- Handle the user returning to your application
- Poll for payment status
Providers Endpoint
Request
https://pay-api.truelayer.com/providers?capability=SingleImmediatePayment
Response
{
"results":[
{
"id":"ob-sandbox-natwest",
"logo":"example.com",
"icon":"example.com",
"displayable_name":"Natwest Sandbox",
"main_bg_color":"#eee",
"supports_app_to_app":false,
"divisions":["retail"]
}
]
}
The providers endpoint serves two purposes:
- Tells you which banks are active, if a bank isn’t listed then we have deactivated it temporarily until its service is returned.
- Gives you the assets to build out a selection screen e.g. logos and icons.
When querying the endpoint, specify capability
in the query string as SingleImmediatePayment
.
Each bank available will have the following fields:
Field | Type | Description |
---|---|---|
id |
string | This is the provider ID that you will send us in the create payment request. |
logo |
string | This is the address of the logo asset in SVG form. |
icon |
string | This is the address of the icon asset in SVG form. |
displayable_name |
string | This is a readable name for the provider. |
main_bg_color |
string | This is a hexacode color that matches the background of the logo. |
supports_app_to_app |
bool | This indicates whether the user will be redirected to the mobile banking app if using their mobile phone. In cases where this is false, the user authenticate in their browser. |
divisions |
string array | This array includes all divisions that are available on this provider, e.g. retail and business would indicate you can use this single provider to access both retail and business accounts. |
steps |
array | This array includes any extra steps in the authentication flow that you are required to send your end user through with some banks. The results of these steps will be used in your create payment request. |
We recommend you query this endpoint every single time you make a payment as we will remove banks that are not currently available.
The steps
parameter structure
Field | Type | Description |
---|---|---|
title | string | Friendly name for this method within the provider |
fields | array | Array of input fields |
fields.type | string | Input field type. Can be a Single Choice Input or a Free Input |
fields.is_sensitive | boolean | OPTIONAL: For Free Input Values, is set to true for sensitive information like passwords |
fields.values | array | OPTIONAL: For Single Choice Input, an array of values |
fields.values.value | string | OPTIONAL: For Single Choice Input, input field value |
fields.values.display_name | string | OPTIONAL: For Single Choice Input, friendly name for this input field value |
fields.validations | array | OPTIONAL: For Free Input Values, an array of RegEx validation rules that need to be satisfied to consider the input valid |
fields.allowed_characters | string | OPTIONAL: For Free Input Values, character ranges allowed. can be alphanumeric or numeric |
fields.id | string | Unique id for this field within the method |
fields.display_name | string | Friendly name for this field within the method |
fields.help_text | string | Input help text for the end user |
fields.mandatory | boolean | Indicates whether the field is required |
Creating the payment
Request
curl -X POST \
-H "Authorization: Bearer ${access_token}" \
--data '{
"amount": 120000,
"currency": "GBP",
"remitter_provider_id": "ob-bank",
"remitter_name": "Mike Smith",
"remitter_sort_code": "987654",
"remitter_account_number": "98765432",
"remitter_reference": "FS-1000001",
"beneficiary_name": "Financial Services Ltd",
"beneficiary_sort_code": "234567",
"beneficiary_account_number": "23456789"
"beneficiary_reference": "FinServ-1a2b3c4d",
"redirect_uri": "https://client.app.com/payment_redirect"
}' \
https://pay-api.truelayer.com/single-immediate-payments
Response
{
"results": [
{
"simp_id": "44708581-1967-4120-8f6a-1e532f1bf52a",
"auth_uri": "https://example.com",
"created_at": "2018-10-01T17:00:00.0000000+00:00",
"amount": 120000,
"currency": "GBP",
"remitter_provider_id": "ob-bank",
"remitter_name": "Mike Smith",
"remitter_sort_code": "987654",
"remitter_account_number": "98765432",
"remitter_reference": "FS-1000001",
"beneficiary_name": "Financial Services Ltd",
"beneficiary_sort_code": "234567",
"beneficiary_account_number": "23456789",
"beneficiary_reference": "FinServ-1a2b3c4d",
"redirect_uri": "https://client.app.com/payment_redirect",
"status": "new"
}
]
}
This method includes the following fields:
Field | Type | Mandatory/Optional | Description |
---|---|---|---|
amount |
int | Mandatory | The amount of money you are requesting in pennies. |
currency |
string | Mandatory | The currency code of the payment in three characters. e.g. GBP or EUR |
beneficiary_reference |
string | Mandatory | The reference that will appear on your bank statement. Note: this can only be 18 characters or less. |
beneficiary_sort_code |
string | Mandatory | The sort code of the receiving account (your account) if the account is a UK account (see below for EU). |
beneficiary_account_number |
string | Mandatory | The account number of the receiving account (your account) if the account is a UK account (see below for EU). |
beneficiary_iban |
string | Conditional | If making payments in Central European countries the beneficiary IBAN is a compulsory field and replaces the account number and sort code. |
remitter_reference |
string | Mandatory | The reference that will appear on the sender’s bank statement. Note: this can only be 18 characters or less. |
beneficiary_name |
string | Mandatory | The name on the receiving account. |
redirect_uri |
string | Mandatory | The URL we will redirect the user to after authorising the payment. |
remitter_provider_id |
string | Optional / Conditional | The ID from the providers endpoint of the bank your user has chosen. If this isn’t specified the user will be sent to TrueLayer to choose their bank in the UK. For banks outside of the UK, you will need to set this. |
remitter_account_number |
string | Optional | The account number of the payer, specify this if you want to lock the account from which the payment is being made if the account is a UK account (see below for EU). This may be an AML requirement. |
remitter_sort_code |
string | Optional | The sort code of the payer, specify this if you want to lock the account from which the payment is being made if the account is a UK account (see below for EU). This may be an AML requirement. |
remitter_iban |
string | Conditional | If making payments in Central European countries the remitter IBAN is a compulsory field. |
direct_bank_link |
bool | Optional / Conditional | If set to true, you will be returned a URI directly from the bank. !WARNING! If using this, you will skip all TrueLayer optimisation and conversion may be lower on desktop. You must specify remitter_provider_id for this request to succeed. This is a required field for European Banks. |
webhook_uri |
string | Optional | An address to send payment webhooks to with the status of your payment. This has to be https. |
auth_inputs |
dictionary | Conditional | If the providers endpoint returns you required steps you will need to list them and their answers here. For example, banks in France require you to specify the branch name. |
The request will return a simp_id
that you should store as, after authorisation, the user will be redirected to your redirect_uri with this appended as payment_id
.
Use the auth_uri
to redirect your user to authorise the payment.
Adapting an existing integration for EU Payments
If you’ve already implemented the payments API and would now like to use our European payment capability here are some key considerations to help you transition.
1. Instead of account numbers and sort codes you need to use our IBAN fields.
1. Both the remitter and beneficiary IBANs are compulsory fields to create a payment with a European Bank in Euros.
1. You’ll need to change the currency code to EUR
1. European banks can only pay to european bank accounts.
1. Some banks have additional steps required (these appear on their provider in the providers endpoint result you get back) and you’ll need to complete these steps before creating the payment and pre-fill the auth_inputs
field.
1. The remitter provider ID is a compulsory field.
1. direct_bank_link
is a compulsory field.
Redirecting your user to the bank
After creating the payment, you need to redirect the user to the auth_uri
.
If you did not specify the remitter_provider_id
your user will be redirected to the TrueLayer Provider Selection screen and from there on to their bank.
Handling a returning user
Once the payment is authorised, the user will return to your redirect_uri
. The URL will include a payment_id
query parameter containing the simp_id
from the payment creation response.
https://client.app.com/payment_redirect?payment_id=a55f2e12-55ef-410c-9341-628033a62dc3
Managing payment status with webhooks
Status Changed Event
X-TL-Signature: "a JWS token"
X-TL-Webhook-Timestamp: 2020-05-18T10:17:52Z
{
"event_type": "single_immediate_payment_status_changed",
"event_body": {
"payment_id": "77a75df0-af60-4785-8e91-809ac77ca8e3",
"status": "executed"
}
}
When the status of a payment changes, we send a single_immediate_payment_status_changed
event to the uri that you specified when creating the payment.
In the header you will see the following fields:
Field | Type | Description |
---|---|---|
X-TL-Signature |
JWS Token | a signature in the form of a JWS token that you can use to validate that the request came from us. Instructions for validating this can be found below. |
X-TL-Webhook-Timestamp |
timestamp | time that the webhook was sent to you. This will be in the following format 2020-05-18T10:17:47Z |
In the body you will see the following fields:
Field | Type | Description |
---|---|---|
event_type |
string | describing which event is detailed. In this case the event will be single_immediate_payment_status_changed |
event_body |
object | containing both the payment_id as a string and the status as a string |
To see all the available payment statuses, read the section below on polling for status where we list what states your payment can exist in.
Webhook Retry Policy
We consider a webhook as having been successfully delivered when we receive a success status code (2xx) from your webhook URI.
If we receive any other status code (e.g. your API is temporarily unavailable), we will start retrying.
Our retry policy is jittered exponential backoff: we will immediately perform some fast retries and then start waiting increasingly longer; we will keep retrying until 24 hours has passed since the first attempt.
Validating the webhook signature
The value of the X-TL-Signature
header contains a JSON Web Signature (JWS) with a detached payload. It takes the form {HEADER}..{SIGNATURE}
.
The JWS header contains the following values:
Field | Type | Description |
---|---|---|
alg |
string | The algorithm used to sign the webhook. We currently use the RS256 algorithm. |
jku |
string | The URI of the JSON Web Key Set (JWKS), a hosted page where a list of public keys owned by TrueLayer can be found. |
kid |
string | The ID of the key used to sign the webhook, used to retrieve the correct key from the JWKS. |
The steps for verifying the signature are as follows:
- Verify the
jku
field in the token header matches the expected value (below). If not, the signature should be rejected as invalid.- Sandbox:
https://pay-api.truelayer-sandbox.com/.well-known/jwks.json
- Production:
https://pay-api.truelayer.com/.well-known/jwks.json
- Sandbox:
- Use the
jku
value to retrieve the JWKS. This may be cached for some time, but if verification fails the JWKS must be re-retrieved to ensure that all keys are up to date. Keys may be rotated or revoked at any time by TrueLayer. - Retrieve the relevant public key by using the
kid
to look up the relevant value from the JWKS. - Reconstruct the signature payload. This is of the form:
{"Content-Type":"<value-of-content-type-header>","X-TL-Webhook-Timestamp":"<value-of-timestamp-header>","body":"<webhook-request-body>"}
. - Use a JWT library to verify the JWS headers combined with the reconstructed payload matches the signature provided in the token. The algorithm used to verify the signature must be that declared in the
alg
header of the JWS.
Code samples for signature validation can be found here.
Polling for payment status
Request
curl -H "Authorization: Bearer ${access_token}" \
https://pay-api.truelayer.com/single-immediate-payments/a55f2e12-55ef-410c-9341-628033a62dc3
Response
{
"results": [
{
"simp_id": "c45d38a6-2384-49aa-98ab-60134a50a5d7",
"created_at": "2018-10-01T16:00:00.0000000+00:00",
"amount": 350,
"currency": "GBP",
"beneficiary_reference": "ecommerce-12345",
"beneficiary_name": "Ecommerce Shop",
"beneficiary_sort_code": "102030",
"beneficiary_account_number": "88881234",
"remitter_reference": "ECOM-12345-ABCD",
"redirect_uri": "http://www.ecommerce.com/redirect",
"remitter_provider_id": "ob-lloyds",
"status": "executed"
}
]
}
The application can poll the payment resource to see if the status has been modified. This allows the application to know if the payment was successful or not.
Note that if the remitter was specified, remitter details will also be included in the response.
The payment resource may exist in different states according to the progress of the transaction:
new
: The payment resource has been created, but the payer has not yet authorised the payment. The initial API response will always have this status if the API call is successful.authorised
: The payer has successfully authorised the payment using the bank portal, but the payment has not yet been submitted for execution.cancelled
: The payer has cancelled the payment using the bank portal. This may also happen for some bank UIs if the payer clicks the “Back” button in their browser. This is a terminal state.failed
: The bank has failed to initiate a payment session, this happens after a bank has been selected but before redirecting the user to the bank UI. This is a terminal state.rejected
: The payer authorised the payment, but the bank rejected it after this. This is a terminal state.submitted
: TrueLayer has successfully submitted the authorised payment initiation request to the bank API.executed
: The funds have left the remitter’s account and will arrive in the beneficiary’s account. This is a terminal state.
The submitted
and executed
states are very close; in fact a bank may respond to the payment submission indicating the payment has already been executed. However, it is also possible for a payment to be queued within the bank for a short period of time; in that case, the payment status will initially be submitted, and then may be updated to executed after polling for a status check.
Note that after a payment has been executed, it may take some time for it to be settled, although for transactions executed via Faster Payments, this normally happens very quickly.
Request
``` shell
curl -H "Authorization: Bearer ${access_token}" \
https://pay-api.truelayer.com/single-immediate-payments/a55f2e12-55ef-410c-9341-628033a62dc3/statuses
>Response
``` json
{
"results": [
{
"status": "New",
"date": "2020-04-08T21:53:35.364038"
},
{
"status": "Authorised",
"date": "2020-04-08T21:54:17.690429"
},
{
"status": "Submitted",
"date": "2020-04-08T21:54:18.546706"
},
{
"status": "Executed",
"date": "2020-04-08T21:54:28.063325"
},
{
"status": "Executed",
"date": "2020-04-08T21:54:28.2761"
}
],
"status": "queued"
}
To see all known states of your payment and trace your payment with the timestamps, add /statuses
to the end of the request.
Technical Notes
Initiate Payment
This diagram illustrates the message flow when a payment is created. - Client gets access token - Client requests creation of payment resource - Client receives representation of payment resource, including a URI to redirect the user to
End-User Authorises Payment
This diagram illustrates the message flow when a user authorises a payment. - User is redirected to bank selection dialog - User selects bank - User is redirected to bank payment consent flow - User authorises payment - User is redirected back to application
Polling Payment Status
This diagram shows messages used to determine the payment status after a payment has been authorised. - Client requests payment resource - Client receives payment resource representation and checks status attribute
Payment Cancelled
This diagram shows the user navigation and messaging when a user cancels the payment during the bank consent flow. - User is redirected to bank selection dialog - User selects bank - User is redirected to bank payment consent flow - User cancels payment - User is redirected back to application - Client requests payment resource - Client receives payment resource representation and checks status attribute
Payment Rejected
This diagram shows the user navigation and messaging when the bank rejects a payment after user authorisation. - User is redirected to bank selection dialog - User selects bank - User is redirected to bank payment consent flow - User authorises payment - User is redirected back to application - Bank rejects payment - Client requests payment resource - Bank responds with rejected payment status - Client receives payment resource representation and checks status attribute
Testing Guidelines
The following guidelines aim to provide practical guidance while testing the integration.
Payments Sandbox
Before testing with live accounts, we recommend that you test your integration with the sandbox. The Payments Quick Start provides instructions on how to access the sandbox APIs.
When you transition to live testing in the production environment:
- Make sure you change all URIs to end with
truelayer.com
instead oftruelayer-sandbox.com
- Change from using your sandbox
client_id_
andclient_secret
to your productionclient_id
andclient_secret
. You can find your productionclient_id
here: https://console.truelayer.com/settings/Application (you should have saved your productionclient_secret
when you last reset it, or when you created your production account) - Have a live bank account to hand which you own to make payments from, as well as one to make payments into. The payer (or remitter) bank account must be from one of the supported providers listed here
Bank Account Limits
Each bank has its own limits on how much money can be transferred using online banking, which also apply to their open banking payment APIs.
Velocity Limits
All banks have controls in place to protect their end users from fraudulent withdrawals. One type of control is a velocity limit, which allows only a certain number of payments, or a maximum aggregate payment amount, per time period, e.g. one hour, one day, etc.
Banks will not publish these limits, as the information could be taken advantage of by fraudsters. Therefore, when testing:
- Do not make an excessive number of payments from the same account within a short time period.
- If it is not possible to make a successful payment, this will be visible in the bank’s authorisation user interface. At this point, it will be necessary to contact the specific bank’s end user support team to get the account unblocked.
Mock Providers
v1 providers endpoint currently exposes a mock provider named Mock UK Payments - Redirect Flow.
Data returned from providers endpoint
{
"id": "mock-payments-gb-redirect",
"name": "Mock UK Payments - Redirect Flow",
"country": "GB",
"divisions": [
"retail"
],
"steps": []
}
Mock UK Payments - Redirect Flow simulates UK banks that use the redirect authorisation flow.
When you initiate a payment using this provider, we will return a URI to redirect your user to our mock provider authorisation page.
On the authorisation prompt page, different actions lead to different outcomes for the payment. The following table describes the different actions you can make on the authorisation page and their outcomes:
Outcome | Action | Username |
---|---|---|
Execute | Enter username | test_executed |
Auth failure | Enter username | test_authorisation_failed |
Execution Rejection | Enter username | test_execution_rejected |
Cancellation | Click cancel button | - |
Once you log in with one of the predetermined usernames, the mock provider will present the account selection page:
When you provide the remitter account details in the payment initiation request, only the stated account can be selected on this screen.
Payments API Changelog
Updates made to the Payments API will be posted here with the release date.
You can also view a list of known issues.
June 30, 2021
Standing orders documentation retired
May 25, 2020
Webhooks added to single immediate payment
February 16, 2020
Standing orders documentation added
December 2, 2019
Addition of direct bank link parameter to create payment request
May 8, 2019
Sandbox environment released
January 29, 2019
Initial beta release:
- Single immediate payments
- UK Open Banking providers
- GBP
Payments API v2
Overview
The TrueLayer Platform is integrated to UK and EU banks which offer Payment Initiation APIs, and provides a single public API which enables clients to request payment via all integrated banks. As our coverage for international banks grow, v2 offers full coverage to all of our integrated banks.
As Payment API v2 is currently in private beta, if you would like to become one of our private beta testers and get access to European Payments, please reach out to our sales team or your CSM.
Note that for access to the production API, you must have:
- created a TrueLayer account using the Console
- been approved for access to the Payments API; contact sales
To get support for the Payments API:
- Check the Payments API FAQs
- Ask TrueLayer Support for help
Payment API v2 Usage Guide
Note that all API endpoint URIs in this section are for the production environment. If you wish to follow this guide using the sandbox environment, please ensure that you change the endpoint domain from truelayer.com
to truelayer-sandbox.com
.
Common concepts to familiarise yourself with
Concept | Description |
---|---|
Provider | A TrueLayer-supported bank, through which payments can be initiated. |
Provider selection | A screen used by your users to select their bank. You can use the providers endpoint, available for each payment type, to build this. |
Authorisation Flow | A method by which a bank allows their users to authorise a payment. Currently, we support redirect and embedded authorisation flows, but additional authorisation flows may be supported in future. |
redirect Authorisation Flow |
An authorisation flow which requires you to redirect your user to their bank’s website or app in order to authorise a payment. |
embedded Authorisation Flow |
An authorisation flow which requires you to present input fields to your user and submit their values to our API in order to authorise a payment. |
Return URI | The return_uri that you send us, when initiating a payment with the redirect authorisation flow. This will be used to return the user to you after they have authorised a payment with their bank. |
Beneficiary | This refers to the bank account receiving the funds. This is most commonly you. |
Remitter | This refers to the bank account making the payment. This is most commonly your user. |
PSU | This refers to the end user. |
Integration Checklist
- Use our providers endpoint to build a ‘Provider Selection screen’ for the user to choose their bank. (All assets are supplied via our providers endpoint.)
- Request an access token from our authentication endpoint.
- Create a new payment initiation request, specifying the provider the user has selected.
- Handle the response to allow the user to authorise the payment.
- For the
redirect
authorisation flow:- Redirect the user to the URI specified in the API response.
- Handle the user returning back from the bank on the
return_uri
you previously set in the console.
- For the
embedded
authorisation flow:- Display the inputs specified in the API response to the user.
- Submit the values they enter to our submission API.
- Repeat if the submission response specifies more inputs.
- For the
- Poll our
GET /v2/single-immediate-payments/{id}
endpoint until you see a final status, or provide a webhook URI for us to call you on.
Required Disclaimer for non-PISPs
Please note, if you are unregulated as a PISP, you are required to add the following disclaimer on the screen where you confirm the payment details with the user:
By clicking next you are permitting TrueLayer to initiate a payment from your bank account. You also agree to TrueLayer end-user terms and privacy policy
For full guidance, please refer to our support post here or reach out to our support team for further information.
Authorisation Flows
Redirect Authorisation Flow
To authorise a payment using the redirect auth flow, you would redirect your user to the bank’s app/website for authentication with a link provided by TrueLayer. The below diagram illustrates the whole flow from payment creation to payment authorisation for the redirect auth flow.
Embedded Authorisation Flow
To authorise a payment using the embedded auth flow, you need to collect the payment details from the user via your application and pass those details to TrueLayer. TrueLayer will provide you what you need to collect from the end user in order to complete authorisation for a payment. The below diagram illustrates the whole flow from payment creation to payment authorisation with the embedded auth flow.
Getting Setup
Using the Sandbox
To use the sandbox, use truelayer-sandbox.com
instead of truelayer.com
when making your requests. Remember to use the right credentials for the sandbox.
In the sandbox, you will have access to providers that have a sandbox environment. With these providers you can send a fake payment that will behave like a real one.
To upgrade your account to the live environment, you will need to give our sales team your client ID. In the sandbox area of the console follow these steps:
- Navigate to the payments tab
- Click 'Go to live env’
- Navigate to the settings tab
- Copy the client ID field
How to present this payment method to your users
When presenting the end user with the option to use this payment method, we recommend you label the option as “Pay with Bank” rather than mentioning TrueLayer or Open Banking. This increases user trust and confidence in using the service.
Handling the redirect
authorisation flow
After creating a payment initiation request using the redirect
authorisation flow, you must redirect the user to their bank’s website or app for them to authorise the payment. Please note, when handling this redirect, you should not embed the bank’s website as a frame within a larger frameset. Most banks will not accept this, and will block the user from continuing. However, running as a webview should not be a problem if you wish to initiate the payment from within a mobile application.
After the user has authorised the payment, they will be returned to the return_uri
provided on the initiation request. This URI must be configured in the console, otherwise we will reject the request. You can configure your allowed return URIs on the settings page. When the user is redirected to this URI, we will append a single_immediate_payment_id
query parameter specifying the payment id and a type
query parameter specifying the payment type. Currently the only value we will send for type
is single_immediate_payment
, however further payment types will be available in the future.
Authentication
Request
curl -X POST \
-d grant_type=client_credentials \
-d client_id=${client_id} \
-d client_secret=${client_secret} \
-d scope=payments \
https://auth.truelayer.com/connect/token
Response
{
"access_token": "JWT-ACCESS-TOKEN-HERE",
"expires_in": 3600,
"token_type": "Bearer"
}
To authenticate to our API you will need to use your client ID and secret for the environment you are using (Live or Sandbox). The client ID can be found in the settings page. If you don’t have your client secret, you can also generate a new one here.
Use our authentication server to obtain an access token using the client_credentials
grant type. You will need to use this on your requests to payments endpoints.
Single Immediate Payment
This section describes how to setup, execute, and monitor progress of a Single Immediate Payment.
A single immediate payment is a one time payment that requires the user to authorise the payment with their bank.
Single Immediate Payments Providers Endpoint
Request
https://pay-api.truelayer.com/v2/single-immediate-payments-providers?client_id=myclient-123456&auth_flow_type=redirect,embedded&account_type=sort_code_account_number,iban&additional_input_type=text,select¤cy=GBP,EUR
Response
{
"results": [
{
"provider_id": "ob-example",
"logo_url": "https://truelayer-client-logos.s3-eu-west-1.amazonaws.com/banks/ob-example.svg",
"icon_url": "https://truelayer-client-logos.s3-eu-west-1.amazonaws.com/banks/banks-icons/ob-example-icon.svg",
"display_name": "Example OB Bank",
"country": "GB",
"divisions": [ "retail", "business" ],
"single_immediate_payment_schemes": [
{
"scheme_id": "faster_payments_service",
"requirements": [
{
"auth_flow": {
"types": [ "redirect" ],
"redirect": {
"data_access_token_supported": true
}
},
"single_immediate_payment": {
"currency": {
"supported_currencies": [ "GBP" ]
},
"beneficiary": {
"account": {
"types": [ "sort_code_account_number" ],
},
"name": {
"mandatory": true,
"min_length": 1,
"max_length": 20,
"regex": "[\\w\\d ]{1,20}",
"format": "any"
}
},
"remitter": {
"mandatory": false,
"account": {
"types": [ "sort_code_account_number" ],
},
"name": {
"mandatory": false,
"min_length": 1,
"max_length": 20,
"regex": "[\\w\\d ]{1,20}",
"format": "any"
}
},
"references": {
"types": [ "single", "separate" ],
"single": {
"min_length": 1,
"max_length": 20,
"regex": "[\\w\\d \\.-]{1,20}",
"format": "any"
},
"separate": {
"beneficiary": {
"min_length": 1,
"max_length": 20,
"regex": "[\\w\\d \\.-]{1,20}",
"format": "any"
},
"remitter": {
"min_length": 1,
"max_length": 20,
"regex": "[\\w\\d \\.-]{1,20}",
"format": "any"
}
}
}
}
}
]
}
],
"release_stage": "live"
},
{
"provider_id": "eur-example",
"logo_url": "https://truelayer-client-logos.s3-eu-west-1.amazonaws.com/banks/eur-example.svg",
"icon_url": "https://truelayer-client-logos.s3-eu-west-1.amazonaws.com/banks/banks-icons/eur-example-icon.svg",
"display_name": "Example EUR Bank",
"country": "DE",
"divisions": [ "retail" ],
"single_immediate_payment_schemes": [
{
"scheme_id": "sepa_credit_transfer_instant",
"fee_options": [
{
"fee_option_id": "remitter_payable",
"beneficiary_fee": "free",
"remitter_fee": "payable"
},
{
"fee_option_id": "beneficiary_payable",
"beneficiary_fee": "payable",
"remitter_fee": "free"
}
],
"requirements": [
{
"auth_flow": {
"types": [ "embedded" ],
"embedded": {
"additional_input_types": [ "text" ],
"additional_inputs": {
"some-upfront-input": {
"type": "select",
"mandatory": true,
"options": [
{
"id": "option-a",
"display_text": "First Option"
},
{
"id": "option-b",
"display_text": "Second Option"
}
]
}
}
}
},
"single_immediate_payment": {
"currency": {
"supported_currencies": [ "EUR" ]
},
"beneficiary": {
"account": {
"types": [ "iban" ],
},
"name": {
"mandatory": true,
"min_length": 1,
"max_length": 20,
"regex": "[\\w\\d ]{1,20}",
"format": "any"
}
},
"remitter": {
"mandatory": true,
"account": {
"types": [ "iban" ],
},
"name": {
"mandatory": false,
"min_length": 1,
"max_length": 20,
"regex": "[\\w\\d ]{1,20}",
"format": "any"
}
},
"references": {
"types": [ "single" ],
"single": {
"min_length": 1,
"max_length": 20,
"regex": "[\\w\\d \\.-]{1,20}",
"format": "any"
}
}
}
}
]
}
],
"release_stage": "live"
}
]
}
The providers endpoint serves three purposes:
- Tells you which banks are currently active (when a bank is temporarily unavailable, we hide them from this list until its service is restored).
- Gives you the assets to build out a selection screen e.g. logos and display names.
- Tells you the available schemes, auth flows, and input requirements for each provider.
To retrieve providers whose requirements you support, you must filter using the following query parameters:
Field | Available Values | Mandatory | Description |
---|---|---|---|
client_id |
Your client ID | Mandatory | Required for verifying access to providers. |
auth_flow_type |
redirect embedded |
Mandatory | Will only return providers with schemes that support the listed auth flows. |
account_type |
sort_code_account_number iban bban nrb |
Mandatory | Will only return providers with schemes that support the listed account identifiers. |
currency |
ISO 4217 currency codes e.g. GBP,EUR |
Mandatory | Will only return providers with schemes that support the listed currencies. |
country |
ISO 3166-1 alpha-2 country codes e.g. GB,FR |
Optional | Will only return providers from the listed countries. |
additional_input_type |
text select text_with_image |
Optional | Will filter out any provider schemes that require additional_inputs field types not specified (including any on subsequent inputs as part of the embedded flow). If omitted, will only return provider schemes that have no required additional inputs. |
release_channel |
live public_beta private_beta |
Optional | Will filter out any providers that are not on the specified release channel (public_beta also includes all those in live , and private_beta also includes all those in public_beta ). If omitted, will only return providers that are generally available (equivalent to live ). |
Each bank available will have the following fields:
Field | Type | Description |
---|---|---|
provider_id |
string |
This is the provider ID that you will send us in the create payment request. |
logo_url |
string |
This is the address of the logo asset in SVG form. |
icon_url |
string |
This is the address of the icon asset in SVG form. |
display_name |
string |
This is a readable name for the provider. |
country |
string |
The ISO 3166-1 alpha-2 country code for the provider. |
divisions |
string[] |
This array includes all divisions that are available on this provider, e.g. retail and business would indicate you can use this single provider to access both retail and business accounts. |
single_immediate_payment_schemes |
SingleImmediatePaymentScheme[] |
The array lists the available schemes the provider can use, within each is described the requirements for the fields on the Single Immediate Payment initiation request. |
release_stage |
string |
This indicates the product maturity of the provider. live and public_beta providers are visible to everyone, while private_beta providers must be enabled for the client_id provided in the query parameters to be visible. Values: live , public_beta , private_beta . |
We recommend you query this endpoint every time you make a payment to ensure that you are always accessing the latest providers information. We are constantly working towards improving your experience with us by removing banks that are not currently available, adding banks as we expand our coverage, and updating banks’ requirements.
SingleImmediatePaymentScheme
Field | Type | Description |
---|---|---|
scheme_id |
string |
A unique identifier for the scheme, shared across providers. This should be provided on the single_immediate_payment.scheme_id field on the initiation request. |
fee_options (optional) |
FeeOption[] |
If present, then fees are payable to make a payment on the scheme, and you must choose an option in this list when initiating a payment. |
requirements |
SingleImmediatePaymentRequirements[] |
Contains at least one set of requirements, one of which should be adhered to in order to create a valid initiation request for the scheme. |
FeeOption
Field | Type | Description |
---|---|---|
fee_option_id |
string |
A unique identifier for the fee option, shared across providers. This should be provided on the single_immediate_payment.fee_option_id field on the initiation request. |
beneficiary_fee |
string |
A value to indicate if the beneficiary would pay any fees on the transaction, when using this fee option. Values: free , payable , unknown |
remitter_fee |
string |
A value to indicate if the remitter would pay any fees on the transaction, when using this fee option. Values: free , payable , unknown |
SingleImmediatePaymentRequirements
Each property in the requirements object corresponds to an identically named property on the initiation request for a Single Immediate Payment. The following sections detail the requirement types and how they should be interpreted in order to build a valid initiation request.
Field | Child Field | Type | Description |
---|---|---|---|
auth_flow |
- | AuthFlowRequirements |
Which auth flows are supported and what fields are required/available to initiate a payment for those flows. |
single_immediate_payment |
currency |
CurrencyRequirements |
Which currencies are supported. |
single_immediate_payment |
beneficiary |
ParticipantRequirements |
Which beneficiary details are required/supported. |
single_immediate_payment |
remitter (optional) |
ParticipantRequirements |
Which remitter details are required/supported. If omitted, the scheme does not support receiving remitter details. |
single_immediate_payment |
references |
ReferenceRequirements |
Which reference types are required/supported. |
AuthFlowRequirements
Field | Type | Description |
---|---|---|
types |
string[] |
A list of supported auth flow types. Values: redirect ,embedded . |
redirect (optional) |
RedirectAuthFlowRequirements |
Will be set if redirect is supported. |
embedded (optional) |
EmbeddedAuthFlowRequirements |
Will be set if embedded is supported. |
RedirectAuthFlowRequirements
Field | Type | Description |
---|---|---|
psu_ip_address_required (optional) |
boolean | Indicates if auth_flow.psu_ip_address is required on the initiation request. |
data_access_token_supported (optional) |
boolean | Indicates if auth_flow.data_access_token can be provided on the initiation request, to maintain long lived consents across products (Data API and Payment API), where the provider only allows a single active consent across both AIS and PIS services. |
additional_inputs (optional) |
AdditionalInputs |
An optional dictionary of ID to additional inputs that must be collected from the end user to initiate a payment. These inputs should be provided using the same IDs in the auth_flow.additional_inputs string dictionary on the initiation request. |
EmbeddedAuthFlowRequirements
Field | Type | Description |
---|---|---|
additional_input_types |
string[] |
A list of additional input field types that may be returned during the embedded authorisation flow (not inclusive of those required on initiation below). Values: text , text_with_image , select . |
additional_inputs (optional) |
AdditionalInputs |
An optional dictionary of ID to additional inputs that must be collected from the end user to initiate a payment. These inputs should be provided using the same IDs in the auth_flow.additional_inputs string dictionary on the initiation request. |
CurrencyRequirements
Field | Type | Description |
---|---|---|
supported_currencies |
string[] |
A list of ISO 4217 currency codes supported by the provider scheme. |
ParticipantRequirements
Field | Child Field | Type | Description |
---|---|---|---|
account |
types |
string[] |
A list of account types supported by the scheme. Values: sort_code_account_number , iban , bban , nrb . |
name (optional) |
- | StringFieldRequirements |
An object detailing the requirements for the name, if omitted then setting the name on the initiation request is not supported for this scheme. |
mandatory |
- | bool | If a remitter is required. Not present on beneficiary as that is always mandatory. |
ReferenceRequirements
Field | Child Field | Type | Description |
---|---|---|---|
types |
- | string[] |
A list of supported reference types. Values: single ,separate |
single (optional) |
- | StringFieldRequirements |
Will be set if single is supported. Specifies the requirements for a single reference string for the payment. |
separate (optional) |
beneficiary |
StringFieldRequirements |
Will be set if separate is supported. Specifies the requirements for the beneficiary reference string for the payment. |
separate (optional) |
remitter |
StringFieldRequirements |
Will be set if separate is supported. Specifies the requirements for the remitter reference string for the payment. |
StringFieldRequirements
Field | Type | Requirement Description |
---|---|---|
mandatory |
boolean |
The corresponding field on the request is mandatory. |
min_length |
integer |
The corresponding field on the request must be at least this many characters. |
max_length |
integer |
The corresponding field on the request must be at most this many characters. |
regex |
string |
The corresponding field on the request must match the regular expression. |
format |
string |
A well known format to help you communicate to your client how the field will be validated. Values: any , numerical , alphabetical , alphanumerical , email |
AdditionalInputs
The additional_inputs
object on responses is a dictionary of input IDs to an object describing the input required. The structure of the input object differs based on the type
property, and can be one of the following:
Input Type | Description | Corresponding Request Value |
---|---|---|
text |
Requires the end user to enter a string value | The string value the end user entered |
text_with_image |
Displays an image to the end user and requires them to enter a string value | The string value the end user entered |
select |
Provides a list of options for the end user to select from | The id of the selected option |
Text Input
Additional Inputs Requirement (Text)
{
"some_input_id": {
"type": "text",
"display_text": "Some display text in English",
"provider_description": "A message from the bank",
"mandatory": true,
"sensitive": false,
"min_length": 5,
"max_length": 15,
"regex": "^[a-z ]{5,15}$",
"format": "alphabetical"
}
}
Additional Inputs Request Example (Text)
{
"some_input_id": "entered value"
}
Field | Type | Description |
---|---|---|
type |
string |
Value indicating the field type: text |
display_text |
string |
Text to describe what the field is asking for (English) |
provider_description (optional) |
string |
Text directly from the bank relating to the field |
mandatory |
boolean |
If the input must be provided |
sensitive |
boolean |
If the input is sensitive (should be masked in UI) |
min_length |
integer |
The minimum length of the input text |
max_length |
integer |
The maximum length of the input text |
regex |
string |
A regular expression the input text must match |
format |
string |
A well known format, to facilitate being able to show useful prompts to the user. Values: any , numerical , alphabetical , alphanumerical , email |
Text With Image Input
Additional Inputs Requirement (Text with Image)
{
"some_input_id": {
"type": "text_with_image",
"display_text": "Some display text in English",
"provider_description": "A message from the bank",
"mandatory": true,
"sensitive": false,
"min_length": 5,
"max_length": 15,
"regex": "^[a-z ]{5,15}$",
"format": "alphabetical",
"image": {
"type": "base64",
"base64": {
"data":
"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8vlr6PwAHHAK+MKsa+gAAAABJRU5ErkJggg==",
"media_type": "image/png"
}
}
}
}
Additional Inputs Request Example (Text with Image)
{
"some_input_id": "entered value"
}
Field | Type | Description |
---|---|---|
type |
string |
Value indicating the field type: text_with_image |
display_text |
string |
Text to describe what the field is asking for (English) |
provider_description (optional) |
string |
Text directly from the bank relating to the field |
mandatory |
boolean |
If the input must be provided |
sensitive |
boolean |
If the input is sensitive (should be masked in UI) |
min_length |
integer |
The minimum length of the input text |
max_length |
integer |
The maximum length of the input text |
regex |
string |
A regular expression the input text must match |
format |
string |
A well known format, to facilitate being able to show useful prompts to the user. Values: any , numerical , alphabetical , alphanumerical , email |
image |
object |
An image to display to the end user (e.g. QR code). The image object can be of two types, base64 or uri .If type is base64 , there will be a base64 property containing the base64 data and media_type .If type is uri , there will be a uri property with a URI to a hosted copy of the image. |
Select Input
Additional Inputs Requirement (Select)
{
"some_input_id": {
"type": "select",
"display_text": "Some display text in English",
"provider_description": "A message from the bank",
"mandatory": true,
"options": [
{
"id": "option-a",
"display_text": "First Option"
},
{
"id": "option-b",
"display_text": "Second Option"
}
]
}
}
Additional Inputs Request Example (Select)
{
"some_input_id": "option-b"
}
Field | Type | Description |
---|---|---|
type |
string |
Value indicating the field type: select |
display_text |
string |
Text to describe what the field is asking for (English) |
provider_description (optional) |
string |
Text directly from the bank relating to the field |
mandatory |
boolean |
If the input must be provided |
options |
SelectOption[] |
A list of id -display_text pairs to present to the end user as options (e.g. a drop down). |
SelectOption
Field | Type | Description |
---|---|---|
id |
string |
Value to be provided on the initiation request, if the option is selected |
display_text |
string |
Text to describe the option |
Creating a payment initiation request
Request
curl -X POST \
-H "Authorization: Bearer ${access_token}" \
--data '{
"single_immediate_payment": {
"single_immediate_payment_id": "dcc3e785-76d3-415c-8bd7-553f17f49c4a",
"provider_id": "eg-provider",
"scheme_id": "payment_scheme",
"fee_option_id": "split_fee",
"amount_in_minor": 120000,
"currency": "GBP",
"beneficiary": {
"account": {
"type": "sort_code_account_number",
"sort_code": "234567",
"account_number": "23456789"
},
"name": "Financial Services Ltd",
},
"remitter": {
"account": {
"type": "sort_code_account_number",
"sort_code": "987654",
"account_number": "98765432"
},
"name": "Mike Smith"
},
"references": {
"type": "separate",
"beneficiary": "FinServ-1a2b3c4d",
"remitter": "FS-1000001",
}
},
"auth_flow": {
"type": "redirect",
"return_uri": "https://client.app.com/payment_return"
}
}' \
https://pay-api.truelayer.com/v2/single-immediate-payment-initiation-requests
Response
{
"result": {
"single_immediate_payment": {
"single_immediate_payment_id": "dcc3e785-76d3-415c-8bd7-553f17f49c4a",
"status": "initiated",
"initiated_at": "2020-10-13T10:01:23.381Z",
"provider_id": "eg-provider",
"scheme_id": "payment_scheme",
"fee_option_id": "split_fee",
"amount_in_minor": 120000,
"currency": "GBP",
"beneficiary": {
"account": {
"type": "sort_code_account_number",
"sort_code": "234567",
"account_number": "23456789"
},
"name": "Financial Services Ltd"
},
"remitter": {
"account": {
"type": "sort_code_account_number",
"sort_code": "987654",
"account_number": "98765432"
},
"name": "Mike Smith"
},
"references": {
"type": "separate",
"beneficiary": "FinServ-1a2b3c4d",
"remitter": "FS-1000001"
}
},
"auth_flow": {
"type": "redirect",
"uri": "https://www.eg-provider.com/authorize?token=0f9e8d7c",
"expiry": "2020-11-03T23:00:00.000Z"
}
}
}
The initiation request includes the following fields:
Field | Type | Mandatory | Description |
---|---|---|---|
single_immediate_payment |
SingleImmediatePaymentRequestDetails |
Mandatory | Specifies the details of the payment to be created. See the SingleImmediatePaymentRequestDetails section below. |
auth_flow |
AuthFlowRequestDetails |
Mandatory | Specifies how the payment should be authorised. See the AuthFlowRequestDetails section below. |
webhook_uri |
string |
Optional | An address to which payment webhooks with the status of the payment should be sent. Has to be https. |
SingleImmediatePaymentRequestDetails
Field | Type | Mandatory | Description |
---|---|---|---|
single_immediate_payment_id |
uuid |
Mandatory | The unique id of the payment you want to create. If two requests are received with the same id, only the first one will be processed. |
amount_in_minor |
number |
Mandatory | The amount, specified in terms of the fractional monetary unit of the payment currency, to be paid. |
currency |
string |
Mandatory | The ISO 4217 code of the currency for the payment. |
provider_id |
string |
Mandatory | The id of the provider, as given on our /providers endpoint. |
scheme_id |
string |
Mandatory | The id of the scheme to make the payment over. This must be one of the schemes advertised by the provider on the /v2/single-immediate-payments-providers endpoint. |
fee_option_id |
string |
Conditional | The id indicating the desired distribution of fees between the beneficiary and remitter. Must be a fee_option_id from one of the options advertised under that scheme on the /v2/single-immediate-payments-providers endpoint. Should be omitted if there are no fee options (the scheme is free). |
beneficiary |
ParticipantDetails |
Mandatory | The details of the beneficiary receiving the payment. See the ParticipantDetails section below. |
remitter |
ParticipantDetails |
Conditional | The details of the remitter sending the payment. See the ParticipantDetails section below. |
references |
ReferencesDetails |
Mandatory | The details of the reference, or references, for the payment. See the ReferencesDetails section below. |
ParticipantDetails
Field | Type | Mandatory | Description |
---|---|---|---|
account |
AccountIdentifierDetails |
Mandatory | The details of the account owned by the participant. |
name |
string |
Conditional | The name on the participant’s account. |
AccountIdentifierDetails
Field | Type | Mandatory | Description |
---|---|---|---|
type |
string |
Mandatory | The type of account. Must be one of sort_code_account_number , iban , bban , or nrb . Please refer to our providers endpoint for details of what account types are supported by each provider. |
sort_code |
string |
Mandatory if type is sort_code_account_number . Invalid otherwise. |
6 digit sort code (no spaces or dashes). |
account_number |
string |
Mandatory if type is sort_code_account_number . Invalid otherwise. |
8 digit account number. |
iban |
string |
Mandatory if type is iban . Invalid otherwise. |
Valid International Bank Account Number (no spaces). Consists of a 2 letter country code, followed by 2 check digits, and then by up to 30 alphanumeric characters (also known as the BBAN). |
bban |
string |
Mandatory if type is bban . Invalid otherwise. |
Valid Basic Bank Account Number (no spaces). Consists of up to 30 alphanumeric characters, with a fixed length per country. Forms the latter part of the IBAN as described above. |
nrb |
string |
Mandatory if type is nrb . Invalid otherwise. |
Valid Polish NRB (no spaces). Consists of 2 check digits, followed by an 8 digit bank branch number, and then by a 16 digit bank account number. Equivalent to a Polish IBAN with the country code removed. |
ReferencesDetails
Field | Type | Mandatory | Description |
---|---|---|---|
type |
string |
Mandatory | The type of references. Must be one of single or separate , depending on whether the provider supports distinct references for the beneficiary and remitter. Please refer to our providers endpoint for details of whether a provider supports a single reference or separate references. |
reference |
string |
Mandatory if type is single . Invalid otherwise. |
The reference to appear on the beneficiary’s and remitter’s statements. |
beneficiary |
string |
Mandatory if type is separate . Invalid otherwise. |
The reference to appear on the beneficiary’s statement. |
remitter |
string |
Mandatory if type is separate . Invalid otherwise. |
The reference to appear on the remitter’s statement. |
AuthFlowRequestDetails
Field | Type | Mandatory | Description |
---|---|---|---|
type |
string |
Mandatory | The type of authorisation flow. Must be redirect or embedded . Providers requiring additional authorisation flows may be available in future. |
return_uri |
string |
Mandatory if type is redirect . Invalid otherwise. |
The URI we will return the user to after authorising the payment. When the user is redirected to this URI, we will append a single_immediate_payment_id query parameter specifying the payment id and a type query parameter with value single_immediate_payment . |
psu_ip_address |
string |
Conditional if type is redirect . Invalid otherwise. |
The IP address of the end user. |
data_access_token |
string |
Optional if type is redirect . Invalid otherwise. |
If the provider only allows a single active consent across both AIS and PIS services, in order to prevent invalidating an existing AIS consent, you can pass the data access token on this field, and we will preserve the data consent when requesting authorisation for the payment. |
additional_inputs |
dictionary<string, string> |
Conditional | A dictionary of additional values required on a per-provider basis. Please refer to our providers endpoint for details of the providers that require these. |
Handling the initiation request response
The response from the /single-immediate-payment-initiation-requests
endpoint, shown above, returns the following fields:
Field | Type | Description |
---|---|---|
single_immediate_payment |
SingleImmediatePaymentResponseDetails |
Contains the details of the payment. This is a superset of the SingleImmediatePaymentRequestDetails object. See the SingleImmediatePaymentResponseDetails section below. Note this is the same object as that which will be returned on the GET /v2/single-immediate-payments/{id} endpoint. |
auth_flow |
AuthFlowResponseDetails |
This provides information on how to have the end user authorise the payment, and will differ in structure based on the authorisation flow. See the AuthFlowResponseDetails section below. |
SingleImmediatePaymentResponseDetails
This contains the following fields in addition to those listed in the SingleImmediatePaymentRequestDetails
section:
Field | Type | Description |
---|---|---|
initiated_at |
string |
The time the payment was initiated, in UTC formatted as an ISO 8601 string (YYYY-MM-DDThh:mm:ss.sssZ ). |
status |
string |
The status of the payment. For newly initiated payments, this will be initiated . |
AuthFlowResponseDetails
Redirect Authorisation
Redirect auth_flow response object
{
"type": "redirect",
"uri": "https://example.com",
"expiry": "2020-11-03T23:00:00.000Z"
}
If the provider uses a redirect
authorisation flow, the auth_flow
object on the response will have the following fields:
Field | Type | Description |
---|---|---|
type |
string |
Value indicating this is a redirect authorisation flow: redirect |
uri |
string |
The URI for the end user to authorise the payment in the bank’s UI. |
expiry (optional) |
string |
An expiry time, if one is known, after which the URI to authorise the payment will become invalid. In UTC, formatted as an ISO 8601 string (YYYY-MM-DDThh:mm:ss.sssZ ). |
After creating the payment, you will need to redirect the user to the authorisation page specified by uri
.
Embedded Authorisation
Embedded auth_flow response object
{
"type": "embedded",
"step": {
"type": "additional_inputs",
"step_id": "STEP_1",
"additional_inputs": {
"some-additional-input": {
"type": "select",
"display_text": "Choose an option",
"mandatory": true,
"options": [
{
"id": "option-a",
"display_text": "First Option"
},
{
"id": "option-b",
"display_text": "Second Option"
}
]
}
}
}
}
If the provider uses an embedded
authorisation flow, the auth_flow
object on the response will have the following fields:
Field | Type | Description |
---|---|---|
type |
string |
Value indicating this is a embedded authorisation flow: embedded |
step |
EmbeddedAuthStep |
An object describing the next step in the authorisation flow. See the EmbeddedAuthStep section below. |
EmbeddedAuthStep
The step
object can have a different structure depending on the type
field.
If the type
is additional_inputs
, then more inputs need to be collected from the end user in order to authorise the payment, and the step
object will have the following fields:
Field | Type | Description |
---|---|---|
type |
string |
Value indicating further inputs required: additional_inputs |
step_id |
string |
The step id, needed to submit additional inputs. |
additional_inputs |
AdditionalInputs |
The additional required inputs in the structure defined in the AdditionalInputs section in the providers endpoint description above. |
You should use the additional_inputs
description to build a UI to collect the inputs from your user, and submit them to our Embedded Auth Step Submission API, detailed below, in order to authorise the payment.
If the type
is completed
, then there is no more input required from the end user, and the step
object will have the following fields:
Field | Type | Description |
---|---|---|
type |
string |
Value indicating no more steps: completed |
outcome |
string |
The result of the authorisation. Values: psu_cancelled , provider_rejected , authorised |
In the completed
case, no further inputs are required from the user, and you should begin polling for status changes, or wait for updates from webhooks.
Submitting embedded authorisation steps
Embedded Auth Steps Submission Request
curl -X PUT \
-H "Authorization: Bearer ${access_token}" \
--data '{
"type": "additional_inputs",
"additional_inputs": {
"some-additional-input": "option-a"
}
}' \
https://pay-api.truelayer.com/v2/single-immediate-payments/44708581-1967-4120-8f6a-1e532f1bf52a/embedded-auth-steps/STEP_1/submission
Embedded Auth Steps Cancel Request
curl -X PUT \
-H "Authorization: Bearer ${access_token}" \
--data '{
"type": "cancel"
}' \
https://pay-api.truelayer.com/v2/single-immediate-payments/44708581-1967-4120-8f6a-1e532f1bf52a/embedded-auth-steps/STEP_1/submission
Further Inputs Response
{
"result": {
"step": {
"type": "additional_inputs",
"step_id": "STEP_2",
"additional_inputs": {
"otp": {
"type": "text",
"mandatory": true,
"sensitive": true,
"min_length": 6,
"max_length": 6,
"regex": "^\\d{6}$",
"format": "numerical"
}
}
}
}
}
Completed Response
{
"result": {
"step": {
"type": "completed",
"outcome": "authorised"
}
}
}
After presenting the additional inputs to the end user in your UI, you need to submit what they enter to the embedded_auth_steps/<step_id>/submission
API, as an additional_inputs
dictionary, using the same structure as the payment initiation request.
The response returns the same step structure as the payment initiation response auth_flow.step
object, with either additional_inputs
or completed
step types - See the EmbeddedAuthStep
section above.
You should keep submitting the end user’s additional inputs, whilst more are returned, until you receive a completed
step type.
Handling error responses
Example
400
response
{
"error": "parameter_error",
"error_description": "Invalid parameters",
"error_details": {
"parameters": {
"single_immediate_payment.single_immediate_payment_id": [
"Value is required"
],
"single_immediate_payment.beneficiary.account.type": [
"Unknown value. Valid values are 'sort_code_account_number', 'iban', 'bban', 'nrb'"
]
}
}
}
Example
500
response
{
"error_description": "An error occurred. Please contact customer support."
}
Example
502
response
{
"error_description": "An error occurred while trying to contact the provider. Please try again later or contact customer support."
}
Our API may respond 4xx
/5xx
status codes to indicate an error handling the request. In particular, we may return:
Http Status | Description |
---|---|
400 |
The request is not valid and will not succeed without modification. The error_details property in the response should assist in diagnosing the reason(s) for the failure. |
403 |
Your client id is not allowed to access the resource. The most likely reason for this is because your client id is not enlisted in the private beta for these endpoints. Please contact customer support if you are interested in participating in the private beta. |
404 |
The requested resource is not found or not accessible to your client id. |
500 |
An issue occurred inside TrueLayer in handling the request. The request may succeed on retry. Please contact customer support if the issue persists. |
502 |
The provider associated with the request was unavailable at the time of the request. The request may succeed on retry. Please contact customer support if the issue persists. |
Managing payment status with webhooks
Status Changed Event
X-TL-Signature: "a JWS token"
{
"event_type": "single_immediate_payment_status_changed",
"event_body": {
"single_immediate_payment_id": "77a75df0-af60-4785-8e91-809ac77ca8e3",
"status": "executed"
}
}
When the status of a payment changes, we send a single_immediate_payment_status_changed
event to the webhook_uri
specified when creating the payment initiation request.
When TrueLayer send a webhook to the specified webhook_uri
, we will include a X-TL-Signature
header, containing a signature in the form of a JWS token that you can use to validate that the request came from us. Instructions for validating this signature can be found below.
In the body you will see the following fields:
Field | Type | Description |
---|---|---|
event_type |
string | describing which event is detailed. In this case the event will be single_immediate_payment_status_changed |
event_body |
object | containing both the single_immediate_payment_id as a string and the status as a string |
To see all the available payment statuses, read the section below on polling for status where we list what states your payment can exist in.
Webhook Retry Policy
We consider a webhook as having been successfully delivered when we receive a success status code (2xx) from your webhook URI.
If we receive any other status code (e.g. your API is temporarily unavailable), we will start retrying.
Our retry policy is jittered exponential backoff: we will immediately perform some fast retries and then start waiting increasingly longer; we will keep retrying until 24 hours has passed since the first attempt.
Validating the webhook signature
The value of the X-TL-Signature
header contains a JSON Web Signature (JWS) with a detached payload. It takes the form {HEADER}..{SIGNATURE}
.
The JWS header contains the following values:
Field | Type | Description |
---|---|---|
alg |
string | The algorithm used to sign the webhook. We currently use the RS256 algorithm. |
jku |
string | The URI of the JSON Web Key Set (JWKS), a hosted page where a list of public keys owned by TrueLayer can be found. |
kid |
string | The ID of the key used to sign the webhook, used to retrieve the correct key from the JWKS. |
iat |
int | The time that the JWS was issued, represented in Unix time (number of seconds since 1970-01-01T00:00:00Z). |
The steps for verifying the signature are as follows:
- Verify the
jku
field in the token header matches the expected value (below). If not, the signature should be rejected as invalid.- Sandbox:
https://pay-api.truelayer-sandbox.com/.well-known/jwks.json
- Production:
https://pay-api.truelayer.com/.well-known/jwks.json
- Sandbox:
- Use the
jku
value to retrieve the JWKS. This may be cached for some time, but if verification fails the JWKS must be re-retrieved to ensure that all keys are up to date. Keys may be rotated or revoked at any time by TrueLayer. - Retrieve the relevant public key by using the
kid
to look up the relevant value from the JWKS. - Use a JWT library to verify the JWS headers combined with the payload (the webhook request body) matches the signature provided in the token. The algorithm used to verify the signature must be that declared in the
alg
header of the JWS.
Code samples for signature validation can be found here.
Polling for payment status
Request
curl -H "Authorization: Bearer ${access_token}" \
https://pay-api.truelayer.com/v2/single-immediate-payments/dcc3e785-76d3-415c-8bd7-553f17f49c4a
Response
{
"result": {
"single_immediate_payment_id": "dcc3e785-76d3-415c-8bd7-553f17f49c4a",
"status": "initiated",
"initiated_at": "2020-10-13T10:01:23.381Z",
"amount_in_minor": 120000,
"currency": "GBP",
"provider_id": "eg-provider",
"scheme_id": "payment_scheme",
"fee_option_id": "split_fee",
"beneficiary": {
"account": {
"type": "sort_code_account_number",
"sort_code": "234567",
"account_number": "23456789"
},
"name": "Financial Services Ltd"
},
"remitter": {
"account": {
"type": "sort_code_account_number",
"sort_code": "987654",
"account_number": "98765432"
},
"name": "Mike Smith"
},
"references": {
"type": "separate",
"beneficiary": "FinServ-1a2b3c4d",
"remitter": "FS-1000001"
}
}
}
The application can poll the payment resource to see if the status has been modified. This allows the application to know if the payment was successful or not.
Note that if the remitter was specified, remitter details will also be included in the response.
The payment resource may exist in different states according to the progress of the transaction:
Status | Terminal? | Description |
---|---|---|
initiated |
- | The payment resource has been created, but the payer has not yet authorised the payment. The initial API response will always have this status if the API call is successful. |
cancelled |
Terminal | The payer has cancelled the payment using the bank portal. This may also happen for some bank UIs if the payer clicks the “Back” button in their browser |
authorisation_failed |
Terminal | The payer attempted to authorise the payment with the bank, but failed to do so successfully |
executing |
- | The payer has successfully authorised the payment using the bank portal, but the payment has not yet executed. |
rejected |
Terminal | The payer authorised the payment, but the bank rejected it after this. |
executed |
Terminal | The funds have left the remitter’s account and will arrive in the beneficiary’s account. This is a terminal state. |
expired |
Terminal | A payment was not authorised within the expiry of the initiation. This status will be coming soon! |
The executing
and executed
/rejected
states may be very close; in fact a bank may respond to the payment submission indicating the payment has already been executed. However, it is also possible for a payment to be queued within the bank for a short period of time; in that case, the payment status will initially be executing, and then may be updated to executed after polling for a status check.
The expired
status is not yet available and will be coming soon.
Note that after a payment has been executed, it may take some time for it to be settled, although for transactions executed via Faster Payments in the UK, this normally happens very quickly.
End User Payment Cancellation
Redirect Authorisation Flow
This diagram shows how payment cancellation by the end user works for payments using the redirect flow. When the end user cancels the payment, they cancel it on the bank’s UI.
Embedded Authorisation Flow
This diagram shows how payment cancellation by the end user works for payments using the embedded flow. When the end user cancels the payment, they cancel it on your application’s UI and that is sent to TrueLayer.
Testing Guidelines
The following guidelines aim to provide practical guidance while testing the integration.
Payments Sandbox
Before testing with live accounts, we recommend that you test your integration with the sandbox. The Payments Quick Start provides instructions on how to access the sandbox APIs.
When you transition to live testing in the production environment:
- Make sure you change all URIs to end with
truelayer.com
instead oftruelayer-sandbox.com
- Change from using your sandbox
client_id_
andclient_secret
to your productionclient_id
andclient_secret
. You can find your productionclient_id
here (you should have saved your productionclient_secret
when you last reset it, or when you created your production account) - Have a live bank account to hand which you own to make payments from, as well as one to make payments into. The payer (or remitter) bank account must be from one of the supported providers listed here
Bank Account Limits
Each bank has its own limits on how much money can be transferred using online banking, which also apply to their open banking payment APIs.
Rate Limits
All banks have controls in place to protect their end users from fraudulent withdrawals. One type of control is a rate limit, which allows only a certain number of payments, or a maximum aggregate payment amount, per time period, e.g. one hour, one day, etc.
Banks will not publish these limits, as the information could be taken advantage of by fraudsters. Therefore, when testing:
- Do not make an excessive number of payments from the same account within a short time period.
- If it is not possible to make a successful payment, this will be visible in the bank’s authorisation user interface. At this point, it will be necessary to contact the specific bank’s end user support team to get the account unblocked.
Mock Providers
The providers endpoint in the sandbox environment includes three mock providers which can be used for testing your integration with our API.
1. Mock UK Payments - Redirect Flow
Data returned from providers endpoint
{
"provider_id": "mock-payments-gb-redirect",
"logo_url": "",
"icon_url": "",
"display_name": "Mock UK Payments - Redirect Flow",
"country": "GB",
"divisions": [
"retail"
],
"single_immediate_payment_schemes": [
{
"scheme_id": "faster_payments_service",
"requirements": [
...
]
}
]
}
Mock UK Payments - Redirect Flow simulates UK banks that use the redirect authorisation flow.
When you initiate a payment using this provider, we will return a URI to redirect your user to our mock provider authorisation page.
On the authorisation prompt page, different actions lead to different outcome for the payment. The following table describes the different actions you can make on the authorisation page and their outcomes:
Outcome | Action | Username |
---|---|---|
Execute | Enter username | test_executed |
Auth failure | Enter username | test_authorisation_failed |
Execution Rejection | Enter username | test_execution_rejected |
Cancellation | Click cancel button | - |
Once you log in with one of the predetermined usernames, the mock provider will present the account selection page:
When you provide the remitter account details in the payment initiation request, only the stated account can be selected on this screen.
2. Mock European Payments – Redirect Flow
Data returned from providers endpoint
{
"provider_id": "mock-payments-es-redirect",
"logo_url": "",
"icon_url": "",
"display_name": "Mock European Payments – Redirect Flow",
"country": "ES",
"divisions": [
"retail"
],
"single_immediate_payment_schemes": [
{
"scheme_id": "sepa_credit_transfer",
"requirements": [
...
]
},
{
"scheme_id": "sepa_credit_transfer_instant",
"fee_options": [
{
"fee_option_id": "sepa_credit_transfer_instant_fee",
"beneficiary_fee": "free",
"remitter_fee": "payable"
}
],
"requirements": [
...
]
}
]
}
Mock European Payments – Redirect Flow represents the typical redirect authorisation flow used by a bank in Europe.
Even though the country code in the provider_id
is currently es
, the functionality can be assumed to be equivalent to the other redirect flow banks that can be found in the European region. Hence this bank can be used to test any redirect flow for the European banks.
When you initiate a payment using this provider, we will return a URI to redirect your user to our mock provider authorisation page.
Different actions on this page will lead to different outcomes for the payment. The following table describes the different actions you can make on the authorisation page and their outcomes:
Outcome | Action | Username |
---|---|---|
Execute | Enter username | test_executed |
Auth failure | Enter username | test_authorisation_failed |
Execution Rejection | Enter username | test_execution_rejected |
Cancellation | Click cancel button | - |
After you log in with one of the predetermined usernames for the test case, an account selection page will be the next step:
If you provide the remitter account details in the payment initiation request, you can only select the account with those details on this screen.
3. Mock European Payments – Embedded Flow
Data returned from providers endpoint
{
"provider_id": "mock-payments-de-embedded",
"logo_url": "",
"icon_url": "",
"display_name": "Mock European Payments – Embedded Flow",
"country": "DE",
"divisions": [
"retail"
],
"single_immediate_payment_schemes": [
{
"scheme_id": "sepa_credit_transfer",
"requirements": [
...
]
},
{
"scheme_id": "sepa_credit_transfer_instant",
"fee_options": [
{
"fee_option_id": "beneficiary_pays",
"beneficiary_fee": "payable",
"remitter_fee": "free"
},
{
"fee_option_id": "remitter_pays",
"beneficiary_fee": "free",
"remitter_fee": "payable"
}
],
"requirements": [
...
]
}
]
}
Mock European Payments – Embedded Flow provider represents European banks that use the embedded authorisation flow.
More information about the flows can be found in the common concepts section.
This mock provider only provides the embedded input flow and no UI elements. As can be seen in the providers response object, this bank requires the additional inputs psu-id and psu-password.
The expected value for psu-id is test_username
.
The expected value for psu-password is test_password
.
Anything other than these values will lead to rejection by the mock provider.
Once you initiate the payment with this mock provider will ask for SCA method with a select type input.
There are two value options.
- SMS
- PhotoTAN
Following the submission of the input value to this embedded step, you will be required to enter a text input (For PhotoTAN, our API will provide an image, however this image does not play any role in how the flow continues.)
Different values to this input will lead to different outcomes for the payment.
The input values required for certain outcomes are the same for SMS
and PhotoTAN
options.
The inputs and related outcomes can be seen in the following table:
Outcome | Input Value |
---|---|
Execute | test_executed |
Auth failure | test_authorisation_failed |
Execution Rejection | test_execution_rejected |
If you use any other value than what is presented in the table, it will result in authorisation failure.
To test the cancellation scenario, use the cancel embedded step instead.
v1 to v2 Migration Guide
Depending on your usage of the v1 single-immediate-payments
endpoint, you may be able to migrate to v2 to take advantage of any new features.
You can only migrate to v2 if you specify direct_bank_link
as true
on your v1 requests. i.e., you do not make any use of our provider selection, payment details, or handoff screens. The v2 single-immediate-payments endpoints do not currently support these use cases.
UK Single Immediate Payments Providers Requests
v1 UK Request URL
https://pay-api.truelayer.com/providers?capability=SingleImmediatePayment
v2 UK Request URL
https://pay-api.truelayer.com/v2/single-immediate-payments-providers?client_id=myclient-123456&auth_flow_type=redirect&account_type=sort_code_account_number¤cy=GBP&country=GB
To retrieve providers from the new v2 Single Immediate Payments Providers API, you must provide query parameters specifying what features you support. For UK providers available on v1, that is the equivalent of these filters:
Field | Value | Description |
---|---|---|
client_id |
Your client ID | Required for verifying access to providers. |
auth_flow_type |
redirect |
Will only return providers with schemes that support the redirect auth flow. |
account_type |
sort_code_account_number |
Will only return providers with schemes that support sort code with account numbers as account identifiers. |
currency |
GBP |
Will only return providers with schemes that support GBP payments. |
country |
GB |
Will only return providers from the UK. |
International Single Immediate Payments Providers Requests
v1 International Request URL
https://pay-api.truelayer.com/providers?capability=SingleImmediatePayment&countryCode=FR&clientId=myclient-123456
v2 International Request URL
https://pay-api.truelayer.com/v2/single-immediate-payments-providers?client_id=myclient-123456&auth_flow_type=redirect&account_type=iban¤cy=EUR&country=FR&additional_input_type=text,select
For international providers available on v1, that is the equivalent of these filters:
Field | Value | Description |
---|---|---|
client_id |
Your client ID | Required for verifying access to providers. |
auth_flow_type |
redirect |
Will only return providers with schemes that support the redirect auth flow. |
account_type |
iban |
Will only return providers with schemes that support IBANs as account identifiers. |
currency |
EUR |
Will only return providers with schemes that support EUR payments. |
country |
e.g. FR |
Will only return providers from e.g. France. |
additional_input_type |
text,select |
Will filter out any provider schemes that require additional_inputs field types not are not text or select . These correspond to the FreeInputField and SingleChoiceField auth inputs on the v1 providers API. |
Single Immediate Payments Providers Response
v1 Response
{
"results": [{
"id": "ob-example",
"logo": "https://the.website/path/to/logo.svg",
"icon": "https://the.website/path/to/icon.svg",
"displayable_name": "Example Provider",
"main_bg_color": "#000000",
"supports_app_to_app": false,
"country_code": "GB",
"divisions": [
"retail"
],
"steps": [
...
]
}]
}
v2 Response
{
"results": [{
"provider_id": "ob-example",
"logo_url": "https://the.website/path/to/logo.svg",
"icon_url": "https://the.website/path/to/icon.svg",
"display_name": "Example Provider",
"country": "GB",
"divisions": [
"retail"
],
"single_immediate_payment_schemes": [
{
"scheme_id": "faster_payments_service",
"requirements": [
{
"auth_flow": {
"types": ["redirect"],
"redirect": {
"additional_inputs": {
...
}
}
},
"single_immediate_payment": {
...
}
}
]
}
]
}]
}
The v2 response has a slightly different structure, along with a new schemes / requirements section.
v1 parameter | v2 parameter | Comment |
---|---|---|
id |
provider_id |
|
logo |
logo_url |
|
icon |
icon_url |
|
displayable_name |
display_name |
|
main_bg_color |
n/a | Not available on v2 |
supports_app_to_app |
n/a | Not available on v2 |
country_code |
country |
|
divisions |
divisions |
|
auth_inputs |
schemes[].requirements[].auth_flow.redirect.additional_inputs |
The inputs have a different structure documented above in the AdditionalInputs section. |
UK Single Immediate Payments Requests
v1 UK Request
curl -X POST \
-H "Authorization: Bearer ${access_token}" \
--data '{
"remitter_provider_id": "ob-provider",
"amount": 100,
"currency": "GBP",
"beneficiary_sort_code": "234567",
"beneficiary_account_number": "23456789"
"beneficiary_name": "Financial Services Ltd",
"remitter_sort_code": "987654",
"remitter_account_number": "98765432",
"remitter_name": "Mike Smith",
"beneficiary_reference": "FinServ-1a2b3c4d",
"remitter_reference": "FS-1000001",
"direct_bank_link": true,
"redirect_uri": "https://client.app.com/payment_return",
"webhook_uri": "https://client.app.com/simp/webhook"
}' \
https://pay-api.truelayer.com/single-immediate-payments
v2 UK Request
curl -X POST \
-H "Authorization: Bearer ${access_token}" \
--data '{
"single_immediate_payment": {
"single_immediate_payment_id": "4b794546-780c-4bab-854b-ee0728828d3e",
"provider_id": "ob-provider",
"scheme_id": "faster_payments_service",
"amount_in_minor": 100,
"currency": "GBP",
"beneficiary": {
"account": {
"type": "sort_code_account_number",
"sort_code": "234567",
"account_number": "23456789"
},
"name": "Financial Services Ltd"
},
"remitter": {
"account": {
"type": "sort_code_account_number",
"sort_code": "987654",
"account_number": "98765432"
},
"name": "Mike Smith"
},
"references": {
"type": "separate",
"beneficiary": "FinServ-1a2b3c4d",
"remitter": "FS-1000001"
}
},
"auth_flow": {
"type": "redirect",
"return_uri": "https://client.app.com/payment_return"
},
"webhook_uri": "https://client.app.com/simp/webhook"
}' \
https://pay-api.truelayer.com/v2/single-immediate-payment-initiation-requests
To adapt an existing integration of UK single immediate payments to use v2 of our single immediate payments API, map the following fields on your requests:
v1 parameter | v2 parameter | Comment |
---|---|---|
n/a | single_immediate_payment.single_immediate_payment_id |
v2 requires that a payment id is supplied on the initiation request |
remitter_provider_id |
single_immediate_payment.provider_id |
|
n/a | single_immediate_payment.scheme_id |
v2 requires the scheme to be specified, which is faster_payments_service in the UK |
amount |
single_immediate_payment.amount_in_minor |
|
currency |
single_immediate_payment.currency |
|
n/a | single_immediate_payment.beneficiary.account.type |
Set this to sort_code_account_number |
beneficiary_sort_code |
single_immediate_payment.beneficiary.account.sort_code |
|
beneficiary_account_number |
single_immediate_payment.beneficiary.account.account_number |
|
beneficiary_name |
single_immediate_payment.beneficiary.name |
|
n/a | single_immediate_payment.remitter.account.type |
If remitter account is specified, set this to sort_code_account_number |
remitter_sort_code |
single_immediate_payment.remitter.account.sort_code |
|
remitter_account_number |
single_immediate_payment.remitter.account.account_number |
|
remitter_name |
single_immediate_payment.remitter.name |
|
n/a | single_immediate_payment.references |
Set this to separate |
beneficiary_reference |
single_immediate_payment.references.beneficiary |
|
remitter_reference |
single_immediate_payment.references.remitter |
|
direct_bank_link |
n/a | Must be true in order to migrate to v2 |
n/a | auth_flow.type |
Set this to redirect |
redirect_uri |
auth_flow.return_uri |
|
webhook_uri |
webhook_uri |
Note, the new endpoint path is now /v2/single-immediate-payment-initiation-requests
.
International Single Immediate Payments Requests
v1 International Request
curl -X POST \
-H "Authorization: Bearer ${access_token}" \
--data '{
"remitter_provider_id": "stet-french-bank",
"amount": 100,
"currency": "EUR",
"beneficiary_iban": "FR2222222222222222222222B02",
"beneficiary_name": "Financial Services Ltd",
"remitter_iban": "FR1111111111111111111111A01",
"remitter_name": "Mike Smith",
"beneficiary_reference": "FinServ-1a2b3c4d",
"remitter_reference": "FS-1000001",
"direct_bank_link": true,
"redirect_uri": "https://client.app.com/payment_return",
"auth_inputs": {
"branch_id": "stet-french-bank-branch-4"
},
"webhook_uri": "https://client.app.com/simp/webhook"
}' \
https://pay-api.truelayer.com/single-immediate-payments
v2 International Request
curl -X POST \
-H "Authorization: Bearer ${access_token}" \
--data '{
"single_immediate_payment": {
"single_immediate_payment_id": "4b794546-780c-4bab-854b-ee0728828d3e",
"provider_id": "stet-french-bank",
"scheme_id": "sepa_credit_transfer_instant",
"amount_in_minor": 100,
"currency": "EUR",
"beneficiary": {
"account": {
"type": "iban",
"iban": "FR2222222222222222222222B02"
},
"name": "Financial Services Ltd"
},
"remitter": {
"account": {
"type": "iban",
"iban": "FR1111111111111111111111A01"
},
"name": "Mike Smith"
},
"references": {
"type": "separate",
"beneficiary": "FinServ-1a2b3c4d",
"remitter": "FS-1000001"
}
},
"auth_flow": {
"type": "redirect",
"return_uri": "https://client.app.com/payment_return",
"additional_inputs": {
"branch_id": "stet-french-bank-branch-4"
}
},
"webhook_uri": "https://client.app.com/simp/webhook"
}' \
https://pay-api.truelayer.com/v2/single-immediate-payment-initiation-requests
To adapt an existing integration of international single immediate payments to use v2 of our single immediate payments API, map the following fields on your requests:
v1 parameter | v2 parameter | Comment |
---|---|---|
n/a | single_immediate_payment.single_immediate_payment_id |
v2 requires that a payment id is supplied on the initiation request |
remitter_provider_id |
single_immediate_payment.provider_id |
|
n/a | single_immediate_payment.scheme_id |
v2 requires the scheme to be specified, which you should choose from those available on the v2 providers API |
n/a | single_immediate_payment.fee_option_id |
v2 requires a fee option to be specified, if fee options are listed on the scheme on the v2 providers API |
amount |
single_immediate_payment.amount_in_minor |
|
currency |
single_immediate_payment.currency |
|
n/a | single_immediate_payment.beneficiary.account.type |
Set this to iban |
beneficiary_iban |
single_immediate_payment.beneficiary.account.iban |
|
beneficiary_name |
single_immediate_payment.beneficiary.name |
|
n/a | single_immediate_payment.remitter.account.type |
If remitter account is specified, set this to iban |
remitter_iban |
single_immediate_payment.remitter.account.iban |
|
remitter_name |
single_immediate_payment.remitter.name |
|
n/a | single_immediate_payment.references |
Set this to separate |
beneficiary_reference |
single_immediate_payment.references.beneficiary |
|
remitter_reference |
single_immediate_payment.references.remitter |
|
direct_bank_link |
n/a | Must be true in order to migrate to v2 |
n/a | auth_flow.type |
Set this to redirect |
redirect_uri |
auth_flow.return_uri |
|
auth_inputs |
auth_flow.additional_inputs |
|
webhook_uri |
webhook_uri |
Note, the new endpoint path is now /v2/single-immediate-payment-initiation-requests
.
Single Immediate Payments Response
v1 Response
{
"results": [{
"simp_id": "4b794546-780c-4bab-854b-ee0728828d3e",
"auth_uri": "https://bank.com/auth-uri",
"status": "new",
"created_at": "2020-01-01T12:00:00.0000000+00:00",
"remitter_provider_id": "ob-provider",
"amount": 100,
"currency": "GBP",
"beneficiary_name": "Financial Services Ltd",
"beneficiary_sort_code": "234567",
"beneficiary_account_number": "23456789",
"remitter_name": "Mike Smith",
"remitter_sort_code": "987654",
"remitter_account_number": "98765432",
"beneficiary_reference": "FinServ-1a2b3c4d",
"remitter_reference": "FS-1000001",
"redirect_uri": "https://client.app.com/payment_return",
"webhook_uri": "https://client.app.com/simp/webhook"
}],
"status": "succeeded"
}
v2 Response
{
"result": {
"single_immediate_payment": {
"single_immediate_payment_id": "4b794546-780c-4bab-854b-ee0728828d3e",
"status": "initiated",
"initiated_at": "2020-01-01T12:00:00.0000000",
"provider_id": "ob-provider",
"amount_in_minor": 100,
"currency": "GBP",
"beneficiary": {
"account": {
"type": "sort_code_account_number",
"sort_code": "234567",
"account_number": "23456789"
},
"name": "Financial Services Ltd"
},
"remitter": {
"account": {
"type": "sort_code_account_number",
"sort_code": "987654",
"account_number": "98765432"
},
"name": "Mike Smith"
},
"references": {
"type": "separate",
"beneficiary": "FinServ-1a2b3c4d",
"remitter": "FS-1000001"
}
},
"auth_flow": {
"type": "redirect",
"uri": "https://bank.com/auth-uri",
"expiry": "2020-09-30T12:33:55Z"
},
"webhook_uri": "https://client.app.com/simp/webhook"
}
}
The same information that was returned in v1 is returned in v2 with a slightly different structure, along with some additional properties.
- The properties that are intrinsic to the single immediate payment are now found nested under a
single_immediate_payment
object. - The information to allow the user to authorise the payment is nested under an
auth_flow
object - in this case the URI to redirect the user to where they can authorise the payment.
v1 parameter | v2 parameter | Comment |
---|---|---|
results[0] |
result.single_immediate_payment |
The payment object now exists under result.single_immediate_payment . Note in v2, this has the same structure as the payment on the initiation request. |
results[0].auth_uri |
result.auth_flow.uri |
The uri to redirect the user to for them to authorise the payment exists in the result.auth_flow object of the response. |
Handling the redirect
Authorisation Flow
For payments initiated through our v1 /single-immediate-payments
endpoint, we return the user to the URI specified by redirect_uri
with a payment_id
query parameter.
Payments initiated through our /v2/single-immediate-payment-initiation-requests
will return the user to the URI specified by auth_flow.return_uri
with a single_immediate_payment_id
query parameter, specifying the payment id, and a type
query parameter, specifying the payment type. Currently the only value we will send for type
is single_immediate_payment
, however further payment types will be available in the future.
Single Immediate Payment Webhooks
The format of the webhook request body has changed as follows:
v1 parameter | v2 parameter | Comment |
---|---|---|
event_body.payment_id |
event_body.single_immediate_payment_id |
The resource identifier is now declared with its full name, single_immediate_payment_id . This is consistent with the v2 payment initiation API. |
The method for validating the webhook signature has also changed. The need to manually construct a payload of a specific format to verify the signature has been removed; the payload is now simply the body of the webhook request. The X-TL-Webhook-Timestamp
header has also been removed in value of the iat
value in the JWS header.
Payouts API v1
Payouts API Overview
The TrueLayer Payouts API brings payout functionality to our payments platform. Using the API, you can execute payments to any IBAN connected to the Faster Payment Scheme.
Note that for access to the production API, you must have:
- created a TrueLayer account using the Console
- been approved for access to the Payouts API; contact the sales team
Payouts API Guide
Note that all API endpoint URIs in this section are for the sandbox environment. If you wish to follow this guide using the production environment, please ensure that you change the endpoint domain from truelayer-sandbox.com
to truelayer.com
.
Getting Setup
Finding your Client ID and Secret
To authenticate to our API you will need to use your Client ID and Secret for the environment you are using (Live or Sandbox). Both can be found in the console.
The client ID can be found in the settings page. If you don’t have your client secret, you can generate a new one here.
Follow our guide to setup Insomnia with our Insomnia collection. It contains sample requests so that you can start using our payouts-api.
To upgrade your account to the live environment, you will need to give our sales team your Client ID. In the sandbox area of the console follow these steps:
- Navigate to the payments tab
- Click ‘Go to live env’
- Navigate to the settings tab
- Copy the client ID field
Authentication
Request
curl -X POST \
-d grant_type=client_credentials \
-d client_id=${client_id} \
-d client_secret=${client_secret} \
-d scope=payouts \
https://auth.truelayer-sandbox.com/connect/token
Response
{
"access_token": "JWT-ACCESS-TOKEN-HERE",
"expires_in": 3600,
"token_type": "Bearer"
}
Use our authentication server to obtain a client credentials grant.
You will need to use this on your requests to the Payouts API.
Topping up your account
Request
curl -H "Authorization: Bearer ${access_token}" \
https://payouts.truelayer-sandbox.com/v1/balances
Response
{
"results":
[
{
"currency": "GBP",
"iban": "GB33BUKB20201555555555",
"status": "enabled",
"current_balance_in_minor": 50000000,
"available_balance_in_minor": 49998000
},
{
"currency": "EUR",
"iban": "FR1420041010050500013M02606",
"status": "disabled",
"current_balance_in_minor": 20000000,
"available_balance_in_minor": 20000000
}
]
}
As soon as you get access to our Payouts API, a collection of accounts will be created for you: one for each currency and payment rail we support (e.g. euro on SEPA, sterling on Faster Payments, etc.).
To create payouts you will need, first of all, to add funds to those accounts. To add funds, you will need their IBANs.
You can retrieve both IBANs and account balances querying our /balances
endpoint: it will return an array of balances detailing the account details and balance currently held in the account.
Accounts can be funded by sending a payment to the iban
specified in the balance response over the same payment rail (e.g. a bank transfer over Faster Payments for sterling accounts, a bank transfer over SEPA for euro accounts). Upon settling into the account, funds will become immediately available and can be used to initiate a payout with.
Setting up a Payout
Request
curl -X POST \
-H "Authorization: Bearer ${access_token}" \
-H "X-TL-Signature: ${signature}" \
--data '{
"transaction_id": "<UUID>"
"beneficiary_name": "John Smith",
"beneficiary_iban": "GB33BUKB20201555555555",
"beneficiary_reference": "Withdrawal 204",
"currency": "GBP",
"amount_in_minor": 10000,
"context_code": "withdrawal"
}' \
https://payouts.truelayer-sandbox.com/v1/payouts
Response (HTTP 202)
To send money to an end user, you will need to setup a payout on the API.
Payout creation is asynchronous: you will receive webhooks for payout status changes, including failures. More details on webhooks are provided in the next section.
All POST requests to Payouts API have to be signed - check our reference section on request signing for more details.
Receiving Webhooks
Payout Authorised Event
X-TL-Webhook-Timestamp: 2020-05-18T10:17:52Z
{
"event_type": "payout_authorised",
"event_id": "33c9fc5b-69d7-4de0-83a9-8177f9af79d2",
"event_body":
{
"transaction_id": "cc328607-e02e-49e2-81c9-5bd044c8f7d7",
"authorised_at": "2019-10-01T17:00:00.0000000Z",
}
}
To receive webhooks you’ll need to add a webhook_uri
to the developer console in the Payouts API area.
Payout Authorised is the first event you will receive on your webhook_uri
when creating a payout on an account holding sufficient funds. You will then receive a Payout Submitted and a Payout Settled event.
If you did not have enough funds or an AML check failed, you should expect a Payout Rejected event.
All other failure scenarios will instead trigger a Payout Failed event.
Details on the structure of events as well as the data associated with each of them can be found in the Webhooks of the Payouts API reference.
Querying your transactions
Request
curl -H "Authorization: Bearer ${access_token}" \
https://payouts.truelayer-sandbox.com/v1/transactions?from="2019-10-01T17:00:00.0000000Z"&to="2019-10-02T17:00:00.0000000Z"&type="Payout"¤cy="GBP"
Response
{
"results": [
{
"transaction_id": "cc328607-e02e-49e2-81c9-5bd044c8f7d7",
"type": "payout",
"authorised_at": "2019-10-01T17:00:00.0000000Z",
"submitted_at": "2019-10-01T17:00:00.0000000Z",
"settled_at": "2019-10-01T17:00:00.0000000Z",
"beneficiary_name": "John Smith",
"beneficiary_iban": "GB33BUKB20201555555555",
"beneficiary_reference": "Withdrawal 204",
"amount_in_minor": 10000,
"currency": "GBP",
"context_code": "withdrawal",
"status": "settled"
},
{
"transaction_id": "gg328607-e02e-49e2-81c9-5bd044c8f7d8",
"type": "payout",
"authorised_at": "2019-10-01T15:00:00.0000000Z",
"submitted_at": "2019-10-01T15:00:00.0000000Z",
"settled_at": "2019-10-01T15:00:00.0000000Z",
"beneficiary_name": "Jane Doe",
"beneficiary_iban": "GB43BUKB20201555555555",
"beneficiary_reference": "Withdrawal 205",
"amount_in_minor": 20000,
"currency": "GBP",
"context_code": "withdrawal",
"status": "settled"
}
]
}
You can leverage our reporting endpoint to query your transactions for each currency account, filtering by date, type of transaction, and currency.
Payouts API Reference
Create Payout
Request
curl -X POST \
-H "Authorization: Bearer ${access_token}" \
-H "X-TL-Signature: ${signature}" \
--data '{
"transaction_id": "<UUID>",
"beneficiary_name": "John Smith",
"beneficiary_iban": "GB33BUKB20201555555555",
"beneficiary_reference": "Withdrawal 204",
"currency": "GBP",
"amount_in_minor": 10000,
"context_code": "withdrawal"
}' \
https://payouts.truelayer-sandbox.com/v1/payouts
Response (HTTP 202)
POST requests to /v1/payouts
have to be signed - check our reference section on request signing for more details.
Field | Type | Description |
---|---|---|
transaction_id |
uuid | The unique id of the payout you want to create. If two POST /payouts requests are submitted with the same transaction_id only the first one will be processed. transaction_id can therefore be used to ensure idempotency for payout creation. |
beneficiary_name |
string | The name of the account holder you are sending funds to. This name must match the name associated with the account, otherwise the payout will fail validation. It must be at most 18 characters long. |
beneficiary_iban |
string | The full IBAN of the account holder you are sending funds to. The IBAN must be accessible by the Faster Payments Scheme if transacting in GBP. |
beneficiary_reference |
string | An 18 character reference that will appear on the account holder’s bank statement. |
currency |
ISO 4217 Currency Code String | The currency you are sending the payment in. Each currency is associated with its own account, therefore the currency denotes which account the funds will be sent from. |
amount_in_minor |
integer | The amount to send to the account holder in the smallest denomination of the currency specified. e.g. if transacting in GBP this will be in pennies. |
context_code |
string | The code to describe why you are making the payout. |
Query a single Payout
Request
curl -H "Authorization: Bearer ${access_token}" \
https://payouts.truelayer-sandbox.com/v1/payouts/{transaction_id}
Response
{
"result": {
"transaction_id": "cc328607-e02e-49e2-81c9-5bd044c8f7d7",
"authorised_at": "2019-10-01T17:00:00.0000000Z",
"submitted_at": "2019-10-01T17:00:00.0000000Z",
"settled_at": "2019-10-01T17:00:00.0000000Z",
"beneficiary_name": "John Smith",
"beneficiary_iban": "GB33BUKB20201555555555",
"beneficiary_reference": "Withdrawal 204",
"amount_in_minor": 10000,
"currency": "GBP",
"context_code": "withdrawal",
"status": "settled"
}
}
A set of core fields is available on all payouts, regardless of their statuses:
Field | Type | Description |
---|---|---|
transaction_id |
uuid | The unique ID of the payout. |
beneficiary_name |
string | The name of the account holder you are sending funds to. |
beneficiary_iban |
string | The full IBAN of the account holder you are sending funds to. |
beneficiary_reference |
string | An 18 character reference that will appear on the account holder’s bank statement. |
currency |
ISO 4217 Currency Code String | The currency you are sending the payment in. |
amount_in_minor |
integer | The amount to send to the account holder in the smallest denomination of the currency specified. e.g. if transacting in GBP this will be in pennies. |
context_code |
string | The code to describe why you are making the payout. A full list of these can be found below. |
status |
string | The current status of the payout. A full description of the state machine can be found in the reference. |
When the payout status is authorised
, you will also get:
Field | Type | Description |
---|---|---|
authorised_at |
Timestamp | The date and time that the payout was authorised at. |
When the payout status is submitted
, you will also get:
Field | Type | Description |
---|---|---|
authorised_at |
Timestamp | The date and time that the payout was authorised at. |
submitted_at |
Timestamp | The date and time that the payout was submitted to the scheme. |
When the payout status is settled
, you will also get:
Field | Type | Description |
---|---|---|
authorised_at |
Timestamp | The date and time that the payout was authorised at. |
submitted_at |
Timestamp | The date and time that the payout was submitted to the scheme. |
settled_at |
Timestamp | The date and time that the payout was settled into the beneficiary account. |
When the payout status is failed
, you will also get:
Field | Type | Description |
---|---|---|
authorised_at |
Timestamp | The date and time that the payout was authorised at. |
submitted_at |
Timestamp (Optional) | The date and time that the payout was submitted to the scheme. A payout status can transition to failed before or after scheme submission. |
failed_at |
Timestamp | The date and time that the payout status changed to failed . |
When the payout status is rejected
, you will also get:
Field | Type | Description |
---|---|---|
rejected_at |
Timestamp | The date and time that the payout was rejected by TrueLayer. |
Query multiple transactions
Request
curl -H "Authorization: Bearer ${access_token}" \
https://payouts.truelayer-sandbox.com/v1/transactions?from="2019-10-01T17:00:00.0000000Z"&to="2019-10-02T17:00:00.0000000Z"&type="Payout"¤cy="GBP"
Response
{
"results":
[
{
"transaction_id": "cc328607-e02e-49e2-81c9-5bd044c8f7d7",
"type": "payout",
"authorised_at": "2019-10-01T17:00:00.0000000Z",
"submitted_at": "2019-10-01T17:00:00.0000000Z",
"settled_at": "2019-10-01T17:00:00.0000000Z",
"beneficiary_name": "John Smith",
"beneficiary_iban": "GB33BUKB20201555555555",
"beneficiary_reference": "Withdrawal 204",
"amount_in_minor": 10000,
"currency": "GBP",
"context_code": "withdrawal",
"status": "settled"
},
{
"transaction_id": "gg328607-e02e-49e2-81c9-5bd044c8f7d8",
"type": "payout",
"authorised_at": "2019-10-01T15:00:00.0000000Z",
"submitted_at": "2019-10-01T15:00:00.0000000Z",
"settled_at": "2019-10-01T15:00:00.0000000Z",
"beneficiary_name": "Jane Doe",
"beneficiary_iban": "GB43BUKB20201555555555",
"beneficiary_reference": "Withdrawal 205",
"amount_in_minor": 20000,
"currency": "GBP",
"context_code": "withdrawal",
"status": "settled"
}
]
}
The type
field can be used to distinguish between topups and payouts.
Query parameters:
Field | Mandatory | Type | Description |
---|---|---|---|
from |
Mandatory | Timestamp | Timestamp as a string for the start of the range you are querying |
to |
Mandatory | Timestamp | Timestramp as a string for the end of the range you are querying |
type |
Optional | String | Filter transactions by type, the available types are topup and payout . If omitted, both payouts and topups will be returned. |
currency |
Optional | ISO 4217 Currency Code String | Filter transactions by currency. |
Query account balances
Request
curl -H "Authorization: Bearer ${access_token}" \
https://payouts.truelayer-sandbox.com/v1/balances
Response
{
"results":
[
{
"currency": "GBP",
"iban": "GB33BUKB20201555555555",
"status": "enabled",
"current_balance_in_minor": 50000000,
"available_balance_in_minor": 49998000,
"account_owner": "Owner Name"
},
{
"currency": "EUR",
"iban": "FR1420041010050500013M02606",
"status": "disabled",
"current_balance_in_minor": 20000000,
"available_balance_in_minor": 20000000,
"account_owner": "Owner Name"
}
]
}
Field | Type | Description |
---|---|---|
currency |
ISO 4217 Currency Code String | The currency of the account. Accounts can only hold 1 currency each. |
iban |
string | The IBAN of the account that can be used to send funds to the account. |
status |
string | Denotes whether the account is active or not, the field can be enabled or disabled . |
current_balance_in_minor |
integer | The current balance of the account in the smallest denomination including transactions that are pending or in transit. |
available_balance_in_minor |
integer | The balance available to spend in the smallest denomination. |
account_owner |
string | The name of the account owner. |
Webhooks
Payouts API will notify you of the following events via webhooks:
- Payout authorised;
- Payout submitted;
- Payout settled;
- Payout rejected;
- Payout failed;
- Topup received.
Details on webhooks overall structure and their payload schemas are provided in the following sections.
Webhook Retry Policy
We consider a webhook as having been successfully delivered when we receive a success status code (2xx) from the webhook URI you specified in your Console settings for Payouts API.
If we receive any other status code (e.g. 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 24 hours waiting ~15 minutes between one delivery attempt and the following one.
Webhook Structure
All webhooks from the Payouts API are structured in the same way. In the header you will see the following fields:
Field | Type | Description |
---|---|---|
X-TL-Webhook-Timestamp |
timestamp | time that the webhook was sent to you. This will be in the following format 2020-05-18T10:17:47Z |
In the body you will see the following fields:
Field | Type | Description |
---|---|---|
event_type |
string | describing which event is detailed. |
event_schema_version |
unsigned integer | the version of the event body schema (e.g. 1). |
event_id |
uuid | unique ID of the event. |
event_body |
object | containing the object relating to the event. The body schema is specified in the following sections for each event type. |
Payout Authorised
Payout Authorised Event
X-TL-Webhook-Timestamp: 2020-05-18T10:17:52Z
{
"event_type": "payout_authorised",
"event_id": "33c9fc5b-69d7-4de0-83a9-8177f9af79d2",
"event_schema_version": 1,
"event_body": {
"transaction_id": "cc328607-e02e-49e2-81c9-5bd044c8f7d7",
"authorised_at": "2019-10-01T17:00:00.0000000Z",
}
}
The event body contains the following fields:
Field | Type | Description |
---|---|---|
transaction_id |
uuid | The unique ID of the payout. |
authorised_at |
Timestamp | The date and time that the payout was authorised at. |
Payout Submitted
Payout Submitted Event
X-TL-Webhook-Timestamp: 2020-05-18T10:17:52Z
{
"event_type": "payout_submitted",
"event_id": "33c9fc5b-69d7-4de0-83a9-8177f9af79d2",
"event_schema_version": 1,
"event_body": {
"transaction_id": "cc328607-e02e-49e2-81c9-5bd044c8f7d7",
"submitted_at": "2019-10-01T17:00:00.0000000Z",
}
}
The event body contains the following fields:
Field | Type | Description |
---|---|---|
transaction_id |
uuid | The unique ID of the payout. |
submitted_at |
Timestamp | The date and time that the payout was submitted to the scheme. |
Payout Settled
Payout Settled Event
X-TL-Webhook-Timestamp: 2020-05-18T10:17:52Z
{
"event_type": "payout_settled",
"event_id": "33c9fc5b-69d7-4de0-83a9-8177f9af79d2",
"event_schema_version": 1,
"event_body": {
"transaction_id": "cc328607-e02e-49e2-81c9-5bd044c8f7d7",
"settled_at": "2019-10-01T17:00:00.0000000Z",
}
}
The event body contains the following fields:
Field | Type | Description |
---|---|---|
transaction_id |
uuid | The unique ID of the payout. |
settled_at |
Timestamp | The date and time that the payout was settled into the beneficiary account. |
Payout Rejected
Payout Rejected Event
X-TL-Webhook-Timestamp: 2020-05-18T10:17:52Z
{
"event_type": "payout_rejected",
"event_id": "33c9fc5b-69d7-4de0-83a9-8177f9af79d2",
"event_schema_version": 1,
"event_body": {
"transaction_id": "cc328607-e02e-49e2-81c9-5bd044c8f7d7",
"rejected_at": "2019-10-01T18:00:00.0000000Z",
"rejection_code": "insufficient_funds",
"rejection_details": "There were not enough funds on the account to authorise the payout.",
}
}
The event body contains the following fields:
Field | Type | Description |
---|---|---|
transaction_id |
uuid | The unique ID of the payout. |
rejected_at |
Timestamp | The date and time that the payout was rejected. |
rejection_code |
String | The reason the payout was rejected as a machine-parsable enum. A full list of rejection codes can be found in the reference. |
rejection_details |
String | The reason the payout was rejected as a human-friendly description. |
Payout Failed
Payout Failed Event
X-TL-Webhook-Timestamp: 2020-05-18T10:17:52Z
{
"event_type": "payout_failed",
"event_id": "33c9fc5b-69d7-4de0-83a9-8177f9af79d2",
"event_schema_version": 1,
"event_body": {
"transaction_id": "cc328607-e02e-49e2-81c9-5bd044c8f7d7",
"failed_at": "2019-10-01T18:00:00.0000000Z",
"failure_code": "server_error",
"failure_details": "We encountered a technical issue while processing your payment, please try again later.",
}
}
The event body contains the following fields:
Field | Type | Description |
---|---|---|
transaction_id |
uuid | The unique ID of the payout. |
failed_at |
Timestamp | The date and time that the payout status moved to failed. |
failure_code |
String | The reason the payout as failed a machine-parsable enum. A full list of failure codes can be found in the reference. |
failure_details |
String | The reason the payout failed as a human-friendly description. |
Topup Received
Topup Received Event
X-TL-Webhook-Timestamp: 2020-05-18T10:17:52Z
{
"event_type": "topup_received",
"event_id": "33c9fc5b-69d7-4de0-83a9-8177f9af79d2",
"event_schema_version": 1,
"event_body": {
"transaction_id": "cc328607-e02e-49e2-81c9-5bd044c8f7d7",
"settled_at": "2019-10-01T17:00:00.0000000Z",
"amount_in_minor": 10000,
"currency": "GBP",
"remitter_iban": "GB33BUKB20201555555555",
"remitter_name": "Payment Corp"
"reference": "Payment Corp Topup"
}
}
In the event body you will see the following fields:
Field | Type | Description |
---|---|---|
transaction_id |
uuid | unique ID of the transaction. |
settled_at |
Timestamp | The date and time the topup was settled into the account. |
amount_in_minor |
integer | The amount received in the smallest denomination of the currency of the account. |
currency |
ISO 4217 Currency Code String | The currency the topup was settled in. |
remitter_iban |
string | The IBAN of the account that sent the funds to the account. |
remitter_name |
string | The name of the account holder that sent the funds to the account. |
reference |
string | The reference that will appear in your transaction history associated with this topup. |
Set up or update automated account sweeping
Request
curl -X POST \
-H "Authorization: Bearer $access_token" \
-H "X-TL-Signature: $signature" \
--data '{
"currency": "GBP",
"max_amount_in_minor": 100000,
"frequency": "daily"
}' \
https://payouts.truelayer-sandbox.com/v1/sweep
Set up automated sweeping for a given currency
. At regular intervals, any available balance in excess of the configured max_amount_in_minor
is withdrawn to a pre-configured IBAN. The default time interval for automated sweeping is daily
.
By default, automated sweeping is not enabled.
You can update your sweep configurations (such as changing the frequency
or max_amount_in_minor
) by making a POST /v1/sweep
call with the updated values. We will use the latest value for a given currency.
Note: This API will be unavailable until KYC onboarding has completed.
Field | Mandatory | Type | Description |
---|---|---|---|
currency |
Mandatory | string | ISO 4217 Currency Code of the account sweep source. |
max_amount_in_minor |
Mandatory | number | The desired maximum amount, specified in terms of the fractional monetary unit of the payment currency, above which funds will be automatically withdrawn. |
frequency |
Optional | string | How often the available balance will be checked for sweeping, daily , weekly or fortnightly , defaults to daily . |
Get automated account sweeping details
Request
curl -H "Authorization: Bearer $access_token" https://payouts.truelayer-sandbox.com/v1/sweep
Response
{
"results": [
{
"currency": "GBP",
"max_amount_in_minor": 100000,
"iban": "GB43BUKB20201666666666",
"frequency": "daily"
}
]
}
You can obtain all current automated sweeping configurations by making a GET /v1/sweep
call. If you haven’t enabled automated sweeping, you’ll get a 404 error in the response.
Field | Type | Description |
---|---|---|
currency |
ISO 4217 Currency Code String | Currency of the account sweep source. |
max_amount_in_minor |
number | The desired maximum amount, specified in terms of the fractional monetary unit of the payment currency, above which funds will be automatically withdrawn. |
iban |
string | The IBAN of the target account that funds will be withdrawn into. Pre-configured & validated as part of KYC onboarding. |
frequency |
string | How often the available balance will be checked for sweeping. |
Disable automated account sweeping
Request
curl -X POST \
-H "Authorization: Bearer $access_token" \
-H "X-TL-Signature: $signature" \
--data '{"currency": "GBP"}' \
https://payouts.truelayer-sandbox.com/v1/sweep/remove
Disable automated sweeping for a given currency
.
Field | Mandatory | Type | Description |
---|---|---|---|
currency |
Mandatory | ISO 4217 Currency Code String | Currency of the account sweep source. |
Request Signing
All POST requests to Payouts API have to be signed.
Signing provides a second layer of security on top of the authorization bearer token and guarantees that the payload has not been tampered with.
This section contains all the details you need to be aware of to successfully sign your POST requests to Payouts API.
Supported algorithms
The only supported signing algorithm for POST requests to Payouts API is ES512.
Generating certificates
ES512 belongs to the family of Elliptic Curve Digital Signature Algorithms (ECDSA). To sign a POST request using ECDSA you will need to generate an Elliptic Curve (EC) key pair:
- a public key, to be uploaded in the Payouts Settings page in our Console;
- a private key, to be used for signing requests, which you should not share with anyone outside of your organisation.
ES512, in particular, requires a key pair that use the P-521 family of elliptic curves (also known as secpt521r1
).
Let’s see how we can generate such a key pair using openssl
.
To generate the private key, run:
openssl ecparam -genkey -name secp521r1 -noout -out ec512-private-key.pem
You can then obtain the public key running:
openssl ec -in ec512-private-key.pem -pubout -out ec512-public-key.pem
ec512-public-key.pem
is the file you should upload in the Payouts Settings page in our Console.
Inspecting certificates
You can inspect the generated public key using:
openssl ec -inform PEM -pubin -in ec512-public-key.pem -text -noout
You can inspect the generated private key using:
openssl ec -inform PEM -in ec512-private-key.pem -text -noout
Signing a POST request
JOSE Header
{
"alg": "ES512",
"kid": "9f2b7bd6-c055-40b5-b616-120ccfd33c49"
}
Detached Payload
{
"transaction_id": "<UUID>",
"beneficiary_name": "A person",
"beneficiary_iban": "GB17CLRB04066800000072",
"beneficiary_reference": "Sandbox",
"currency": "GBP",
"amount_in_minor": 1,
"context_code": "withdrawal"
}
You need to specify a X-Tl-Signature
header in your POST request.
The header value is a JWS with detached content, signed using the ES512 algorithm.
A JWS with detached content has the following structure:
<Base64URLSafeEncoding(JOSEHeader)>..<Base64URLSafeEncoding(signature)>
As you can see, the payload segment is omitted (but it is necessary to generate the signature!).
The JOSE header must contain:
- The
alg
header parameter withES512
as value; - The
kid
header parameter, with the id of the certificate used for signing as value (i.e. the UUID value shown in the Payouts Settings in Console next to your uploaded public certificate).
The JWS payload should be the serialised HTTP request body.
Code examples can be found on GitHub.
Testing your signing logic
Request
curl -X POST \
-H "Authorization: Bearer ${access_token}" \
-H "X-TL-Signature: ${signature}" \
--data '{
"nonce": "9f952b2e-1675-4be8-bb39-6f4343803c2f",
}' \
https://payouts.truelayer-sandbox.com/v1/test
Response (HTTP 200)
You can send a POST request to our /test
endpoint to verify that you have correctly implemented request signing.
The /test
endpoint will validate your X-TL-Signature
header and return a 200 OK
in case of success, it does not perform any kind of validation on the body schema.
Payout Rejection Codes
Code | Description |
---|---|
insufficient_funds |
Your account does not have sufficient funds required to make the payout. |
server_error |
We encountered a technical issue when authorising the payment. Please try again later. |
Payout Failure Codes
Code | Description |
---|---|
scheme_error |
The scheme was unable to fulfill the payment. |
server_error |
We encountered a technical issue when processing the payment. Please try again later. |
Payout Context Codes
Code | Description |
---|---|
withdrawal |
The payout is allowing an end user to withdraw funds from your service. For example, this code would be used if you are an iGaming company allowing users to withdraw their winnings. |
service_payment |
The payout is being used to pay for a service. For example, you are a Gig Economy company paying a driver or you are a platform paying a merchant. |
internal |
You are paying yourself. Use this code to withdraw your funds from your account with us. |
Payout State Machine
State | Terminal | Description |
---|---|---|
new |
No | The payout has been created with TrueLayer but has not yet been authorised and sent to the payment scheme for execution. |
authorised |
No | TrueLayer has performed a funds check and there are sufficient funds to make the transaction. |
submitted |
No | TrueLayer has submitted the payout to the payment scheme for execution. |
settled |
Yes | The scheme has notified TrueLayer that the payout has settled into the end account. |
failed |
Yes | The payout failed, this may be because of an internal error or an error with the payment scheme. This state can occur at any stage before settled and is a final state. |
rejected |
Yes | The payout was rejected, this can be because of a lack of funds or a risk check. This state can occur at any stage before settled and is a final state. |
PayDirect API v1
PayDirect API Overview
The TrueLayer PayDirect API makes it easy to verify account ownership, and offer instant deposits and withdrawals to your users. This brings together the power of open banking with the fastest payment rails, allowing you to accept open banking payments, and execute payments across the UK and Europe.
The API is currently in Beta. Get in touch to learn more.
PayDirect API Guide
Getting Started
Get your Client ID and Secret
To authenticate to our API, you will need your Client ID and Secret for the environment you are using (live or sandbox). You can find these values in the console.
You can get your sandbox Client ID in the App settings. If you don’t have your Client Secret, you can generate a new one.
Follow our guide to setup Insomnia with our Insomnia collection. It contains sample requests so that you can start using the PayDirect API.
To upgrade your account to the live environment, you have to give our sales team your Client ID. To find your live Client ID:
- Go to your console > Paydirect API.
- Select the Go to live env button.
- Go to App settings.
- Copy the
client_id
.
Authenticate
Request
curl -X POST \
-d grant_type=client_credentials \
-d client_id=${client_id} \
-d client_secret=${client_secret} \
-d scope=paydirect \
https://auth.truelayer-sandbox.com/connect/token
Response
{
"access_token": "JWT-ACCESS-TOKEN-HERE",
"expires_in": 3600,
"token_type": "Bearer"
}
Use our authentication server to obtain a client credentials grant. You will need to use this in your requests to the PayDirect API.
Deposit funds into your account
When using our PayDirect API, you get access to different merchant accounts on your console, one for each currency and payment rail we support (for example, euro on SEPA, sterling on Faster Payments, and so on).
Accounts are funded by creating a deposit. Once they are settled, funds will become immediately available for withdrawal.
Make withdrawals
You need funds in your account to create withdrawals. The PayDirect API supports two types of withdrawal:
Closed loop withdrawal
Request
curl -X POST \
-H "Authorization: Bearer ${access_token}" \
-H "X-TL-Signature: ${signature}" \
--data '{
"user_id": "<UUID>",
"account_id": "<UUID>"
"transaction_id": "<UUID>",
"beneficiary_reference": "Withdrawal 204",
"currency": "GBP",
"amount_in_minor": 10000
}' \
https://paydirect.truelayer-sandbox.com/v1/users/withdrawals
With a closed loop withdrawal, you can send funds to an account that your user has previously made a deposit from. By specifying a user_id
and account_id
, you can make sure that you are sending funds back to the original account, making it easier to meet any AML obligations.
Open loop withdrawal
Request
curl -X POST \
-H "Authorization: Bearer ${access_token}" \
-H "X-TL-Signature: ${signature}" \
--data '{
"transaction_id": "<UUID>"
"beneficiary_name": "John Smith",
"beneficiary_iban": "GB33BUKB20201555555555",
"beneficiary_reference": "Withdrawal 204",
"currency": "GBP",
"amount_in_minor": 10000,
"context_code": "withdrawal"
}' \
https://paydirect.truelayer-sandbox.com/v1/withdrawals
With an open loop withdrawl,you can send funds to any account. This type of withdrawal is useful for sending funds to your bank account, or to a user account that hasn’t previously been used to deposit funds.
Receive webhooks
Deposit Settled Event
X-TL-Webhook-Timestamp: 2020-05-18T10:17:52Z
{
"event_type": "deposit_settled",
"event_id": "61523b95-527a-431d-a1a6-94c5df6c2325",
"event_schema_version": 1,
"event_body": {
"transaction_id": "5675c939-953b-40fc-84c4-b5c514a36927",
"deposit_id": "84e76e9e-811a-4f02-9624-f808c5925bfb",
"user_id": "bCc96bf3-788b-4266-92dc-77351b680ac5",
"account_id": "5356e5af-7bf2-49a4-96b3-7fde5ec8ddfe",
"settled_at": "2021-03-08T10:30:46Z",
"amount_in_minor": 1,
"currency": "GBP",
"remitter_iban": "GB11CLRB04066200002723",
"remitter_name": "JANE DOE"
}
}
To receive webhooks, you’ll need to add a webhook_uri
to your console.
Details on the structure of events as well as the data associated with each of them can be found in the Webhooks section of the PayDirect API reference.
Set up automated account sweeping
Request
curl -X POST \
-H "Authorization: Bearer $access_token" \
-H "X-TL-Signature: $signature" \
--data '{
"currency": "GBP",
"max_amount_in_minor": 100000,
"frequency": "daily"
}' \
https://paydirect.truelayer-sandbox.com/v1/sweep
You can set up automated sweeping to maintain a certain maximum balance in your accounts. We will move excess funds into a pre-configured IBAN at regular intervals. The sweep target IBAN is validated and configured as part of the KYC onboarding process.
Instant Guarantee
If enabled for your client_id
, your SEPA Credit deposits settlement will be instantly guaranteed.
This is subject to internal checks and capped to a daily amount limit per user.
To allow some flexibility in user experience, we have an endpoint available to retrieve a given user’s current limits, which can be used as a soft-check to determine whether we’re likely to give an instant guarantee for a payment or not.
When a deposit meets the criteria to have an instant guarantee from TrueLayer, the
is_guaranteed
boolean field will be set to true
in the deposit executed
webhook payload and in a single deposit details
payload.
Test and go live
To go live, make sure PayDirect is enabled in your live console, then change the endpoint domain from truelayer-sandbox.com
to truelayer.com
.
PayDirect API Reference
Authentication
You must provide a valid Bearer access token when calling the PayDirect API.
Request a PayDirect Access Token
Use our authentication server to obtain a client credentials grant. You will need to include this within the Bearer token header in future requests.
Request
curl -X POST \
-d grant_type=client_credentials \
-d client_id=${client_id} \
-d client_secret=${client_secret} \
-d scope=paydirect \
https://auth.truelayer-sandbox.com/connect/token
Response
{
"access_token": "JWT-ACCESS-TOKEN-HERE",
"expires_in": 3600,
"token_type": "Bearer",
"scope": "paydirect payments"
}
Then include this in the Bearer token header for future requests. For example:
curl -X POST \
-H "Authorization: Bearer ${access_token}" \
--data '{...}' \
https://paydirect.truelayer-sandbox.com/v1/users/deposits/create_deposit
Create deposit
This section describes how to setup, execute, and monitor progress of a deposit.
A deposit is a one-time payment into your wallet that requires your user to authorise the payment with their bank.
Deposits Providers Endpoint
Request
https://paydirect.truelayer-sandbox.com/v1/deposits/providers?auth_flow_type=redirect,embedded&account_type=sort_code_account_number,iban&additional_input_type=text,select¤cy=GBP,EUR
Response
{
"results": [
{
"provider_id": "ob-example",
"logo_url": "https://truelayer-client-logos.s3-eu-west-1.amazonaws.com/banks/ob-example.svg",
"display_name": "Example OB Bank",
"country": "GB",
"divisions": [ "retail", "business" ],
"deposit_schemes": [
{
"scheme_id": "faster_payments_service",
"requirements": [
{
"auth_flow": {
"types": [ "redirect" ],
"redirect": {
"data_access_token_supported": true
}
},
"deposit": {
"currency": {
"supported_currencies": [ "GBP" ]
},
"beneficiary": {
"account": {
"types": [ "sort_code_account_number" ],
},
"name": {
"mandatory": true,
"min_length": 1,
"max_length": 20,
"regex": "[\\w\\d ]{1,20}",
"format": "any"
}
},
"remitter": {
"mandatory": false,
"account": {
"types": [ "sort_code_account_number" ],
},
"name": {
"mandatory": false,
"min_length": 1,
"max_length": 20,
"regex": "[\\w\\d ]{1,20}",
"format": "any"
}
},
"references": {
"types": [ "single", "separate" ],
"single": {
"min_length": 1,
"max_length": 20,
"regex": "[\\w\\d \\.-]{1,20}",
"format": "any"
},
"separate": {
"beneficiary": {
"min_length": 1,
"max_length": 20,
"regex": "[\\w\\d \\.-]{1,20}",
"format": "any"
},
"remitter": {
"min_length": 1,
"max_length": 20,
"regex": "[\\w\\d \\.-]{1,20}",
"format": "any"
}
}
}
}
}
]
}
],
"release_stage": "live"
},
{
"provider_id": "eur-example",
"logo": "https://truelayer-client-logos.s3-eu-west-1.amazonaws.com/banks/eur-example.svg",
"display_name": "Example EUR Bank",
"country": "DE",
"divisions": [ "retail" ],
"deposit_schemes": [
{
"scheme_id": "sepa_credit_transfer_instant",
"fee_options": [
{
"fee_option_id": "remitter_payable",
"beneficiary_fee": "free",
"remitter_fee": "payable"
},
{
"fee_option_id": "beneficiary_payable",
"beneficiary_fee": "payable",
"remitter_fee": "free"
}
],
"requirements": [
{
"auth_flow": {
"types": [ "embedded" ],
"embedded": {
"additional_input_types": [ "text" ],
"additional_inputs": {
"some-upfront-input": {
"type": "select",
"mandatory": true,
"options": [
{
"id": "option-a",
"display_text": "First Option"
},
{
"id": "option-b",
"display_text": "Second Option"
}
]
}
}
}
},
"deposit": {
"currency": {
"supported_currencies": [ "EUR" ]
},
"beneficiary": {
"account": {
"types": [ "iban" ],
},
"name": {
"mandatory": true,
"min_length": 1,
"max_length": 20,
"regex": "[\\w\\d ]{1,20}",
"format": "any"
}
},
"remitter": {
"mandatory": true,
"account": {
"types": [ "iban" ],
},
"name": {
"mandatory": false,
"min_length": 1,
"max_length": 20,
"regex": "[\\w\\d ]{1,20}",
"format": "any"
}
},
"references": {
"types": [ "single" ],
"single": {
"min_length": 1,
"max_length": 20,
"regex": "[\\w\\d \\.-]{1,20}",
"format": "any"
}
}
}
}
]
}
],
"release_stage": "live"
}
]
}
The providers endpoint serves three purposes:
- Tells you which banks are currently active (when a bank is temporarily unavailable, we hide them from this list until its service is restored).
- Gives you the assets to build out a selection screen e.g. logos and display names.
- Tells you the available schemes, auth flows, and input requirements for each provider.
To retrieve providers whose requirements you support, you must filter using the following query parameters:
Field | Available Values | Mandatory | Description |
---|---|---|---|
auth_flow_type |
redirect embedded |
Mandatory | Will only return providers with schemes that support the listed auth flows. |
account_type |
sort_code_account_number iban bban nrb |
Mandatory | Will only return providers with schemes that support the listed account identifiers. |
currency |
ISO 4217 currency codes e.g. GBP,EUR |
Mandatory | Will only return providers with schemes that support the listed currencies. |
country |
ISO 3166-1 alpha-2 country codes e.g. GB,FR |
Optional | Will only return providers from the listed countries. |
additional_input_type |
text select text_with_image |
Optional | Will filter out any provider schemes that require additional_inputs field types not specified (including any on subsequent inputs as part of the embedded flow). If omitted, will only return provider schemes that have no required additional inputs. |
release_channel |
live public_beta private_beta |
Optional | Will filter out any providers that are not on the specified release channel (public_beta also includes all those in live , and private_beta also includes all those in public_beta ). If omitted, will only return providers that are generally available (equivalent to live ). |
Each bank available will have the following fields:
Field | Type | Description |
---|---|---|
provider_id |
string |
This is the provider ID that you will send us in the create payment request. |
logo_url |
string |
This is the address of the logo asset in SVG form. |
display_name |
string |
This is a readable name for the provider. |
country |
string |
The ISO 3166-1 alpha-2 country code for the provider. |
divisions |
string[] |
This array includes all divisions that are available on this provider, e.g. retail and business would indicate you can use this single provider to access both retail and business accounts. |
deposit_schemes |
DepositScheme[] |
The array lists the available schemes the provider can use, within each is described the requirements for the fields on the Deposit initiation request. |
release_stage |
string |
This indicates the product maturity of the provider. live and public_beta providers are visible to everyone, while private_beta providers must be enabled for the client_id provided in the query parameters to be visible. Values: live , public_beta , private_beta . |
We recommend you query this endpoint every time you make a payment to ensure that you are always accessing the latest providers information. We are constantly working towards improving your experience with us by removing banks that are not currently available, adding banks as we expand our coverage, and updating banks’ requirements.
DepositScheme
Field | Type | Description |
---|---|---|
scheme_id |
string |
A unique identifier for the scheme, shared across providers. This should be provided on the deposit.scheme_id field on the initiation request. |
fee_options (optional) |
FeeOption[] |
If present, then fees are payable to make a payment on the scheme, and you must choose an option in this list when initiating a payment. |
requirements |
DepositRequirements[] |
Contains at least one set of requirements, one of which should be adhered to in order to create a valid initiation request for the scheme. |
FeeOption
Field | Type | Description |
---|---|---|
fee_option_id |
string |
A unique identifier for the fee option, shared across providers. This should be provided on the deposit.fee_option_id field on the initiation request. |
beneficiary_fee |
string |
A value to indicate if the beneficiary would pay any fees on the transaction, when using this fee option. Values: free , payable , unknown |
remitter_fee |
string |
A value to indicate if the remitter would pay any fees on the transaction, when using this fee option. Values: free , payable , unknown |
DepositRequirements
Each property in the requirements object corresponds to an identically named property on the initiation request for a Deposit. The following sections detail the requirement types and how they should be interpreted in order to build a valid initiation request.
Field | Child Field | Type | Description |
---|---|---|---|
auth_flow |
- | AuthFlowRequirements |
Which auth flows are supported and what fields are required/available to initiate a payment for those flows. |
deposit |
currency |
CurrencyRequirements |
Which currencies are supported. |
deposit |
beneficiary |
ParticipantRequirements |
Which beneficiary details are required/supported. |
deposit |
remitter (optional) |
ParticipantRequirements |
Which remitter details are required/supported. If omitted, the scheme does not support receiving remitter details. |
deposit |
references |
ReferenceRequirements |
Which reference types are required/supported. |
AuthFlowRequirements
Field | Type | Description |
---|---|---|
types |
string[] |
A list of supported auth flow types. Values: redirect ,embedded . |
redirect (optional) |
RedirectAuthFlowRequirements |
Will be set if redirect is supported. |
embedded (optional) |
EmbeddedAuthFlowRequirements |
Will be set if embedded is supported. |
RedirectAuthFlowRequirements
Field | Type | Description |
---|---|---|
psu_ip_address_required (optional) |
boolean | Indicates if auth_flow.psu_ip_address is required on the initiation request. |
data_access_token_supported (optional) |
boolean | Indicates if auth_flow.data_access_token can be provided on the initiation request, to maintain long lived consents across products (Data API and Payment API), where the provider only allows a single active consent across both AIS and PIS services. |
additional_inputs (optional) |
AdditionalInputs |
An optional dictionary of ID to additional inputs that must be collected from the end user to initiate a payment. These inputs should be provided using the same IDs in the auth_flow.additional_inputs string dictionary on the initiation request. |
EmbeddedAuthFlowRequirements
Field | Type | Description |
---|---|---|
additional_input_types |
string[] |
A list of additional input field types that may be returned during the embedded authorisation flow (not inclusive of those required on initiation below). Values: text , text_with_image , select . |
additional_inputs (optional) |
AdditionalInputs |
An optional dictionary of ID to additional inputs that must be collected from the end user to initiate a payment. These inputs should be provided using the same IDs in the auth_flow.additional_inputs string dictionary on the initiation request. |
CurrencyRequirements
Field | Type | Description |
---|---|---|
supported_currencies |
string[] |
A list of ISO 4217 currency codes supported by the provider scheme. |
ParticipantRequirements
Field | Child Field | Type | Description |
---|---|---|---|
account |
types |
string[] |
A list of account types supported by the scheme. Values: sort_code_account_number , iban , bban , nrb . |
name (optional) |
- | StringFieldRequirements |
An object detailing the requirements for the name, if omitted then setting the name on the initiation request is not supported for this scheme. |
mandatory |
- | bool | If a remitter is required. Not present on beneficiary as that is always mandatory. |
ReferenceRequirements
Field | Child Field | Type | Description |
---|---|---|---|
types |
- | string[] |
A list of supported reference types. Values: single ,separate |
single (optional) |
- | StringFieldRequirements |
Will be set if single is supported. Specifies the requirements for a single reference string for the payment. |
separate (optional) |
beneficiary |
StringFieldRequirements |
Will be set if separate is supported. Specifies the requirements for the beneficiary reference string for the payment. |
separate (optional) |
remitter |
StringFieldRequirements |
Will be set if separate is supported. Specifies the requirements for the remitter reference string for the payment. |
StringFieldRequirements
Field | Type | Requirement Description |
---|---|---|
mandatory |
boolean |
The corresponding field on the request is mandatory. |
min_length |
integer |
The corresponding field on the request must be at least this many characters. |
max_length |
integer |
The corresponding field on the request must be at most this many characters. |
regex |
string |
The corresponding field on the request must match the regular expression. |
format |
string |
A well known format to help you communicate to your client how the field will be validated. Values: any , numerical , alphabetical , alphanumerical , email |
AdditionalInputs
The additional_inputs
object on responses is a dictionary of input IDs to an object describing the input required. The structure of the input object differs based on the type
property, and can be one of the following:
Input Type | Description | Corresponding Request Value |
---|---|---|
text |
Requires the end user to enter a string value | The string value the end user entered |
text_with_image |
Displays an image to the end user and requires them to enter a string value | The string value the end user entered |
select |
Provides a list of options for the end user to select from | The id of the selected option |
Text Input
Additional Inputs Requirement (Text)
{
"some_input_id": {
"type": "text",
"display_text": "Some display text in English",
"provider_description": "A message from the bank",
"mandatory": true,
"sensitive": false,
"min_length": 5,
"max_length": 15,
"regex": "^[a-z ]{5,15}$",
"format": "alphabetical"
}
}
Additional Inputs Request Example (Text)
{
"some_input_id": "entered value"
}
Field | Type | Description |
---|---|---|
type |
string |
Value indicating the field type: text |
display_text |
string |
Text to describe what the field is asking for (English) |
provider_description (optional) |
string |
Text directly from the bank relating to the field |
mandatory |
boolean |
If the input must be provided |
sensitive |
boolean |
If the input is sensitive (should be masked in UI) |
min_length |
integer |
The minimum length of the input text |
max_length |
integer |
The maximum length of the input text |
regex |
string |
A regular expression the input text must match |
format |
string |
A well known format, to facilitate being able to show useful prompts to the user. Values: any , numerical , alphabetical , alphanumerical , email |
Text With Image Input
Additional Inputs Requirement (Text with Image)
{
"some_input_id": {
"type": "text_with_image",
"display_text": "Some display text in English",
"provider_description": "A message from the bank",
"mandatory": true,
"sensitive": false,
"min_length": 5,
"max_length": 15,
"regex": "^[a-z ]{5,15}$",
"format": "alphabetical",
"image": {
"type": "base64",
"base64": {
"data":
"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8vlr6PwAHHAK+MKsa+gAAAABJRU5ErkJggg==",
"media_type": "image/png"
}
}
}
}
Additional Inputs Request Example (Text with Image)
{
"some_input_id": "entered value"
}
Field | Type | Description |
---|---|---|
type |
string |
Value indicating the field type: text_with_image |
display_text |
string |
Text to describe what the field is asking for (English) |
provider_description (optional) |
string |
Text directly from the bank relating to the field |
mandatory |
boolean |
If the input must be provided |
sensitive |
boolean |
If the input is sensitive (should be masked in UI) |
min_length |
integer |
The minimum length of the input text |
max_length |
integer |
The maximum length of the input text |
regex |
string |
A regular expression the input text must match |
format |
string |
A well known format, to facilitate being able to show useful prompts to the user. Values: any , numerical , alphabetical , alphanumerical , email |
image |
object |
An image to display to the end user (e.g. QR code). The image object can be of two types, base64 or uri .If type is base64 , there will be a base64 property containing the base64 data and media_type .If type is uri , there will be a uri property with a URI to a hosted copy of the image. |
Select Input
Additional Inputs Requirement (Select)
{
"some_input_id": {
"type": "select",
"display_text": "Some display text in English",
"provider_description": "A message from the bank",
"mandatory": true,
"options": [
{
"id": "option-a",
"display_text": "First Option"
},
{
"id": "option-b",
"display_text": "Second Option"
}
]
}
}
Additional Inputs Request Example (Select)
{
"some_input_id": "option-b"
}
Field | Type | Description |
---|---|---|
type |
string |
Value indicating the field type: select |
display_text |
string |
Text to describe what the field is asking for (English) |
provider_description (optional) |
string |
Text directly from the bank relating to the field |
mandatory |
boolean |
If the input must be provided |
options |
SelectOption[] |
A list of id -display_text pairs to present to the end user as options (e.g. a drop down). |
SelectOption
Field | Type | Description |
---|---|---|
id |
string |
Value to be provided on the initiation request, if the option is selected |
display_text |
string |
Text to describe the option |
Initiating a deposit
Request
curl -X POST \
-H "Authorization: Bearer ${access_token}" \
-H "X-TL-Signature: ${signature}" \
--data '{
"user_id": "c17cae3a-98d1-44cc-aebe-8bcbffd57280",
"deposit": {
"deposit_id": "dcc3e785-76d3-415c-8bd7-553f17f49c4a",
"provider_id": "eg-provider",
"amount_in_minor": 120000,
"currency": "GBP",
"remitter": {
"account": {
"type": "sort_code_account_number",
"sort_code": "987654",
"account_number": "98765432"
},
"name": "Mike Smith"
},
"remitter_reference": "abcdefg123"
},
"auth_flow": {
"type": "redirect",
"return_uri": "https://client.app.com/payment_return"
}
}' \
https://paydirect.truelayer.com/v1/users/deposits
Response
{
"result": {
"deposit": {
"deposit_id": "dcc3e785-76d3-415c-8bd7-553f17f49c4a",
"status": "initiated",
"initiated_at": "2020-10-13T10:01:23.381Z",
"provider_id": "eg-provider",
"scheme_id": "payment_scheme",
"fee_option_id": "split_fee",
"amount_in_minor": 120000,
"currency": "GBP",
"remitter": {
"account": {
"type": "sort_code_account_number",
"sort_code": "987654",
"account_number": "98765432"
},
"name": "Mike Smith"
},
"references": {
"remitter": "FS-1000001"
}
},
"auth_flow": {
"type": "redirect",
"uri": "https://www.eg-provider.com/authorize?token=0f9e8d7c",
"expiry": "2020-11-03T23:00:00.000Z"
}
}
}
The initiation request includes the following fields:
Field | Type | Mandatory | Description |
---|---|---|---|
deposit |
DepositRequestDetails |
Mandatory | Specifies the details of the payment to be created. See the DepositRequestDetails section below. |
auth_flow |
AuthFlowRequestDetails |
Mandatory | Specifies how the payment should be authorised. See the AuthFlowRequestDetails section below. |
webhook_uri |
string |
Optional | An address to which payment webhooks with the status of the payment should be sent. Has to be https. |
DepositRequestDetails
Field | Type | Mandatory | Description |
---|---|---|---|
user_id |
uuid |
Mandatory | The unique id representing your end-user. Subsequent API calls involving the same end-user should use the same user id. |
deposit_id |
uuid |
Mandatory | The unique id of the payment you want to create. If two requests are received with the same id, only the first one will be processed. |
amount_in_minor |
number |
Mandatory | The amount, specified in terms of the fractional monetary unit of the payment currency, to be paid. |
currency |
string |
Mandatory | The ISO 4217 code of the currency for the payment. |
provider_id |
string |
Mandatory | The id of the provider, as given on our /providers endpoint. |
scheme_id |
string |
Conditional | The id of the scheme to make the payment over. This must be one of the schemes advertised by the provider on the /v1/deposits/providers endpoint. If omitted, the default value of faster_payments_service will be used. |
fee_option_id |
string |
Conditional | The id indicating the desired distribution of fees between the beneficiary and remitter. Must be a fee_option_id from one of the options advertised under that scheme on the /v1/deposits/providers endpoint. Should be omitted if there are no fee options (the scheme is free). |
remitter |
ParticipantDetails |
Optional | The details of the remitter sending the payment. See the ParticipantDetails section below. |
remitter_reference |
string |
Optional | The reference to appear on the remitters’ statement. |
ParticipantDetails
Field | Type | Mandatory | Description |
---|---|---|---|
account |
AccountIdentifierDetails |
Mandatory | The details of the account owned by the participant. |
name |
string |
Conditional | The name on the participant’s account. |
AccountIdentifierDetails
Field | Type | Mandatory | Description |
---|---|---|---|
type |
string |
Mandatory | The type of account. Must be one of sort_code_account_number , iban , bban , or nrb . Please refer to our providers endpoint for details of what account types are supported by each provider. |
sort_code |
string |
Mandatory if type is sort_code_account_number . Invalid otherwise. |
6 digit sort code (no spaces or dashes). |
account_number |
string |
Mandatory if type is sort_code_account_number . Invalid otherwise. |
8 digit account number. |
iban |
string |
Mandatory if type is iban . Invalid otherwise. |
Valid International Bank Account Number (no spaces). Consists of a 2 letter country code, followed by 2 check digits, and then by up to 30 alphanumeric characters (also known as the BBAN). |
bban |
string |
Mandatory if type is bban . Invalid otherwise. |
Valid Basic Bank Account Number (no spaces). Consists of up to 30 alphanumeric characters, with a fixed length per country. Forms the latter part of the IBAN as described above. |
nrb |
string |
Mandatory if type is nrb . Invalid otherwise. |
Valid Polish NRB (no spaces). Consists of 2 check digits, followed by an 8 digit bank branch number, and then by a 16 digit bank account number. Equivalent to a Polish IBAN with the country code removed. |
AuthFlowRequestDetails
Field | Type | Mandatory | Description |
---|---|---|---|
type |
string |
Mandatory | The type of authorisation flow. Must be redirect or embedded . Providers requiring additional authorisation flows may be available in future. |
return_uri |
string |
Mandatory if type is redirect . Invalid otherwise. |
The URI we will return the user to after authorising the payment. When the user is redirected to this URI, we will append a deposit_id query parameter specifying the payment id and a type query parameter with value deposit . |
psu_ip_address |
string |
Conditional if type is redirect . Invalid otherwise. |
The IP address of the end user. |
data_access_token |
string |
Optional if type is redirect . Invalid otherwise. |
If the provider only allows a single active consent across both AIS and PIS services, in order to prevent invalidating an existing AIS consent, you can pass the data access token on this field, and we will preserve the data consent when requesting authorisation for the payment. |
additional_inputs |
dictionary<string, string> |
Conditional | A dictionary of additional values required on a per-provider basis. Please refer to our providers endpoint for details of the providers that require these. |
Handling the initiation request response
The response from the /users/deposits/
endpoint, shown above, returns the following fields:
Field | Type | Description |
---|---|---|
deposit |
DepositResponseDetails |
Contains the details of the payment. This is a superset of the DepositRequestDetails object. See the DepositResponseDetails section below. Note this is the same object as that which will be returned on the GET /v1/users/{userId}/deposits/{id} endpoint. |
auth_flow |
AuthFlowResponseDetails |
This provides information on how to have the end user authorise the payment, and will differ in structure based on the authorisation flow. See the AuthFlowResponseDetails section below. |
DepositResponseDetails
This contains the following fields in addition to those listed in the DepositRequestDetails
section:
Field | Type | Description |
---|---|---|
initiated_at |
string |
The time the payment was initiated, in UTC formatted as an ISO 8601 string (YYYY-MM-DDThh:mm:ss.sssZ ). |
status |
string |
The status of the payment. For newly initiated payments, this will be initiated . |
AuthFlowResponseDetails
Redirect Authorisation
Redirect auth_flow response object
{
"type": "redirect",
"uri": "https://example.com",
"expiry": "2020-11-03T23:00:00.000Z"
}
If the provider uses a redirect
authorisation flow, the auth_flow
object on the response will have the following fields:
Field | Type | Description |
---|---|---|
type |
string |
Value indicating this is a redirect authorisation flow: redirect |
uri |
string |
The URI for the end user to authorise the payment in the bank’s UI. |
expiry (optional) |
string |
An expiry time, if one is known, after which the URI to authorise the payment will become invalid. In UTC, formatted as an ISO 8601 string (YYYY-MM-DDThh:mm:ss.sssZ ). |
After creating the payment, you will need to redirect the user to the authorisation page specified by uri
.
Deposit Statuses
Below are the various states a deposit can be in. You can query the status of your deposit using the GET v1/users/{user_id}/deposits/{deposit_id}
endpoint. PayDirect will send webhook events for status transitions. For more information see webhook-events.
Status | Terminal? | Description |
---|---|---|
initiated |
No | The payment resource corresponding to the deposit has been created, but the user has not yet authorised the payment. The initial API response will always have this status if the API call is successful. |
cancelled |
Yes | The user has cancelled the deposit payment using the bank portal. This may also happen for some bank UIs if the payer clicks the “Back” button in their browser |
authorisation_failed |
Yes | The user attempted to authorise the deposit payment with the bank, but failed to do so successfully |
executing |
No | The user has successfully authorised the deposit payment using the bank portal, but the payment has not yet executed. |
rejected |
Yes | The user authorised the deposit payment, but the bank rejected it after this. |
executed |
No | The funds have left the remitter’s account and will arrive your merchant account. |
expired |
Yes | The deposit payment was not authorised within the expiry of the initiation. |
settled |
Yes | The deposit payment has settled into your merchant account. |
Get Deposit Example
You can retrieve the details and status of a deposit at any time using the deposit_id
.
Request
curl -H "Authorization: Bearer ${access_token}" \
https://paydirect.truelayer-sandbox.com/v1/users/${userId}/deposits/${depositId}
Response
{
"result": {
"deposit_id": "8361f601-cc39-43f5-a761-89ae54d7440e",
"initiated_at": "2021-03-09T17:04:27.58",
"status": "settled",
"provider_id": "mock-payments",
"amount_in_minor": 1,
"currency": "GBP",
"is_guaranteed": false,
"beneficiary": {
"account": {
"type": "sort_code_account_number",
"sort_code": "040662",
"account_number": "00003151"
},
"name": "Jane Doe"
},
"remitter": {
"account": {
"type": "sort_code_account_number",
"sort_code": "040662",
"account_number": "00002723"
},
"name": "JANE DOE"
},
"references": {
"type": "single",
"reference": "VH/4LH4Y1DJ8LCA67Z"
},
"settled": {
"account_id": "5156e5af-7bf2-49a4-96b3-7fde5ec8ddfe",
"transaction_id": "af59237f-fa61-476a-aad6-66a6c13cd40b",
"settled_at": "2021-03-09T17:05:32.427Z"
}
}
}
Once a deposit has been settled, we include the settled
object which contains additional information regarding the deposit.
Field | Type | Description |
---|---|---|
settled.account_id |
uuid | The unique TrueLayer generated id of the account the deposit came from. |
settled.transaction_id |
uuid | The unique id of the transaction that will correspond to the transaction_id in the transactions returned by the /transactions endpoint. |
settled.settled_at |
Timestamp | The date and time the deposit settled into the account. |
Closed Loop Withdrawal
Request
curl -X POST \
-H "Authorization: Bearer ${access_token}" \
-H "X-TL-Signature: ${signature}" \
--data '{
"user_id": "<UUID>",
"account_id": "<UUID>",
"transaction_id": "<UUID>",
"beneficiary_reference": "Withdrawal 204",
"currency": "GBP",
"amount_in_minor": 10000
}' \
https://paydirect.truelayer-sandbox.com/v1/users/withdrawals
Response (HTTP 202)
POST requests to /v1/users/withdrawals
have to be signed. Check our reference section on request signing for more details.
Field | Type | Description |
---|---|---|
user_id |
uuid | The unique id of the user you would like to pay out to. For more information, see create deposit. |
account_id |
uuid | The unique id of the user’s account you would like to pay out to. |
transaction_id |
uuid | The unique id of the withdrawal you want to create. If two POST /withdrawal requests are submitted with the same transaction_id only the first one will be processed. transaction_id can therefore be used to ensure idempotency for withdrawal creation. |
beneficiary_reference |
string | An 18 character reference that will appear on the account holder’s bank statement. |
currency |
ISO 4217 Currency Code String | The currency you are sending the payment in. Each currency is associated with its own account, therefore the currency denotes which account the funds will be sent from. |
amount_in_minor |
integer | The amount to send to the account holder in the smallest denomination of the currency specified. e.g. if transacting in GBP this will be in pennies. |
Retrieve Closed Loop Withdrawal
You can query the status of a closed loop deposit using the v1/users/{user_id}/accounts/{account_id}/withdrawals/{transaction_id}
endpoint. Using the user_id
, account_id
and transaction_id
used in creating the closed loop withdrawal.
Request
curl -H "Authorization: Bearer ${access_token}" \
https://paydirect.truelayer-sandbox.com/v1/users/${user_id}/accounts/${account_id}/withdrawals/${transaction_id}
Response
{
"result": {
"transaction_id": "32ca16ba-3eea-4494-a105-49586cb293a8",
"authorised_at": "2021-09-08T12:45:59.969503Z",
"submitted_at": "2021-09-08T12:46:00.252166Z",
"settled_at": "2021-09-08T12:46:01.927Z",
"rejected_at": null,
"failed_at": null,
"beneficiary_name": "John Smith",
"beneficiary_iban": "GB33BUKB20201555555555",
"beneficiary_reference": "Test Withdrawal",
"amount_in_minor": 10000,
"currency": "EUR",
"status": "settled",
"context_code": "withdrawal"
}
}
Open Loop Withdrawal
Request
curl -X POST \
-H "Authorization: Bearer ${access_token}" \
-H "X-TL-Signature: ${signature}" \
--data '{
"transaction_id": "<UUID>"
"beneficiary_name": "John Smith",
"beneficiary_iban": "GB33BUKB20201555555555",
"beneficiary_reference": "Withdrawal 204",
"currency": "GBP",
"amount_in_minor": 10000,
"context_code": "withdrawal"
}' \
https://paydirect.truelayer-sandbox.com/v1/withdrawals
Response (HTTP 202)
For withdrawals (also known as “payouts”) to a bank account that has never been used to make a deposit before, we need the beneficiary’s IBAN. Use our Verification API to collect the user’s bank account details and verify account ownership.
POST requests to /v1/withdrawals
have to be signed. Check our reference section on request
signing for more details.
Field | Type | Description |
---|---|---|
transaction_id |
uuid | The unique id of the withdrawal you want to create. If two POST /withdrawal requests are submitted with the same transaction_id only the first one will be processed. transaction_id can therefore be used to ensure idempotency for withdrawal creation. |
beneficiary_name |
string | The name of the account holder you are sending funds to. This name must match the name associated with the account, otherwise the withdrawal will fail validation. It must be at most 18 characters long. |
beneficiary_iban |
string | The full IBAN of the account holder you are sending funds to. The IBAN must be accessible by the Faster Payments Scheme if transacting in GBP. |
beneficiary_reference |
string | An 18 character reference that will appear on the account holder’s bank statement. |
currency |
ISO 4217 Currency Code String | The currency you are sending the payment in. Each currency is associated with its own account, therefore the currency denotes which account the funds will be sent from. |
amount_in_minor |
integer | The amount to send to the account holder in the smallest denomination of the currency specified. e.g. if transacting in GBP this will be in pennies. |
context_code |
string | The code to describe why you are making the withdrawal. |
Retrieve Open Loop Withdrawal
You can query the status of an open loop deposit using the v1/withdrawals/{transaction_id}
endpoint. Using the transaction_id
used in creating the open loop withdrawal.
Request
curl -H "Authorization: Bearer ${access_token}" \
https://paydirect.truelayer-sandbox.com/v1/withdrawals/{transaction_id}
Response
{
"result": {
"transaction_id": "dfbec5cf-567a-4ebe-aa2a-7aa71de654f5",
"authorised_at": "2021-09-07T16:25:23.315517Z",
"submitted_at": "2021-09-07T16:25:23.607579Z",
"settled_at": "2021-09-07T16:25:25.043Z",
"rejected_at": null,
"failed_at": null,
"beneficiary_name": "John Smith",
"beneficiary_iban": "GB33BUKB20201555555555",
"beneficiary_reference": "Test Withdrawal",
"amount_in_minor": 10000,
"currency": "EUR",
"status": "settled",
"context_code": "withdrawal"
}
}
Withdrawal Statuses
Below are the various states a withdrawal can be in. If it is an closed loop withdrawal, you can query the status of your withdrawal using the GET v1/users/{user_id}/accounts/{account_id}/withdrawals/{withdrawal_id}
endpoint. PayDirect will send webhook events for status transitions (including open loop withdrawals). For more information see webhook-events.
State | Terminal | Description |
---|---|---|
new |
No | The withdrawal has been created with TrueLayer but has not yet been authorised and sent to the payment scheme for execution. |
authorised |
No | TrueLayer has performed a funds check and there are sufficient funds to make the transaction. |
submitted |
No | TrueLayer has submitted the withdrawal to the payment scheme for execution. |
settled |
Yes | The scheme has notified TrueLayer that the withdrawal has settled into the end account. |
failed |
Yes | The withdrawal failed, this may be because of an internal error or an error with the payment scheme. This state can occur at any stage before settled . |
rejected |
Yes | The withdrawal was rejected, this can be because of a lack of funds or a risk check. This state can occur at any stage before settled . |
Webhook Events
PayDirect API will notify you of the following events via webhooks:
- Deposit initiated
- Deposit cancelled
- Deposit auth_failed
- Deposit expired
- Deposit executing
- Deposit rejected
- Deposit settled
- Deposit executed
- Withdrawal authorised
- Withdrawal submitted
- Withdrawal settled
- Withdrawal rejected
- Withdrawal failed
Check out the details on the overall structure of the webhooks and their payload schemas in the following sections:
Webhook Retry Policy
A webhook is successfully delivered when we receive a success status code (2xx) from the webhook URI that you specified in your Console settings for PayDirect API.
If we receive any other status code (e.g. 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 24 hours waiting approximately 15 minutes between delivery attempts.
Webhook Structure
All webhooks from the PayDirect API are structured in the same way:
In the header you will see the following fields:
Field | Type | Description |
---|---|---|
X-TL-Webhook-Timestamp |
timestamp | Time that the webhook was sent to you. This will be in the following format 2020-05-18T10:17:47Z . |
In the body you will see the following fields:
Field | Type | Description |
---|---|---|
event_type |
string | Describing which event is detailed. |
event_schema_version |
unsigned integer | The version of the event body schema (e.g. 1). |
event_id |
uuid | Unique ID of the event. |
event_body |
object | Containing the object relating to the event. The body schema is specified in the following sections for each event type. |
Validating the webhook signature
The value of the X-TL-Signature
header contains a JSON Web Signature (JWS) with a detached payload. It takes the form {HEADER}..{SIGNATURE}
.
The JWS header contains the following values:
Field | Type | Description |
---|---|---|
alg |
string | The algorithm used to sign the webhook. We currently use the RS256 algorithm. |
jku |
string | The URI of the JSON Web Key Set (JWKS), a hosted page where a list of public keys owned by TrueLayer can be found. |
kid |
string | The ID of the key used to sign the webhook, used to retrieve the correct key from the JWKS. |
iat |
int | The time that the JWS was issued, represented in Unix time (number of seconds since 1970-01-01T00:00:00Z). |
The steps for verifying the signature are as follows:
- Verify the
jku
field in the token header matches the expected value as listed below. If not, the signature should be rejected as invalid.- Sandbox:
https://webhooks.truelayer-sandbox.com/.well-known/jwks
- Production:
https://webhooks.truelayer.com/.well-known/jwks
- Sandbox:
- Use the
jku
value to retrieve the JWKS. This may be cached for some time, but if verification fails the JWKS must be retrieved again to ensure that all keys are up to date. TrueLayer may rotate or revoke keys at any time. - Retrieve the relevant public key by using the
kid
to look up the relevant value from the JWKS. - Use a JWT library to verify the JWS headers combined with the payload (the webhook request body) matches the signature provided in the token. The algorithm used to verify the signature must be that declared in the
alg
header of the JWS.
Deposit Initiated
Deposit Initiated Event
X-TL-Webhook-Timestamp: 2020-05-18T10:17:52Z
{
"event_type": "deposit_initiated",
"event_id": "714040e3-288e-468d-9575-e5116ff0a9fc",
"event_schema_version": 1,
"event_body": {
"client_id": "client-8806da",
"deposit_id": "bd780cca-46a6-4f28-a0e4-d36e4e8c57c2",
"user_id": "8c2f148a-c026-4ce4-8fe4-6afac4f71b6e"
}
}
In the event body you will see the following fields:
Field | Type | Description |
---|---|---|
client_id |
string | A unique string identifying a Client. |
deposit_id |
uuid | Unique ID of the deposit. |
user_id |
uuid | Unique ID of the user. |
Deposit Cancelled
Deposit Cancelled Event
X-TL-Webhook-Timestamp: 2020-05-18T10:17:52Z
{
"event_type": "deposit_cancelled",
"event_id": "714040e3-288e-468d-9575-e5116ff0a9fc",
"event_schema_version": 1,
"event_body": {
"client_id": "client-8806da",
"deposit_id": "bd780cca-46a6-4f28-a0e4-d36e4e8c57c2",
"user_id": "8c2f148a-c026-4ce4-8fe4-6afac4f71b6e"
}
}
In the event body you will see the following fields:
Field | Type | Description |
---|---|---|
client_id |
string | A unique string identifying a Client. |
deposit_id |
uuid | Unique ID of the deposit. |
user_id |
uuid | Unique ID of the user. |
Deposit Auth Failed
Deposit Auth Failed Event
X-TL-Webhook-Timestamp: 2020-05-18T10:17:52Z
{
"event_type": "deposit_auth_failed",
"event_id": "714040e3-288e-468d-9575-e5116ff0a9fc",
"event_schema_version": 1,
"event_body": {
"client_id": "client-8806da",
"deposit_id": "bd780cca-46a6-4f28-a0e4-d36e4e8c57c2",
"user_id": "8c2f148a-c026-4ce4-8fe4-6afac4f71b6e"
}
}
In the event body you will see the following fields:
Field | Type | Description |
---|---|---|
client_id |
string | A unique string identifying a Client. |
deposit_id |
uuid | Unique ID of the deposit. |
user_id |
uuid | Unique ID of the user. |
Deposit Expired
Deposit Expired Event
X-TL-Webhook-Timestamp: 2020-05-18T10:17:52Z
{
"event_type": "deposit_expired",
"event_id": "714040e3-288e-468d-9575-e5116ff0a9fc",
"event_schema_version": 1,
"event_body": {
"client_id": "client-8806da",
"deposit_id": "bd780cca-46a6-4f28-a0e4-d36e4e8c57c2",
"user_id": "8c2f148a-c026-4ce4-8fe4-6afac4f71b6e"
}
}
In the event body you will see the following fields:
Field | Type | Description |
---|---|---|
client_id |
string | A unique string identifying a Client. |
deposit_id |
uuid | Unique ID of the deposit. |
user_id |
uuid | Unique ID of the user. |
Deposit Executing
Deposit Executing Event
X-TL-Webhook-Timestamp: 2020-05-18T10:17:52Z
{
"event_type": "deposit_executing",
"event_id": "714040e3-288e-468d-9575-e5116ff0a9fc",
"event_schema_version": 1,
"event_body": {
"client_id": "client-8806da",
"deposit_id": "bd780cca-46a6-4f28-a0e4-d36e4e8c57c2",
"user_id": "8c2f148a-c026-4ce4-8fe4-6afac4f71b6e"
}
}
In the event body you will see the following fields:
Field | Type | Description |
---|---|---|
client_id |
string | A unique string identifying a Client. |
deposit_id |
uuid | Unique ID of the deposit. |
user_id |
uuid | Unique ID of the user. |
Deposit Rejected
Deposit Rejected Event
X-TL-Webhook-Timestamp: 2020-05-18T10:17:52Z
{
"event_type": "deposit_rejected",
"event_id": "714040e3-288e-468d-9575-e5116ff0a9fc",
"event_schema_version": 1,
"event_body": {
"client_id": "client-8806da",
"deposit_id": "bd780cca-46a6-4f28-a0e4-d36e4e8c57c2",
"user_id": "8c2f148a-c026-4ce4-8fe4-6afac4f71b6e"
}
}
In the event body you will see the following fields:
Field | Type | Description |
---|---|---|
client_id |
string | A unique string identifying a Client. |
deposit_id |
uuid | Unique ID of the deposit. |
user_id |
uuid | Unique ID of the user. |
Deposit Executed
Deposit Executed Event
X-TL-Webhook-Timestamp: 2020-05-18T10:17:52Z
{
"event_type": "deposit_executed",
"event_id": "714040e3-288e-468d-9575-e5116ff0a9fc",
"event_schema_version": 1,
"event_body": {
"client_id": "client-8806da",
"deposit_id": "bd780cca-46a6-4f28-a0e4-d36e4e8c57c2",
"user_id": "8c2f148a-c026-4ce4-8fe4-6afac4f71b6e",
"is_guaranteed": false
}
}
In the event body you will see the following fields:
Field | Type | Description |
---|---|---|
client_id |
string | A unique string identifying a Client. |
deposit_id |
uuid | Unique ID of the deposit. |
user_id |
uuid | Unique ID of the user. |
is_guaranteed |
boolean | Instant guarantee status (see Instant Guarantee). |
Deposit Settled
Deposit Settled Event
X-TL-Webhook-Timestamp: 2020-05-18T10:17:52Z
{
"event_type": "deposit_settled",
"event_id": "33c9fc5b-69d7-4de0-83a9-8177f9af79d2",
"event_schema_version": 1,
"event_body": {
"client_id": "client-8806da",
"transaction_id": "cc328607-e02e-49e2-81c9-5bd044c8f7d7",
"deposit_id": "88e76e9e-811a-4f02-9624-f808c5925bfb",
"user_id": "bec96bf3-788b-4266-92dc-77351b680ac5",
"account_id": "5156e5af-7bf2-49a4-96b3-7fde5ec8ddfe",
"settled_at": "2019-10-01T17:00:00.0000000Z",
"amount_in_minor": 10000,
"currency": "GBP",
"remitter_iban": "GB33BUKB20201555555555",
"remitter_name": "Bob Brown"
}
}
In the event body you will see the following fields:
Field | Type | Description |
---|---|---|
client_id |
string | A unique string identifying a Client. |
transaction_id |
uuid | Unique ID of the transaction. |
deposit_id |
uuid | Unique ID of the deposit. |
user_id |
uuid | Unique ID of the user. |
account_id |
uuid | Unique ID of the user’s account. |
settled_at |
timestamp | The date and time the deposit was settled into the account. |
amount_in_minor |
integer | The amount received in the smallest denomination of the currency of the account. |
currency |
ISO 4217 Currency Code String | The currency the deposit was settled in. |
remitter_iban |
string | The IBAN of the account that sent the funds to the account. |
remitter_name |
string | The name of the account holder that sent the funds to the account. |
Withdrawal Authorised
Withdrawal Authorised Event
X-TL-Webhook-Timestamp: 2020-05-18T10:17:52Z
{
"event_type": "withdrawal_authorised",
"event_id": "33c9fc5b-69d7-4de0-83a9-8177f9af79d2",
"event_schema_version": 1,
"event_body": {
"client_id": "client-8806da",
"transaction_id": "cc328607-e02e-49e2-81c9-5bd044c8f7d7",
"authorised_at": "2019-10-01T17:00:00.0000000Z"
}
}
The event body contains the following fields:
Field | Type | Description |
---|---|---|
client_id |
string | A unique string identifying a Client. |
transaction_id |
uuid | The unique ID of the withdrawal. |
authorised_at |
Timestamp | The date and time that the withdrawal was authorised at. |
Withdrawal Submitted
Withdrawal Submitted Event
X-TL-Webhook-Timestamp: 2020-05-18T10:17:52Z
{
"event_type": "withdrawal_submitted",
"event_id": "33c9fc5b-69d7-4de0-83a9-8177f9af79d2",
"event_schema_version": 1,
"event_body": {
"client_id": "client-8806da",
"transaction_id": "cc328607-e02e-49e2-81c9-5bd044c8f7d7",
"submitted_at": "2019-10-01T17:00:00.0000000Z"
}
}
The event body contains the following fields:
Field | Type | Description |
---|---|---|
client_id |
string | A unique string identifying a Client. |
transaction_id |
uuid | The unique ID of the withdrawal. |
submitted_at |
Timestamp | The date and time that the withdrawal was submitted to the scheme. |
Withdrawal Settled
Withdrawal Settled Event
X-TL-Webhook-Timestamp: 2020-05-18T10:17:52Z
{
"event_type": "withdrawal_settled",
"event_id": "33c9fc5b-69d7-4de0-83a9-8177f9af79d2",
"event_schema_version": 1,
"event_body": {
"client_id": "client-8806da",
"transaction_id": "cc328607-e02e-49e2-81c9-5bd044c8f7d7",
"settled_at": "2019-10-01T17:00:00.0000000Z"
}
}
The event body contains the following fields:
Field | Type | Description |
---|---|---|
client_id |
string | A unique string identifying a Client. |
transaction_id |
uuid | The unique ID of the withdrawal. |
settled_at |
Timestamp | The date and time that the withdrawal was settled into the beneficiary account. |
Withdrawal Rejected
Withdrawal Rejected Event
X-TL-Webhook-Timestamp: 2020-05-18T10:17:52Z
{
"event_type": "withdrawal_rejected",
"event_id": "33c9fc5b-69d7-4de0-83a9-8177f9af79d2",
"event_schema_version": 1,
"event_body": {
"client_id": "client-8806da",
"transaction_id": "cc328607-e02e-49e2-81c9-5bd044c8f7d7",
"rejected_at": "2019-10-01T18:00:00.0000000Z",
"rejection_code": "insufficient_funds",
"rejection_details": "There were not enough funds on the account to authorise the payout."
}
}
The event body contains the following fields:
Field | Type | Description |
---|---|---|
client_id |
string | A unique string identifying a Client. |
transaction_id |
uuid | The unique ID of the withdrawal. |
rejected_at |
Timestamp | The date and time that the withdrawal was rejected. |
rejection_code |
String | The reason the withdrawal was rejected as a machine-parsable enum. A full list of rejection codes can be found in the reference. |
rejection_details |
String | The reason the withdrawal was rejected as a human-friendly description. |
Withdrawal Failed
Withdrawal Failed Event
X-TL-Webhook-Timestamp: 2020-05-18T10:17:52Z
{
"event_type": "withdrawal_failed",
"event_id": "33c9fc5b-69d7-4de0-83a9-8177f9af79d2",
"event_schema_version": 1,
"event_body": {
"client_id": "client-8806da",
"transaction_id": "cc328607-e02e-49e2-81c9-5bd044c8f7d7",
"failed_at": "2019-10-01T18:00:00.0000000Z",
"failure_code": "server_error",
"failure_details": "We encountered a technical issue while processing your payment, please try again later."
}
}
The event body contains the following fields:
Field | Type | Description |
---|---|---|
client_id |
string | A unique string identifying a Client. |
transaction_id |
uuid | The unique ID of the withdrawal. |
failed_at |
Timestamp | The date and time that the withdrawal status moved to failed. |
failure_code |
String | The reason the withdrawal as failed a machine-parsable enum. A full list of failure codes can be found in the reference. |
failure_details |
String | The reason the withdrawal failed as a human-friendly description. |
Withdrawal Rejection Codes
Code | Description |
---|---|
insufficient_funds |
Your account does not have sufficient funds required to make the withdrawal. |
server_error |
We encountered a technical issue when authorising the payment. Please try again later. |
Query User’s Accounts
Request
curl -H "Authorization: Bearer ${access_token}" \
https://paydirect.truelayer-sandbox.com/v1/users/${userId}/accounts
Response
{
"results": [
{
"account_id": "5156e5af-7bf2-49a4-96b3-7fde5ec8ddfe",
"name": "JONAS DOE",
"iban": "GB53CLRB04066200002723"
},
{
"account_id": "77156e5af-7bf2-49a4-96b3-7fde5ec8ddfe",
"name": "JONAS DOE",
"iban": "GB99CLRB04066200002723"
}
]
}
View a list of accounts an end-user has previously deposited from.
Field | Type | Description |
---|---|---|
account_id |
uuid | unique ID of the account. |
name |
string | The name of the account holder. |
iban |
string | The IBAN of the account. |
Query User’s Limits
Request
curl -H "Authorization: Bearer ${access_token}" \
https://paydirect.truelayer-sandbox.com/v1/users/${userId}/limits
Response
{
"result": {
"instant_guarantee_eur": {
"pending_amount_in_minor": 30000,
"available_amount_in_minor": 170000
}
}
}
View a hash-map of limits applicable to a given user. Currently, the only limit object available is for the Instant Guarantee feature.
instant_guarantee_eur
Field | Type | Description |
---|---|---|
pending_amount_in_minor |
integer | Total amount currently guaranteed and pending settlement, for the given user. |
available_amount_in_minor |
integer | Total amount currently available for instant guarantee, for the given user. |
Query Account Balances
Request
curl -H "Authorization: Bearer ${access_token}" \
https://paydirect.truelayer-sandbox.com/v1/balances
Response
{
"results": [
{
"currency": "GBP",
"iban": "GB33BUKB20201555555555",
"status": "enabled",
"current_balance_in_minor": 50000000,
"available_balance_in_minor": 49998000,
"account_owner": "Owner Name"
},
{
"currency": "EUR",
"iban": "FR1420041010050500013M02606",
"status": "disabled",
"current_balance_in_minor": 20000000,
"available_balance_in_minor": 20000000,
"account_owner": "Owner Name"
}
]
}
Field | Type | Description |
---|---|---|
currency |
ISO 4217 Currency Code String | The currency of the account. Accounts can only hold one currency each. |
iban |
string | The IBAN of the account that can be used to send funds to the account. |
status |
string | Denotes whether the account is active or not, the field can be enabled or disabled . |
current_balance_in_minor |
integer | The current balance of the account in the smallest denomination including transactions that are pending or in transit. |
available_balance_in_minor |
integer | The balance available to spend in the smallest denomination. |
account_owner |
string | The name of the account owner. |
Query Transactions
Request
curl -H "Authorization: Bearer ${access_token}" \
https://paydirect.truelayer-sandbox.com/v1/transactions?from="2019-10-01T17:00:00.0000000Z"&to="2019-10-02T17:00:00.0000000Z"&type="payout"¤cy="GBP"
Response
{
"results": [
{
"transaction_id": "cc328607-e02e-49e2-81c9-5bd044c8f7d7",
"type": "payout",
"authorised_at": "2019-10-01T17:00:00.0000000Z",
"submitted_at": "2019-10-01T17:00:00.0000000Z",
"settled_at": "2019-10-01T17:00:00.0000000Z",
"beneficiary_name": "John Smith",
"beneficiary_iban": "GB33BUKB20201555555555",
"beneficiary_reference": "Withdrawal 204",
"amount_in_minor": 10000,
"currency": "GBP",
"context_code": "withdrawal",
"status": "settled"
},
{
"transaction_id": "gg328607-e02e-49e2-81c9-5bd044c8f7d8",
"type": "payout",
"authorised_at": "2019-10-01T15:00:00.0000000Z",
"submitted_at": "2019-10-01T15:00:00.0000000Z",
"settled_at": "2019-10-01T15:00:00.0000000Z",
"beneficiary_name": "Jane Doe",
"beneficiary_iban": "GB43BUKB20201555555555",
"beneficiary_reference": "Withdrawal 205",
"amount_in_minor": 20000,
"currency": "GBP",
"context_code": "withdrawal",
"status": "settled"
}
]
}
The type
field can be used to distinguish between deposits (topup
) and withdrawals (payout
).
Query parameters:
Field | Mandatory | Type | Description |
---|---|---|---|
from |
Mandatory | timestamp | Timestamp as a string for the start of the range you are querying |
to |
Mandatory | timestamp | Timestamp as a string for the end of the range you are querying |
type |
Optional | string | Filter transactions by type, the available types are deposit /topup and withdrawal /payout for deposits and withdrawals respectively. If omitted, both deposits and withdrawals will be returned. |
currency |
Optional | ISO 4217 Currency Code String | Filter transactions by currency. |
Request Signing
All POST requests to PayDirect API have to be signed.
Signing provides a second layer of security on top of the authorization bearer token and guarantees that the payload has not been tampered with.
This section contains all the details you need to be aware of to successfully sign your POST requests to PayDirect API.
Supported algorithms
The only supported signing algorithm for POST requests to PayDirect API is ES512.
Generating certificates
ES512 belongs to the family of Elliptic Curve Digital Signature Algorithms (ECDSA). To sign a POST request using ECDSA you will need to generate an Elliptic Curve (EC) key pair:
- a public key, to be uploaded in the PayDirect Settings page in our Console;
- a private key, to be used for signing requests, which you should not share with anyone outside of your organisation.
ES512, in particular, requires a key pair that use the P-521 family of elliptic curves (also known as secpt521r1
).
Let’s see how we can generate such a key pair using openssl
.
To generate the private key, run:
openssl ecparam -genkey -name secp521r1 -noout -out ec512-private-key.pem
You can then obtain the public key running:
openssl ec -in ec512-private-key.pem -pubout -out ec512-public-key.pem
ec512-public-key.pem
is the file you should upload in the PayDirect Settings page in our Console.
Inspecting certificates
You can inspect the generated public key using:
openssl ec -inform PEM -pubin -in ec512-public-key.pem -text -noout
You can inspect the generated private key using:
openssl ec -inform PEM -in ec512-private-key.pem -text -noout
Signing a POST request
JOSE Header
{
"alg": "ES512",
"kid": "9f2b7bd6-c055-40b5-b616-120ccfd33c49"
}
Detached Payload
{
"transaction_id": "<UUID>",
"beneficiary_name": "A person",
"beneficiary_iban": "GB17CLRB04066800000072",
"beneficiary_reference": "Sandbox",
"currency": "GBP",
"amount_in_minor": 1,
"context_code": "withdrawal"
}
You need to specify a X-Tl-Signature
header in your POST request.
The header value is a JWS with detached content, signed using the ES512 algorithm.
A JWS with detached content has the following structure:
<Base64URLSafeEncoding(JOSEHeader)>..<Base64URLSafeEncoding(signature)>
As you can see, the payload segment is omitted (but it is necessary to generate the signature!).
The JOSE header must contain:
- The
alg
header parameter withES512
as value; - The
kid
header parameter, with the id of the certificate used for signing as value (i.e. the UUID value shown in the PayDirect Settings in Console next to your uploaded public certificate).
The JWS payload should be the serialised HTTP request body.
Code examples can be found on GitHub.
Testing your signing logic
Request
curl -X POST \
-H "Authorization: Bearer ${access_token}" \
-H "X-TL-Signature: ${signature}" \
--data '{
"nonce": "9f952b2e-1675-4be8-bb39-6f4343803c2f",
}' \
https://paydirect.truelayer-sandbox.com/v1/test
Response (HTTP 200)
You can send a POST request to our /test
endpoint to verify that you have correctly implemented request signing.
The /test
endpoint will validate your X-TL-Signature
header and return a 200 OK
in case of success, it does not perform any kind of validation on the body schema.
Set up or update automated account sweeping
Request
curl -X POST \
-H "Authorization: Bearer $access_token" \
-H "X-TL-Signature: $signature" \
--data '{
"currency": "GBP",
"max_amount_in_minor": 100000,
"frequency": "daily"
}' \
https://paydirect.truelayer-sandbox.com/v1/sweep
Set up automated sweeping for a given currency
. At regular intervals, any available balance in excess of the configured max_amount_in_minor
is withdrawn to a pre-configured IBAN. The default time interval for automated sweeping is daily
.
By default, automated sweeping is not enabled.
You can update your sweep configurations (such as changing the frequency
or max_amount_in_minor
) by making a POST /v1/sweep
call with the updated values. We will use the latest value for a given currency.
Note: This API will be unavailable until KYC onboarding has completed.
Field | Mandatory | Type | Description |
---|---|---|---|
currency |
Mandatory | string | ISO 4217 Currency Code of the account sweep source. |
max_amount_in_minor |
Mandatory | number | The desired maximum amount, specified in terms of the fractional monetary unit of the payment currency, above which funds will be automatically withdrawn. |
frequency |
Optional | string | How often the available balance will be checked for sweeping, daily , weekly or fortnightly , defaults to daily . |
Get automated account sweeping details
Request
curl -H "Authorization: Bearer $access_token" https://paydirect.truelayer-sandbox.com/v1/sweep
Response
{
"results": [
{
"currency": "GBP",
"max_amount_in_minor": 100000,
"iban": "GB43BUKB20201666666666",
"frequency": "daily"
}
]
}
You can obtain all current automated sweeping configurations by making a GET /v1/sweep
call. If you haven’t enabled automated sweeping, you’ll get a 404 error in the response.
Field | Type | Description |
---|---|---|
currency |
ISO 4217 Currency Code String | Currency of the account sweep source. |
max_amount_in_minor |
number | The desired maximum amount, specified in terms of the fractional monetary unit of the payment currency, above which funds will be automatically withdrawn. |
iban |
string | The IBAN of the target account that funds will be withdrawn into. Pre-configured & validated as part of KYC onboarding. |
frequency |
string | How often the available balance will be checked for sweeping. |
Disable automated account sweeping
Request
curl -X POST \
-H "Authorization: Bearer $access_token" \
-H "X-TL-Signature: $signature" \
--data '{"currency": "GBP"}' \
https://paydirect.truelayer-sandbox.com/v1/sweep/remove
Disable automated sweeping for a given currency
.
Field | Mandatory | Type | Description |
---|---|---|---|
currency |
Mandatory | ISO 4217 Currency Code String | Currency of the account sweep source. |
Mock Providers
The providers endpoint in the sandbox environment includes three mock providers which can be used for testing your integration with our API.
1. Mock UK Deposits - Redirect Flow
Data returned from providers endpoint
{
"provider_id": "mock-payments-gb-redirect",
"logo_url": "",
"icon_url": "",
"display_name": "Mock UK Payments - Redirect Flow",
"country": "GB",
"divisions": [
"retail"
],
"deposit_schemes": [
{
"scheme_id": "faster_payments_service",
"requirements": [
...
]
}
]
}
Mock UK Deposits - Redirect Flow simulates UK banks that use the redirect authorisation flow.
When you initiate a deposit using this provider, we will return a URI to redirect your user to our mock provider authorisation page.
On the authorisation prompt page, different actions lead to different outcome for the deposit. The following table describes the different actions you can make on the authorisation page and their outcomes:
Outcome | Action | Username |
---|---|---|
Execute | Enter username | test_executed |
Auth failure | Enter username | test_authorisation_failed |
Execution Rejection | Enter username | test_execution_rejected |
Cancellation | Click cancel button | - |
Once you log in, you will see the mock account selection page:
When you provide the remitter account details in the deposit request, only the stated account can be selected on this screen.
2. Mock European Deposits – Redirect Flow
Data returned from providers endpoint
{
"provider_id": "mock-payments-es-redirect",
"logo_url": "",
"icon_url": "",
"display_name": "Mock European Payments – Redirect Flow",
"country": "ES",
"divisions": [
"retail"
],
"deposit_schemes": [
{
"scheme_id": "sepa_credit_transfer",
"requirements": [
...
]
},
{
"scheme_id": "sepa_credit_transfer_instant",
"fee_options": [
{
"fee_option_id": "sepa_credit_transfer_instant_fee",
"beneficiary_fee": "free",
"remitter_fee": "payable"
}
],
"requirements": [
...
]
}
]
}
Mock European Deposits – Redirect Flow represents the typical redirect authorisation flow used by a bank in Europe.
Even though the country code in the provider_id
is currently es
, the functionality can be assumed to be equivalent to the other redirect flow banks that can be found in the European region. Hence this bank can be used to test any redirect flow for the European banks.
When you initiate a deposit using this provider, we will return a URI to redirect your user to our mock provider authorisation page.
Different actions on this page will lead to different outcomes for the deposit. The following table describes the different actions you can make on the authorisation page and their outcomes:
Outcome | Action | Username |
---|---|---|
Execute | Enter username | test_executed |
Auth failure | Enter username | test_authorisation_failed |
Execution Rejection | Enter username | test_execution_rejected |
Cancellation | Click cancel button | - |
Once you log in, you will see the mock account selection page:
If you provide the remitter account details in the deposit initiation request, you can only select the account with those details on this screen.
3. Mock European Deposits – Embedded Flow
Data returned from providers endpoint
{
"provider_id": "mock-payments-de-embedded",
"logo_url": "",
"icon_url": "",
"display_name": "Mock European Payments – Embedded Flow",
"country": "DE",
"divisions": [
"retail"
],
"deposit_schemes": [
{
"scheme_id": "sepa_credit_transfer",
"requirements": [
...
]
},
{
"scheme_id": "sepa_credit_transfer_instant",
"fee_options": [
{
"fee_option_id": "beneficiary_pays",
"beneficiary_fee": "payable",
"remitter_fee": "free"
},
{
"fee_option_id": "remitter_pays",
"beneficiary_fee": "free",
"remitter_fee": "payable"
}
],
"requirements": [
...
]
}
]
}
Mock European Deposits – Embedded Flow provider represents European banks that use the embedded authorisation flow.
More information about the flows can be found in the common concepts section.
This mock provider only provides the embedded input flow and no UI elements. As can be seen in the providers response object, this bank requires the additional inputs psu-id and psu-password.
The expected value for psu-id is test_username
.
The expected value for psu-password is test_password
.
Anything other than these values will lead to rejection by the mock provider.
Once you initiate the deposit with this mock provider will ask for SCA method with a select type input.
There are two value options.
- SMS
- PhotoTAN
Following the submission of the input value to this embedded step, you will be required to enter a text input (For PhotoTAN, our API will provide an image, however this image does not play any role in how the flow continues.)
Different values to this input will lead to different outcomes for the deposit.
The input values required for certain outcomes are the same for SMS
and PhotoTAN
options.
The inputs and related outcomes can be seen in the following table:
Outcome | Input Value |
---|---|
Execute | test_executed |
Auth failure | test_authorisation_failed |
Execution Rejection | test_execution_rejected |
If you use any other value than what is presented in the table, it will result in authorisation failure.
To test the cancellation scenario, use the cancel embedded step instead.
Payouts Quickstart
Our quickstart guide to payouts introduces verifying and paying out to an account in TrueLayer’s sandbox environment, leveraging TrueLayer’s Verification API and PayDirect API capabilities.
Setup console in sandbox
Sign up to the TrueLayer developer console to get your client_id
and client_secret
. The Data API is enabled for all clients by default. Make sure you have
enabled the PayDirect API product capabilities for your test application in sandbox. You can do
so by navigating to the PayDirect API page in the console
and following four simple steps to get setup in no time.
You can find guidance on certificate generation and examples of request signing in our GitHub.
Insomnia setup
We offer the Insomnia collections for our Verification API and PayDirect API as a helper to make
these requests. POST
requests to the PayDirect API have to be
signed and we have written an Insomnia plugin to help make initial
exploration of our APIs easier.
Follow our guide to setup Insomnia with our Verificaton API collection and PayDirect API collection. It contains sample requests so that you can start using the APIs straightaway.
First payout to an account
Verifying an account – generate a test authentication page
First, we generate a test authentication link. This creates an authentication page where a user can authenticate with their bank, which in turn will give your application permissions to view information about their bank account.
The following steps happen in the Auth Link Builder of our developer console:
In the Providers tab, make sure Mock is selected. This is the mock bank used in our sandbox for test purposes.
In the Permissions tab, make sure
info
andaccounts
are selected. These scopes are required for account verification.Make sure the URI selected in the “Redirect URIs” tab is allow-listed in the App settings section of the console.
Finally click the Preview your Auth Dialog button (eye-shaped icon) to test your auth page.
Select Mock Bank and use the following details when asked for input–this is a user within our sandbox mock bank:
- Username:
john
- Password:
doe
- Username:
You will now get a code which you can exchange for an access token to verify the accounts belonging to “john doe”.
Exchange the code for an API access token
Using the code
from the previous step, call the Authentication API to get an access token which
allows you to read details about the user’s account. This is the Exchange Code request in the
Insomnia collection.
Exchange Code for Access Token
export CLIENT_ID="your-client-id"
export CLIENT_SECRET="your-client-secret"
export CALLBACK_URI="your redirect uri"
export CODE="your-code"
curl -X POST -H "Content-Type: application/x-www-form-urlencoded" \
"https://auth.truelayer-sandbox.com/connect/token" \
--data-urlencode "grant_type=authorization_code" \
--data-urlencode "client_id=${CLIENT_ID}" \
--data-urlencode "client_secret=${CLIENT_SECRET}" \
--data-urlencode "redirect_uri=${CALLBACK_URI}" \
--data-urlencode "code=${CODE}"
Response
{
"access_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6IjE0NTk4OUIwNTdDOUMzMzg0MDc4MDBBOEJBNkNCOUZFQjMzRTk1MTBSUzI1NiIsInR5cCI6ImF0K2p3dCIsIng1dCI6IkZGbUpzRmZKd3poQWVBQ291bXk1X3JNLWxSQSJ9.eyJuYmYiOjE2MTUzODg2ODEsImV4cCI6MTYxNTM5MjI4MSwiaXNzIjoiaHR0cHM6Ly9hdXRoLnRydWVsYXllci",
"expires_in": 3600,
"token_type": "Bearer",
"refresh_token": "B921073229D5B520F47EC1D8970982D77C8BAA06B818C357D281",
"scope": "info accounts"
}
This access token will allow you to verify the user’s account and will be valid for one hour.
Verify the user
We can now call the Verification API to verify the user, using the access_token
from the previous
step.
Verify Account Holder
curl -X POST -H "Authorization: Bearer ${access_token}" \
-H "Content-Type: application/json" \
"https://verification.truelayer-sandbox.com/v1/verification/" \
-d '{"name": "John Doe"}'
Response
{
"verified": true,
"account_holder_name": "John Doe",
"match_score": 100,
"report": [
{
"verifiable": true,
"currency": "GBP",
"provider_id": "mock",
"account_type": "CURRENT",
"account_holders": [
{
"name": "John Doe",
"verified": true,
"match_score": 100
}
],
"display_name": "TRANSACTION ACCOUNT 1",
"iban": "GB08CLRB04066800003435",
"swift_bic": "CPBKGB00",
"account_number": "10000000",
"sort_code": "01-21-31"
},
...
]
}
In the response from the Verification API, the "verfied": true
field means that the given account
belongs indeed to someone named “John Doe”. There are also details of the user’s account–we will
use the iban
field as the beneficiary IBAN when creating a payout in the next step.
Get PayDirect access token
You must provide a valid Bearer
access token when calling the PayDirect API. It will be used to
authenticate your application before initiating the payout.
Use your client_id
and client_secret
to generate an access token, which you will have to include
within the Bearer
token header in future requests. We have a “Generate PayDirect Token” Insomnia
request for this.
Generate PayDirect Token
curl -X POST \
-d grant_type=client_credentials \
-d client_id=${client_id} \
-d client_secret=${client_secret} \
-d scope=paydirect \
https://auth.truelayer-sandbox.com/connect/token
Response
{
"access_token": "JWT-ACCESS-TOKEN-HERE",
"expires_in": 3600,
"token_type": "Bearer",
"scope": "paydirect payments"
}
Payout to the user’s account
We can then use the POST /v1/withdrawals
endpoint in the PayDirect API to initiate a payout to the
user’s account using the iban
as the beneficiary IBAN. Read more about the concept of open loop
withdrawal in the PayDirect API reference.
Create Withdrawal
curl -X POST \
-H "Authorization: Bearer ${access_token}" \
-H "X-TL-Signature: ${signature}" \
--data '{
"transaction_id": "<UUID>"
"beneficiary_name": "John Doe",
"beneficiary_iban": "GB08CLRB04066800003435",
"beneficiary_reference": "Payouts Quickstart",
"currency": "GBP",
"amount_in_minor": 10,
"context_code": "withdrawal"
}' \
https://paydirect.truelayer-sandbox.com/v1/withdrawals
We can query the status using the GET v1/withdrawals/<transaction_id>
endpoint.
Get Withdrawal
curl -H "Authorization: Bearer ${access_token}" \
https://paydirect.truelayer-sandbox.com/v1/withdrawals/{transaction_id}
Response
{
"result": {
"transaction_id": "4cee2e78-4213-4a83-8ef7-50b5207e5eaf",
"authorised_at": "2021-09-09T16:54:18.051837Z",
"submitted_at": "2021-09-09T16:54:18.431168Z",
"settled_at": "2021-09-09T16:54:20.117Z",
"rejected_at": null,
"failed_at": null,
"beneficiary_name": "John Doe",
"beneficiary_iban": "GB08CLRB04066800003435",
"beneficiary_reference": "Payouts Quickstart",
"amount_in_minor": 1,
"currency": "GBP",
"status": "settled",
"context_code": "withdrawal"
}
}
Once the status reaches settled
, you have effectively made your first payout!
Payout to a verified account
Once you’ve already verified a user’s account, you don’t have to run through the verification steps again, unless the user wants to use a different bank account, in which case you can follow the instructions to make a Payout to an account for the first time again.
Providing that you have already verified a user’s bank account and you have saved their details in your system, you simply need to get an access token and initiate a new Payout using their IBAN. We call this an open loop withdrawal in the PayDirect API.
Create Withdrawal
curl -X POST \
-H "Authorization: Bearer ${access_token}" \
-H "X-TL-Signature: ${signature}" \
--data '{
"transaction_id": "<UUID>"
"beneficiary_name": "John Doe",
"beneficiary_iban": "GB08CLRB04066800003435",
"beneficiary_reference": "Payouts Quickstart",
"currency": "GBP",
"amount_in_minor": 10,
"context_code": "withdrawal"
}' \
https://paydirect.truelayer-sandbox.com/v1/withdrawals
We can query the status using the GET v1/withdrawals/<transaction_id>
endpoint.
Get Withdrawal
curl -H "Authorization: Bearer ${access_token}" \
https://paydirect.truelayer-sandbox.com/v1/withdrawals/{transaction_id}
Response
{
"result": {
"transaction_id": "4cee2e78-4213-4a83-8ef7-50b5207e5eaf",
"authorised_at": "2021-09-09T16:54:18.051837Z",
"submitted_at": "2021-09-09T16:54:18.431168Z",
"settled_at": "2021-09-09T16:54:20.117Z",
"rejected_at": null,
"failed_at": null,
"beneficiary_name": "John Doe",
"beneficiary_iban": "GB08CLRB04066800003435",
"beneficiary_reference": "Payouts Quickstart",
"amount_in_minor": 1,
"currency": "GBP",
"status": "settled",
"context_code": "withdrawal"
}
}
Go live
Check out the full guides on the Verification API and PayDirect API for more information.
Status API v1
Status API Overview
The Status API exposes the availability and error rates of the TrueLayer Data API, Payments API and Payouts API in JSON format.
The returned error rates are broken down by provider and by internal/external error (i.e. TrueLayer or provider error). You can, therefore, use them to determine whether a certain product is offering degraded service or we are experiencing difficulty contacting a third party reliably and are still offering a good service with other providers.
Please note that we calculate availability as percentage of total requests within a given hour that completed successfully. Consequently when there have not been sufficient requests we cannot calculate availability; you may notice this particularly if requesting the status of a product, provider or country that is in beta.
You can see the Status API in action in the TrueLayer Status page.
For updates on availability of our services you can subscribe to our TrueLayer Status Twitter feed.
Status API Reference
Query TrueLayer status
Request
curl "https://status-api.truelayer.com/api/v1/data/status?\
from=2019-06-20T12:00:00&to=2019-06-20T13:00:00&providers=ob-barclays,ob-monzo\
&endpoints=accounts"
Response
{
"status": "ok",
"results": [
{
"timestamp": "2019-06-20T12:00:00.0000000",
"providers": [
{
"provider_id": "barclays",
"endpoints": [
{
"endpoint": "accounts",
"availability": 93.68421052631578,
"provider_error": 3.1578947368421053,
"truelayer_error": 3.1578947368421053,
"latency_percentiles": {
"50": 15,
"75": 74,
"90": 78.2,
"95": 140,
"99": 1401.5,
}
}
],
"availability": 93.68421052631578,
"provider_error": 3.1578947368421053,
"truelayer_error": 3.1578947368421053
},
{
"provider_id": "oauth-monzo",
"endpoints": [
{
"endpoint": "accounts",
"availability": 100,
"provider_error": 0,
"truelayer_error": 0,
"latency_percentiles": {
"50": 17,
"75": 74.3,
"90": 73.2,
"95": 240,
"99": 1401.5,
}
}
],
"availability": 100,
"provider_error": 0,
"truelayer_error": 0
}
],
"availability": 94.39252336448598,
"provider_error": 2.803738317757009,
"truelayer_error": 2.803738317757009
}
]
}
GET requests to /{product}/status
retrieve the status of one of our products grouped by hour
, provider
and endpoint
. product
must be one of:
Name | Function |
---|---|
auth |
Connecting to (or reauthenticating) an account using our Data API |
data |
Retrieving data from a connected account through our Data API |
payments |
Initiating a payment with our Payments API |
payouts |
Initiating a payout from our Payouts API (only sandbox availability) |
Parameters
Below is a list of optional query string parameters to use when calling the status-api.
Name | Example | Description |
---|---|---|
from |
from=2019-01-07T10:00:00 |
A timestamp that specifies the date and time data should be fetched from. This defaults to 24 hours. Results are rounded down to the nearest hour. |
to |
to=2019-01-07T14:00:00 |
A timestamp that specifies the date and time data should be fetched until. This defaults the current time. Results are rounded down to the nearest hour. |
providers |
providers=hsbc,oauth-monzo,ob-barclays |
A comma-separated list of providers, only data related to the supplied providers will be returned |
endpoints |
endpoints=accounts,info |
A comma-separated list of endpoints, only data related to the supplied endpoints will be returned |
environment |
environment=sandbox |
A string that specifies the desired environment from which to fetch availability. Can be sandbox or production . Defaults to production |
Response
Name | Description |
---|---|
results |
A JSON array containing data bucket objects |
provider_id |
A string containing the provider id |
timestamp |
The start of a one-hour time bucket |
endpoints |
A comma-separated list of endpoints, only data related to the supplied endpoints will be returned |
latency_percentiles |
A dictionary with percentiles as keys and latencies as values (in milliseconds). For example, a latency of 128 milliseconds on the 50th percentiles means that half of the requests directed to that endpoint completed in 128 milliseconds or less. |
availability |
The percentage of successful requests for a provider’s endpoint represented as a float value between 0-100 |
provider_error |
The percentage of unsuccessful requests (that we know are on the provider side) for a provider’s endpoint represented as a float value between 0-100 |
truelayer_error |
The percentage of unsuccessful requests (due to TrueLayer) for a provider’s endpoint represented as a float value between 0-100 |
Check the providers and endpoints supported here.
Status API Changelog
Updates made to the Status API will be posted here with the release date.
October 13, 2020
Release notes:
- Payouts API availability added
- Querying by environment added
August 12, 2020
Release notes:
- Payments API added
January 5, 2019
Initial release:
- Data API availability
- Access to last seven days of availability
Verification API v1
Overview
The Verification API can be used to verify a user’s bank account and return the associated bank details.
How it works
- The user gives consent for you to access their bank data.
- They are redirected to their bank to authenticate, then sent back to your app.
- To request verification, send the user’s name to the Verification API.
- We compare the identity data to the account holder’s name for all the connected account(s) the user has given consent for.
- The result of the comparison along with its
match_score
is returned.
Coverage
We offer the Verification API in the UK, France, Germany, and Spain in public beta.We can only support Open Banking providers that return account holder names.
Learn more about the account holder name format that is returned for each bank.
Connecting An Account
Before accessing any bank data, users must connect their account to your application.
To authenticate a user you will need to:
- Specify the data you’d like the user to share.
- Ask the user to select their provider (bank).
- Collect the user’s consent to share that data.
- Send the user to their mobile banking app or online banking where they’ll select the account(s) they’d like to connect. Note that they can choose more than one.
- Intercept the user upon their return from their online/mobile banking and exchange a one-time code for an access token.
We manage this entire flow for you as well as providing APIs if you’d like to implement certain parts within your app or website. Regulated clients can manage this entire flow via APIs such that the user never interacts with a TrueLayer UI.
Once you have an access token, you can use this to authenticate requests to the Verification API.
Verification API Guide
Sandbox environment
Step 1 - Sign up
- Sign up to the TrueLayer Console to get your Sandbox
client_id
andclient_secret
. - Install Postman and download our Sandbox Postman collection. It contains sample requests so that you can quickly retrieve data, and generate code snippets in various languages of your choice. It also has our Sandbox environment endpoints preconfigured.
Step 2 - Authorise a user
Create a test authentication link to authenticate users via the Auth Link Builder in our Console. With the test auth link, you can easily connect to our mock bank.
To create your test auth link:
- Select the set of Permissions with
info
andaccount
scopes to include in the authentication link. - Choose a Redirect URI where the user will be redirected after authenticating.
- Check that the Mock provider is enabled to use our mock bank user credentials for testing.
- Select Test to open the generated test auth link and connect to our mock bank.
- To get an exchange code, select Mock Bank and fill in the following when asked for credentials:
- First name: john
- Last name: doe
Step 3 - Obtain an access token
Use the Postman Exchange Code request in the Authentication folder to exchange the generated code
into an access_token
. To do so:
- Add the missing variables:
client_id
: Your sandboxclient_id
. You can find this value in your console.client_secret
: Your sandboxclient_secret
. You can find this value in your console.code
: Thecode
that you generated in Step 2 with a link to the step we’re referring to here.
- Send the request and retrieve a response containing an
access_token
andrefresh_token
.
Step 4 - Access data
With the access_token
, run any of the requests in the Sandbox Postman collection to verify an account holder name.
Live environment
Generate Verification authentication link
Sample Auth-Link
https://auth.truelayer.com/?response_type=code&client_id=<your_client_id>&redirect_uri=<your_redirect_URI>&scope=info accounts&providers=uk-ob-monzo uk-ob-hsbc uk-oauth-all
To get started, you need to generate an Authentication Link. You’ll need the accounts
and info
scopes to access the service. Once authentication link is generated, you need to whitelist your redirect uri’s in the App Settings in the console.
Your users can connect their account(s) to your app with the auth link. The link takes them to our auth dialogue where we collect consent from a user before sending them on to their respective provider.
Note that authentication links require JavaScript so that they can function in web browsers.
The following example shows what an auth link looks like:
Generate access token
Sample Redirect URI
curl --location --request GET '<your_redirect_uri>?code=<users_unique_code>&scope=info%20accounts'
The user opens the auth link in their browser via the client app or browser and follows the steps detailed to link their bank account(s). Once they have connected their bank account(s), make the following call to the Redirect URI with the scope
and code
. You can also use our Postman collection to make the following requests.
Generate Access Token
export CLIENT_ID="your-client-id"
export CLIENT_SECRET="your-client-secret"
export CALLBACK_URI="your redirect uri"
export CODE="your-code"
curl --location --request POST 'https://auth.truelayer.com/connect/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'grant_type=authorization_code' \
--data-urlencode 'client_id=$CLIENT_ID' \
--data-urlencode 'client_secret=$CLIENT_SECRET' \
--data-urlencode 'redirect_uri=$CALLBACK_URI' \
--data-urlencode 'code=$CODE'
The client can then use this user-specific code to generate a user-specific access_token
using the following API call.
Response
{
"access_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6IjE0NTk4OUIwNTdDOUMzMzg0MDc4MDBBOEJBNkNCOUZFQjMzRTk1MTBSUzI1NiIsInR5cCI6ImF0K2p3dCIsIng1dCI6IkZGbUpzRmZKd3poQWVBQ291bXk1X3JNLWxSQSJ9.eyJuYmYiOjE2MTUzODg2ODEsImV4cCI6MTYxNTM5MjI4MSwiaXNzIjoiaHR0cHM6Ly9hdXRoLnRydWVsYXllci",
"expires_in": 3600,
"token_type": "Bearer",
"refresh_token": "B921073229D5B520F47EC1D8970982D77C8BAA06B818C357D281",
"scope": "info accounts"
}
You get an access_token
in the response. You can use this token to authenticate calls to the Verification API. This token lasts for up to one hour.
Once you have the access_token
, use our Postman collection to test Verification API.
Verification API Reference
Common headers
Request Headers
Header | Value |
---|---|
Authorization |
Bearer <ACCESS_TOKEN> |
X-Client-Correlation-Id |
Optional client-set correlation Id. We do not return this in response headers |
X-PSU-IP |
The PSU’s IP address to be passed on to the bank in order to avoid rate limiting. (see End-user IP Address) |
Response Headers
Header | Value |
---|---|
X-TL-Correlation-Id |
Unique Id per request - we recommend logging this and always sharing it with our client-care team when opening incident tickets |
X-Credentials-Id |
CredentialsId of the access token used |
Cache-Control |
no-store |
Content-Encoding |
gzip |
Content-Type |
application/json; charset=utf-8 |
Date |
Date and time the message was sent |
Content-Security-Policy |
default-src 'none'; frame-ancestors 'none'; |
X-Content-Type-Options |
nosniff |
X-Frame-Options |
deny |
X-XSS-Protection |
1; mode=block |
Referrer-Policy |
no-referrer |
Verify account holder name
Returns the result of comparison with the account holder name(s) returned by the bank. This would be authorised by the end-user during the authentication and consent flow.
Request
Request
export ACCESS_TOKEN="users-access-token"
export name="Will Johnson"
curl --location --request POST 'https://verification.truelayer.com/v1/verification' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer $ACCESS_TOKEN' \
--data-raw '{"name": "'"$name"'"}'
Field | Type | Description | |
---|---|---|---|
name |
string | Name that needs to be verified with an account |
Response
Response
{
"verified": true,
"account_holder_name": "William Johnson",
"match_score": 89,
"report": [
{
"verifiable": true,
"currency": "GBP",
"provider_id": "ob-monzo",
"account_type": "CURRENT",
"account_holders": [
{
"name": "William Johnson",
"verified": true,
"match_score": 89
}
],
"display_name": "1st Account",
"iban": "GB70MONZ03952941110044",
"swift_bic": "MONZGB26",
"account_number": "53920022",
"sort_code": "04-11-34"
},
{
"verifiable": false,
"failure_description": "Credit cards cannot be verified by this service.",
"failure_code": "CREDIT_CARD",
"provider_id": "ob-monzo",
"account_type": "CREDIT_CARD",
"display_name": "Gold card"
}
]
}
Field | Type | Description |
---|---|---|
verifiable |
bool | A boolean that describes if a user’s account is verifiable or not. If true, then the account is a verifiable CURRENT or SAVINGS account. We can only verify accounts that either have an IBAN or have an account number and a sort code. |
verified |
bool | Indicates whether there is a successful match. |
match_score |
integer | Score from 0 to 100 indicating confidence that provided and retrieved names refer to the same entity. |
currency |
string | Associated currency of the account. |
account_holder_name |
array | The name of the account holder returned by the bank. One account may have multiple account holders. For example, a joint bank account. |
provider_id |
string | The name of the bank. |
iban |
string | Account’s IBAN number. |
swift_bic |
string | Swift code of account. |
account_number |
string | The account number. |
sort_code |
string | Sort code of account. |
failure_description |
string | Describes the reason for failure. |
failure_code |
string | Machine-readable code. |
account_type |
string | Type of the account returned by the bank. |
display_name |
string | Name of the account returned by the bank. |
Verification API Errors
Our endpoint returns a Problem JSON on client usage errors (4xx status codes) as well as server side processing errors (5xx status codes).
RFC 7807 defines a Problem JSON object using the media type application/problem+json
. It provides extensible human and machine-readable failure information beyond the HTTP response status code. The information includes details such as the kind of failure (type / title) and its cause and location (instance / detail). The following table describes the fields we return:
Field | Required | Description |
---|---|---|
type |
Yes | An absolute URI that identifies the problem type. When dereferenced, it provides human-readable documentation for the problem type (for example, using HTML). |
title |
Yes | A short summary of the problem type. Written in English and readable for engineers. |
status |
Yes | The HTTP status code generated by the origin server for this occurrence of the problem. |
trace_id |
Yes | Extension. The TrueLayer trace identifier for the request |
detail |
No | A human-readable explanation specific to this occurrence of the problem. |
instance |
No | An absolute URI that identifies the specific occurrence of the problem. |
Verification API Error Codes
The following error codes can be returned with the associated HTTP status.
HTTP Status | Description | Error Code | Retry | How to handle |
---|---|---|---|---|
200 |
Success | |||
400 |
The supplied parameters are not valid. | validation_error |
Yes | There’s a problem with the request. Read the error message which explains what’s wrong with the request specifically. |
400 |
The provider has been deprecated. | deprecated_provider |
No | The provider has been deprecated. It is no longer supported. |
401 |
The credentials or token are no longer valid | unauthorized |
No | Refresh your access token. The access token may be invalid or expired. You can check for more details in the error description. |
401 |
The token is no longer valid | invalid_token |
No | Refresh your access token. The access token may be invalid or expired. You can check for more details in the error description. |
403 |
Access to a specific resource has been denied. | access_denied |
No | Ask the user to reconnect their account. This error is returned when the access to their account is no longer valid, either because it expired or because the user revoked it themselves. |
403 |
The provided credentials encryption key is invalid. | invalid_credentials_key |
||
403 |
SCA exemption has expired. This resource is protected and should be accessed shortly after PSU Authentication. In order to access this resource, please have the PSU re-authenticate. | sca_exceeded |
No | The access to that specific endpoint has expired. For example, for some European banks you may only access the /info endpoint, or transanctions older than 90 days, during the 5 minutes after the user first grants access. Access to other data (balances, recent transactions) should still be working. |
404 |
The requested account cannot be found. | account_not_found |
No | Check the accountId parameter used within your request. Confirm this matches an accountId returned from /accounts endpoint. |
429 |
Provider rate limit exceeded. | provider_too_many_requests |
Yes | Include the X-PSU-IP header or retry later. Requests exceed the bank’s rate limit. |
429 |
Maximum number of requests per user allowed by provider exceeded. | provider_request_limit_exceeded |
Yes | Include the X-PSU-IP header or retry later. The bank has a regulatory limit on how often the account can be accessed (for example, many European banks have a limit of 4 requests for a given user per endpoint per day, unless the user has initiated the request). |
500 |
Internal server error. | internal_server_error |
Yes | Retry later. |
501 |
Feature not supported by the provider. | endpoint_not_supported |
No | Check supported endpoints for each provider via our Help Desk FAQ. |
503 |
The provider service is unavailable. | provider_error |
Yes | Retry later - the bank is currently undergoing maintenance. |
503 |
The connector service is currently overloaded. | connector_overload |
Yes | Retry later - TrueLayer is currently overloaded. |
503 |
The provider service is unavailable. | temporarily_unavailable |
Yes | Retry later - the bank is experiencing unexpected downtime. |
504 |
The provider service timed out. | provider_timeout |
Yes | Retry later - the bank is experiencing issues. |
504 |
The connector service timed out. | connector_timeout |
Yes | Retry later - TrueLayer is experiencing a transient issue. |