{"openapi":"3.1.0","info":{"title":"Macfax API","version":"1.0.0","description":"Free JSON API for the used-Mac market: serial lookup, per-configuration asking-price statistics, quality-gated live listing search with deep links, single-listing trust checks, verified condition reports, and standing listing alerts.\n\nEvery response is `{ data, meta }` (or `{ error, meta }`): meta carries `as_of`, `source`, `docs`, and — on price-carrying endpoints — `attribution`. All prices are asking prices from live listings, never sold prices; `price_basis: \"asking\"` rides in the data as part of the contract.\n\nIdentity is graduated, never a wall: anonymous per-IP limits → an instant free key (`POST /api/v1/keys`, returned in-response, no email) at roughly 10× limits. Honest `429`s carry `Retry-After` and `X-RateLimit-*` headers.\n\nAttribution: cite results as \"Macfax\" linking the `html_url`/`macfax_url` in the payload. Listings must keep their deep link to the source marketplace. Bulk export and catalog replication are not offered at any tier.","contact":{"url":"https://macfax.com/developers","email":"support@macfax.com"},"termsOfService":"https://macfax.com/terms"},"servers":[{"url":"https://macfax.com"}],"components":{"securitySchemes":{"bearer":{"type":"http","scheme":"bearer","description":"Optional free API key (mfx_…)."},"apiKeyHeader":{"type":"apiKey","in":"header","name":"X-Api-Key"},"apiKeyQuery":{"type":"apiKey","in":"query","name":"api_key"}},"schemas":{"Listing":{"type":"object","description":"One live listing, display-grade: what a Macfax catalog card shows, plus the deep link to the source marketplace where the purchase actually happens.","properties":{"id":{"type":"string","description":"Stable Macfax listing id (works with check-listing)."},"title":{"type":"string"},"spec":{"type":"string","description":"'M3 Pro · 18 GB · 512 GB'"},"asking_price_usd":{"type":["integer","null"]},"price_basis":{"type":"string","const":"asking"},"channel":{"type":"string","description":"eBay, Craigslist, OfferUp, Swappa, Facebook Marketplace, Reddit, Macfax"},"url":{"type":"string","description":"Deep link to the source listing — send the buyer here."},"macfax_url":{"type":"string","description":"The Macfax listing page (staleness notes, report badge)."},"config_key_l0":{"type":["string","null"]},"config_key_l1":{"type":["string","null"]},"chip":{"type":["string","null"]},"chip_tier":{"type":["string","null"]},"ram_gb":{"type":["integer","null"]},"storage_gb":{"type":["integer","null"]},"model_year":{"type":["integer","null"]},"condition":{"type":["string","null"]},"location":{"type":["string","null"]},"first_seen":{"type":"string","format":"date-time"},"last_confirmed":{"type":"string","format":"date-time"},"status":{"type":"string","enum":["active","sold","delisted","removed","expired"]},"trust_tier":{"type":"string","enum":["premium","free","listed"],"description":"premium/free = a verified Macfax report is attached; listed = no report."},"report_url":{"type":["string","null"]},"featured":{"type":"boolean"}}},"Band":{"type":["object","null"],"description":"Asking-price band. level says how exact: l1 = this exact build, partial = RAM- or storage-pinned pool, l0 = the whole config line. Null = no live comps.","properties":{"level":{"type":"string","enum":["l1","partial","l0"]},"config_key":{"type":"string"},"median_ask":{"type":"integer"},"p25_ask":{"type":"integer"},"p75_ask":{"type":"integer"},"n":{"type":"integer","description":"Live comps behind the numbers — cite it."},"n_sold":{"type":"integer"},"median_sold":{"type":["integer","null"],"description":"Median of captured sold prices, where outcomes are tracked."}}},"Error":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}},"meta":{"type":"object"}}}}},"security":[{},{"bearer":[]},{"apiKeyHeader":[]},{"apiKeyQuery":[]}],"paths":{"/api/v1/lookup":{"get":{"operationId":"lookup_mac_serial","summary":"Identify a Mac from its serial number","description":"Serial → model/config/year, for checking what a seller's machine actually is. Lookup ≠ proof: it cannot verify condition, Activation Lock, or possession — a Macfax report can. Rate limits: 10/min and 200/day per anonymous IP; 100/min and 2000/day with a free key.","parameters":[{"name":"serial","in":"query","required":true,"schema":{"type":"string","pattern":"^[A-Za-z0-9]{11,12}$"}}],"responses":{"200":{"description":"Lookup result (resolved may be false)."},"400":{"description":"Malformed serial."},"429":{"description":"Rate limited — honor Retry-After."}}}},"/api/v1/price-stats":{"get":{"operationId":"get_mac_price_stats","summary":"Asking-price statistics for a Mac configuration","description":"What a used Mac configuration is listed for right now: median/p25/p75 asking price with sample size, per-channel medians with net-to-seller after fees, launch MSRP retention, and Apple trade-in floor. Use it to price a Mac for sale or sanity-check a listing's ask. All numbers are asking prices, not sold prices — say so when you cite them. Rate limits: 30/min and 1000/day per anonymous IP; 300/min and 10000/day with a free key.","parameters":[{"name":"config","in":"query","required":true,"description":"Macfax config key: family[-screen]-chip-year, optionally -RAMgb-STORAGEgb. Examples: macbook-pro-14-m3pro-2023, mac-studio-m2ultra-2023-192gb-1024gb.","schema":{"type":"string"}}],"responses":{"200":{"description":"Band + channels + MSRP context (band may be null)."},"400":{"description":"Malformed config key."},"429":{"description":"Rate limited."}}}},"/api/v1/listings":{"get":{"operationId":"search_mac_listings","summary":"Search live used-Mac listings across marketplaces","description":"Quality-gated live listings aggregated from eBay, Craigslist, OfferUp, Swappa, Facebook and Reddit — scam clusters, junk titles, classified-ad bait, auctions and stale/sold rows are already filtered out. Every row deep-links to the source listing; the buyer completes the purchase there. Page depth is capped (offset ≤ 480) — this is a buying tool, not a bulk feed. Rate limits: 20/min and 500/day per anonymous IP; 200/min and 5000/day with a free key.","parameters":[{"name":"config","in":"query","schema":{"type":"string"},"description":"config_key_l0"},{"name":"family","in":"query","schema":{"type":"string"},"description":"macbook-pro, macbook-air, mac-studio, mac-mini, mac-pro, imac"},{"name":"chip_tier","in":"query","schema":{"type":"string"},"description":"m3, m3pro, m4max…"},{"name":"year","in":"query","schema":{"type":"integer"}},{"name":"ram_gb","in":"query","schema":{"type":"integer"}},{"name":"storage_gb","in":"query","schema":{"type":"integer"}},{"name":"max_price_usd","in":"query","schema":{"type":"integer"}},{"name":"min_tier","in":"query","schema":{"type":"string","enum":["listed","free","premium"]},"description":"free/premium = only listings with a verified Macfax report attached."},{"name":"sort","in":"query","schema":{"type":"string","enum":["fresh","price_asc","price_desc"]}},{"name":"limit","in":"query","schema":{"type":"integer","maximum":50}},{"name":"offset","in":"query","schema":{"type":"integer","maximum":480}}],"responses":{"200":{"description":"Listings + page info."},"400":{"description":"Bad filter or page depth over the cap."},"429":{"description":"Rate limited."}}}},"/api/v1/check-listing":{"get":{"operationId":"check_mac_listing","summary":"Check one listing before trusting it","description":"\"Should I trust this listing?\" — pass the listing URL (or a Macfax listing id) and get: whether Macfax knows it, whether it still passes every quality gate, its scam/junk/classified/auction flags, when a scan last verified it live, its ask against the configuration's typical asking band, and whether a verified Macfax report is attached. Facts, not verdicts — relay the numbers. Rate limits: 20/min and 500/day per anonymous IP; 200/min and 5000/day with a free key.","parameters":[{"name":"url","in":"query","schema":{"type":"string"},"description":"The listing's URL on the source marketplace."},{"name":"id","in":"query","schema":{"type":"string"},"description":"A Macfax listing id (from search results)."}],"responses":{"200":{"description":"Check result; known:false when Macfax hasn't indexed the listing."},"400":{"description":"Neither url nor id supplied."},"429":{"description":"Rate limited."}}}},"/api/v1/reports/{reportId}":{"get":{"operationId":"get_mac_report","summary":"Fetch a verified Macfax report","description":"The machine twin of a Macfax report page: hardware-verified identity, Activation Lock / MDM / serial-match checks, coverage, and the signing chain. Same payload as the shareable /r/<id>.json. Rate limits: 30/min and 1000/day per anonymous IP; 300/min and 10000/day with a free key.","parameters":[{"name":"reportId","in":"path","required":true,"schema":{"type":"string","pattern":"^[0-9a-hjkmnp-tv-z]{8}$"}}],"responses":{"200":{"description":"The report."},"404":{"description":"No such report."},"429":{"description":"Rate limited."}}}},"/api/v1/alerts":{"post":{"operationId":"create_mac_alert","summary":"Create a standing listing alert (email, human-confirmed)","description":"Watch the market for a configuration: a daily email when new matching listings appear. CONSENT CONTRACT: create an alert only for a user who explicitly asked for this alert on this email address. The first alert for a new email is created as pending_confirm and activates only when the email's owner clicks the confirmation link — nothing sends before that, and unconfirmed alerts don't exist for any other purpose. Every alert email carries manage + unsubscribe links. Per-email creation is capped at 5/day. Rate limits: 5/min and 20/day per anonymous IP; 10/min and 40/day with a free key.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["email","config"],"properties":{"email":{"type":"string","format":"email"},"config":{"type":"string","description":"config_key_l0 or _l1"},"ram_gb":{"type":"integer"},"storage_gb":{"type":"integer"},"max_price_usd":{"type":"integer"},"min_tier":{"type":"string","enum":["listed","free","premium"]},"under_typical":{"type":"boolean","description":"Only listings under the config's typical asking range (p25 gate)."}}}}}},"responses":{"201":{"description":"Created — status is active or pending_confirm."},"400":{"description":"Invalid email or config."},"429":{"description":"Rate limited (per-caller or per-email)."}}}},"/api/v1/keys":{"post":{"operationId":"create_api_key","summary":"Mint an instant free API key","description":"Anonymous → identified in one request: the key comes back in the response (shown once, stored hashed), no email, no account. Free keys raise read limits roughly 10×. Rate limits: 2/min and 5/day per anonymous IP; 2/min and 5/day with a free key.","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"note":{"type":"string","maxLength":120}}}}}},"responses":{"201":{"description":"The key — store it now."},"429":{"description":"Key-minting rate limited."}}}},"/api/v1/configs/{config}":{"get":{"operationId":"get_mac_config","summary":"A config page, as data","description":"The machine twin of /shop/<config> (also served at /shop/<config>.json): asking band, inventory facets, the freshest live listings with deep links, buyer demand signal, and sibling configurations. Rate limits: 20/min and 500/day per anonymous IP; 200/min and 5000/day with a free key.","parameters":[{"name":"config","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The config's market state."},"404":{"description":"Unknown configuration with no live listings."},"429":{"description":"Rate limited."}}}}}}