---
title: "Look up up to 100 MAC addresses in one request"
method: POST
path: "/v1/mac/batch"
---

# Look up up to 100 MAC addresses in one request

`POST /v1/mac/batch`

## Request

- Base URL: `https://api.macadress.com`
- URL: `https://api.macadress.com/v1/mac/batch`
- Auth: one of:
  - HTTP bearer
  - API key in query parameter `api_key`
- TypeScript: <https://skmtc.dev/macadress/apis/macadress-com-api/docs/v1/mac/batch/post.ts> (a function with typed inputs; its response is checked against the schema)

One HTTP call, but each address that resolves is billed against your cycle quota separately: 100 addresses in one batch draws down 100 lookups, the same as making 100 separate calls to GET /v1/mac/{mac} would. The requests-per-minute rate limit is the opposite - this whole call counts once against it, not once per address.

## Request body

- object
  - `macs` string[], required
  - `api_key` string: Alternative to the Authorization header or ?api_key= query param.

## Response `200`

One result per input, in the same order, each with the same shape as GET /v1/mac/{mac}

- object
  - `count` integer
  - `results` BatchItem[]
    - `mac` string, required: Canonical colon-separated uppercase form.
    - `valid` boolean, required
    - `oui` string, required: Always the first 24 bits of the address itself, regardless of matched block width. See matched_prefix for the complete matched registry block.
    - `organization` string, nullable
    - `vendor_address` string, nullable
    - `country` string, nullable: ISO 3166-1 alpha-2
    - `block_type` 'MA-L' | 'MA-M' | 'MA-S' | 'IAB' | 'CID' | 'null', nullable
    - `address_capacity` integer, nullable
    - `range_start` string, nullable
    - `range_end` string, nullable
    - `registered` boolean, required
    - `transmission_type` 'unicast' | 'multicast' | 'broadcast', required
    - `administration_type` 'universally_administered' | 'locally_administered', required
    - `locally_administered` boolean, required
    - `slap_quadrant` 'AAI' | 'ELI' | 'reserved' | 'SAI' | 'null', nullable
    - `eui64` string, nullable
    - `ipv6_link_local` string, nullable
    - `potentially_randomized` boolean, required
    - `randomization_confidence` 'none' | 'possible' | 'likely' | 'unlikely', required
    - `vendor_lookup_reliable` boolean, required
    - `is_zero` boolean, required
    - `is_broadcast` boolean, required
    - `explanation` string, required
    - `is_private` boolean, required: Use organization === null and vendor_lookup_reliable instead.
    - `matched_prefix` string, nullable: The complete registered prefix actually matched, at its real width (colon-separated bytes plus a trailing bare hex nibble for a non-byte-aligned width like /28 or /36). Null when unregistered.
    - `prefix_length` integer, nullable
    - `registry` object, nullable
      - `source` 'IEEE'
      - `record_type` 'MA-L' | 'MA-M' | 'MA-S' | 'IAB' | 'CID'
      - `record_updated_at` string, date, nullable: Always null today: IEEE's public feeds carry no per-record update-date column.
      - `database_synced_at` string, date-time, nullable
    - `device` object, required
      - `category` 'computer' | 'smartphone' | 'tablet' | 'router' | 'switch' | 'wireless_access_point' | 'firewall' | 'server' | 'storage' | 'printer' | 'camera' | 'smart_tv' | 'media_device' | 'gaming_console' | 'iot' | 'embedded_device' | 'industrial' | 'medical' | 'automotive' | 'virtual_machine' | 'container' | 'network_interface' | 'consumer_electronics' | 'unknown': Controlled taxonomy. "unknown" when the vendor is too broad or no vendor profile exists in this deployment's starter dataset: most registered organizations fall here today.
      - `possible_categories` DeviceCategory[]
      - `confidence` 'none' | 'low' | 'medium' | 'high'
      - `inference_source` 'vendor_profile' | 'null', nullable
      - `exact_model_known` false: Always false: a MAC address alone never identifies an exact model.
    - `virtualization` object, required
      - `detected` boolean
      - `platform` string, nullable
      - `confidence` 'none' | 'low' | 'high' | 'exact'
      - `signals` string[]
    - `special_use` object, required
      - `detected` boolean
      - `type` string, nullable
      - `protocol` string, nullable
      - `name` string, nullable
      - `source` string, nullable
      - `confidence` 'none' | 'high' | 'exact'
    - `vendor_location` object, required
      - `raw` string, nullable
      - `address_line` string, nullable
      - `city` string, nullable
      - `region` string, nullable
      - `postal_code` string, nullable
      - `country_code` string, nullable
      - `country_name` string, nullable
      - `parse_confidence` 'none' | 'low' | 'medium'
    - `randomization` object, required: Machine-readable explanation of potentially_randomized/ randomization_confidence, cross-checked against virtualization and local_vendor_derivation so the three never contradict each other: e.g. a Docker container's address, or one recovered at medium+ confidence via local_vendor_derivation, reports "unlikely" here rather than the bit-pattern-only "likely" a locally administered unicast address gets by default. A registered CID/ELI match reports "none": a real IEEE identity, not a randomization candidate at all.
      - `potentially_randomized` boolean
      - `confidence` 'none' | 'possible' | 'likely' | 'unlikely'
      - `signals` string[]
      - `alternative_explanations` string[]
    - `local_vendor_derivation` object, required: Best-effort vendor recovery for a locally administered unicast address, tried as a ranked pipeline (first match wins; every method attempted is listed in methods_tried regardless of outcome): virtualization_prefix (a documented hypervisor/ container convention, e.g. Docker's 02:42 bridge driver or QEMU/KVM's 52:54:00, checked both on the address as submitted and on its U/L-cleared counterpart) then ul_bit_clear (clearing the U/L bit yields a prefix registered to a real organization). detected is true only when one of these fires, the address is not already registered (a registered CID/ELI address has its own real identity via the top-level organization field, and is never offered here), it is unicast, it is not an SAI-quadrant protocol address, and its suffix is not all zero. This is never a decode of OS randomization, whose 46 non-fixed bits are set uniformly at random; it is the alternative reading of the same bits.
      - `detected` boolean
      - `method` '' | 'virtualization_prefix' | 'ul_bit_clear'
      - `methods_tried` string[]: Every method the pipeline attempted, in order, whether or not it fired. Empty when the address was ineligible (see detected's description) and no method ran at all.
      - `universal_mac` string, nullable: The address actually looked up, i.e. this address with the U/L bit cleared. Null for method virtualization_prefix (nothing was unflipped) or when detected is false.
      - `confidence` 'none' | 'low' | 'medium' | 'high'
      - `likelihood_ratio` number, nullable: How much more likely this hit is under "a real assignment with the U/L bit set" than under "a uniformly random address that happened to land on an allocated prefix": 2^22 (the universal-unicast 24-bit prefix space) divided by however many distinct 24-bit prefixes the registry currently covers. Deliberately not a posterior probability: that needs a prior on how common derived-vs-randomized locally administered addresses are in the wild, which this API does not have, so apply your own. Null when detected is false or the count isn't available.
      - `organization` string, nullable: Registered organization behind the cleared prefix. Null when the block is private or nothing was derived.
      - `country` string, nullable: ISO 3166-1 alpha-2 of the derived block.
      - `matched_prefix` string, nullable
      - `block_type` 'MA-L' | 'MA-M' | 'MA-S' | 'IAB' | 'CID' | 'null', nullable
      - `registry` 'oui' | 'convention' | 'null', nullable: "oui": matched_prefix came from the IEEE registry via ul_bit_clear. "convention": a virtualization_prefix match with no IEEE registry lookup involved (e.g. Docker's 02:42, which isn't an assigned OUI at all).
      - `vendor_class` string, nullable: "virtualization" for a virtualization_prefix match; "networking_infrastructure" for a ul_bit_clear match whose organization is network equipment (router/switch/wireless AP/firewall) at medium+ device-classification confidence, the vendor class that raises confidence to "medium" (see confidence's description); otherwise the matched organization's own device category (e.g. "consumer_electronics"), from the same taxonomy as the top-level device.category field. Null when detected is false.
      - `lookup_url` string, uri, nullable
      - `device` object, nullable: enrich device-category inference run against the derived organization; same shape as the top-level device object. Null for a virtualization_prefix match (there is no single organization to classify).
        - `category` 'computer' | 'smartphone' | 'tablet' | 'router' | 'switch' | 'wireless_access_point' | 'firewall' | 'server' | 'storage' | 'printer' | 'camera' | 'smart_tv' | 'media_device' | 'gaming_console' | 'iot' | 'embedded_device' | 'industrial' | 'medical' | 'automotive' | 'virtual_machine' | 'container' | 'network_interface' | 'consumer_electronics' | 'unknown': Controlled taxonomy. "unknown" when the vendor is too broad or no vendor profile exists in this deployment's starter dataset: most registered organizations fall here today.
        - `possible_categories` DeviceCategory[]
        - `confidence` 'none' | 'low' | 'medium' | 'high'
        - `inference_source` 'vendor_profile' | 'null', nullable
        - `exact_model_known` false
      - `signals` string[]: Deprecated: use signal_details, which carries the same codes plus a human-readable detail. Kept for existing consumers reading plain strings.
      - `signal_details` object[]
        - `code` string
        - `detail` string
    - `assignment` object, nullable
      - `registered_at` string, nullable: Always null: no authoritative IEEE registration date exists in the source feed.
      - `first_seen_at` string, date, nullable: When this deployment first observed the record
      - `last_changed_at` string, date, nullable
      - `withdrawn_at` string, date, nullable: Date IEEE stopped listing this block, null while it is listed. A withdrawn block still resolves.
      - `withdrawn_date_unknown` boolean: True when the block was removed before monitoring began, making withdrawn_at only the latest that can have happened.
    - `vendor` object, nullable: Conservative canonical identity: a mechanical slug of the exact registered name, never a merge of spelling variants or subsidiaries.
      - `id` string
      - `registered_name` string
      - `canonical_name` string
      - `slug` string
      - `block_count` integer
      - `lookup_url` string, uri
    - `meta` object, required
      - `request_id` string
      - `api_version` 'v1'
      - `database_version` string, date, nullable
      - `processed_at` string, date-time
      - `cached` boolean
    - `input` string: The original input string as submitted.
    - `error` string: Present only when this entry failed to resolve.

## Other responses

- `400`: Malformed request body, empty macs array, or more than 100 entries
- `401`: Missing or invalid API key
- `429`: Requests-per-minute limit exceeded for the authenticated plan

---

[API](https://skmtc.dev/macadress/apis/macadress-com-api.md) - [All operations](https://skmtc.dev/macadress/apis/macadress-com-api/llms.txt) - [OpenAPI document](https://skmtc.dev/macadress/apis/macadress-com-api/revisions/b25e0c82f1a1?raw)
