# Back Market API — live refurbished-electronics marketplace data from 15 Back Market storefronts (backmarket.com, .de, .co.uk, .it, .nl, .be, .at, .pt, .fi, .ie, .gr, .sk, .se, .co.jp, .com.au). Search the catalogue of refurbished iPhones, Android phones, MacBooks, laptops, tablets, watches, consoles and audio, then pull every seller offer for one product: the price in that market's currency, Back Market's own condition grade and the price step between grades, stock, warranty months, the new-retail reference price, the product rating and Back Market's own repairability and longevity scores. No login, no API key.

> Search or browse one Back Market storefront. `market` picks the storefront and therefore the catalogue, the price list and the currency. Give `query` for keyword search, or leave it out and use `brand` / `model` / `category_id` / `grade` / `storage` / `colour` / `price_min` / `price_max` / `deals_only` to walk a slice of the catalogue — every one of those filters was measured against the unfiltered total in the same run and every one changes it. `total` is the storefront's own exact count for the request, so an ignored filter is impossible to miss. Each row carries Back Market's own condition grade (name, numeric value and the storefront's own label), the live price with the market's currency AND the price string the site itself printed, the separate new-retail reference price, stock, warranty months and the seller's numeric id. 🔴 Only about 1000 rows are retrievable per query however large `total` is — `pagination` says where the floor is.
> ReefAPI engine `backmarket` · 4 endpoints · clean JSON, no scraping or browsers to manage.

## How to call
- **Endpoint:** `POST https://api.reefapi.com/backmarket/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/backmarket/v1/search — 2 credits
Search or browse one Back Market storefront. `market` picks the storefront and therefore the catalogue, the price list and the currency. Give `query` for keyword search, or leave it out and use `brand` / `model` / `category_id` / `grade` / `storage` / `colour` / `price_min` / `price_max` / `deals_only` to walk a slice of the catalogue — every one of those filters was measured against the unfiltered total in the same run and every one changes it. `total` is the storefront's own exact count for the request, so an ignored filter is impossible to miss. Each row carries Back Market's own condition grade (name, numeric value and the storefront's own label), the live price with the market's currency AND the price string the site itself printed, the separate new-retail reference price, stock, warranty months and the seller's numeric id. 🔴 Only about 1000 rows are retrievable per query however large `total` is — `pagination` says where the floor is.

**Parameters:**
- `market` (enum, optional, default "de") — Which Back Market storefront to read. This picks the catalogue, the price list, the currency and the language of the condition-grade label, so it is the single most important parameter: the same phone is a different price and a different currency in every market. 15 storefronts are supported and each one was verified live. backmarket.fr and backmarket.es exist but their search back end refused every probe, so they are not offered and answer MARKET_UNAVAILABLE instead of pretending. [one of: de, us, gb, it, nl, be, at, pt, fi, ie, gr, sk, se, jp, au]
- `query` (string, optional) — Free-text keyword, exactly as typed into the site's own search box ('iphone 13', 'macbook air m1', 'galaxy s22'). Either `query` or a filter such as `brand`, `model` or `category_id` should be given; calling with neither is allowed and walks the whole catalogue of that market, which is what `total` will tell you.
- `brand` (string, optional) — Manufacturer, lower-case, as the source's own prefix-free brand key spells it ('apple', 'samsung', 'google', 'lenovo', 'dell'). Measured to bite: 310 rows unfiltered, 69 with brand=apple on backmarket.de.
- `model` (string, optional) — Exact model name, lower-case ('iphone 13', 'iphone 13 pro', 'galaxy s21'). This is a whole-value match on the source's own model key, not a substring search — 'iphone 13' does NOT include 'iphone 13 pro'. Use `query` for loose matching.
- `colour` (string, optional) — Colour exactly as that storefront prints it, which means it is in that market's language ('Gold', 'Mitternacht', 'Sierrablau' on backmarket.de). Read the available values out of `facets.color` in the response of an unfiltered call.
- `storage` (string, optional) — Storage capacity exactly as the source prints it, including the unit and the space: '64 GB', '128 GB', '256 GB', '512 GB', '1 TB'. Measured to bite: 310 → 37 for '256 GB'.
- `grade` (enum, optional) — Back Market's appearance grade, named by the source's own market-independent numeric value. 🔴 The storefront's WORDING for the same value differs per market and is returned separately as `grade_label`: value 12 prints as 'Gut' on backmarket.de, 'Fair' on backmarket.com and 'Buono' on backmarket.it — all measured live. Filter and compare on `grade`/`grade_value`; show `grade_label` to a human. This is the defining attribute of a refurbished marketplace: the same device is a different price in every grade (one live iPhone 13 128 GB: good 258, excellent 289, very good 289.99, premium 365 EUR). The numeric `grade_value` returned on every row is market-independent; the `grade_label` is in that storefront's language. Measured to bite: 310 → 30 for premium. [one of: premium, excellent, very_good, good]
- `price_min` (number, optional) — Lowest price to include, in that market's own currency (see `currency` in the response). Measured to bite: 310 → 24 for 300–500 EUR on backmarket.de.
- `price_max` (number, optional) — Highest price to include, in that market's own currency. Measured to bite: 310 → 289 for price_max=300 on backmarket.de.
- `deals_only` (boolean, optional, default false) — Only products that currently carry a Back Market deal or seller flash sale. Measured to bite: 310 → 38 on backmarket.de.
- `category_id` (integer, optional) — Numeric category id, as returned by the `categories` action and on every row as `category_id` (2 = Smartphone). Measured to bite: 310 → 37 for 2.
- `sort` (enum, optional, default "best_sellers") — Result order. Each value is a separate index on the source's side, so the order is the storefront's own and not re-sorted here. Verified live: the same query's first prices were 258/250/360 by default, 13.45/16.99/17.00 ascending and 1006/801/652 descending. [one of: best_sellers, price_asc, price_desc]
- `page` (integer, optional, default 1) — 1-based page number. 🔴 Only about 1000 rows are retrievable per query no matter how large `total` is — the whole backmarket.de catalogue reports total 18141 but serves 42 pages of 24. `pagination.last_page`, `pagination.retrievable_max` and `pagination.has_more` in the response say exactly where the floor is. Past the last page the source returns 0 rows; it does not repeat the last page.
- `page_size` (integer, optional, default 24) — Rows per page, 1..100. The storefront's own grid uses 24. A larger page does not raise the ~1000-row retrievable ceiling, it only uses fewer pages to reach it (measured: 42×24, 20×50, 10×100).
- `include_facets` (boolean, optional, default true) — Return the storefront's own live facet counts and price statistics alongside the rows (every brand, model, colour, storage, grade and category with its count, plus min/max/avg price). This is what lets you build a filter UI or find the real spelling of a colour in that market's language. Turn it off for a smaller response.

**Returns:** products[]{product_id, offer_id, listing_id, title, model_name, url, image, market, price, currency, price_display, price_new_reference, price_new_reference_display, discount_pct_vs_new, has_deal, flash_sale_discount_pct, grade, grade_value, grade_label, condition, brand, model, colour, category, category_id, connector, sim_lock, specs_summary, colour_options, stock, warranty_months, seller_id, rating, rating_count, scores} + meta{market, locale, currency, total, rows, pagination{page, page_size, last_page, retrievable_max, has_more}, filters_applied, facets, price_stats, index, attempts, warnings}}

**Example request body:**
```json
{
  "query": "iphone 13",
  "market": "de",
  "page_size": 24
}
```

### POST https://api.reefapi.com/backmarket/v1/detail — 1 credit
Every live seller offer for ONE product in one market, by `product_id`. This is the action that makes Back Market worth querying: a product page is a competition between sellers and grades, and this returns the whole ladder in one call — each offer with its own condition grade, its own price in the market's currency, its own stock, its own warranty and its own seller id, cheapest first. On top of that it returns the product itself: title, brand, model, colour, storage summary, category, the colour options the source lists, the new-retail reference price, the product rating with its review count and Back Market's own repairability, camera, performance, screen and longevity scores. `price_range`, `grades_available` and `sellers_count` are computed from the offers in the same response. A product id that is not live in that market answers NOT_FOUND — never an empty success (verified against a non-existent UUID, which the source answers with total 0).

**Parameters:**
- `product_id` (string, required) — The product UUID, as returned in `product_id` on every search row and as the last path segment of a Back Market product URL (backmarket.de/de-de/p/iphone-13-128-gb-ohne-vertrag/<THIS>). A full product URL is also accepted and the id is taken out of it.
- `market` (enum, optional, default "de") — Which Back Market storefront to read. This picks the catalogue, the price list, the currency and the language of the condition-grade label, so it is the single most important parameter: the same phone is a different price and a different currency in every market. 15 storefronts are supported and each one was verified live. backmarket.fr and backmarket.es exist but their search back end refused every probe, so they are not offered and answer MARKET_UNAVAILABLE instead of pretending. [one of: de, us, gb, it, nl, be, at, pt, fi, ie, gr, sk, se, jp, au]
- `grade` (enum, optional) — Back Market's appearance grade, named by the source's own market-independent numeric value. 🔴 The storefront's WORDING for the same value differs per market and is returned separately as `grade_label`: value 12 prints as 'Gut' on backmarket.de, 'Fair' on backmarket.com and 'Buono' on backmarket.it — all measured live. Filter and compare on `grade`/`grade_value`; show `grade_label` to a human. This is the defining attribute of a refurbished marketplace: the same device is a different price in every grade (one live iPhone 13 128 GB: good 258, excellent 289, very good 289.99, premium 365 EUR). The numeric `grade_value` returned on every row is market-independent; the `grade_label` is in that storefront's language. Measured to bite: 310 → 30 for premium. [one of: premium, excellent, very_good, good]

**Returns:** product{product_id, title, url, image, market, currency, brand, model, colour, category, category_id, specs_summary, colour_options, rating, rating_count, scores, price_min, price_max, price_min_display, price_new_reference, grades_available[], sellers_count, offers_count, offers[]{product_id, offer_id, listing_id, title, model_name, url, image, market, price, currency, price_display, price_new_reference, price_new_reference_display, discount_pct_vs_new, has_deal, flash_sale_discount_pct, grade, grade_value, grade_label, condition, brand, model, colour, category, category_id, connector, sim_lock, specs_summary, colour_options, stock, warranty_months, seller_id, rating, rating_count, scores}} + meta{market, locale, currency, total, index, attempts}}

**Example request body:**
```json
{
  "product_id": "ef5660d2-6883-4b81-b47d-86e5720687ef",
  "market": "de"
}
```

### POST https://api.reefapi.com/backmarket/v1/categories — 1 credit
The live category tree of one storefront, read off the storefront's own navigation: every universe (Smartphones, Laptops, Tablets, Audio, Gaming, Household …) with its child categories, each with the id you can pass back as `category_id` and the title in that market's own language. Cheap lookup action — one small request, no product data. Use it to discover what a market actually sells before searching it.

**Parameters:**
- `market` (enum, optional, default "de") — Which Back Market storefront to read. This picks the catalogue, the price list, the currency and the language of the condition-grade label, so it is the single most important parameter: the same phone is a different price and a different currency in every market. 15 storefronts are supported and each one was verified live. backmarket.fr and backmarket.es exist but their search back end refused every probe, so they are not offered and answer MARKET_UNAVAILABLE instead of pretending. [one of: de, us, gb, it, nl, be, at, pt, fi, ie, gr, sk, se, jp, au]

**Returns:** categories[]{id, name, title, type, children[]{id, name, title, type, image}} + meta{market, locale, count}

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

### POST https://api.reefapi.com/backmarket/v1/markets — 1 credit
The storefronts this engine serves, with each one's host, locale and ISO currency — every value verified against a live query of that storefront, plus the two storefronts that exist but whose search back end refuses us and the two hostnames that do not resolve at all. No network call, no credit-worthy work: this is the honest coverage map, including the parts that go against us.

**Parameters:** none

**Returns:** markets[]{market, host, locale, currency, status} + meta{supported, walled, nonexistent}

## 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=backmarket
- Human docs page: https://reefapi.com/docs/backmarket
- Overview page: https://reefapi.com/backmarket-api
- Every ReefAPI API in one file (for your AI): https://reefapi.com/llms-full.txt
