curl

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:

  1. Data API - instant access to financial data
  2. Payments API - instant payment initiation
  3. PayDirect API - instant verification, deposits, and withdrawals
  4. 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

  1. Sign-up and obtain your client_id and client_secret. You will need to register at least one redirect_uri.
  2. Create an Authentication Link to authenticate your End users
  3. Obtain an access_token following the End user Authentication oAuth 2.0 flow
  4. Use the Data API to retrieve End user’s personal information, account numbers and transaction data.

Getting started with the Payments API

  1. Sign-up in the sandbox environment and obtain your client_id and client_secret. You will need to register at least one redirect_uri.
  2. Create a client credentials grant to get a token to call the API.
  3. 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

  1. Sign up in the sandbox environment and obtain your client_id and client_secret. You will need to register at least one redirect_uri.
  2. Go to the PayDirect section of the sandbox console.
  3. Select the request access button and wait for the email confirmation.
  4. Configure your webhook_uri and public certificate in the settings.
  5. Create a client credentials grant to get a token to call the API.
  6. Use the PayDirect API to create deposits and withdrawals, and verify account ownership.

Getting started with the Verification API

  1. Choose the providers you want to integrate with. Verification API is avaliable in the UK, France, Germany, and Spain in public beta.
  2. Implement the authentication flow detailed in the Connecting an account guide and:
    1. Set the scopes field to ["info", "accounts"] only.
    2. Set the providers field according to your needs.
  3. Contact Support with your client_id so that we can enable your access.
  4. Generate an auth link and whitelist your redirect uri’s in the App Settings in the console.
  5. Generate an access token.
  6. 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:

  1. Via your Console. You must be logged into the correct account to view them.
  2. 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:

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:

Non-regulated customers must use TrueLayer’s flow, which is customisable to fit seamlessly into your application.

Authentication features:

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:

  1. 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.
  2. 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 this access_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

  1. Sign up to the TrueLayer Console to get your Sandbox client_id and client_secret.
  2. 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:

  1. 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.
  2. You must also choose a Redirect URI where the user will be redirected after authenticating.
  3. Make sure the Mock provider is enabled so that you can use our Mock Bank user credentials for testing.
  4. Next, click the test button to open the generated Sandbox Auth Link and connect to Mock Bank.

Auth Link Builder

  1. Select Mock Bank and use a set of our Mock Bank credentials (eg. “john”/”doe”) in order to obtain a code.

Sandbox Authentication 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:

  1. Add the missing required variables : Sandbox client_id and Sandbox client_secret (found in the Console) as well as the code (generated in Step 2).

Postman Collection Example

  1. Send the request and retrieve a response containing an access_token and refresh_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

  1. Sign up to the TrueLayer Console to get your client_id and client_secret.
  2. 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:

  1. 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.
  2. You must also choose a Redirect URI where the user will be redirected after authenticating.
  3. Enable the providers you want to to make available.
  4. Next, click “Test” to open the generated link and connect a bank.

Auth Link Builder

  1. 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.

Authentication 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:

  1. Add the missing required variables : client_id and client_secret (found in the Console) as well as the code (generated in Step 2). Postman Collection Example
  2. Send the request and retrieve a response containing an access_token and refresh_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

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:

OpenBanking Sequence Diagram

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.

Auth Link Builder

End user log-in: The End user selects a Provider and authenticates securely on the TrueLayer authorization server using their Provider credentials.

Choose your bank

  1. Code Redirect: End user’s browser is redirected to the redirect_uri controlled by the Client with a code, the requested scope and the optional state

  2. Exchange code with access_token: The application exchanges the code received with a short-lived access_token (and optionally a refresh_token if the scope offline_access was requested) making a HTTP POST to the TrueLayer authorization server including the application client_id, client_secret and redirect_uri

  3. Access Data API: The application can use the obtained access_token to access data on behalf of the End user. An Authorization header must be provided to access any endpoint of the Data API

  4. Renew the access_token: After the short-lived access_token expires (1 hour by default or provider specified) a new access_token can be obtained using the refresh_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:

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

  1. 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"
}
  1. 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",
}
  1. 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

  1. Submit a POST request to batch endpoint specifying access token and transaction time period;
  2. Await a single webhook notifying you that the job is complete;
  3. 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

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.

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.

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:

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 or
2019-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

October 29, 2020

September 25, 2020

August 27th, 2020

May 21, 2020

August 1, 2019

June 20, 2019

June 19, 2019

May 24, 2019

May 21, 2019

March 29, 2019

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:

Payments API: Contents

In this section of the documentation you will find:

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:

  1. After signing up to our Console, make a note of the client_id and the client_secret. These credentials allow you to obtain an access_token.
  2. Using that token, set up a single immediate payment, specifying recipient and amount.
  3. 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

  1. Sign up to the TrueLayer Console to get your client_id and client_secret.
  2. 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

  1. Open the first step in the Postman collection and click the Body tab.
  2. Replace CLIENT_ID and CLIENT_SECRET with your own values obtained in Step 1.
  3. Click the Send button to forward the request to our server.
  4. In response you’ll receive an access_token, which you can copy into your clipboard.

Step 2 - Create a Single Immediate Payment

  1. Now open the second step in the postman collection and click the Authorization tab.
  2. Replace the token value ACCESS-TOKEN-HERE with the value obtained in the previous step.
  3. Now click on Body and replace the values with the actual payment details. Make sure redirect_uri is one of the URIs that has been whitelisted in the TrueLayer Console.
  4. Click the blue Send button to forward the request to our server.
  5. Open the auth_uri in a browser to complete the payment.

Step 3 - Get Payment Status

  1. Now open the third step in the Postman collection and click the Authorization tab.
  2. Replace the token value ACCESS-TOKEN-HERE with the value obtained in Step 1.
  3. Replace PAYMENT-ID-HERE in the URI with the value of simp_id obtained in Step 2.
  4. 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

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

  1. Use our providers endpoint to build a ‘Provider Selection screen’ for the user to choose their bank. (all assets are supplied)
  2. Obtain a client credentials grant from the authentication server
  3. Create a new Single Immediate Payment, specifying the bank the user wants to use
  4. Redirect the user to the URI specified in the API response
  5. Handle the redirect back from the bank on the redirect_uri you set in the console.
  6. 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

  1. Obtain a client credentials grant from the authentication server
  2. Create a new Single Immediate Payment
  3. Redirect the user to the URI specified in the API response
  4. Handle the redirect back from the bank on the redirect_uri you set in the console.
  5. 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:

  1. Navigate to the payments tab
  2. Click 'Go to live env’
  3. Navigate to the settings tab
  4. 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:

  1. Build a provider selection screen for your users to select their bank
  2. Create a payment
  3. Redirect a user to authenticate
  4. Handle the user returning to your application
  5. 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:

  1. Tells you which banks are active, if a bank isn’t listed then we have deactivated it temporarily until its service is returned.
  2. 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. Bank selection dialog

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:

  1. 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
  2. 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.
  3. Retrieve the relevant public key by using the kid to look up the relevant value from the JWKS.
  4. 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>"}.
  5. 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:

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.

State transition diagram

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

Initiate Payment

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

End-User Authorises Payment

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

Polling Payment Status

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

Cancelled Payment

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

Rejected Payment

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:

  1. Make sure you change all URIs to end with truelayer.com instead of truelayer-sandbox.com
  2. Change from using your sandbox client_id_ and client_secret to your production client_id and client_secret. You can find your production client_id here: https://console.truelayer.com/settings/Application (you should have saved your production client_secret when you last reset it, or when you created your production account)
  3. 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.

Bank Details
Lloyds https://www.lloydsbank.com/online-banking/benefits-online-banking/view-pay-your-bills.asp#tab-row-5
Halifax https://www.halifax.co.uk/bankaccounts/help-guidance/online-banking-help/fasterpayments/
(click tab “Payment limits and timeframes”)
Bank of Scotland https://www.bankofscotland.co.uk/helpcentre/internet-banking/faster-payments/
(click tab FAQs)
Royal Bank of Scotland https://www.supportcentre-rbs.co.uk/Searchable/997053272/What-are-the-payment-limits.htm
NatWest https://supportcentre.natwest.com/Searchable/913208362/What-are-the-payment-limits.htm
Ulster https://supportcentre.ulsterbank.co.uk/Searchable/997054072/What-are-the-payment-limits.htm
Barclays https://www.barclays.co.uk/current-accounts/online-payment-limits/
HSBC From https://www.hsbc.co.uk/1/2/linklaunch/contactandsupport : “You can make payments of up to £25,000, per day via Online Banking if the funds are available, for larger amounts, you would need to visit an HSBC Branch with Identification and there may be a charge”
Santander https://www.santandercb.co.uk/contact-support/connect-helpcentre/making-payments/standard-domestic-payments-faster-payments
Nationwide https://www.nationwide.co.uk/support/support-articles/important-information/faster-payments#xtab:payment-limits
Danske Bank https://danskebank.co.uk/SiteCollectionDocuments/personal/payment-table-personal.pdf (see table on page 4 referencing Open Banking payment limits)
Post Office Bank (Bank of Ireland) https://www.postoffice.co.uk/current-account-faqs (see item “How much money can I send?”
AIB (Allied Irish Bank) https://aibgb.co.uk/ways-to-bank/online-banking/transaction-limit-information
First Trust Bank https://firsttrustbank.co.uk/ways-to-bank/transaction-limit-information
Starling https://www.starlingbank.com/paymentservices/
Monzo http://fasterpayments.org.uk/monzo
Revolut https://www.revolut.com/help/exploring-revolut/sending-money/sending-money-to-a-bank-account/what-are-the-transfer-limits/
TSB https://www.tsb.co.uk/business/payment-services/faster-payments/
Tesco https://yourcommunity.tescobank.com/t5/Help-Support/Faster-payments-and-daily-withdrawal-limits/td-p/11580

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:

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.

UK mock login

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:

UK account selection

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:

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:

To get support for the Payments API:

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

  1. 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.)
  2. Request an access token from our authentication endpoint.
  3. Create a new payment initiation request, specifying the provider the user has selected.
  4. Handle the response to allow the user to authorise the payment.
    • For the redirect authorisation flow:
      1. Redirect the user to the URI specified in the API response.
      2. Handle the user returning back from the bank on the return_uri you previously set in the console.
    • For the embedded authorisation flow:
      1. Display the inputs specified in the API response to the user.
      2. Submit the values they enter to our submission API.
      3. Repeat if the submission response specifies more inputs.
  5. 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.

high level sequence diagram of payment creation and authorisation in 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.

high level sequence diagram of payment creation and authorisation in 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:

  1. Navigate to the payments tab
  2. Click 'Go to live env’
  3. Navigate to the settings tab
  4. 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&currency=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:

  1. Tells you which banks are currently active (when a bank is temporarily unavailable, we hide them from this list until its service is restored).
  2. Gives you the assets to build out a selection screen e.g. logos and display names.
  3. 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:

  1. 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
  2. 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.
  3. Retrieve the relevant public key by using the kid to look up the relevant value from the JWKS.
  4. 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.

State model showing the valid transitions for the above payment statuses

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.

Sequence diagram for Payment cancellation in redirect flow

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.

Sequence digram for Payment cancellation in embedded flow

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:

  1. Make sure you change all URIs to end with truelayer.com instead of truelayer-sandbox.com
  2. Change from using your sandbox client_id_ and client_secret to your production client_id and client_secret. You can find your production client_id here (you should have saved your production client_secret when you last reset it, or when you created your production account)
  3. 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.

Bank Details
Lloyds https://www.lloydsbank.com/online-banking/benefits-online-banking/view-pay-your-bills.asp#tab-row-5
Halifax https://www.halifax.co.uk/bankaccounts/help-guidance/online-banking-help/fasterpayments/
(click tab “Payment limits and timeframes”)
Bank of Scotland https://www.bankofscotland.co.uk/helpcentre/internet-banking/faster-payments/
(click tab FAQs)
Royal Bank of Scotland https://www.supportcentre-rbs.co.uk/Searchable/997053272/What-are-the-payment-limits.htm
NatWest https://supportcentre.natwest.com/Searchable/913208362/What-are-the-payment-limits.htm
Ulster https://supportcentre.ulsterbank.co.uk/Searchable/997054072/What-are-the-payment-limits.htm
Barclays https://www.barclays.co.uk/current-accounts/online-payment-limits/
HSBC From https://www.hsbc.co.uk/1/2/linklaunch/contactandsupport : “You can make payments of up to £25,000, per day via Online Banking if the funds are available, for larger amounts, you would need to visit an HSBC Branch with Identification and there may be a charge”
Santander https://www.santandercb.co.uk/contact-support/connect-helpcentre/making-payments/standard-domestic-payments-faster-payments
Nationwide https://www.nationwide.co.uk/support/support-articles/important-information/faster-payments#xtab:payment-limits
Danske Bank https://danskebank.co.uk/SiteCollectionDocuments/personal/payment-table-personal.pdf (see table on page 4 referencing Open Banking payment limits)
Post Office Bank (Bank of Ireland) https://www.postoffice.co.uk/current-account-faqs (see item “How much money can I send?”
AIB (Allied Irish Bank) https://aibgb.co.uk/ways-to-bank/online-banking/transaction-limit-information
First Trust Bank https://firsttrustbank.co.uk/ways-to-bank/transaction-limit-information
Starling https://www.starlingbank.com/paymentservices/
Monzo http://fasterpayments.org.uk/monzo
Revolut https://www.revolut.com/help/exploring-revolut/sending-money/sending-money-to-a-bank-account/what-are-the-transfer-limits/
TSB https://www.tsb.co.uk/business/payment-services/faster-payments/
Tesco https://yourcommunity.tescobank.com/t5/Help-Support/Faster-payments-and-daily-withdrawal-limits/td-p/11580

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:

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.

UK mock login

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:

UK account selection

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.

login prompt

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:

EU account selection

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.

  1. SMS
  2. 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&currency=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&currency=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.

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:

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:

  1. Navigate to the payments tab
  2. Click ‘Go to live env’
  3. Navigate to the settings tab
  4. 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"&currency="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"&currency="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:

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:

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 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:

  1. Go to your console > Paydirect API.
  2. Select the Go to live env button.
  3. Go to App settings.
  4. 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&currency=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:

  1. Tells you which banks are currently active (when a bank is temporarily unavailable, we hide them from this list until its service is restored).
  2. Gives you the assets to build out a selection screen e.g. logos and display names.
  3. 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.

PD Deposit Statuses

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.

PD Withdrawal Statuses

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:

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:

  1. 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
  2. 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.
  3. Retrieve the relevant public key by using the kid to look up the relevant value from the JWKS.
  4. 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"&currency="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:

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 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.

UK mock login

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:

UK account selection

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.

login prompt

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:

EU account selection

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.

  1. SMS
  2. 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:

  1. In the Providers tab, make sure Mock is selected. This is the mock bank used in our sandbox for test purposes.

  2. In the Permissions tab, make sure info and accounts are selected. These scopes are required for account verification.

  3. Make sure the URI selected in the “Redirect URIs” tab is allow-listed in the App settings section of the console.

  4. Finally click the Preview your Auth Dialog button (eye-shaped icon) to test your auth page.

  5. 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
  6. 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.

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:

August 12, 2020

Release notes:

January 5, 2019

Initial release:

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

  1. The user gives consent for you to access their bank data.
  2. They are redirected to their bank to authenticate, then sent back to your app.
  3. To request verification, send the user’s name to the Verification API.
  4. We compare the identity data to the account holder’s name for all the connected account(s) the user has given consent for.
  5. 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:

  1. Specify the data you’d like the user to share.
  2. Ask the user to select their provider (bank).
  3. Collect the user’s consent to share that data.
  4. 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.
  5. 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

  1. Sign up to the TrueLayer Console to get your Sandbox client_id and client_secret.
  2. 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:

  1. Select the set of Permissions with info and account scopes to include in the authentication link.
  2. Choose a Redirect URI where the user will be redirected after authenticating.
  3. Check that the Mock provider is enabled to use our mock bank user credentials for testing.
  4. Select Test to open the generated test auth link and connect to our mock bank.

Auth Link Builder

  1. To get an exchange code, select Mock Bank and fill in the following when asked for credentials:
    • First name: john
    • Last name: doe

Sandbox Authentication Code

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:

Postman Collection Example

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

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'

Exchange 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.