# Swappa API — search used and refurbished phones, tablets, laptops, watches, cameras, drones and consoles on swappa.com, and pull a full listing with price, condition, battery health, storage/carrier/colour variant, GTIN, model number, device weight and dimensions, the complete photo gallery, seller rating and ship-from location — no API key or account required

> Search Swappa for live listings. Give a free-text `query` ('iphone 15 pro', 'macbook pro 14', 'playstation 5') or an exact `model` slug, and get back that model's listings for sale right now — each with Swappa's own listing code, price, condition grade, battery health, storage / memory / colour / carrier / model number, photo count, seller name, seller star-rating and ship-from city. Narrow with condition, carrier, colour, storage, memory, processor, model_number, edition, and the warranty / card-payment / individual-seller / Phonecheck / international-shipping switches; sort by price or newest. Paginated 50 per page. Every filter value a model actually supports is returned in `filters_available`, so you never have to guess.
> ReefAPI engine `swappa` · 3 endpoints · clean JSON, no scraping or browsers to manage.

## How to call
- **Endpoint:** `POST https://api.reefapi.com/swappa/v1/<action>` with a JSON body.
- **Auth:** header `x-api-key: <YOUR_REEFAPI_KEY>` — create one free (1,000 credits, no card): https://reefapi.com/signup
- **Response (every call):** `{ ok: boolean, data: ..., meta: { record_count, credits, ... }, error: { code, message } }` — branch on `ok`. Failed or blocked calls are free.
- **One key + one shared credit pool** across every ReefAPI API. Per-call credits are listed on each endpoint below.
- **Use it from an AI agent (MCP):** connect `https://api.reefapi.com/mcp` (remote streamable-http, `Authorization: Bearer <key>`) and your assistant can call these actions directly.

## Endpoints

### POST /swappa/v1/search — 1 credit
Search Swappa for live listings. Give a free-text `query` ('iphone 15 pro', 'macbook pro 14', 'playstation 5') or an exact `model` slug, and get back that model's listings for sale right now — each with Swappa's own listing code, price, condition grade, battery health, storage / memory / colour / carrier / model number, photo count, seller name, seller star-rating and ship-from city. Narrow with condition, carrier, colour, storage, memory, processor, model_number, edition, and the warranty / card-payment / individual-seller / Phonecheck / international-shipping switches; sort by price or newest. Paginated 50 per page. Every filter value a model actually supports is returned in `filters_available`, so you never have to guess.

**Parameters:**
- `query` (string, optional) — What to look for on Swappa — brand, model, or model + variant ('iphone 15 pro', 'macbook pro 14', 'playstation 5', 'canon eos r5'). Swappa searches its CATALOG, so the query is resolved to the best-matching product model and that model's live listings are returned; every other candidate model comes back in `models[]` so you can re-run against an exact `model` slug. Provide `query` OR `model`.
- `model` (string, optional) — A Swappa product-model slug, exactly as it appears in a swappa.com/listings/<slug> URL (e.g. apple-iphone-15, samsung-galaxy-s24-ultra, macbook-pro-2023-14, playstation-5). Skips keyword resolution — one fewer request and a stable, repeatable target. Provide `model` OR `query`.
- `max_results` (integer, optional, default 50) — How many listings to return (1-200). Swappa paginates 50 per page; asking for more than 50 fetches the next pages automatically.
- `page` (integer, optional, default 1) — Which result page to start from (1-based, 50 listings per page). Page until meta.pagination.has_more is false.
- `sort` (enum, optional) — Result ordering. Swappa's default (omit this) is its own relevance/featured ranking. [one of: price_low, price_high, listing_created_newest, listing_created_oldest]
- `condition` (enum, optional) — Only listings in this condition grade. Swappa grades devices New / Mint / Good / Fair; simpler product lines (AirPods, drones) only offer New / Used. Which grades a given model supports is returned in `filters_available.condition`. [one of: new, mint, good, fair, used]
- `carrier` (string, optional) — Connectivity / carrier lock — unlocked, att, t-mobile, verizon, mint for phones, watches and cellular tablets, and wi-fi vs a carrier for Wi-Fi-only tablets and Surface-style laptops. The exact values a model supports come back in `filters_available.carrier`.
- `color` (string, optional) — Device colour (lowercase, hyphenated — e.g. black, space-gray, midnight). Per-model values are in `filters_available.color`.
- `storage` (string, optional) — Storage capacity, written the way Swappa writes it: 128gb, 256gb, 512gb, 1tb. Per-model values are in `filters_available.storage`.
- `memory` (string, optional) — RAM / unified memory, for laptops, tablets and phones that list it (16gb, 32gb…). Per-model values are in `filters_available.memory`.
- `processor` (string, optional) — Processor variant, for computers (e.g. apple-m2-pro-12-core). Per-model values are in `filters_available.processor`.
- `model_number` (string, optional) — Swappa's 'Model' facet — normally the manufacturer/regulatory model number (A2846 for an iPhone 15, G1MNW for a Pixel 8 Pro, A2727 - Cellular for an Apple Watch SE), but on product lines that are sized rather than modelled it is that variant label instead (an Oura Ring lists Size 8 / Size 10). Pass the human value — or the opaque token from `filters_available.modeln` — either works.
- `edition` (string, optional) — Product-line edition, where Swappa defines one (Aluminum vs Stainless for Apple Watch, USB-C vs Lightning for AirPods, Standard Edition for a console). Human label or the token from `filters_available.edition`.
- `with_warranty` (boolean, optional, default false) — Only listings the seller sells with a warranty.
- `accepts_stripe` (boolean, optional, default false) — Only listings whose seller takes credit-card (Stripe) payment.
- `exclude_businesses` (boolean, optional, default false) — Exclude business/store sellers, leaving individual sellers only.
- `phone_check_certified` (boolean, optional, default false) — Only listings the seller has certified with a Phonecheck diagnostic report (offered on phones and tablets).
- `international` (boolean, optional, default false) — Only listings whose seller ships internationally.

**Returns:** product{slug, name, brand, image, description, url, guide_url, rating{average, review_count}, price_range{low, high, currency}, offer_count, availability} + listings[]{listing_id, url, title, headline, price, currency, price_valid_until, availability, condition, battery_health_pct, storage, memory, color, carrier, model_number, processor, edition, gtin, quantity, image, image_count, featured, phonecheck_certified, business_seller, international_shipping, payment_methods[], attributes[]{label, value}, seller{name, type, profile_id, profile_url, rating, ratings_count, location, badges[]}, product_slug, brand} + filters_available{condition[], carrier[], color[], storage[], memory[], processor[], modeln[], edition[], sort[], flags[]} (each {value, label}) + models[]{slug, name, image, min_price, preset_filters, url} — the other catalog matches, returned only when you searched by free-text `query`. meta.pagination{page, per_page, total_results, returned, has_more, next_page}. Notes: `gtin` is only present when the seller/catalog supplied one; `battery_health_pct` is null when a seller left it unreported or the product has no battery grade; `memory`, `processor`, `carrier`, `model_number` and `image_count` exist only for the categories Swappa publishes them for, and are null otherwise.

**Example request body:**
```json
{
  "model": "apple-iphone-15",
  "max_results": 25
}
```

### POST /swappa/v1/price — 2 credits
Re-check ONE listing's price, availability and condition, cheaply. Give it the Swappa listing code you already hold and it returns what the seller is asking right now, whether the listing is still buyable, and the condition grade — and nothing else: no photos, description, specs, seller block or reviews. Built for refreshing a catalogue you already have rather than discovering listings. It reads the small slide-over card Swappa's own grid fetches on hover instead of the whole listing page, so it costs a fraction of `product_detail` — measured live on nine listings across nine product lines: 6.8-11.5 KB against 122.3-171.0 KB for a full `product_detail` (10.7x-19.7x), or 73.5-82.6 KB with its reviews switched off (6.4x-10.9x). Remember what a Swappa listing IS: one specific used device from one seller, not a catalogue entry — when it sells, Swappa takes it down, and this action then returns NOT_FOUND. That is the answer, not a failure: it means the unit you were tracking is gone.

**Parameters:**
- `listing_id` (string, optional) — REQUIRED. Swappa's own listing code — the value in a swappa.com/listing/view/<code> URL and the `listing_id` on every `search` row. An opaque uppercase alphanumeric string (e.g. LAGY58046); never numeric. It identifies ONE physical used device from ONE seller: two identical phones in the same condition are two codes at two prices. Provide `listing_id` OR `url`.
- `url` (string, optional) — Full swappa.com listing URL — an alternative to `listing_id`.

**Returns:** listing_id, url, current_price, regular_price, currency, on_sale, in_stock, condition, condition_schema. Honest caveats, all measured: (1) `regular_price` and `on_sale` are ALWAYS null, and that is a fact about Swappa rather than a gap here — a listing carries ONE seller-set asking price with no struck-through or previous price anywhere on the card, the listing page or its structured data, so filling them in would be inventing a discount; use the price history on a model's own Swappa page if you need a reference price. (2) `in_stock` is true while Swappa still offers Buy Now on the listing and null — never false — otherwise, because silence is not an out-of-stock claim; a listing that has actually sold is removed by Swappa and returns NOT_FOUND. (3) `condition` is Swappa's own grade (New / Mint / Good / Fair, or Used on simpler product lines) and `condition_schema` is the schema.org enum it marks up beside it. On a used-goods marketplace the grade is what decides whether a price is comparable at all, which is why it is here and the specs are not. COMPARE ON `condition`, not on `condition_schema`: Swappa publishes TWO schema.org condition statements for a listing and they can disagree with each other — on 1 of 9 listings measured, its page microdata said UsedCondition while its JSON-LD offer said RefurbishedCondition for the same listing in the same second. `price` reports the microdata value (that is what the card carries) and `product_detail` reports the JSON-LD one, so those two fields can differ between the actions. The human grade was identical on both surfaces for all 9. (4) A listing code Swappa does not have returns NOT_FOUND, never a substituted listing — verified, and the code in the answer is compared against the code you asked for as well.

### POST /swappa/v1/product_detail — 2 credits
Get one Swappa listing in full, by its listing code or its swappa.com URL — the asking price and currency, quantity available, condition grade with Swappa's own condition criteria, the seller's damage description, battery health, storage / memory / colour / carrier / model number / processor, GTIN and GTIN-13, the COMPLETE photo gallery at full resolution, carrier compatibility, shipping (free-shipping flag, rate, ship-from city, handling time, international), payment methods, returns policy, listing created / updated / expiry dates, and the seller (display name, individual-vs-business, profile, star rating, number of ratings, location). Also returns the product the listing belongs to: brand, catalog slug, star rating and review count, top buyer reviews, and — for models with a Swappa product guide — the device spec tables including width, height, depth and weight in grams and ounces, for shipping-cost calculation.

**Parameters:**
- `listing_id` (string, optional) — Swappa's own listing code — the value shown on the listing page and in the /listing/view/<code> URL, and the `listing_id` returned by search. An opaque uppercase string (e.g. LAGY58046); never numeric. Provide `listing_id` OR `url`.
- `url` (string, optional) — Full swappa.com listing URL — an alternative to `listing_id`.
- `include_reviews` (boolean, optional, default true) — Include the product's top buyer reviews inline (`product.top_reviews`). These are reviews of the MODEL written by Swappa buyers — Swappa publishes no per-listing reviews. Costs one extra page fetch; set false for the fastest possible response.
- `max_reviews` (integer, optional, default 6) — How many of the product's most recent reviews to include (1-20).

**Returns:** listing{listing_id, url, title, headline, description, damage_description, price, currency, price_valid_until, quantity, availability, condition, condition_schema, condition_criteria[], battery_health_pct, storage, memory, color, carrier, model_number, processor, attributes[]{label, value}, facet_values, phonecheck_certified, badges[], approved, featured, images[], image_count, carrier_compatibility{network, compatible_carriers[]}, shipping{free, rate, currency, ships_from, handling, international}, payment_methods[], returns_policy[], date_created, date_updated, date_expires (all three ISO YYYY-MM-DD), seller{name, type, profile_id, profile_url, rating, ratings_count, location, badges[]}} + product{slug, name, brand, gtin, gtin13, image, url, guide_url, catalog_url, rating{average, review_count}, specs[]{group, name, value, values[]}, size_and_weight{width_mm, height_mm, depth_mm, weight_g, weight_oz}, top_reviews[]{rating, text, author, date}}. Honest caveats: `gtin`/`gtin13` appear only when Swappa's catalog carries a barcode for that exact variant (common on phones and consoles, usually absent on accessories, drones and cameras); `specs` and `size_and_weight` exist only for models that have a Swappa product guide (phones, tablets, laptops, watches — not cameras, drones, consoles, audio); `top_reviews` exists only where Swappa publishes a reviews page for the model — for catalog-only products it publishes the aggregate `rating` but no review text, and `meta.fetched.reviews` then says `not_published` rather than pretending the fetch failed; `battery_health_pct` is null unless the seller reported it; `carrier`, `model_number`, `memory` and `processor` are per-category. Category-specific descriptors that have no cross-category meaning — an Apple Watch case material, an AirPods connector, a console edition, a 5G band, an iPad glass option — are returned verbatim and in page order in `attributes[]` with a null label (search labels those with Swappa's own facet name, because the filter vocabulary is published on the search page and not on a listing page). Nothing the listing page shows is dropped.

## More
- Try it live, no code: https://reefapi.com/playground?engine=swappa
- Human docs page: https://reefapi.com/docs/swappa
- Every ReefAPI API in one file (for your AI): https://reefapi.com/llms-full.txt
