Verification of Payee API

Check the name before you pay.

Compare the beneficiary name in your payment instruction with the account-holder information from the bank. Add VoP alongside IBAN validation to help reduce misdirected payments and flag name mismatches before approval.

Prepaid add-on · Supported SEPA banks
Example check
IBAN
FR76 3000 6000 0112 3456 7890 189
Payee name
John Doe
MATCH
The payee name matches the account-holder information.

It works alongside standard IBAN validation to help reduce misdirected payments, fraud, and manual reconciliation issues. A successful API response means the check was completed; use the payee_name_match result to decide whether your payment workflow should continue, be reviewed, or be stopped.

VoP is powered by a partner certified by the European Payments Council that operates as a Routing and Verification Mechanism. Requests are routed to EU banks under the SEPA scheme in a fully compliant manner.

How it works

Send a POST request to the /v2/iban endpoint with the iban and payee_name fields in the JSON body. The response will include all the usual IBAN data plus a payee_name_match field with one of the following values:

  • MATCH – the name matches the account holder
  • CLOSE_MATCH – the name is similar but not an exact match (e.g. a typo or abbreviation)
  • NO_MATCH – the name does not match the account holder
  • NOT_APPLICABLE – the account does not exist or is explicitly excluded from VoP by the payment service provider
  • BANK_UNAVAILABLE – the bank has not implemented VoP services yet. Learn more

Example request

To verify the payee name for an IBAN, call /v2/iban with the POST method and include the iban and payee_name in the request body:

curl 'https://api.fincodesapi.com/v2/iban' \
    --request POST \
    --header 'Authorization: Bearer your-api-key-here' \
    --header 'Accept: application/json' \
    --header 'Content-Type: application/json' \
    --data '{"iban":"DE75512108001245126199","payee_name":"John Doe"}'
# INSTALLATION
$ composer require guzzlehttp/guzzle
# REQUEST
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('POST', 'https://api.fincodesapi.com/v2/iban', [
    'headers' => [
        'Accept' => 'application/json',
        'Authorization' => 'Bearer your-api-key-here',
    ],
    'json' => [
        'iban' => 'DE75512108001245126199',
        'payee_name' => 'John Doe',
    ],
]);

echo $response->getBody();
# INSTALLATION
$ python -m pip install requests
# REQUEST
import requests

url = "https://api.fincodesapi.com/v2/iban"

headers = {
    "Accept": "application/json",
    "Authorization": "Bearer your-api-key-here"
}

payload = {
    "iban": "DE75512108001245126199",
    "payee_name": "John Doe"
}
response = requests.request("POST", url, json=payload, headers=headers)

print(response.text)
# INSTALLATION
$ npm install node-fetch --save
// REQUEST
import fetch from 'node-fetch';

const url = 'https://api.fincodesapi.com/v2/iban';
const options = {
  method: 'POST',
  headers: {
    'Accept': 'application/json',
    'Authorization': 'Bearer your-api-key-here',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    'iban': 'DE75512108001245126199',
    'payee_name': 'John Doe'
  })
};

fetch(url, options)
  .then(res => res.json())
  .then(json => console.log(json))
  .catch(err => console.error('error:' + err));
const options = {
  method: 'POST',
  headers: {
    'Accept': 'application/json',
    'Authorization': 'Bearer your-api-key-here',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    'iban': 'DE75512108001245126199',
    'payee_name': 'John Doe'
  })
};

fetch('https://api.fincodesapi.com/v2/iban', options)
  .then(response => response.json())
  .then(response => console.log(response))
  .catch(err => console.error(err));

The response includes the standard IBAN validation data with an additional payee_name_match field:

{
    "success": true,
    "data": {
        "id": "DE75512108001245126199",
        "account_number": "1245126199",
        "national_bank_code": "51210800",
        "national_branch_code": "",
        "payee_name_match": "MATCH",
        "bic": {
            "id": "SOGEDEFF",
            "address": "NEUE MAINZER STRASSE 46-50",
            "postcode": "60311",
            "branch_name": "SOGEBANK Frankfurt Main",
            "branch_code": "",
            "country": {
                "id": "DE",
                "name": "Germany"
            },
            "city": {
                "id": "c3eb05ae-2709-45c7-9799-d5e2fee08946",
                "country_id": "DE",
                "name": "Frankfurt Am Main"
            },
            "bank": {
                "id": "cfb1758f-1195-4be9-b981-3fc63da7306b",
                "country_id": "DE",
                "code": "SOGE",
                "name": "SOCIETE GENERALE S.A."
            }
        },
        "country": {
            "id": "DE",
            "name": "Germany"
        }
    }
}

Matched payee name

When the result is CLOSE_MATCH, the response also includes matched_payee_name with the name supplied by the bank. Because matched payee names are not stored by FinCodesAPI, a cached close match is checked with the bank again. Other cached match results are reused as usual.

{
    "iban": "DE75512108001245126199",
    "payee_name": "Jon Doe"
}
{
    "success": true,
    "data": {
        "id": "DE75512108001245126199",
        "account_number": "1245126199",
        "national_bank_code": "51210800",
        "national_branch_code": "",
        "payee_name_match": "CLOSE_MATCH",
        "matched_payee_name": "John Doe",
        "bic": {
            "id": "SOGEDEFF",
            "address": "NEUE MAINZER STRASSE 46-50",
            "postcode": "60311",
            "branch_name": "SOGEBANK Frankfurt Main",
            "branch_code": "",
            "country": {
                "id": "DE",
                "name": "Germany"
            },
            "city": {
                "id": "c3eb05ae-2709-45c7-9799-d5e2fee08946",
                "country_id": "DE",
                "name": "Frankfurt Am Main"
            },
            "bank": {
                "id": "cfb1758f-1195-4be9-b981-3fc63da7306b",
                "country_id": "DE",
                "code": "SOGE",
                "name": "SOCIETE GENERALE S.A."
            }
        },
        "country": {
            "id": "DE",
            "name": "Germany"
        }
    }
}

Supported countries

VoP is available for SEPA IBANs from the following countries:

limited coverage VoP is currently mandatory only for PSPs operating in SEPA countries that use the Euro. For EU member states that do not use the Euro, the implementation timeline has been extended, with a compliance deadline set for 9 July 2027. As a result, some banks in these countries have not yet implemented VoP services. In such cases, a BANK_UNAVAILABLE result is returned. Broader support is expected closer to the 2027 compliance deadline.

Testing

You can use the test IBAN DE75512108001245126199 with the following payee names to simulate different results without being charged:

Payee name Result
John Doe MATCH
Full Match MATCH
Close Match CLOSE_MATCH
Not Applicable NOT_APPLICABLE
Bank Unavailable BANK_UNAVAILABLE
Any other name NO_MATCH

Pricing

VoP is a pre-paid add-on. Each check costs $0.20 and is deducted from your VoP wallet balance. You can purchase checks from the billing page. Purchased checks do not expire.

Sanctions screening

VoP confirms that you are paying the right account holder. It doesn't tell you whether you are allowed to pay them. As an additional check before you approve a payment, screen the payee name against the EU, UK, UN, OFAC, Swiss, Australian and Canadian sanctions lists with the Sanctions Screening API.

You can find full API documentation here.

Need to validate multiple types of bank details? Explore our Bank Account Validation API.