Mexico CLABE Validation

CLABE (Clave Bancaria Estandarizada, Spanish for "standardized bank code") is the eighteen-digit account number used for interbank transfers in Mexico. Every SPEI transfer is addressed to a CLABE, and unlike most domestic bank codes it identifies a single account, not just a bank or branch.

A CLABE contains the bank code (3 digits), the plaza code for the city where the account was opened (3 digits), the account number (11 digits) and a control digit.

For example, CLABE number 002010077777777771:

  • 002 - bank code (Banco Nacional de México)
  • 010 - plaza (city) code
  • 07777777777 - account number
  • 1 - control digit

How the control digit works

The last digit is calculated from the first seventeen. Each digit is multiplied by a repeating weight of 3, 7, 1, and only the last digit of each product is kept. Those values are added up, and the control digit is 10 minus the last digit of the sum (or 0 when the sum ends in 0).

For the example above the kept products are 0, 0, 2, 0, 7, 0, 0, 9, 7, 1, 9, 7, 1, 9, 7, 1, 9. They add up to 69, and 10 − 9 = 1, which matches the last digit. A single mistyped digit always breaks this check, and most swaps of two neighbouring digits do too.

What the API checks

  • Format - exactly 18 digits. Otherwise the API returns 400 Invalid CLABE. Must be exactly 18 digits long.
  • Control digit - calculated as described above. A mismatch returns 400 Invalid CLABE. Checksum is incorrect.
  • Bank - the three-digit bank code must belong to a known Mexican institution, otherwise 404 Bank not found.
  • Plaza - the plaza code must exist, otherwise 404 City not found.

How to validate a CLABE number

To start using our Fin Codes API sign up here and create your API key. Pass this key as a bearer token in the Authorization HTTP header, e.g. Authorization: Bearer your-api-key-here.

To validate a CLABE number call /v2/clabe/{clabe_number} endpoint using HTTP client of your preference, i.e.:

curl 'https://api.fincodesapi.com/v2/clabe/002010077777777771' \
    --header 'Authorization: Bearer your-api-key-here' \
    --header 'Accept: application/json'
# INSTALLATION
$ composer require guzzlehttp/guzzle
# REQUEST
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('GET', 'https://api.fincodesapi.com/v2/clabe/002010077777777771', [
    'headers' => [
        'Accept' => 'application/json',
        'Authorization' => 'Bearer your-api-key-here',
    ],
]);

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

url = "https://api.fincodesapi.com/v2/clabe/002010077777777771"

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

response = requests.request("GET", url, headers=headers)

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

const url = 'https://api.fincodesapi.com/v2/clabe/002010077777777771';
const options = {
  method: 'GET',
  headers: {
    'Accept': 'application/json',
    'Authorization': 'Bearer your-api-key-here'
  }
};

fetch(url, options)
  .then(res => res.json())
  .then(json => console.log(json))
  .catch(err => console.error('error:' + err));
const options = {
  method: 'GET',
  headers: {
    'Accept': 'application/json',
    'Authorization': 'Bearer your-api-key-here'
  }
};

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

The response should be:

{
    "success": true,
    "data": {
        "id": "002010077777777771",
        "account_number": "07777777777",
        "bank": {
            "id": "60ad62b6-26cf-4686-960b-e06219e0e0b1",
            "country_id": "MX",
            "code": "002",
            "name": "Banco Nacional de México"
        },
        "cities": [
            {
                "id": "80c7c515-a340-49ed-b3fe-4cef261451c4",
                "country_id": "MX",
                "name": "Aguascalientes"
            }
        ]
    }
}

Response fields

  • id - the CLABE
  • account_number - the eleven-digit account number inside the CLABE
  • bank - the institution identified by the bank code
  • cities - the cities that share the plaza code. One plaza code can cover several cities, so this is always a list.

Common mistakes

  • Sending a card number - a 16-digit debit card number is not a CLABE, even though both can receive transfers. The API only accepts 18-digit CLABEs.
  • Sending the bare account number - the shorter account number shown in a banking app needs the bank code, plaza code and control digit around it to become a CLABE.
  • Lost leading zeros - most bank codes start with 0 (002, 012, 014, 072), and spreadsheets drop them. Store CLABEs as text.

Where the data comes from

Bank and plaza codes are refreshed weekly. The control digit is calculated on every request, so it doesn't depend on any directory.

You can find full documentation here.