---
title: "Identify a Mac, iPad or iPhone by serial number"
method: GET
path: "/api/v1/lookup"
---

# Identify a Mac, iPad or iPhone by serial number

`GET /api/v1/lookup`

## Request

- Base URL: `https://macfax.com`
- URL: `https://macfax.com/api/v1/lookup`
- Auth: one of:
  - none
  - HTTP bearer
  - API key in header `X-Api-Key`
  - API key in query parameter `api_key`

Resolves an Apple serial number to its exact model, including 2021+ randomized serials whose characters encode nothing (so no character-decoder can read them). Macs, iPads and iPhones resolve; device_type carries Apple's device class. status says what came back (resolved, unknown_serial, unsupported, retry) so a batch never has to parse note. record is the device's history on Macfax: first seen, how often it has been looked up (in buckets), countries in 30 days, and any listing, report or sanitization record on file. For a Mac it also reports whether a verified Macfax report exists for the serial (report carries its URL) and what the model is worth (market: the same object /api/v1/market returns, or null). Lookup ≠ proof: it cannot verify condition, Activation Lock, or possession; a Macfax report can. One credit answers one distinct serial, any Apple device and any year, and the same serial again within 24 hours is free. Running a batch: https://macfax.com/developers#batch. Rate limits: 10/min and 200/day per anonymous IP; 100/min and 2000/day with a free key; 100/min and 5000/day with a paid key.

## Query parameters

- `serial` string, required
- `context` 'inventory' | 'intake' | 'resale' | 'buyer' | 'support' | 'other'
- `run_id` string, uuid

## Response `200`

The answer for this serial, including the unresolved ones: status tells them apart, and billing says what the call cost.

- object
  - `data` LookupResult: One serial's answer. Branch on status; note says the same thing in English for a person.
    - `serial` string: The serial the answer is about, uppercased (with letter O read as zero when only that resolved).
    - `corrected_from` string, nullable: The serial as sent, when it only resolved after reading letter O as zero.
    - `serial_kind` 'randomized' | 'legacy': randomized = 10 characters (2021 on), legacy = 11-12 characters.
    - `status` 'resolved' | 'unknown_serial' | 'unsupported' | 'retry': resolved: the model is identified. unknown_serial: no device has this serial, usually a typo; final, cached, so asking again is free. unsupported: a real Apple device whose model cannot be identified yet; never charged, and asking again gives the same answer. retry: a temporary upstream failure; never charged, so resend it later.
    - `resolved` boolean: True exactly when status is resolved.
    - `model` string, nullable: Apple's name for the model, e.g. "MacBook Pro (14-inch, 2021)" or "iPad (A16)". Display text: names vary between sources.
    - `device_type` string, nullable: Apple's device class: "Mac laptops", "Mac desktops", "iPad" or "iPhone". Null when unresolved, or for a device outside those four. For iPads and iPhones it is the one structured field, since model_identifiers and market come from the Mac catalogue.
    - `model_identifier` string, nullable: The Apple model identifier when exactly one fits, e.g. "MacBookPro18,3".
    - `model_identifiers` string[]: Every Apple model identifier the model can be: the stable join key for a Mac catalogue. Empty for iPads and iPhones.
    - `model_code` string, nullable: Apple's configuration code, when the resolver returns one.
    - `year` integer, nullable: Model year when Apple's name carries one. Null for chip-only names such as "MacBook Air (13-inch, M5)" or "iPad (A16)".
    - `report` object, nullable: A verified Macfax report on file for this serial (id, url, model_name, model_identifier, tier, hardware_verified, issued_at), or null.
    - `market` object, nullable: What the model is worth, the same object /api/v1/market returns. Null for iPads, iPhones and Macs from before Apple Silicon.
    - `record` object, nullable: What Macfax has seen of this device, built from every lookup of the serial and joined to what is on file. Counts are buckets, never raw numbers. Null when the serial did not resolve. No identity, place finer than a country, or referrer is ever returned.
      - `first_seen` string: Month of the first lookup Macfax has of this serial, "YYYY-MM".
      - `times_seen` 'first_time' | '2_to_5' | '6_or_more': Lookups of this serial, counted as distinct callers per day and including this one.
      - `times_seen_30d` 'first_time' | '2_to_5' | '6_or_more': The same count over the last 30 days.
      - `countries_30d` integer: Distinct countries the serial was looked up from in the last 30 days.
      - `listed` object, nullable: A live listing on Macfax for this device (source, url, asking_usd, since), or null.
      - `report_url` string, nullable: The latest verified Macfax report on this serial.
      - `sanitization_url` string, nullable: The latest sanitization record on this serial that was not voided.
    - `note` string: The answer in one sentence, for a person.
    - `caveat` string
    - `billing` object
      - `unit` 'answer' | 'novel': How this key's credits are spent. answer: One credit answers one distinct serial, any Apple device and any year, and the same serial again within 24 hours is free. novel: the earlier unit, one credit per brand new 2021+ resolution, kept by keys bought before 2026-10-08 until their next purchase.
      - `billed` boolean: Whether this call spent a credit.
      - `billable_resolution` boolean: Whether the answer needed a brand new 2021+ resolution, which is what the free daily allowances count. False for cached serials, pre-2021 serials and repeats within 24 hours.
      - `credits_remaining` integer, nullable: The key's balance after this call, on every answered lookup by a paid key (one that has been granted credits). Null for anonymous and free-key callers.
  - `meta` object

## Other responses

- `400`: invalid_serial: not the shape of a serial (a word, or an O where a zero belongs). invalid_context: context is not one of the listed values. Both free.
- `401`: invalid_key: the key sent is unknown or revoked.
- `402`: insufficient_credits: this key's credits are spent. Nothing was charged; serials this key already had answered in the last 24 hours still answer. The offer object carries the top-up path.
- `403`: blocked: contact support@macfax.com.
- `429`: Honor Retry-After and resend the same serial; nothing was charged. error.code says which wall: rate_limited (the per-minute or daily request limit for this caller), novel_budget (the free daily allowance of brand new 2021+ resolutions, which credits remove), answer_budget (a free key's 200 distinct serials a day, which credits remove), or daily_capacity (the shared daily ceiling on new serial resolutions across every caller. Its last 500 a day are held for paid keys, so a free caller refused short of the full ceiling is offered credits; at the full ceiling credits do not help). Sleep for the Retry-After given, never a fixed pause: a daily wall can take hours.

---

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