Skip to main content

macadress

Official Python client for the macadress.com MAC address and OUI vendor lookup API.

  • Vendor name, OUI, IEEE block, country, address type, EUI-64 / IPv6 link-local, randomization confidence, device guess
  • Keyless vendor-name lookup, plus keyed single / batch / directory-search calls
  • Typed dataclass results with a raw escape hatch, typed exceptions per failure mode
  • Sync Client and async AsyncClient from the same API, one dependency (httpx)
from macadress import Client

mac = Client("mk_live_xxx")

mac.vendor("00:03:93:AB:12:34")            # "Apple, Inc."   (no API key required)
mac.lookup("00:03:93:AB:12:34").country    # "US"

Install

pip install macadress

Requires Python 3.10+.

Getting a key

vendor() needs no key. Everything else does. A free key (1,000 lookups a day) is instant at macadress.com/signup; see pricing for more.

Usage

Create a client

from macadress import Client

mac = Client("mk_live_xxx")

# keyless: only vendor() will work
anon = Client()

# options
mac = Client(
    "mk_live_xxx",
    base_url="https://api.macadress.com",   # change only for a self-hosted deployment
    timeout=10.0,
    headers={"X-Trace": "my-app"},
)

# reuse / close
with Client("mk_live_xxx") as mac:
    ...

vendor() - name only, no key

Returns None when the address is valid but has no vendor to report (unregistered, private, or locally administered / randomized).

mac.vendor("00:03:93:AB:12:34")   # "Apple, Inc."
mac.vendor("02:1a:2b:3c:4d:5e")   # None

:, -, . and space grouping are all accepted, as is a bare 12-hex string.

lookup() - full analysis

r = mac.lookup("3C:22:FB:12:34:56")

r.organization              # str | None
r.vendor_lookup_reliable    # bool  (False for a private block / LAA)
r.oui                       # "3C:22:FB"
r.matched_prefix            # full matched block at its real width
r.block_type                # BlockType.MA_L (compares equal to "MA-L")
r.country                   # "US" | None
r.administration_type       # AdministrationType.UNIVERSALLY_ADMINISTERED | ...
r.potentially_randomized    # bool
r.randomization_confidence  # RandomizationConfidence.NONE | POSSIBLE | LIKELY
r.eui64                     # "3E:22:FB:FF:FE:12:34:56" | None
r.ipv6_link_local           # "fe80::3e22:fbff:fe12:3456" | None
r.device.category           # DeviceCategory.UNKNOWN (usually)
r.explanation               # plain-English summary
r.meta.database_version     # "2026-08-30"

Any field not covered by an attribute is still reachable:

r.get("vendor_location.city")   # dotted path into r.raw, default None
r.raw                           # the decoded payload as given

batch() - up to 100 at once

Results come back in input order; check each item.

for item in mac.batch(["00:03:93:00:00:00", "3C:22:FB:00:00:00", "bad"]):
    if item.failed:
        print(item.input, "->", item.error)
    else:
        print(item.input, "->", item.organization)

Raises ValueError (no request made) if the iterable is empty or has more than macadress.MAX_BATCH_SIZE (100) entries.

search_vendors() - the directory

result = mac.search_vendors("Cisco", country="US", limit=20)

result.total   # total matches, ignoring the limit
for block in result:
    print(block.block_type, block.organization, block.country)

health()

mac.health()   # bool, keyless, uncounted; a transport failure is False

Async

AsyncClient mirrors Client method for method:

import asyncio
from macadress import AsyncClient

async def main():
    async with AsyncClient("mk_live_xxx") as mac:
        print(await mac.vendor("00:03:93:AB:12:34"))
        r = await mac.lookup("3C:22:FB:12:34:56")
        print(r.organization)

asyncio.run(main())

Errors

Every failure is a MacadressError.

Class When
InvalidMACError HTTP 400, the input did not parse
AuthenticationError HTTP 401, missing or invalid API key
RateLimitError HTTP 429, per-minute rate exceeded. .retry_after (seconds) when sent
QuotaExceededError HTTP 429, billing-cycle quota spent. Subclass of RateLimitError
APIError any other 4xx/5xx, or an unreadable response
TransportError never reached the API: DNS, connection, TLS, timeout (__cause__ is the httpx error)
ConfigurationError bad client options (raised before any request)

Each carries .status_code, .request_id and .body where available.

from macadress import Client, RateLimitError, MacadressError

try:
    r = mac.lookup(value)
except RateLimitError as exc:
    time.sleep(exc.retry_after or 5)
except MacadressError as exc:
    log.warning("macadress %s: %s (%s)", exc.status_code, exc, exc.request_id)

Development

python -m venv .venv && . .venv/bin/activate
pip install -e ".[dev]"

pytest
mypy
ruff check .

The version lives in src/macadress/_version.py; keep CHANGELOG.md and the release tag in step with it.

Links

License

MIT, see LICENSE. A product of ApisOS FZE.

Download files

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

Source Distribution

macadress-1.0.0.tar.gz (16.5 kB view details)

Uploaded Source

Built Distribution

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

macadress-1.0.0-py3-none-any.whl (14.6 kB view details)

Uploaded Python 3

File details

Details for the file macadress-1.0.0.tar.gz.

File metadata

  • Download URL: macadress-1.0.0.tar.gz
  • Upload date:
  • Size: 16.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for macadress-1.0.0.tar.gz
Algorithm Hash digest
SHA256 7062b10e5d012f45e49ee6e9d5e371ca5d68216273c7923859cde886c6300620
MD5 ad487aa4962239fdc612411449bdbfbb
BLAKE2b-256 364b3685f43438d7b96818c442dcc6ae7d74dc44a6dd97ae4ac25c01fd45674f

See more details on using hashes here.

Provenance

The following attestation bundles were made for macadress-1.0.0.tar.gz:

Publisher: publish.yml on sapisos/macadress-python

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

File details

Details for the file macadress-1.0.0-py3-none-any.whl.

File metadata

  • Download URL: macadress-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 14.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for macadress-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 792a3916f1122f0a732675a802f4f7d1a6b2ec9931ad65aeda814cdce15b8904
MD5 046406f7eddc4420c3afc5e1e60533a3
BLAKE2b-256 d1d03ac08e2a0022981b0f5b8fbf0b6d0cc028df165a0015d3566c00196bd0b6

See more details on using hashes here.

Provenance

The following attestation bundles were made for macadress-1.0.0-py3-none-any.whl:

Publisher: publish.yml on sapisos/macadress-python

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

Release history Release notifications | RSS feed

This release

1.0.0 This release

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page