Skip to main content

Library for local BIN/IIN lookup from public CSV datasets.

Project description

card_bin_data

card_bin_data is an async Python library for local BIN/IIN lookup from public CSV datasets. It normalizes multiple sources into a SQLite or PostgreSQL database and exposes typed lookup results for backend services.

Tests Coverage Downloads PyPI Python versions License Docs

Documentation: https://zylvext.github.io/card-bin-data/

The MVP is a library only. CLI commands such as card_bin_data update and card_bin_data lookup are post-MVP.

Install

From a local checkout:

uv pip install -e .

The package requires Python 3.12 or newer and uses async SQLAlchemy drivers: sqlite+aiosqlite for SQLite and postgresql+asyncpg for PostgreSQL.

SQLite Quickstart

from pathlib import Path

from card_bin_data import BinData, BinDataStore, LookupStatus
from card_bin_data.sources import (
    BinlistDataAdapter,
    MarlonlpBinlistDataAdapter,
    VenelinkochevBinListDataAdapter,
)


async def run() -> None:
    store = BinDataStore.from_url("sqlite+aiosqlite:///var/lib/card_bin_data/card_bin_data.db")
    await store.init()

    await store.import_sources(
        [
            BinlistDataAdapter(Path("datasets/binlist_data/ranges.csv")),
            VenelinkochevBinListDataAdapter(Path("datasets/venelinkochev_binlist_data/bin-list-data.csv")),
            MarlonlpBinlistDataAdapter(Path("datasets/marlonlp_binlist_data/binlist-data.csv")),
        ],
    )

    client = BinData(store=store)
    result = await client.lookup("12345678")

    if result.status is LookupStatus.FOUND and result.data is not None:
        print(result.data.scheme, result.data.issuer_name)

    await store.close()

The database URL is always explicit. The library does not read a default path or environment variable on its own.

PostgreSQL Setup

Use PostgreSQL when several services need the same normalized dataset:

from card_bin_data import BinDataStore


store = BinDataStore.from_url("postgresql+asyncpg://card_bin_data_user@localhost/card_bin_data")
await store.init()

Treat credential-bearing URLs as secrets in application code. store.database_url masks passwords for display; keep using your original secret configuration value for connection setup.

Lookup Results

BinData.lookup() returns a LookupResult with one of three statuses:

  • LookupStatus.FOUND: data contains a BinInfo value.
  • LookupStatus.NOT_FOUND: the input was valid but no record matched.
  • LookupStatus.INVALID: the input failed normalization or optional Luhn validation.

Successful results include source attribution:

result = await client.lookup("12345678")

if result.found:
    for source in result.sources:
        print(source.source_id, source.license)

Import And Update

BinDataStore owns schema initialization and write operations:

await store.init()
summary = await store.import_sources([primary_adapter, enrichment_adapter, fallback_adapter])

import_sources() runs a replace-all import inside one store-managed transaction and delegates to BinDataStore.import_sources_with_session(session, adapters). By default, provenance rows include each adapter row's raw payload. Pass store_raw_payload=False to store {} in bin_record_sources.raw_payload instead while keeping source_row_key and data-source attribution intact:

summary = await store.import_sources(
    [primary_adapter, enrichment_adapter, fallback_adapter],
    store_raw_payload=False,
)

Use the bring-your-own-session APIs when your application already owns the SQLAlchemy unit of work:

async with store.session() as session:
    result = await BinData.lookup_with_session(session, "12345678")

async with store.session_factory.begin() as session:
    summary = await BinDataStore.import_sources_with_session(session, adapters, store_raw_payload=False)

lookup() is read-only and can be shared across concurrent async tasks. The store does not keep an in-process write lock; replace-all imports rely on the caller's transaction and database locking behavior. SQLite connections use a 30 second busy timeout so overlapping writers wait before failing. If your deployment needs single-writer scheduling across processes or services, enforce that in the host application.

Source Priority And Attribution

The MVP source priority is:

  1. binlist/data as the primary source.
  2. venelinkochev/bin-list-data as enrichment.
  3. marlonlp/binlist-data as fallback.

The normalized fields use scheme for the card network. In binlist/data, brand maps to product_brand; in the two larger datasets, Brand or brand maps to scheme.

Public datasets are unofficial, can conflict, and may be stale. card_bin_data keeps row-level source attribution so callers can inspect which source rows contributed to a result. The venelinkochev and marlonlp sources are documented as CC BY 4.0 by their repositories. The final binlist/data license statement must be verified before public release claims are finalized.

PAN Safety

Lookup accepts 6-digit BINs, 8-digit IINs, and full card-number-like input. Spaces and hyphens are stripped before validation, but only safe prefixes are kept in LookupResult.query. Full input values are not stored in card_bin_data tables and are not returned in result objects.

Luhn validation is disabled by default:

result = await client.lookup(card_number_from_user, validate_luhn=True)

If validate_luhn=True is used with a short BIN/IIN, the result includes a validation warning instead of raising. card_bin_data is not a PCI validation service and does not guarantee card validity.

Documentation

See the docs in docs/:

  • docs/api.md
  • docs/backends.md
  • docs/sources.md
  • docs/security.md
  • docs/performance.md

Runnable examples live in examples/.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

card_bin_data-0.2.0.tar.gz (5.4 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

card_bin_data-0.2.0-py3-none-any.whl (34.6 kB view details)

Uploaded Python 3

File details

Details for the file card_bin_data-0.2.0.tar.gz.

File metadata

  • Download URL: card_bin_data-0.2.0.tar.gz
  • Upload date:
  • Size: 5.4 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.13

File hashes

Hashes for card_bin_data-0.2.0.tar.gz
Algorithm Hash digest
SHA256 56db0f165a7ed097d2aaaad7b54e1c5bea9e8124c53c2ee6f69fe6e8cd88eb23
MD5 7e8db8f0576210a0ceaa7fc0ed86d28e
BLAKE2b-256 797c0500c01ceca30df0a96d0e502cff8b1638d07af901af56306cbe4b553656

See more details on using hashes here.

Provenance

The following attestation bundles were made for card_bin_data-0.2.0.tar.gz:

Publisher: 3_release.yml on ZYLVEXT/card-bin-data

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file card_bin_data-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: card_bin_data-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 34.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.13

File hashes

Hashes for card_bin_data-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 11472c00188666e4788da6fc496e22c954bf635dda7175000dc5b9d9835c3e47
MD5 57ab45765185b472fa2af9a948cbf81f
BLAKE2b-256 d1697ebc991fea2833183191d5c50facf90ba920c96cc0ee0e06c381f5259209

See more details on using hashes here.

Provenance

The following attestation bundles were made for card_bin_data-0.2.0-py3-none-any.whl:

Publisher: 3_release.yml on ZYLVEXT/card-bin-data

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page