# Swappie API — live data from swappie.com, Europe's largest refurbished-Apple first-party store (Helsinki, 23 countries). Browse the refurbished iPhone, iPad, MacBook and AirPods catalogue of any national storefront, then open a model for its COMPLETE live price table: every SKU (storage x colour x cosmetic grade x battery type x VAT scheme) with its own price, its unit stock count, a per-warehouse stock breakdown and the timestamp Swappie last changed that price. Also returns Swappie's trade-in payouts — what it PAYS for a used iPhone or iPad in each market. Prices and stock are per country and really differ. No login, no API key.

> Browse one device catalogue of one Swappie market with the storefront's own filters and sort: one row per MODEL with its from-price in the market's currency, the colours and capacities it is stocked in, its bestseller flag and Swappie's own popularity score. The whole category arrives in a single request (30 iPhone, 17 iPad, 16 MacBook, 2 AirPods models on 2026-10-07), so there is no paging to manage. Every filter offered here was measured against an unfiltered call in the SAME run and really changes the result; filters the source accepts and then ignores are not exposed, and any value the source drops is reported in `meta.warnings` instead of passing as a successful filtered call. `grade` is special: it also re-quotes each model's from-price AT that grade. There is no keyword search on swappie.com and none is faked here — use `models` for an exact model.
> ReefAPI engine `swappie` · 4 endpoints · clean JSON, no scraping or browsers to manage.

## How to call
- **Endpoint:** `POST https://api.reefapi.com/swappie/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 calls are free except verified SHEIN NOT_FOUND on product/detail and price (4 credits).
- **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). Send the key as `Authorization: Bearer <key>`, or put it in the URL (`?key=<key>`) when the client has no header field, as ChatGPT does.

## Endpoints

### POST https://api.reefapi.com/swappie/v1/search — 3 credits
Browse one device catalogue of one Swappie market with the storefront's own filters and sort: one row per MODEL with its from-price in the market's currency, the colours and capacities it is stocked in, its bestseller flag and Swappie's own popularity score. The whole category arrives in a single request (30 iPhone, 17 iPad, 16 MacBook, 2 AirPods models on 2026-10-07), so there is no paging to manage. Every filter offered here was measured against an unfiltered call in the SAME run and really changes the result; filters the source accepts and then ignores are not exposed, and any value the source drops is reported in `meta.warnings` instead of passing as a successful filtered call. `grade` is special: it also re-quotes each model's from-price AT that grade. There is no keyword search on swappie.com and none is faked here — use `models` for an exact model.

**Parameters:**
- `market` (enum, required, default "fi") — Which Swappie storefront to read, by the site's own locale slug. Prices, stock and currency are PER MARKET and really differ: on 2026-10-07 the same iPhone 15 128 GB grade D read EUR 425.00 on `de`/`nl`, EUR 435.00 on `it` and EUR 445.00 on `fi`/`en`, and `se` quoted SEK 4,999.00. Five currencies are live: EUR (34 locales), SEK, DKK, PLN, CZK (2 each). A country with two languages has two slugs (fi / fi-sv / fi-en) that serve the same inventory in different wording. This is a CLOSED list on purpose: swappie.com answers an unknown locale with the international EUR site and HTTP 200, so a typo would silently bill you for the wrong country's prices. [one of: en, at, at-en, be, be-fr, be-en, cz, cz-en, de, de-en, dk, dk-en, ee, ee-en, es, es-en, fi, fi-sv, fi-en, fr, fr-en, gr-en, hr-en, hu-en, ie, it, it-en, lt-en, lu-en, lv-en, mt-en, nl, nl-en, pl, pl-en, pt, pt-en, se, se-en, si-en, sk, sk-en]
- `category` (enum, optional, default "iphone") — Which device catalogue to browse. The whole category comes back in one request (no paging): 30 + 17 + 16 + 2 = 65 models in stock across the four on 2026-10-07. Filters differ by category — colour, storage, price and model work everywhere, while `camera` and `size` are iPhone concepts. [one of: iphone, ipad, macbook, airpods]
- `models` (array, optional) — Keep only these models. The source's own model names, several allowed. Measured on `iphone`/`en`: 30 models unfiltered -> 1 for ['iPhone 15'] -> 2 for ['iPhone 15','iPhone 16'].
- `colors` (array, optional) — Keep only models offered in these colour families (Swappie's own tokens, which group its shade names: `black` covers Black, Graphite, Jet Black, Midnight and Space Black). Measured on `iphone`/`en`: 30 -> 4 for ['yellow'] -> 16 for ['blue','yellow']. [one of: white, black, silver, gray, midnight, starlight, skyBlue, gold, roseGold, pink, purple, blue, red, orange, yellow, mint, green]
- `storages` (array, optional) — Keep only models offered with these capacities, in GB (32, 64, 128, 256, 512, 1024, 2048). Measured on `iphone`/`en`: 30 -> 6 for [64] -> 25 for [512] -> 29 for [128,256].
- `grade` (enum, optional) — Only models available in this cosmetic grade, AND quote each model's from-price AT that grade. This filter moves the price, not just the row count: measured on `iphone`/`en` in one run, the iPhone 14 card read EUR 319.00 at D, 325.00 at C, 335.00 at B and 389.00 at A, and the model count went 30 -> 24 (D), 30 (C), 29 (B), 29 (A). Use `detail` for the full per-grade price table of one model. [one of: A, B, C, D]
- `camera` (enum, optional) — iPhone camera count. Measured on `iphone`/`en`: 30 -> single 5, dual 12, triple 13 (5+12+13 = 30, so it partitions the catalogue exactly). The source silently ignores any other value, e.g. `3`, so only these three are accepted. [one of: single, dual, triple]
- `size` (enum, optional) — iPhone body size class, Swappie's own three buckets. Measured on `iphone`/`en`: 30 -> small 4, normal 17, large 9 (4+17+9 = 30). 'regular' and 'medium' are NOT the source's words and are silently dropped by it, so they are rejected here. [one of: small, normal, large]
- `min_price` (number, optional) — Lowest price, in the market's own currency and MAJOR units (800 = EUR 800, not 80000). Like every filter here it selects VARIANTS, so a model survives when any of its variants is in range and is then quoted at the cheapest IN-RANGE variant. Measured on `iphone`/`en`: 30 models -> 12 at min_price 800. On `macbook`/`en` all 16 survived but were re-quoted (MacBook Air M1 13: EUR 609.00 -> 959.00), which is the same rule seen from the other side.
- `max_price` (number, optional) — Highest from-price, same units as `min_price`. Measured on `iphone`/`en`: 30 models -> 6 at max_price 250. Combine with `min_price` for a band.
- `release_year` (array, optional) — Keep only models Apple released in these calendar years. Measured on `iphone`/`en`: 30 -> 4 for [2023] and 4 for [2024]. NOTE the asymmetry the source has: this FILTER takes real years, but the row field the source calls `releaseYear` is an internal rank on phones and tablets — this engine publishes that raw number as `catalog_rank` and leaves `release_year` null rather than return a wrong year.
- `sort` (enum, optional, default "popular") — Row order, the storefront's own seven values. Verified to really reorder on `iphone`/`en` in one run: `lowest` opened at EUR 145.00 (iPhone SE 2020), `highest` at EUR 1,149.00 (iPhone 17 Pro Max) and `newest` at the iPhone 17e. Any other word is silently ignored by the source, so it is rejected here. [one of: popular, lowest, highest, newest, oldest, promoted, promoted_popularity]
- `include_pii` (boolean, optional, default false) — Accepted for gateway compatibility. There is no personal data on this source: the only seller is Swappie Oy, a company, and it is always returned in full.

**Returns:** models[]{model, model_slug, device_category, sku, from_price, from_price_minor, currency, from_price_display, reference_price, reference_price_display, is_discounted, discount_display, from_price_storage_gb, available_colors[], available_storages_gb[], is_bestseller, popularity_score, catalog_rank, release_year, ram_gb, cpu_cores, gpu_cores, sim_type, connector_type, anc_type, wireless_charging_type, headphone_configs[], image_url, url, category_url, detail_params{market, model}} + meta{market, country, language, currency, category, total_models, filters_applied{}, filters_ignored[], price_range{min,max}, seller{}}

**Example request body:**
```json
{
  "market": "de",
  "category": "iphone",
  "sort": "lowest"
}
```

### POST https://api.reefapi.com/swappie/v1/detail — 2 credits
The COMPLETE live offer table of one model in one market, straight from the storefront's own inventory call: one row per sellable SKU — storage x colour x cosmetic grade (A Premium / B Excellent / C Good / D Acceptable) x battery type x VAT scheme — each with its own price, its own unit stock count, the stock split across Swappie's warehouses (Finland, Germany, the Italian 3PL and the in-transit buckets) and the timestamp Swappie last repriced it. Measured on 2026-10-07: 106 SKUs for iPhone 15, 128 for MacBook Air M1 13, 18 for iPad Air 7 2025 13, 2 for AirPods 4. MacBook rows also carry RAM, CPU/GPU cores, chip variant, screen size and the keyboard language and layout of the actual unit. The summary gives the cheapest price per grade so you can see the condition ladder at a glance. An unknown model name is NOT_FOUND.

**Parameters:**
- `market` (enum, required, default "fi") — Which Swappie storefront to read, by the site's own locale slug. Prices, stock and currency are PER MARKET and really differ: on 2026-10-07 the same iPhone 15 128 GB grade D read EUR 425.00 on `de`/`nl`, EUR 435.00 on `it` and EUR 445.00 on `fi`/`en`, and `se` quoted SEK 4,999.00. Five currencies are live: EUR (34 locales), SEK, DKK, PLN, CZK (2 each). A country with two languages has two slugs (fi / fi-sv / fi-en) that serve the same inventory in different wording. This is a CLOSED list on purpose: swappie.com answers an unknown locale with the international EUR site and HTTP 200, so a typo would silently bill you for the wrong country's prices. [one of: en, at, at-en, be, be-fr, be-en, cz, cz-en, de, de-en, dk, dk-en, ee, ee-en, es, es-en, fi, fi-sv, fi-en, fr, fr-en, gr-en, hr-en, hu-en, ie, it, it-en, lt-en, lu-en, lv-en, mt-en, nl, nl-en, pl, pl-en, pt, pt-en, se, se-en, si-en, sk, sk-en]
- `model` (string, required) — A model name exactly as Swappie writes it — 'iPhone 15', 'iPhone 16 Pro Max', 'iPad Air 7 2025 13', 'MacBook Air M1 13', 'AirPods Pro 2'. Every `search` row returns it as `model` (and as ready-made `detail_params`). The source matches the NAME, not the url slug: 'iphone-15' is answered with HTTP 404 -> NOT_FOUND.
- `in_stock_only` (boolean, optional, default false) — `detail` only: drop SKUs whose stock is 0. Swappie publishes sold-out SKUs with stock 0 and a live price; measured on iPhone 15 / `en`: 106 SKUs published, 63 with stock > 0. Off by default so you can see the full price table.
- `include_pii` (boolean, optional, default false) — Accepted for gateway compatibility. There is no personal data on this source: the only seller is Swappie Oy, a company, and it is always returned in full.

**Returns:** model, market, country, currency, seller{}, offers[]{sku, model, device_category, grade, grade_label, color, color_localized, storage_gb, battery_type, sim_type, price, price_minor, currency, reference_price, is_discounted, stock, in_stock, stock_on_hand, stock_in_transit, stock_display_capped, stock_is_capped_on_site, stock_by_warehouse{}, vat_margin_scheme, price_updated_at, country, slug, url, ram_gb, cpu_cores, gpu_cores, chip_variant, screen_size_in, screen_coating, keyboard_language, keyboard_layout, anc_type, connector_type, wireless_charging_type, inventory_priority, images[], cross_sell_skus[]}, summary{offer_count, in_stock_offer_count, units_in_stock, units_on_hand, units_in_transit, offers_with_capped_site_stock, min_price, max_price, price_by_grade{}, stock_by_grade{}, warehouses[]}, facets{colors[], storages_gb[], grades[], battery_types[], sim_types[], keyboard_languages[], laptop_configs[]} + meta{offers_hidden_out_of_stock}

**Example request body:**
```json
{
  "market": "fi",
  "model": "iPhone 15"
}
```

### POST https://api.reefapi.com/swappie/v1/trade_in — 3 credits
What Swappie PAYS for a used device in one market — the buy-back side of the same company, which almost no refurbished catalogue publishes. One row per model it currently buys (28 phone + 18 tablet models on 2026-10-07) with the top payout for that model in perfect condition and top capacity, the capacities it accepts and the full model name per capacity. Payouts are per market and really differ: iPhone 17 Pro Max read EUR 1,264 on `fi`, EUR 1,290 on `de` and SEK 14,270 on `se` in one run. Put next to the `search` sell-price for the same model it gives the live buy/sell spread. The list also runs ahead of the sell catalogue — Swappie was already quoting an iPhone 18 Pro on 2026-10-07. 10 of the 43 locales have no trade-in site and answer MARKET_UNAVAILABLE.

**Parameters:**
- `market` (enum, required, default "fi") — Which Swappie storefront to read, by the site's own locale slug. Prices, stock and currency are PER MARKET and really differ: on 2026-10-07 the same iPhone 15 128 GB grade D read EUR 425.00 on `de`/`nl`, EUR 435.00 on `it` and EUR 445.00 on `fi`/`en`, and `se` quoted SEK 4,999.00. Five currencies are live: EUR (34 locales), SEK, DKK, PLN, CZK (2 each). A country with two languages has two slugs (fi / fi-sv / fi-en) that serve the same inventory in different wording. This is a CLOSED list on purpose: swappie.com answers an unknown locale with the international EUR site and HTTP 200, so a typo would silently bill you for the wrong country's prices. [one of: en, at, at-en, be, be-fr, be-en, cz, cz-en, de, de-en, dk, dk-en, ee, ee-en, es, es-en, fi, fi-sv, fi-en, fr, fr-en, gr-en, hr-en, hu-en, ie, it, it-en, lt-en, lu-en, lv-en, mt-en, nl, nl-en, pl, pl-en, pt, pt-en, se, se-en, si-en, sk, sk-en]
- `category` (enum, optional, default "all") — Which trade-in list to return. Swappie buys back phones and tablets only (28 phone + 18 tablet models on 2026-10-07); it publishes no MacBook or AirPods trade-in price. [one of: all, phone, tablet]
- `include_pii` (boolean, optional, default false) — Accepted for gateway compatibility. There is no personal data on this source: the only seller is Swappie Oy, a company, and it is always returned in full.

**Returns:** devices[]{model, device_category, max_payout, currency, currency_symbol, price_sku_id, model_id, storage_options[], full_name_by_storage{}, image_url, url} + meta{market, country, currency, phone_models, tablet_models, payout_range{min,max}}

**Example request body:**
```json
{
  "market": "fi",
  "category": "phone"
}
```

### POST https://api.reefapi.com/swappie/v1/popular — 1 credit
The 20 refurbished iPhones Swappie is pushing right now in one market, as its own home-page carousel builds them: real SKUs, not models — each with its grade, colour, capacity, battery type, live price, unit stock and a flag for whether a new battery can be added. 13.5 KB in one request, the cheapest way to sample live Swappie prices and to watch what moves day to day.

**Parameters:**
- `market` (enum, required, default "fi") — Which Swappie storefront to read, by the site's own locale slug. Prices, stock and currency are PER MARKET and really differ: on 2026-10-07 the same iPhone 15 128 GB grade D read EUR 425.00 on `de`/`nl`, EUR 435.00 on `it` and EUR 445.00 on `fi`/`en`, and `se` quoted SEK 4,999.00. Five currencies are live: EUR (34 locales), SEK, DKK, PLN, CZK (2 each). A country with two languages has two slugs (fi / fi-sv / fi-en) that serve the same inventory in different wording. This is a CLOSED list on purpose: swappie.com answers an unknown locale with the international EUR site and HTTP 200, so a typo would silently bill you for the wrong country's prices. [one of: en, at, at-en, be, be-fr, be-en, cz, cz-en, de, de-en, dk, dk-en, ee, ee-en, es, es-en, fi, fi-sv, fi-en, fr, fr-en, gr-en, hr-en, hu-en, ie, it, it-en, lt-en, lu-en, lv-en, mt-en, nl, nl-en, pl, pl-en, pt, pt-en, se, se-en, si-en, sk, sk-en]
- `include_pii` (boolean, optional, default false) — Accepted for gateway compatibility. There is no personal data on this source: the only seller is Swappie Oy, a company, and it is always returned in full.

**Returns:** offers[]{sku, model, grade, grade_label, color, color_localized, color_hex, storage_gb, battery_type, price, price_display, reference_price_display, currency, stock, in_stock, is_premium_series, new_battery_available, slug, url, image_url} + meta{market, country, currency, price_range{min,max}}

**Example request body:**
```json
{
  "market": "fi"
}
```

## At scale
- **Volume:** 5M+ requests a day, measured at 60 requests a second across the fleet with no
  central bottleneck. Per-key limits are raised for high-volume accounts; volume pricing on request.
- **Missing a source:** tell us a site we do not cover and it becomes an engine. A customer asked
  for bestprice.gr on 21 Sep 2026 and it was in the catalog on 22 Sep.
- **Support:** 2 minute median time from a question in the live chat to the first answer. Setup
  help included, no support tier to buy.
- **One key, one credit pool** across every API. No per-site plans, no separate subscriptions.

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