MPB API & Scraper
The MPB API returns mpb.com, the managed marketplace for used photo and video equipment, as clean JSON in six actions: search, models, product, model, facets and suggest.
🤖 Using an AI assistant? Copy this link into ChatGPT / Claude / Cursor — it reads every endpoint and parameter instantly and tells you if this API fits your use case.
MPB is not a classifieds board. It buys gear in, inspects and grades it in its own hubs and resells it with a warranty, so every listing is ONE physical item with ONE cosmetic grade, ONE usage counter and ONE price — which is why this API is item-level: a search row is a specific camera body, not a model page. Each row carries MPB's own cosmetic grade three ways, because on a graded marketplace the grade IS the product: the source's code (LIKE_NEW, EXCELLENT, GOOD, WELL_USED, HEAVILY_USED, NEW, SPARES_OR_REPAIRS), MPB's own display name for it, and MPB's own star rating as a normalised rank from 0 to 6 you can sort and compare on. Rows also carry the price in that storefront's currency, the brand, MPB's own category and gear type, the lens bayonet as a separate field, the accessories that are physically in the box with that item, the photos, the date it first went online, and — this is the field the second-hand camera trade actually buys — the usage counter MPB publishes for that class of gear: shutter actuations on bodies, recorded hours on camcorders, battery charge cycles on drones. The product action opens one item in full: MPB's own written definition of the grade that item carries, the per-item inspection notes MPB publishes when it found something (a worn rubber grip, corrosion on the hot shoe, a mark on the sensor filter — each with MPB's own code, title and explanation), the accessory checklist with a present-or-absent flag per accessory, the firmware version where MPB records it, the model's full spec sheet, every photo, and every other graded copy of the same model in stock with its own grade and price, so the grade-to-price ladder for that camera is one call. models rolls the same search up one row per model with the live in-stock count and the price band, and facets returns MPB's own live taxonomy with counts, so you never have to guess a filter value. MPB runs thirteen storefronts over three catalogues: the UK in GBP, the US in USD and one shared European catalogue in EUR that the German, French, Italian, Spanish, Portuguese, Dutch, Austrian, Irish and both Belgian storefronts read — the API accepts all thirteen market codes, reports which catalogue it actually read, and returns the model name, category and gear type in that market's own language. No MPB account and no API key on their side: one ReefAPI key and the standard { ok, data, meta, error } envelope.
MPB's seven cosmetic grades, and how much UK stock each one had on 2026-10-07
The grade names and the star rating are MPB's own, carried verbatim; the rank is the number MPB's own storefront filters on, so 0 is the worst and 6 the best. Counts are MPB's own totals for the UK catalogue in a single run (19,829 items unfiltered). Spares-and-repairs stock is excluded unless you ask for it by name, which is what MPB's own storefront does.
| grade (MPB's own name) | condition value | rank | UK items |
|---|---|---|---|
| Brand new | new | 6 | 170 |
| Like new | like_new | 5 | 3,454 |
| Excellent | excellent | 4 | 9,495 |
| Good | good | 3 | 5,936 |
| Well used | well_used | 2 | 728 |
| Heavily used | heavily_used | 1 | 56 |
| Spares and repairs | spares_or_repairs | 0 | excluded by default |
Several grades can be OR-ed in one call: like_new plus excellent returned 12,943 of the same 19,829. The product action adds MPB's own written definition of the grade for that exact item, in the market's language.
Real request and response JSON
Captured from the indexed primary action, search, on .
{
"method": "POST",
"url": "https://api.reefapi.com/mpb/v1/search",
"headers": {
"x-api-key": "$REEF_KEY",
"content-type": "application/json"
},
"body": {
"query": "canon eos r6",
"market": "UK",
"sort": "price_asc"
}
}{
"ok": true,
"meta": {
"api": "mpb",
"endpoint": "search",
"mode": "live",
"latency_ms": 1383.5,
"record_count": 24,
"bytes": 36667,
"cache_hit": false,
"completeness_pct": 17.39,
"market": "UK",
"catalog": "UK",
"currency": "GBP",
"page": 1,
"page_size": 24,
"pagination": {
"page": 1,
"page_size": 24,
"has_more": true,
"total_results": 138
},
"price_source": "search index (see `product` for the page price)",
"upstream_requests": 1,
"total_results": 138,
"charged_credits": 2,
"version": "1.0.0",
"request_id": "0000f05fbb5e4630",
"queue_ms": 1.9,
"fetched_at": "2026-10-08T11:33:20.140Z"
},
"data": {
"products": [
{
"product_id": 9518331,
"sku": "4168605",
"url": "https://www.mpb.com/en-uk/product/canon-eos-r6/sku-4168605",
"model_id": 69474,
"model_name": "Canon EOS R6",
"model_name_localized": "Canon EOS R6",
"model_slug": "canon-eos-r6",
"brand": "Canon",
"category": "Canon R mirrorless cameras",
"category_localized": "Canon R mirrorless cameras",
"product_type": "Prosumer Mirrorless",
"product_type_localized": "Prosumer Mirrorless",
"lens_mount": [
"Canon RF"
],
"condition": "GOOD",
"condition_label": "Good",
"condition_rank": 3,
"price": 719,
"price_was": null,
"price_reduction": null,
"currency": "GBP",
"market": "UK",
"shutter_count": 363000,
"hour_count": null,
"battery_charge_count": null,
"included_accessories": [
"Canon LP-E6NH Battery",
"Canon LC-E6 Battery Charger",
"Canon EOS R6 Battery Door"
],
"images": [
"https://www.mpb.com/media-service/0a87871d-098f-4b4d-b8b4-cb88b849dd20",
"https://www.mpb.com/media-service/8a600418-a076-4412-a71a-b699e23b2d28",
"https://www.mpb.com/media-service/4d1afbb0-476d-41b1-b861-2069e05f5bc4"
],
"first_listed": "2026-09-15T00:00:00Z",
"last_seen": "2026-09-15T00:00:00Z",
"year_of_release": 2020,
"weight_grams": 680,
"model_available_new": false,
"model_new_price": null
},
{
"product_id": 9568954,
"sku": "4219228",
"url": "https://www.mpb.com/en-uk/product/canon-eos-r6/sku-4219228",
"model_id": 69474,
"model_name": "Canon EOS R6",
"model_name_localized": "Canon EOS R6",
"model_slug": "canon-eos-r6",
"brand": "Canon",
"category": "Canon R mirrorless cameras",
"category_localized": "Canon R mirrorless cameras",
"product_type": "Prosumer Mirrorless",
"product_type_localized": "Prosumer Mirrorless",
"lens_mount": [
"Canon RF"
],
"condition": "GOOD",
"condition_label": "Good",
"condition_rank": 3,
"price": 854,
"price_was": null,
"price_reduction": null,
"currency": "GBP",
"market": "UK",
"shutter_count": 123000,
"hour_count": null,
"battery_charge_count": null,
"included_accessories": [
"Third Party LP-E6NH Battery",
"Canon LC-E6 Battery Charger",
"Canon EOS R6 Battery Door"
],
"images": [
"https://www.mpb.com/media-service/09335a74-becf-44be-82c0-a25f5d168100",
"https://www.mpb.com/media-service/92a9826c-c2fe-4286-afa9-0a2e57626727",
"https://www.mpb.com/media-service/0afa5293-9632-4bd2-b27d-6c1ae4b8ed8d"
],
"first_listed": "2026-10-07T00:00:00Z",
"last_seen": "2026-10-07T00:00:00Z",
"year_of_release": 2020,
"weight_grams": 680,
"model_available_new": false,
"model_new_price": null
},
{
"product_id": 9575525,
"sku": "4225799",
"url": "https://www.mpb.com/en-uk/product/canon-eos-r6/sku-4225799",
"model_id": 69474,
"model_name": "Canon EOS R6",
"model_name_localized": "Canon EOS R6",
"model_slug": "canon-eos-r6",
"brand": "Canon",
"category": "Canon R mirrorless cameras",
"category_localized": "Canon R mirrorless cameras",
"product_type": "Prosumer Mirrorless",
"product_type_localized": "Prosumer Mirrorless",
"lens_mount": [
"Canon RF"
],
"condition": "GOOD",
"condition_label": "Good",
"condition_rank": 3,
"price": 909,
"price_was": null,
"price_reduction": null,
"currency": "GBP",
"market": "UK",
"shutter_count": 1000,
"hour_count": null,
"battery_charge_count": null,
"included_accessories": [
"Third Party LP-E6NH Battery",
"Canon LC-E6 Battery Charger",
"Canon EOS R6 Battery Door"
],
"images": [
"https://www.mpb.com/media-service/cfde5dea-e7ae-4f74-b29d-d6c0ee267fbb",
"https://www.mpb.com/media-service/5c3bd2fd-266e-47be-9d70-54be52993a7a",
"https://www.mpb.com/media-service/c652665e-0f7b-4c3e-a1d4-3036e74cbb37"
],
"first_listed": "2026-10-06T00:00:00Z",
"last_seen": "2026-10-06T00:00:00Z",
"year_of_release": 2020,
"weight_grams": 680,
"model_available_new": false,
"model_new_price": null
}
]
}
}What the MPB API does
| Action | Description | Concrete use case | Key params |
|---|---|---|---|
| search | Search or browse one MPB storefront at ITEM level - every row is a specific physical camera, lens or accessory MPB has in stock, with MPB's own cosmetic grade, that item's shutter / hour / battery-charge count, what is in the box with it, its price and the direct product URL. Pass `query`, or any combination of `brand` / `category` / `product_type` / `lens_mount` / `condition` / `price_min` / `price_max`, or nothing at all to walk the whole catalogue. `meta.total_results` is MPB's own exact match count for the request, so a filter that bites and a filter that is ignored are told apart without guessing. NOTE the price in a search row comes from MPB's search index: on 24 items checked against the product page on 2026-10-07, 23 agreed and one was 250.00 EUR stale - call `product` when the exact live price matters. | Pricing teams call search to search or browse one MPB storefront at ITEM level - every row is a specific physical camera,…. | query, market, brand, category, product_type, ... |
| models | The same search, rolled up ONE ROW PER MODEL instead of one row per item: how many graded copies MPB currently holds and the live price band (cheapest to dearest) for that model in that market. This is the question a flat listing cannot answer - 'which Canon RF primes does MPB have in stock right now and from what price'. Takes every filter `search` takes. Measured 2026-10-07: the UK catalogue's 19,839 live items roll up to 3,866 models. | Marketplace operators call models to get the same search, rolled up ONE ROW PER MODEL instead of one row per item. | query, market, brand, category, product_type, ... |
| product | The complete record of ONE item by its `sku`, read off the product page a buyer sees. Adds everything a search row cannot carry: MPB's written definition of the grade this item carries, the per-item inspection notes MPB publishes when it found something (a worn grip, corrosion on the hot shoe, a mark on the sensor filter - each with MPB's own code, title and explanation), the full accessory checklist with a present/absent flag per accessory, the shutter / hour / battery-charge count and firmware, the model's full spec sheet, every photo, and the other graded copies of the same model in stock with their prices. Pass `slug` alongside `sku` (both come from one `search` row) to answer in a single upstream request. A sku that is not live in this market answers NOT_FOUND - MPB's own URL quietly falls back to the model page there, and this engine does not pass that off as a result. | Catalog enrichment teams call product to get the complete record of ONE item by its `sku`, read off the product page a buyer sees. | sku, slug, market, include_pii |
| model | One MODEL and everything MPB has of it: the model record with its full spec sheet, the accessories MPB expects in the box for that model, and every live graded copy in that market with its sku, grade, usage count and price - sorted cheapest first, so the grade-to-price ladder for that camera is one call. Pass `model_id` or `slug`. | Retail analysts call model to get one MODEL and everything MPB has of it. | model_id, slug, market, condition, include_pii |
| facets | The live filter taxonomy of one MPB market: every brand, category, gear type, lens mount and condition grade that actually has stock right now, each with MPB's own count. This is how you discover the exact value to pass to `search` instead of guessing it - and the counts alone answer 'how much Canon glass does MPB hold in the US today'. Accepts the same filters as `search`, so you can ask for the taxonomy INSIDE a scope (the lens mounts available under Fujifilm, say). | Pricing teams call facets to get the live filter taxonomy of one MPB market. | market, facets, query, brand, category, ... |
| suggest | MPB's own model autocomplete: turn a half-typed camera or lens name into the model names MPB actually carries. One tiny request (under 1 KB measured), meant to be called before `search` so a keyword lands on a real model. | Marketplace operators call suggest to get mPB's own model autocomplete. | query, market, count, include_pii |
Call search from your stack
curl -X POST https://api.reefapi.com/mpb/v1/search \
-H "x-api-key: $REEF_KEY" \
-H "content-type: application/json" \
-d '{"query":"canon eos r6","market":"UK","sort":"price_asc"}'import requests
r = requests.post(
"https://api.reefapi.com/mpb/v1/search",
headers={"x-api-key": REEF_KEY},
json={
"query": "canon eos r6",
"market": "UK",
"sort": "price_asc"
},
)
print(r.json()["data"])const res = await fetch("https://api.reefapi.com/mpb/v1/search", {
method: "POST",
headers: {
"x-api-key": process.env.REEF_KEY,
"content-type": "application/json",
},
body: JSON.stringify({
"query": "canon eos r6",
"market": "UK",
"sort": "price_asc"
}),
});
const { ok, data, meta, error } = await res.json();Ask your MCP-connected assistant: call reefapi.mpb.search with {"query":"canon eos r6","market":"UK","sort":"price_asc"}.Who uses this API and why
- Price used bodies by shutter wear: pull every live copy of one camera with its grade, its shutter count and its price in a single call, and see what 250,000 actuations costs against 25,000 on the same model.
- Track the second-hand camera market across the UK, the US and Europe: the same model, the same grade, three currencies, with MPB's own stock counts and price bands per model.
- Build a buying guide or deal alert for photographers: filter by lens mount and grade, set a budget, and get the exact items in stock with their inspection notes and what is in the box.
- Benchmark your own trade-in or resale pricing against a graded reference market, where every comparable is one physical item with a published grade, usage counter and accessory list rather than an average.
- Measure supply and condition mix in used photo gear: MPB's own totals per brand, category, gear type, mount and grade — for example 19,829 UK items of which 9,495 are Excellent and 3,454 Like new on 2026-10-07.
Questions developers ask before integrating
Do I get the shutter count?
Yes, as a separate field, never buried in a description. MPB publishes one usage counter per class of gear and the API returns all three as their own fields: shutter_count on bodies, hour_count on camcorders, battery_charge_count on drones. Measured over 24 rows per group: shutter_count was filled 24 of 24 on professional DSLR bodies and 0 of 24 on prime lenses, hour_count 23 of 24 on camcorders, battery_charge_count 24 of 24 on drones. A null means MPB publishes no counter for that kind of item, not that we dropped it. The product action also returns the firmware version where MPB records it.
How is the condition returned, and can I sort on it?
Three ways on every row. condition is the source's own code (LIKE_NEW, EXCELLENT, GOOD, WELL_USED, HEAVILY_USED, NEW, SPARES_OR_REPAIRS), condition_label is MPB's own display name for it, and condition_rank is MPB's own star rating as a number from 0 to 6 — the same number MPB's storefront filters on — so you can sort, compare and threshold on it without mapping anything yourself. The product action adds condition_description, MPB's own written definition of that grade, in the language of the market you asked for.
Does MPB say what is wrong with a specific item?
Yes, and the API returns it. When MPB's inspection finds something it publishes a note with its own code, the area, a short summary and a full explanation — for example 'Damaged rubber grips / The rubber grip shows signs of wear, but this is just cosmetic', 'Damage to hot shoe / Hot shoe mount has signs of corrosion, but is in full working order', or 'Sensor damage / There's a mark on the sensor filter, but this doesn't affect images'. The product action returns these as observations, one object per finding. A clean item returns none, which is itself the answer. Of 15 items sampled across five gear groups, 4 carried one or two notes.
Do I know what is in the box?
Yes. Search rows carry included_accessories, the list of accessories physically present with that item as MPB lists them (battery, charger, body cap, eyecup, lens hood and so on). The product action upgrades it to MPB's full checklist with a present flag per accessory, so you can tell a body sold with its charger from one sold without. Measured fill: 24 of 24 on bodies, lenses, camcorders and drones; 4 of 24 on batteries and chargers, where there is nothing to include.
Which markets and currencies?
Thirteen MPB storefronts over three real catalogues, measured in one run: the UK catalogue in GBP (19,841 live items), the US catalogue in USD (34,197) and one shared European catalogue in EUR (34,962). The German, French, Italian, Spanish, Portuguese, Dutch, Austrian, Irish and both Belgian storefronts all read that single EU catalogue and the same EUR price list — asking any of those ten market codes for its own separate stock returns zero, because MPB's own storefront rewrites them to the European catalogue before it searches. The API accepts all thirteen codes, reports in meta.catalog which one it actually read, and returns the model name, category and gear type in that market's language.
Is the price the one on the page?
On the product action, yes — it is the product page's own price, cross-checked inside the same response against the decimal string the page prints, and any disagreement is published as price_mismatch rather than quietly resolved. A search row's price comes from MPB's search index instead, and we checked that index against the page on 24 items across all three catalogues and both price extremes: 23 agreed and one was stale by 250.00 EUR. So filter and discover with search, and call product when the exact live price is what you are paying on.
How do I know a filter actually did something?
Every response carries meta.total_results, MPB's own match count for your exact request, plus meta.filters_applied. Against the whole UK catalogue (19,829) in one run: Canon 4,866, Canon plus Nikon 7,747, DSLR lenses 4,949, prime lenses 1,783, Canon EF mount 2,639, like new 3,452, like new plus excellent 12,943, under 200 GBP 9,232, over 1,000 GBP 2,325. Inside a narrower scope of 918 mirrorless bodies the same filters gave 231, 401, 197, 728, 1 and 438 — and Canon EF correctly gave 0, because no mirrorless body carries an EF mount. Four filter fields that MPB's own code lists are deliberately not offered, because the live index returns no values for them at all.
How do I find the right filter value instead of guessing?
Call facets. It returns MPB's own live taxonomy for the market you ask about — every brand, category, gear type, lens mount and grade that has stock right now, each with MPB's own count — and every value it returns is a value search accepts. It also takes the same filters as search, so you can ask for the taxonomy inside a scope, such as which lens mounts are available under Fujifilm. The values are the same English spellings in all thirteen markets, so one integration works everywhere.
Can I get every copy of one camera and compare grades?
That is what the model action is for. Give it a model id or the model slug and it returns the model record with its full spec sheet and the accessories MPB expects in the box, plus every live graded copy in that market with its sku, grade, usage count and price, cheapest first. On the Canon EOS R6 in the UK that was 57 items in stock. The models action does the same thing one level up: the UK catalogue's 19,839 items roll up to 3,866 models, each with its live in-stock count and price band.
Is there a seller to read?
No, and that is the nature of this source rather than something removed. MPB buys the gear, inspects it and sells it itself, so there is no third-party merchant, seller profile or seller rating anywhere on the page — the warranty and the grade are MPB's own. Nothing is masked here; there is simply no seller entity to publish.
How deep does paging go?
To the real end of the catalogue, honestly. Asking past the last page returns an empty page with MPB's own total, not a silent repeat of the last page — verified by requesting the row after the end of a 19,839-item catalogue and a position far past it. page_size runs from 1 to 100; meta.pagination carries the page, the page size, MPB's total and whether another page exists.
What happens with a sku that has already sold?
You get NOT_FOUND. This matters here because MPB's own URL does not: a dead sku answers HTTP 200 and quietly renders the model page instead, which a naive integration would read as a successful result for the wrong product. The API detects that and refuses it. A keyword with no matches is different — it returns ok with zero rows and MPB's own total of zero, because an empty answer is an answer.
What is the MPB API?
MPB API is a ReefAPI endpoint group for used cameras, lenses and cine kit from mpb.com as json: every item with mpb's own cosmetic grade, its shutter, hour or battery-charge count, what is in the box and its uk, us or eur price. It returns live JSON through POST requests under /mpb/v1.
Is the MPB API free to try?
Yes. ReefAPI starts with 1,000 free credits, no card required. MPB calls use the same shared credit balance as every other ReefAPI engine.