Every payment card number starts with a block of digits that isn’t random. The first six to eight identify the bank that issued the card, the network it runs on, and the type of product it is. That block is the Bank Identification Number, or BIN, and reading it in code gives a Python application useful context before a charge is ever attempted.
With a few lines of Python you can tell a prepaid card from a credit card, spot when a card was issued in a different country than the shipping address, and show the right card logo as a customer types. This guide covers how BIN data is structured, how to fetch it from an API, and how to put the result to work.
What the BIN actually tells you
The BIN is the opening segment of the card number, standardized so that networks and banks can route transactions. Decode it and you get a compact profile of the card:
- Scheme or brand: Visa, Mastercard, American Express, Discover, and so on.
- Funding type: credit, debit, or prepaid.
- Issuer: the bank that put the card in the customer’s hand, often with its website and support number.
- Country: where the card was issued, with ISO codes and currency.
- Card level and flags: classic, gold, platinum, world, plus indicators for commercial or reloadable cards.
None of this identifies the cardholder, and none of it requires the full card number. You only need the first six to eight digits, which keeps the sensitive part of the number out of your lookup entirely.
Calling a BIN lookup API from Python
Maintaining your own BIN database means keeping millions of ranges current as banks issue and retire them, so most teams call an API instead. The pattern is a single POST request. The call below uses the requests library and returns in well under a second:
import requests
def lookup_bin(bin_number, api_key):
response = requests.post(
“https://api.binlookupapi.com/v1/bin”,
headers={“Authorization”: f”Bearer {api_key}”},
json={“number”: bin_number},
timeout=5,
)
response.raise_for_status()
return response.json()[“data”]
The example above calls a BIN lookup API, a developer service that returns the issuing bank, brand, card type and country for any BIN and hands back a small JSON object you can read directly. A typical response looks like this:
{
“bin”: “42467101”,
“scheme”: “visa”,
“funding”: “credit”,
“brand”: “VISA”,
“category”: “CLASSIC”,
“country”: { “code”: “US”, “name”: “UNITED STATES” },
“issuer”: { “name”: “JPMORGAN CHASE BANK, N.A.” },
“prepaid”: false,
“commercial”: false
}
Every field is a plain value you can branch on. No parsing of the raw number, no lookup tables to maintain.
Turning the response into fraud signals
BIN data is at its most useful as an early risk signal. A card issued in one country while the billing address sits in another is not proof of fraud, but it is worth a closer look. So is a prepaid card on a high-value order, or a commercial card where you would expect a consumer one.
data = lookup_bin(42467101, api_key)
flags = []
if data[“country”][“code”] != billing_country:
flags.append(“card_country_mismatch”)
if data[“prepaid”]:
flags.append(“prepaid_card”)
if flags:
send_to_manual_review(order_id, flags)
The point is not to block on any single flag. It is to feed these attributes into whatever scoring you already run, so the decision rests on the whole picture rather than the card number alone.
Showing the right thing at checkout
The same call improves the customer’s experience. As soon as enough digits are entered, you can detect the brand and swap in the correct card icon, or adjust validation rules for a format like American Express that uses a different length and security code. Debit and credit cards can carry different messaging where it matters. Small touches like these cut input errors and the false starts that push people away from a checkout.
Handling real card numbers responsibly
Two practical habits keep a BIN integration clean. First, send only the BIN, never the full card number, to any lookup service. Second, cache results, because a given BIN’s attributes rarely change and repeated calls for the same range waste both time and quota.
Anything that touches cardholder data also brings obligations under the PCI Data Security Standard, so keep the lookup on the server side and out of client-side code where the key could leak.
Start by logging the BIN attributes you already have access to at checkout and looking for patterns: how often the card country differs from the billing country, how many prepaid cards you see, which issuers show up most. Once the data is visible, the fraud rules and the interface tweaks tend to write themselves.


