# Reverb API — musical instrument marketplace data scraper: guitars, synths, pedals, amps and pro audio from reverb.com with prices in USD, seller and shipping detail, model pages with the lowest new and used asking price, and filters for condition, brand, price band, year and country — no API key, no login

> Search Reverb's live marketplace. Every filter offered here was measured to change the result set: price band, condition, brand, category, the seller's country, the country an item ships to, a year range, free shipping, local pickup, preferred sellers and one shop. Rows carry the price in USD (whatever currency the seller lists in), the condition, the year, the shop, the shipping rate per region and the full description.
> ReefAPI engine `reverb` · 10 endpoints · clean JSON, no scraping or browsers to manage.

## How to call
- **Endpoint:** `POST https://api.reefapi.com/reverb/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/reverb/v1/search — 2 credits
Search Reverb's live marketplace. Every filter offered here was measured to change the result set: price band, condition, brand, category, the seller's country, the country an item ships to, a year range, free shipping, local pickup, preferred sellers and one shop. Rows carry the price in USD (whatever currency the seller lists in), the condition, the year, the shop, the shipping rate per region and the full description.

**Parameters:**
- `query` (string, optional) — Free text: a model name, a brand, a serial-era nickname, anything a buyer would type. Optional — leave it out and send a filter instead to browse a whole category or shop.
- `make` (array, optional) — Brand name(s), exactly as Reverb spells them (Fender, Gibson, Squier, Boss, Roland). Several values are OR-ed: ['Fender','Gibson'] returned 117 853 guitars against 790 216 unfiltered. 🔴 Reverb matches brand FAMILIES: asking for Squier also returns rows whose own `make` field reads 'Fender' (5 of 24 on a measured page — 'Fender Squier Sonic Stratocaster'). Filter on the row's `make` yourself if you need the strict brand.
- `product_type` (enum, optional) — Top-level department. Only ONE value is accepted — an array here is a 400 from the source. Use `category_uuid` for a sub-category such as Solid Body. [one of: electric-guitars, acoustic-guitars, bass-guitars, effects-and-pedals, amps, drums-and-percussion, keyboards-and-synths, pro-audio, folk-instruments, orchestral-strings, band-and-orchestra, dj-and-lighting-gear, home-audio, parts, accessories, software]
- `category_uuid` (string, optional) — A sub-category uuid from `categories` — e.g. Electric Guitars / Solid Body narrowed the marketplace to 148 331 listings. 🔴 The category SLUG on its own is silently ignored by the source, which is why this API takes the uuid.
- `condition` (array, optional) — Condition grade(s). Several values are OR-ed. 🔴 The source silently ignores a slug it does not know, so this API validates it — and note that Brand New is `new`, not `brand-new`. [one of: new, b-stock, mint, excellent, very-good, good, fair, poor, non-functioning, used]
- `price_min` (number, optional) — Lowest price in US dollars, inclusive.
- `price_max` (number, optional) — Highest price in US dollars, inclusive. With price_min=1000 this narrowed 'stratocaster' from 76 993 to 8 390.
- `year_min` (integer, optional) — Earliest build year the seller stated. 🔴 Only ~49 % of listings state a year, so a year filter also drops every listing with no year.
- `year_max` (integer, optional) — Latest build year. 1960-1969 left 770 stratocasters of 76 993.
- `item_region` (string, optional) — Where the ITEM is, as a two-letter country code (US, GB, DE, JP). US 56 778 vs GB 5 051 on the same search.
- `ships_to` (string, optional) — Only listings that ship to this two-letter country code. 🔴 Leave it out and the source answers for 'Everywhere Else', which is NOT the whole marketplace — pinning ships_to=US cut 'stratocaster' from 77 000 to 41 496. The value actually used is echoed in `ships_to` on every response.
- `shop_id` (integer, optional) — Only this shop's listings. The NUMERIC id — a shop slug here is silently ignored by the source and hands you the whole marketplace, so use `shop/listings` if you only have a slug.
- `handmade` (boolean, optional) — Only items the seller marked handmade (2 817 of 76 993).
- `free_shipping` (boolean, optional) — Only items that ship free to somewhere (416 of 76 993). 🔴 This is NOT the row's `free_expedited_shipping` flag, which was False on all 8 rows a measured call returned — read `has_free_shipping` and `shipping_rates` to see which region the 0.00 rate is for.
- `local_pickup` (boolean, optional) — Only items offering local pickup (26 252 of 76 993).
- `preferred_seller` (boolean, optional) — Only Reverb Preferred Sellers (48 914 of 76 993).
- `sort` (enum, optional) — Leave empty for Reverb's own relevance order. Only the three orders the source demonstrably applies are offered; it silently ignores any other value. 🔴 The price sort is monotonic in the SELLER's currency, not in the USD you are handed: on a measured `price_desc` page a JPY listing converting to $98,652 came ahead of a USD one at $100,000. Sort by `price_usd` yourself if you need exact USD order. [one of: price_asc, price_desc, newest]
- `page` (integer, optional, default 1) — 1-based page number. The source prints `total_pages: 50` on every envelope no matter how large the result is — that cap is cosmetic and this API ignores it: pages 51, 60, 100 and 200 all return real, distinct rows. Read `total_pages` from this response, which is computed from `total`.
- `limit` (integer, optional, default 24) — Rows per page, 1-50. 50 is the source's own ceiling; it clamps anything larger instead of refusing it, so this API clamps it too and tells you in `limit`.

**Returns:** listings[]{listing_id, url, title, make, model, year, finish, condition, condition_slug, price_usd, price_display, currency, original_price_usd, price_drop_percent, listing_currency, categories[], shop_name, shop_id, shop_slug, preferred_seller, inventory, offers_enabled, auction, state, published_at, created_at, free_expedited_shipping, has_free_shipping, local_pickup, shipping_rates[]{region, amount_usd, display}, image, description}, total, page, limit, total_pages, ships_to, filters_applied

**Example request body:**
```json
{
  "query": "stratocaster"
}
```

### POST https://api.reefapi.com/reverb/v1/listing — 1 credit
One listing in full: everything a search row carries plus the seller's city and country, the shipping rate to every region it ships to, how many people have viewed and watched it, the offer count, the return and shipping policy, whether it is sold as-is, and the model id that links it to Reverb's model page.

**Parameters:**
- `listing_id` (string, required) — The numeric Reverb listing id (98282577), the id-slug form (98282577-fender-stratocaster-…) or a reverb.com/item/… URL. Every search row carries the id and the URL.

**Returns:** listing{… every search field …, images[], location{city, region, country_code, display}, origin_country_code, handmade, sold_as_is, local_pickup_only, offer_count, views, watches, accepted_payment_methods[], return_policy, shipping_policy, model_id, live}

**Example request body:**
```json
{
  "listing_id": "66178726"
}
```

### POST https://api.reefapi.com/reverb/v1/shop — 1 credit
One seller's record by slug: name, city and country, whether Reverb marks them a Preferred Seller / quick shipper / quick responder, their feedback count and rating, their shipping and payment policy, and whether the shop is on vacation.

**Parameters:**
- `shop` (string, required) — The shop slug as it appears in reverb.com/shop/<slug>, or the full shop URL. Search rows carry it as `shop_slug`.

**Returns:** shop{shop_id, slug, name, description, url, location{…}, preferred_seller, quick_shipper, quick_responder, on_vacation, feedback_count, rating_percent, website, shipping_policy, payment_policy, avatar}

**Example request body:**
```json
{
  "shop": "sound-to-parts"
}
```

### POST https://api.reefapi.com/reverb/v1/shop/listings — 3 credits
One seller's whole inventory, paged — the same rows as `search`, plus the shop record when you addressed it by slug. This is how a dealer's catalogue is mirrored: a shop with 603 listings is 13 calls at 50 rows a page.

**Parameters:**
- `shop` (string, optional) — The shop slug. Costs one extra upstream call to resolve the slug to the numeric id the marketplace filter needs; pass `shop_id` instead to skip it.
- `shop_id` (integer, optional) — The numeric shop id, from a search row or from `shop`. One of `shop` / `shop_id` is required.
- `query` (string, optional) — Optional keyword to search inside this seller's inventory.
- `condition` (array, optional) — Condition grade(s), same enum as search. [one of: new, b-stock, mint, excellent, very-good, good, fair, poor, non-functioning, used]
- `price_min` (number, optional) — Lowest price in US dollars.
- `price_max` (number, optional) — Highest price in US dollars.
- `product_type` (string, optional) — Department slug, same values as search.
- `sort` (enum, optional) — Same three orders as search. [one of: price_asc, price_desc, newest]
- `page` (integer, optional, default 1) — 1-based page number. The source prints `total_pages: 50` on every envelope no matter how large the result is — that cap is cosmetic and this API ignores it: pages 51, 60, 100 and 200 all return real, distinct rows. Read `total_pages` from this response, which is computed from `total`.
- `limit` (integer, optional, default 24) — Rows per page, 1-50. 50 is the source's own ceiling; it clamps anything larger instead of refusing it, so this API clamps it too and tells you in `limit`.

**Returns:** listings[] (same shape as search), shop{…} (only when addressed by slug), shop_id, total, page, limit, total_pages

**Example request body:**
```json
{
  "shop": "sound-to-parts"
}
```

### POST https://api.reefapi.com/reverb/v1/models — 2 credits
Reverb's MODEL pages — one row per instrument model rather than per listing, each with the lowest live asking price for a NEW one, the lowest for a USED one, and how many of each are for sale. This is the closest thing Reverb publishes to a price guide, and it is a snapshot of asks, not of completed sales. 78 791 models are browsable with no keyword at all.

**Parameters:**
- `query` (string, optional) — A model or family name. Omit it to walk the whole model catalogue.
- `make` (array, optional) — Brand name(s). 'les paul' 1 387 models → 799 for Gibson.
- `product_type` (string, optional) — Department slug, same values as search (935 of the 1 387).
- `category_uuid` (string, optional) — Sub-category uuid from `categories` (919 of the 1 387).
- `year_min` (integer, optional) — Earliest model year.
- `year_max` (integer, optional) — Latest model year.
- `page` (integer, optional, default 1) — 1-based page number. The source prints `total_pages: 50` on every envelope no matter how large the result is — that cap is cosmetic and this API ignores it: pages 51, 60, 100 and 200 all return real, distinct rows. Read `total_pages` from this response, which is computed from `total`.
- `limit` (integer, optional, default 24) — Rows per page, 1-50. 50 is the source's own ceiling; it clamps anything larger instead of refusing it, so this API clamps it too and tells you in `limit`.

**Returns:** models[]{model_id, slug, url, title, brand, summary, new_low_price_usd, new_low_price_display, new_listings, used_low_price_usd, used_low_price_display, used_listings, category_slug, category_uuid, image}, total, page, limit, total_pages

**Example request body:**
```json
{
  "query": "les paul"
}
```

### POST https://api.reefapi.com/reverb/v1/model/detail — 1 credit
One model page by numeric id: the lowest new and used asking price, the live count of each, Reverb's own star rating and review count for the model, the description and the image.

**Parameters:**
- `model_id` (string, required) — The numeric model id, from a `models` row (`model_id`) or from a listing's `model_id`. 🔴 The model's slug does NOT work as an id — the source answers 404 for it. Use `models` to look one up by name.

**Returns:** model{model_id, slug, url, title, brand, summary, new_low_price_usd, new_listings, used_low_price_usd, used_listings, rating, review_count, category_slug, category_uuid, image}

**Example request body:**
```json
{
  "model_id": "104711"
}
```

### POST https://api.reefapi.com/reverb/v1/model/listings — 3 credits
Every live listing OF one model, not merely matching its name — Reverb keeps a list of the exact product variants behind each model page and this action uses it, so a search for 'Fender American Professional II Stratocaster' that would return 76 000 loose matches returns the 574 that really are one. Two upstream calls: the model page, then its listings.

**Parameters:**
- `model_id` (string, required) — The numeric model id, from a `models` row (`model_id`) or from a listing's `model_id`. 🔴 The model's slug does NOT work as an id — the source answers 404 for it. Use `models` to look one up by name.
- `condition` (array, optional) — Condition grade(s) — this is how you read only the used market for one model. [one of: new, b-stock, mint, excellent, very-good, good, fair, poor, non-functioning, used]
- `price_min` (number, optional) — Lowest price in US dollars.
- `price_max` (number, optional) — Highest price in US dollars.
- `sort` (enum, optional) — Same three orders as search. [one of: price_asc, price_desc, newest]
- `page` (integer, optional, default 1) — 1-based page number. The source prints `total_pages: 50` on every envelope no matter how large the result is — that cap is cosmetic and this API ignores it: pages 51, 60, 100 and 200 all return real, distinct rows. Read `total_pages` from this response, which is computed from `total`.
- `limit` (integer, optional, default 24) — Rows per page, 1-50. 50 is the source's own ceiling; it clamps anything larger instead of refusing it, so this API clamps it too and tells you in `limit`.

**Returns:** listings[] (same shape as search), model{model_id, title, brand, new_low_price_usd, used_low_price_usd}, total, page, limit, total_pages

**Example request body:**
```json
{
  "model_id": "104711"
}
```

### POST https://api.reefapi.com/reverb/v1/categories — 1 credit
Reverb's whole category tree, flattened: 320 categories with the uuid that `search` and `models` take as `category_uuid`, the department slug that `product_type` takes, and the human name. One call, and it barely changes.

**Parameters:**
- `product_type` (string, optional) — Only the sub-categories of this department.
- `query` (string, optional) — Only categories whose name contains this text.

**Returns:** categories[]{category_uuid, name, full_name, slug, product_type, root_uuid, listable}, count

**Example request body:**
```json
{
  "product_type": "electric-guitars"
}
```

### POST https://api.reefapi.com/reverb/v1/conditions — 1 credit
The condition grades Reverb uses, with the slug each filter takes and Reverb's own definition of the grade. 🔴 Note that Brand New's slug is `new`, not `brand-new`.

**Parameters:** none

**Returns:** conditions[]{slug, name, description, filterable}

### POST https://api.reefapi.com/reverb/v1/brand — 1 credit
One brand record by slug: its Reverb id, its canonical name — which is the spelling the `make` filter wants — and its header images. There is no brand INDEX to walk: the source's `/brands` route answers with an empty list whatever you ask it.

**Parameters:**
- `brand` (string, required) — The brand slug as it appears in reverb.com/brand/<slug> — lowercase, hyphenated ('fender', 'gibson', 'electro-harmonix').

**Returns:** brand{brand_id, name, slug, url, image}

**Example request body:**
```json
{
  "brand": "fender"
}
```

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