JSON API

Build with macvendor

Query the maintained public service at https://macvendor.io/v1. No API key is currently required. Responses are JSON, include release metadata, and use RFC 9457 problem details for errors.

Quickstart

Make your first lookup

Use a canonical 12-character hexadecimal MAC to avoid an HTTP 308 redirect.

cURL
curl --fail --silent --show-error --location \
  'https://macvendor.io/v1/lookup/00000C123456?mode=enriched'
Open this JSON response

Trimmed response

JSON
{
  "query": {
    "normalized": "00000C123456"
  },
  "matchStatus": "matched",
  "assignment": {
    "prefix": "00000C",
    "prefixLength": 24,
    "registry": "MA-L",
    "organizationName": "Cisco Systems, Inc",
    "source": { "slug": "ieee-ma-l" }
  },
  "curatedMatches": [],
  "insights": [],
  "data": {
    "activeVersion": 21,
    "publicationVersion": 25,
    "policyVersion": "v2"
  }
}
JavaScript
const response = await fetch(
  "https://macvendor.io/v1/lookup/00000C123456?mode=enriched"
);

if (!response.ok) throw new Error(`Lookup failed: ${response.status}`);
const result = await response.json();
console.log(result.assignment?.organizationName ?? "No match");

Core endpoints

Start with these three

Single lookup

GET /v1/lookup/{mac}

Defaults to enriched mode: official assignment, reviewed claims, insights, and release metadata.

Bulk lookup

POST /v1/lookups

Accepts up to 100 official or 50 enriched lookups in one bounded request.

Exact assignment

GET /v1/assignments/{registry}/{prefix}

Retrieves one active registry assignment and can include its evidence chain.

Bulk request

Omit mode for the backward-compatible official response. Use enriched to include reviewed matches and insights without merging them into the assignment.

Bulk cURL
curl --fail --silent --show-error \
  --request POST \
  --header 'Content-Type: application/json' \
  --data '{"mode":"enriched","macs":["00000C123456","001B63AABBCC"]}' \
  'https://macvendor.io/v1/lookups'
More endpoints
Enriched lookupGET /v1/lookup/{mac}?mode=enriched
Official layer onlyGET /v1/lookup/{mac}?mode=official
Active releaseGET /v1/data-release
Release changesGET /v1/data-release/changes
Organization searchGET /v1/organizations?q=Apple
Organization identityGET /v1/organizations/{key}
Correction intakePOST /v1/corrections

Response model

Keep each layer distinct

matchStatus

matched or explicit no_match for the official assignment layer. No match is still HTTP 200.

assignment

The official registry holder for the longest matching prefix, or null when no assignment matches.

curatedMatches

Reviewed third-party or owner claims. They do not override the official assignment.

insights

Supporting aliases, device hints, and usage notes kept separate from assignment data.

data

The resolution and publication versions needed to reproduce or audit a stored result.

Official lookup probes 36, then 28, then 24 bits. The longest matching active assignment wins. A registry assignment identifies an address-block holder; it is not proof of the physical device's manufacturer, model, owner, or identity.

Version and cache contract

Cache only what is reusable

Every v1 response includes X-API-Version, X-App-Version, and X-Request-Id. Data responses also carry release metadata in the JSON body.

ResponseCache-ControlETag
Matched lookuppublic, max-age=60, s-maxage=300, stale-while-revalidate=60Opaque validator
No matchpublic, max-age=30, s-maxage=60Opaque validator
Bulk, evidence, correction, errorprivate, no-storeNone
Canonical redirectpublic, max-age=300None
Send If-None-Match on repeated GETs and treat ETags as opaque. Compression may expose a weak encoded variant. A matching validator returns HTTP 304 with the same ETag, cache policy, and version headers.

Service signals

Handle errors deliberately

StatusMeaningClient action
308Canonical MAC URLFollow the Location header or send canonical paths directly.
400Invalid requestFix the input; retrying the same request will not help.
404Exact resource not foundUsed by endpoints that request one specific resource.
429Rate limitedWait for the number of seconds in Retry-After before retrying.
503Temporary degradationUse bounded exponential backoff and a client timeout.
Every error uses the same RFC 9457 fields: type, title, status, code, detail, requestId, apiVersion, and appVersion.

Rate limits

Budget requests by cost

The standard public quota is 50 cost units per client IP in each fixed 10-second window. A rejected request returns HTTP 429 and Retry-After in seconds.

OperationMaximumCost
Single lookup1 MAC1 unit
Official bulk100 MACs1 unit per 2 submitted MACs, rounded up
Enriched bulk50 MACs1 unit per submitted MAC
Organization lookup1 request2 units
Evidence or correction1 request5 units
Quota is calculated from submitted entries, including duplicates. Do not parallelize retries; wait for Retry-After.

Integration

Use the published contract

Honor Retry-After, reuse cacheable GET responses with ETag, and never send credentials or unrelated personal data.

See the public plan and exact usage limits before scheduling discovery workloads.

Send only what is needed

Use HTTPS and choose official mode when reviewed matches and insights are unnecessary.

Store release metadata

Assignments and reviewed claims can change between governed publications.