Part of the Bank Account Verification service. One request asks the bank that holds an IBAN whether the name you send is the name on that account. The bank answers through the Verification of Payee scheme, and the API returns its verdict, yes, partial, no or unavailable, together with the bank’s BIC. Use it before you pay a new beneficiary, to catch typing errors and misdirected payments while they can still be corrected. Accounts in 21 countries can be verified.
https://api.iban.com/clients/api/verify/v3/x-api-key header, the input in a JSON body with Content-Type: application/json. There is no GET form and no form-encoded form.unavailable, is in the body. 400, 401, 405, 415, 500: the request was refused, the body is just {"error":"CODE"}; no bank was contacted, except for INTERNAL_SERVER_ERROR:UNERSP, where the request to the bank network failed. 429: rejected by the rate limit (see Rate limits).Content-Type: application/json; charset=UTF-8 (the 405 and 415 refusals send application/json without the charset).INVALID_IBAN_CHECKSUM and INTERNAL_SERVER_ERROR:UNERSP use one; everything refused before that point (the other 400s, 401, 405, 415, 429, INTERNAL_SERVER_ERROR:BNFDBS) uses none.Start with the sandbox: same API, fixed answers, nothing charged.
curl "https://sandbox.iban.com/clients/api/verify/v3/" -H "x-api-key: testkey" -H "Content-Type: application/json" -d '{"IBAN":"FR7630006000011234567890189","name":"John Doe"}'The answer:
{
"query": {
"IBAN": "FR7630006000011234567890189",
"name": "John Doe",
"success": true
},
"result": {
"valid": true,
"name_match": "yes",
"bic": "AGRIFRPPXXX"
},
"error": ""
}Then switch the host to api.iban.com and the key to yours. Each verification there is real, answered by the account’s bank, and uses one query. Requests in seven languages are under Example request.
x-api-key header, never in the URL: headers are not written to proxy, load-balancer and web-server access logs, query strings are.IP_NOT_ALLOWED.| Header | Required | Value | Description |
|---|---|---|---|
x-api-key | yes | string | Your personal key, shown under API Access. Missing: MISSING_API_KEY (400); wrong: INVALID_API_KEY (401). The header name is matched case-insensitively (X-API-KEY works). The key is checked before the body: a missing or wrong key is reported even when the body is malformed. |
Content-Type | yes | application/json | The only accepted media type, matched case-insensitively; a charset parameter is allowed (application/json; charset=utf-8, which some HTTP libraries add on their own). Any other type such as text/json, and a missing header, gives UNSUPPORTED_FORMAT (415). |
A JSON object with two fields. Other fields are ignored.
| Field | Required | Value | Description |
|---|---|---|---|
IBAN | yes | string | The IBAN of the account to verify, in one of the supported countries, as a JSON string. Spaces and any other characters that are not letters or digits are removed, and letters are converted to upper case, before the checks, so DE63 3702 0500 0005 0233 07 is accepted and echoed back as DE63370205000005023307. The country code is checked first (COUNTRY_NOT_SUPPORTED, 400), then the check digits (INVALID_IBAN_CHECKSUM, 400, also for a value that is too short); both are refused before any bank is contacted. Missing or empty: MISSING_INPUT_IBAN (400). The field name is case-sensitive: iban is reported as missing. |
name | yes | string | The name of the account holder as it should appear on the account: first and last name for a personal account, the legal name for a company (a trade name usually gives partial or no). UTF-8; accents and other non-ASCII characters are passed through unchanged. Missing or empty: MISSING_INPUT_NAME (400). Both fields are checked for presence before the IBAN is examined. |
IBANs of these 21 countries can be verified. Any other country code is refused with COUNTRY_NOT_SUPPORTED before the bank is contacted, so it costs nothing to try.
AT Austria | BE Belgium | HR Croatia |
CY Cyprus | EE Estonia | FI Finland |
FR France | DE Germany | GR Greece |
IE Ireland | IT Italy | LV Latvia |
LT Lithuania | LU Luxembourg | MT Malta |
NL Netherlands | PT Portugal | SK Slovakia |
SI Slovenia | ES Spain | GB United Kingdom |
Every example verifies the same account: the published donation account of the German Red Cross, DE63370205000005023307, held by Deutsches Rotes Kreuz e.V. Its response is shown in the next section. Replace YOUR_API_KEY with the key from API Access. Each run is a real verification and uses one query; to try the code for free, point it at the sandbox.
curl "https://api.iban.com/clients/api/verify/v3/" \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"IBAN":"DE63370205000005023307","name":"Deutsches Rotes Kreuz e.V"}'A completed verification returns three members: query (what you sent), result (the bank’s answer) and error (the status code of the verification, empty for a match). The response to the example request, a match:
{
"query": {
"IBAN": "DE63370205000005023307",
"name": "Deutsches Rotes Kreuz e.V",
"success": true
},
"result": {
"valid": true,
"name_match": "yes",
"bic": "BFSWDE33XXX"
},
"error": ""
}| Field | Type | Description |
|---|---|---|
query.IBAN | string | The IBAN as checked: separators removed, upper case. |
query.name | string | The name as you sent it, unchanged. |
query.success | boolean | true when the verification was carried out. It is true for every 200 response, including partial match, no match and unavailable; a refused request has no query object at all (see Response codes). |
result.valid | boolean or null | Whether the IBAN and the name are a valid pair: true for a match, a partial match and a verdict-less answer; false when the bank rejected the pair (the name does not match, NAME_NOT_MATCH); null when no verdict could be obtained (VERIFICATION_NOT_SUPPORTED, VOP_REQUEST_FAILED). It is a statement about the pair, not about the account alone: the same existing account answers true with the right name and false with a wrong one. |
result.name_match | string | Outcome of the name check, one of four lower-case values: yes (match), partial (close match), no (no match), unavailable (no verdict: the bank could not check the name, or answered without a name verdict). See Reading the result. |
result.bic | string | BIC of the bank that issued the IBAN, 11 characters. Head office (branch code XXX) or a branch BIC, depending on the country and on what the bank directory holds for the IBAN; the recorded responses all returned the head-office form. |
error | string | Status code of the verification: empty for a match and for unavailable, NAME_PARTIAL_MATCH for a partial match, NAME_NOT_MATCH for no match, VERIFICATION_NOT_SUPPORTED or VOP_REQUEST_FAILED when the bank network could not answer (then valid is null). Not an indication that the request failed: query.success is true alongside it. |
The Italian Red Cross, sent as Associazione della Croce Rossa Italiana – ODV, the form published on its website; the bank holds the name slightly differently. error carries NAME_PARTIAL_MATCH while query.success stays true:
{
"query": {
"IBAN": "IT12T0623003204000030737371",
"name": "Associazione della Croce Rossa Italiana – ODV",
"success": true
},
"result": {
"valid": true,
"name_match": "partial",
"bic": "CRPPIT2PXXX"
},
"error": "NAME_PARTIAL_MATCH"
}The German Red Cross account again, with the name John Doe. name_match is no, error is NAME_NOT_MATCH and valid is false: the account exists, as the first example shows, but the IBAN and this name are not a valid pair:
{
"query": {
"IBAN": "DE63370205000005023307",
"name": "John Doe",
"success": true
},
"result": {
"valid": false,
"name_match": "no",
"bic": "BFSWDE33XXX"
},
"error": "NAME_NOT_MATCH"
}A French foundation’s account: the name could not be checked. name_match is unavailable, valid is true and error is empty:
{
"query": {
"IBAN": "FR7630027174110002636660114",
"name": "Fondation pour le Logement des Défavorisés",
"success": true
},
"result": {
"valid": true,
"name_match": "unavailable",
"bic": "CMCIFRPPXXX"
},
"error": ""
}A refused request has neither query nor result, only the code. The IBAN of the example with its last digit changed:
{"error":"INVALID_IBAN_CHECKSUM"}The responses on this page were recorded on 8 October 2026 against published donation accounts of charities, with the account holder name exactly as each organisation publishes it, and once with a wrong name:
| Country | IBAN | name sent | valid | name_match | error | bic | Time |
|---|---|---|---|---|---|---|---|
| DE | DE63370205000005023307 | Deutsches Rotes Kreuz e.V | true | yes | "" | BFSWDE33XXX | 0.3 s |
| NL | NL13INGB0000004054 | Artsen zonder Grenzen | true | yes | "" | INGBNL2AXXX | 0.4 s |
| GB | GB74BARC20792533979512 | St George Foundation Limited | true | yes | "" | BARCGB22XXX | 3.0 s |
| IT | IT12T0623003204000030737371 | Associazione della Croce Rossa Italiana – ODV | true | partial | NAME_PARTIAL_MATCH | CRPPIT2PXXX | 0.7 s |
| FR | FR7630027174110002636660114 | Fondation pour le Logement des Défavorisés | true | unavailable | "" | CMCIFRPPXXX | 0.8 s |
| DE | DE63370205000005023307 | John Doe | false | no | NAME_NOT_MATCH | BFSWDE33XXX | 0.4 s |
The API does not return the name the bank holds, only the verdict.
Every code is an upper-case string in the error field. The HTTP status separates the two kinds: a refused request (nothing was sent to a bank; nothing charged except INVALID_IBAN_CHECKSUM) and a completed verification with a status.
| HTTP | Code | Meaning | What to do |
|---|---|---|---|
| 400 | MISSING_API_KEY | No x-api-key header. | Add the header. |
| 401 | INVALID_API_KEY | The key is not known. | Copy it exactly as shown under API Access. |
| 401 | IP_NOT_ALLOWED | The key is restricted to certain IP addresses and the request came from another one. | Add the calling server’s address under Settings. |
| 401 | USER_NOT_ALLOWED | The BAV service is not active on this account. | Order the service, or contact support if you have. |
| 401 | SUBSCRIPTION_EXPIRED | The BAV service has expired. | Renew it under My Services. |
| 401 | NO_CREDITS_AVAILABLE | The query balance is used up. | Top up under Pricing. |
| 405 | METHOD_NOT_ALLOWED | The request was not a POST. | Use POST; there is no GET form of this API. |
| 415 | UNSUPPORTED_FORMAT | The Content-Type is not application/json, or the header is missing. | Send the header and a JSON body; form-encoded bodies are not read. |
| 400 | INVALID_JSON | The body could not be parsed as JSON. Also returned for an empty body. | Build the body with your language’s JSON encoder. |
| 400 | MISSING_INPUT_IBAN | No IBAN field, or it is empty. Also returned when the body is not a JSON object (an array, for instance). | Send the IBAN; the field name is case-sensitive. |
| 400 | MISSING_INPUT_NAME | No name field, or it is empty. | Send the account holder’s name. |
| 400 | COUNTRY_NOT_SUPPORTED | The first two characters of the IBAN are not a country on the supported list. Checked before the check digits, so a value that is not an IBAN at all gets this code. | The account cannot be verified through this service. |
| 400 | INVALID_IBAN_CHECKSUM | The country is supported but the IBAN fails the ISO 13616 check-digit test (or is too short): a typo or a made-up number. This validation uses one query. | Correct the IBAN. Do not resend it unchanged. Checking the IBAN check digits on your side first saves the query. |
| 429 | – | More than 20 requests per second (see Rate limits). | Wait and resend at a lower rate. |
| 500 | INTERNAL_SERVER_ERROR:BNFDBS | The bank code in the IBAN is not in our bank directory, so no BIC could be determined for the verification. Not charged. | Do not resend unchanged; check the IBAN. Contact support with the IBAN if it is a real account. |
| 500 | INTERNAL_SERVER_ERROR:UNERSP | The verification request to the bank network failed before an answer came back. Uses one query. | Retry later; contact support if it persists. |
| 500 | INTERNAL_SERVER_ERROR:… | Any other unexpected error on our side; the part after the colon is an internal tag. Match on the prefix INTERNAL_SERVER_ERROR. | Retry later; contact support if it persists. |
HTTP 200, with query and result present and query.success true. One query is used. The first four rows were recorded; the last three follow the API source and were not observed during testing.
| HTTP | error | name_match | valid | Meaning |
|---|---|---|---|---|
| 200 | "" | yes | true | The name matches the name on the account. |
| 200 | NAME_PARTIAL_MATCH | partial | true | The name is close to, but not exactly, the name on the account. |
| 200 | NAME_NOT_MATCH | no | false | The bank holds a different name for this account; the IBAN and the name sent are not a valid pair. |
| 200 | "" | unavailable | true | The bank network answered with a notice or warning that carries no name verdict. The name is unverified. |
| 200 | "" | no | false | The bank network rejected the IBAN and name pair for a reason other than the name. |
| 200 | VERIFICATION_NOT_SUPPORTED | unavailable | null | The bank answered, but this account or bank does not take part in the verification of payee scheme (not applicable in the scheme’s terms). |
| 200 | VOP_REQUEST_FAILED | unavailable | null | The verification request failed in the bank network: the bank did not answer. |
What each outcome means for your code. A verification is answered by a bank, so the same input can give a different answer at a different time (a bank that was unreachable comes back, an account is renamed); the input errors, on the other hand, are deterministic.
| Situation | Meaning | What to do |
|---|---|---|
| 400 or 415 | The request is malformed, or the IBAN is wrong or from an unsupported country. Nothing was sent to a bank (a check-digit failure still uses one query). | Fix the request or the input; do not resend it unchanged. Show the user the IBAN error. |
| 401 | The key, the IP address or the subscription is the problem. | Stop sending; every request will fail the same way until it is fixed. Check the key under API Access, the balance and expiry under My Services. |
| 405 | The request was not a POST. | Use POST. |
| 429 | More than 20 requests per second. The request was rejected before reaching the API: not processed, not charged. | Wait a moment and resend; lower the sending rate. Safe to retry. |
| 500, timeout, connection error | Temporary problem on the way to the API or on the API itself. | Retry with increasing delays (5 s, 30 s, 2 min, then give up and queue). A request that got no response may still have been completed and charged. |
200 with unavailable | The verification could not be completed: the bank is unreachable, not in the scheme, or the account is of a kind that cannot be checked. | Do not retry in a loop; every completed request is charged. Treat the name as unverified, and either retry later or ask the user to confirm the payee another way. |
200 with partial or no | The verification completed; the name does not (fully) match. | Do not retry with the same name: the answer is deterministic. Ask the user to check the name, then verify again before paying. |
Decide on result.name_match and error, never on the HTTP status alone: a 200 response can say that the name does not match.
yes): the name you sent is the name on the account. The payment can go ahead.partial, NAME_PARTIAL_MATCH): the bank judged the names to differ only slightly: a middle name, an initial, an abbreviation, a legal-form suffix such as ODV, e.V. or Ltd. The scheme lets the bank disclose the name it holds in this case, but this version of the API does not return it; ask the payer to confirm the name before paying.no, NAME_NOT_MATCH): the account exists but is held under a different name. Common causes: a trade name instead of the legal company name, a spelling that differs between the local language and an English rendering, a wrong IBAN that happens to be valid. Do not pay without checking with the payee.unavailable): no verdict. With VERIFICATION_NOT_SUPPORTED or VOP_REQUEST_FAILED (valid null) the name could not be checked; with an empty error (valid true) the bank network answered without a name verdict. Causes: the bank is not reachable or does not take part in the scheme; the bank’s system timed out, is overloaded or in maintenance; a problem in the scheme’s infrastructure; the account is closed, blocked or not found; the account is of a kind that is outside the scheme (savings, loan, card, investment and escrow accounts). The name is unverified, not wrong.result.valid says whether the IBAN and the name are a valid pair: false means the bank holds a different name for the account. It does not say that the account exists or is open; a pair that could not be checked is null, a verdict-less answer true, so read it together with name_match and treat only yes as verified.A copy of the API with fixed answers for development and automated tests. It contacts no bank, needs no subscription and uses no queries. Same request format, same JSON bodies, same error codes.
https://sandbox.iban.com/clients/api/verify/v3/Use the key testkey. The answer depends on the IBAN, the name and the key:
| IBAN | name | x-api-key | HTTP | Response |
|---|---|---|---|---|
FR7630006000011234567890189 | John Doe | testkey | 200 | name_match yes, bic AGRIFRPPXXX |
DE89370400440532013000 | John Doe | testkey | 200 | name_match yes, bic COBADEFFXXX |
DE89370400440532013000 | John | testkey | 200 | name_match partial |
NL91ABNA0417164300 | any | testkey | 200 | error VERIFICATION_NOT_SUPPORTED |
BR9700360305000010009795493P1 | any | testkey | 400 | COUNTRY_NOT_SUPPORTED |
FR7630006000011234567890183 | any | testkey | 400 | INVALID_IBAN_CHECKSUM |
| any | any | nomorecredits | 401 | NO_CREDITS_AVAILABLE |
| any | any | serviceexpired | 401 | SUBSCRIPTION_EXPIRED |
| any | any | usernotallowed | 401 | USER_NOT_ALLOWED |
| any | any | ipnotallowed | 401 | IP_NOT_ALLOWED |
| any other IBAN | any | testkey | 400 | SANDBOX_NOT_SUPPORTED_IBAN |
IBANs are matched exactly after spaces are removed (the fixture in lower case is “any other IBAN”); SANDBOX_NOT_SUPPORTED_IBAN exists only on the sandbox.
The request-format errors (MISSING_API_KEY, INVALID_API_KEY, UNSUPPORTED_FORMAT, INVALID_JSON, MISSING_INPUT_IBAN, MISSING_INPUT_NAME, METHOD_NOT_ALLOWED) behave exactly as in production. The sandbox has no fixture for no or unavailable; test those paths with a mocked response.
The services endpoint returns every service on your account with its remaining queries and expiry date, the same information as My Services. Poll it from your monitoring to catch a low balance before the API starts answering 401 NO_CREDITS_AVAILABLE. It takes your api_key and a format (json or xml) and does not use a query.
https://api.iban.com/clients/api/v4/services/?api_key=YOUR_API_KEY&format=jsonhttps://api.iban.com/clients/api/v4/services/?api_key=YOUR_API_KEY&format=xmlThe response, shortened to the entry of this service (the endpoint lists every service on your account, one object each):
{
"services": [
{
"service_name": "BAV (2,500 queries)",
"credits": 52,
"expiry_date": "2027-05-15",
"service_expired": 0
}
],
"errors": []
}The HTTP status is 200 in every case. With a wrong key, services is empty and errors carries code 301 ({"services":[],"errors":[{"code":"301","message":"API Key is invalid"}]}); without format the body is empty.
| Field | Type | Description |
|---|---|---|
service_name | string | Name of the service as shown under My Services. The BAV entry carries the plan size in brackets: BAV (2,500 queries). Match on the prefix BAV. |
credits | number or string | Remaining queries. Services without a quota return the string Unlimited instead of a number, so test the type before comparing. |
expiry_date | string | Expiry date of the service, YYYY-MM-DD. Requests after this date are refused as expired. |
service_expired | 0 or 1 | 1 when the service has expired. |
INVALID_IBAN_CHECKSUM and INTERNAL_SERVER_ERROR:UNERSP; requests refused before the bank is identified use none. Your balance and expiry date are shown under My Services and by the services endpoint.| Term | Meaning |
|---|---|
| Verification of Payee (VoP) | The scheme of the European Payments Council under which a payer’s bank asks the payee’s bank, before a SEPA credit transfer, whether the name given by the payer matches the name on the account. Mandatory for banks in the euro area since October 2025. This API gives you the same check through your own integration. |
| Payee | The account holder who is to receive a payment; the person or company whose IBAN and name you send. |
| PSP | Payment service provider: a bank or other licensed institution that holds accounts. The responding PSP is the one that holds the IBAN and answers the verification. |
| Match / close match / no match | The three possible answers of the scheme when the check could be carried out; returned as yes, partial and no. A close match means the responding bank judged the names to differ only slightly (a middle name, an abbreviation, a legal-form suffix). |
| IBAN | International Bank Account Number (ISO 13616): country code, two check digits and the national account identifier. The check digits are verified before the request is sent to the bank. |
| BIC | Business Identifier Code (ISO 9362), the 8- or 11-character code of a bank or branch. The API returns the issuing bank’s BIC in the 11-character form, head office or branch. |
| Query | One unit of your BAV balance, used by each completed verification. |