Account holder verification

When you make a payout, an account holder verification check is performed on the beneficiary. In this process, the beneficiary’s name and account identifiers (sort code and account number) are checked against what is on file at the bank.

Make an account holder verification request

To verify a specific account holder, you need:

  • An account holder name
  • A sort code and account number, or an IBAN
  • A valid access token with the scope verification.
📘

To enable the verification scope for account holder verification requests, contact us.

Make a POST request to the /v3/account-holder-verifications/requests endpoint with this information:

{
  "account_holder_name": "John Doe",
  "account_identifier": {
	  "type": "sort_code_account_number",
    "sort_code": "123456",
    "account_number": "12345678"
  }
}
{
  "account_holder_name": "John Doe",
  "account_identifier": {
	  "type": "iban",
    "iban": "FR7630006000011234567890189"
}

In the API response, you receive an id for the request.

{
  "id": "550e8400-e29b-41d4-a716-446655440000"
}

You do not receive any information on the status of the verification check in the response. To find out the result of the check, you need to make a GET request to the same endpoint, using the id you received in the response.

Monitor an account holder verification check

When you make an account holder verification check, it can have one of the following results:

  • Account holder verification is complete and the result was match
  • Account holder verification is complete and the result was partial_match , which also includes the account holder name
  • Account holder verification is complete and the result was no_match
  • Account holder verification is complete and the result was match_not_possible, which also includes a failure reason in plain English
  • The verification attempt failed.

Normally, the verification process takes a few seconds.

GET account holder verification

To see the status of a particular check, you can make a GET request to the /v3/account-holder-verifications/requests/{id} endpoint (where id is the ID of the request that you created earlier).

{
  "id": "550e8400-e29b-41d4-a716-446655440003",
  "status": "pending"
}
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "completed",
  "match_result": {
    "type": "match"
  }
}
{
  "id": "550e8400-e29b-41d4-a716-446655440002",
  "status": "completed",
  "match_result": {
    "type": "no_match"
  }
}

The response will contain:

  • the id of the verification request
    You already submitted this in the previous step.
  • the status of the request
    This can be pending, complete or failed.
  • the result of the check, if the check is completed or failed
    This can be match, partial_match, no_match or match_not_possible.

If you receive a partial_match result, you also receive the account holder’s name in the response, so you can decide whether to move forward with the payout:

{
  "id": "550e8400-e29b-41d4-a716-446655440001",
  "status": "completed",
  "match_result": {
    "type": "partial_match",
    "account_holder_name": "Jean D."
  }
}

If you receive a match_not_possible or failed response, you also receive a failure reason with information on why verification failed:

{
  "id": "550e8400-e29b-41d4-a716-446655440002",
  "status": "completed",
  "match_result": {
    "type": "match_not_possible",
    "failure_reason": "Bank unable to match"
  }
}
{
  "id": "550e8400-e29b-41d4-a716-446655440004",
  "status": "failed",
  "failure_reason": "provider_error"
}

If you receive a failed webhook or response to a GET request, we recommend retrying the check.

Webhooks

To set up webhooks for account holder verification, contact us. You won't be able to set up account holder verification webhooks in Console.

{
  "type": "account_holder_verification_completed",
  "event_version": 1,
  "event_id": "b8d4dda0-ff2c-4d77-a6da-4615e4bad941",
  "account_holder_verification_id": "550e8400-e29b-41d4-a716-446655440000",
  "match_result": {
    "type": "match"
  }
}
{
  "type": "account_holder_verification_completed",
  "event_version": 1,
  "event_id": "e2g7ggc3-h25f-74g7-d049-7798h8e77263",
  "account_holder_verification_id": "880h1733-h5ce-74h7-e049-7798h8e77263",
  "match_result": {
    "type": "no_match"
  }
}
{
  "type": "account_holder_verification_completed",
  "event_version": 1,
  "event_id": "d1f6ffb2-g14e-63f6-c938-6687g7d66152",
  "account_holder_verification_id": "770g0622-g4bd-63g6-d938-6687g7d66152",
  "match_result": {
    "type": "partial_match",
    "account_holder_name": "J Smith"
  }
}
{
  "type": "account_holder_verification_failed",
  "event_version": 1,
  "event_id": "c9e5eeb1-f03d-52e5-b827-5576f6c55041",
  "account_holder_verification_id": "660f9511-f3ac-52f5-c827-5576f6c55041",
  "failure_reason": "provider_error"
}
{
  "type": "account_holder_verification_completed",
  "event_version": 1,
  "event_id": "e2g7ggc3-h25f-74g7-d049-7798h8e77263",
  "account_holder_verification_id": "880h1733-h5ce-74h7-e049-7798h8e77263",
  "match_result": {
    "type": "match_not_possible",
    "failure_reason": "Bank unable to match"
  }
}

Pay out to a known payee even without a verification match

As part of the EPC regulations around verification of a payee, every payout to an external beneficiary account will undergo a name check. If the result is partial_match, no_match or match_not_possible, you will need to input on whether to progress with the payout as the payout will be failed.

For these situations, you can choose to push through with the payout anyway, using the beneficiary.type of verified_external_account. If you use this beneficiary type, you can also include two other fields:

  • account_holder_verification_id (required), which is a unique ID attached to that instance of account verification
  • override_bank_matched_name (optional), which in the case of a partial_match indicates whether to use the account holder name on file at the bank or use the one you supplied in your verification check.

Below is an example Create Payout request, with the verified_external_account beneficiary type. In this case, the override_bank_matched_name value is set to true because the user wants to use the name on file at the bank, not the one supplied in the verification request.

{
  "id": "0a495e9f-2f41-4669-ba33-85407c0b26cb",
  "merchant_account_id": "24089aed-4fd4-9e13-f8b2-f458f30c836c",
  "amount_in_minor": 100,
  "currency": "EUR",
  "beneficiary": {
    "type": "verified_external_account",
    "account_holder_verification_id": "f8c3a9e0-69ae-4918-b5b2-4d8f91e4e1af",
    "override_bank_matched_name": true,
  }
}

You can get the account_holder_verification_id from a previously executed/failed external_account payout (which included an account holder verification check). This ID appears in the following webhooks:

  • account_holder_verification_completed
  • account_holder_verification_failed

You also receive this ID in successful responses from the Get Payout endpoint, inside the account_holder_verification object. Below is an example:

{
  "id": "0cd1b0f7-71bc-4d24-b209-95259dadcc20",
  "merchant_account_id": "ae094a73-d874-4241-a65f-6dcda7ac07b1",
  "amount_in_minor": 100,
  "currency": "EUR",
  "beneficiary": {
    "type": "external_account",
    "reference": "a-reference",
    "account_holder_name": "John Doe",
    "account_identifiers": [
      {
        "type": "iban",
        "iban": "FR1234567890123"
      }
    ],
    "account_holder_verification": {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "status": "completed",
      "match_result": {
        "type": "match"
      }
    }
  },
  "scheme_id": "sepa_credit_transfer_instant",
  "created_at": "2021-12-25T14:00:00.000Z",
  "status": "executed",
  "executed_at": "2021-12-25T15:00:00.000Z",
  "metadata": {
    "prop1": "value1",
    "prop2": "value2"
  }
}

You can also get the account_holder_verification.id from webhooks. Allowing you to perform a name check on a customer’s account before initiating a payout by using the beneficiary type verified_external_account.

⚠️

At minimum, you must be able to handle the account_holder_verification.id from the payout_failed and payout_executed webhooks.

You must also be able to create payouts using the beneficiary.type of verified_external_account.


Test account holder verification in sandbox

We recommend that you test account holder verification endpoints in our sandbox environment (https://api.truelayer-sandbox.com) as part of your integration.

Use the data in the table below to test specific scenarios, including different failure reasons. Where you see ANY_IBAN for theiban value, substitute any valid IBAN.

For ANY_NAME, substitute any name except those that would produce a different, specific result (so don’t use John Doe, John partial, John impossiblematch or John pspfail for this field).

When you make a request to the POST endpoint, you receive an AHV_ID value. This is an identifier for the specific verification check that you've just done.

Then, to confirm the result of each of these test scenarios, call the GET account holder verification endpoint. Include the AHV_ID in the endpoint URL. Depending on the result of the verification check, you receive a different outcome when calling the GET endpoint.

POST Request endpoint: https://https://api.truelayer-sandbox.com/v3/account-holder-verifications/requests

GET Response endpoint: https://https://api.truelayer-sandbox.com/v3/account-holder-verifications/requests/{{AHV_ID}}

POST Request bodyStatus of verification checkMatch result received
{ "account_holder_name": "John Doe", "account_identifier": { "type": "iban", "iban": "ANY_IBAN" } }CompletedMatch
{ "account_holder_name": "ANY_NAME", "account_identifier": { "type": "iban", "iban": "ANY_IBAN" } }CompletedNo Match
{ "account_holder_name": "John partial", "account_identifier": { "type": "iban", "iban": "ANY_IBAN" } }CompletedPartial Match
{ "account_holder_name": "John impossiblematch", "account_identifier": { "type": "iban", "iban": "ANY_IBAN" } }CompletedMatch Not Possible
{ "account_holder_name": "John pspfail", "account_identifier": { "type": "iban", "iban": "ANY_IBAN" } }FailedN/A

Below are the GET responses that you receive for each match result.

Match resultGET response
Match{ "id": "4c7d28cb-20be-40a3-a952-07cdd6e628b2", "status": "completed", "match_result": { "type": "match" } }
No match{ "id": "38118169-8384-4091-9aef-c41127eead62", "status": "completed", "match_result": { "type": "no_match" } }
Partial match{ "id": "942e66b7-6e1a-4cbe-9a11-8d322ea1207b", "status": "completed", "match_result": { "type": "partial_match", "account_holder_name": "John Doe" } }
Match not possible{ "id": "ac0f5311-55ba-4284-8097-69ca58eaacd9", "status": "completed", "match_result": { "type": "match_not_possible", "reason": "Bank unable to match" } }
No match result, because the verification check failed{ "id": "408b1b61-dd41-432c-b480-c48f88186c4a", "status": "failed", "failure_reason": "VOP scheme provider error" }