Read Etsy listings and shop data without an Etsy app
The Etsy API returns handmade and vintage listings, shop and review data as clean JSON.
8 active endpoints, on 1 and 2 credit tiers.
- POST/etsy/v1/listings/search
- POST/etsy/v1/listings/detail
- POST/etsy/v1/shops/detail
- POST/etsy/v1/shops/listings
- POST/etsy/v1/listings/category
- POST/etsy/v1/reviews/shop
- POST/etsy/v1/reviews/listing
- +1 more
What Etsy endpoints does ReefAPI ship?
8 live read endpoints. Read-only data API: no writes, no account actions, no dashboard access on the target site.
Etsy API
3 of 8 endpoints, ready to run
The results grid: listing_id, title, price, list price, currency, shop id and the listing URL.
// Press "Try it" and this pane shows exactly what the // live site returned this second — including an empty // result, if that is the truth. No key, no account.
How the Etsy API works
Etsy is a normal ReefAPI surface — the same four rules that hold for every other engine on the key.
No OAuth app, no request signing, no per-site account. One key covers all 185 engines.
Every route is a POST with a JSON body. Parameters are validated against the published schema before anything is charged.
Credits, not seats. Failed and blocked calls are never charged, and cache hits cost nothing.
One envelope everywhere. meta carries latency_ms, record_count and the endpoint that answered.
Size up a niche: what sells, at what price, from how established a seller
The interesting question on Etsy is rarely one listing — it is whether a category is dominated by three shops with fifteen thousand sales each or spread across two hundred small ones. Three calls answer it.
{"query": "leather journal", "max_pages": 5}About a dozen rows per page, each with a listing_id, a price and a shop_id. Billed 2 credits per 25 rows.
{"listing_id": "..."}The option matrix, and this is where the real price range of a customisable item lives.
{"shop_slug": "..."}sales_count, rating, followers and active_listings_count — the four numbers that tell you how concentrated a niche is.
Sixty listings and their shops for a couple of dozen credits, with per-option pricing rather than the single headline number the grid shows.
curl -X POST https://api.reefapi.com/etsy/v1/listings/search \
-H "x-api-key: $REEF_KEY" \
-H "content-type: application/json" \
-d '{"query":"silver ring"}'{
"ok": true,
"data": { … },
"meta": {
"api": "etsy",
"endpoint": "listings/search",
"mode": "live",
"latency_ms": …,
"record_count": …
},
"error": null
}Etsy identifiers, price fields and page sizes, as they actually come back
The same idea has a different field name in each action, and two of the identifiers are typed differently depending on where you read them. Everything below was measured on 2026-08-27 against listings 1509738931, 4389097710 and 1112702820 and shop GlamAndGemsNY (shop_id 7357402). Use it to work out which field you are actually holding before you join two responses together.
| Field | Where it appears | What we measured |
|---|---|---|
| listing_id | listings/search, listings/detail, shops/listings | A digit string: "1509738931". The same value appears as schema_product.sku. |
| listing_id / transaction_id | reviews/shop rows | Integers here, not strings: 1899686745 and 5160518010. Cast before joining to a search row. |
| shop_id | listings/search, listings/detail, shops/detail | Numeric string, and it is the first path segment of every i.etsystatic.com image URL. Listing 1509738931 returned shop_id "7357402" and images under i.etsystatic.com/7357402/. reviews/shop takes this number, never the slug. |
| price + list_price | listings/search, shops/detail featured_listings, shops/listings | Decimal strings. price is what the buyer pays now, list_price is the struck-through original: "12.90" against "42.99". |
| price + original_price | listings/detail | The detail action renames the pair. original_price came back null and on_sale false on all three listings tested, including 4389097710, whose own shop grid showed list_price "3059.00" against price "1529.50". |
| currency | Every action that carries a price | "USD" on every row measured. There is no currency or locale parameter. |
| rating vs schema_product.aggregateRating.ratingValue | listings/detail | rating sits one notch below the schema value: 4.9 vs "5.0", 4.7 vs "4.8", 5.0 vs "5.0". review_count_display matched schema reviewCount exactly (4, 2, 4987). |
| created_at | reviews/shop | Unix epoch seconds as an integer (1787400100), not an ISO string. |
| reviewer | reviews/shop | null on every row returned. language ("en") and photo_url are populated; the buyer name is not. |
| Rows per page | listings/search | About 12, not the ~48 the max_pages description implies: max_pages 1, 2 and 3 returned 12, 24 and 35 rows for the same query. |
| Rows per page | listings/category | 64 rows in a single page for category "jewelry/rings". |
| Rows per page | shops/listings | 38 rows on page 1, with total_listings 2202 giving the size of the whole catalog. |
shop_slug is null in every shops/listings row and was null on one of the three listings/detail responses, while shop_id was always present. Join on shop_id.
The price is a string, the option list has a stray, and one endpoint is not ready
Measured on 2026-08-27 across journals, jewellery and one full shop catalogue. Four of these lines go against us.
Both listings/search and listings/detail return price as "7.49" — quoted. So does list_price. Every other engine in this batch returns a number here, so if you are writing one loader for several sources this is the one that will silently sort your prices alphabetically. Cast it.
Against us. Across 59 search rows, listing_id, shop_id, price and currency were on every single one — but shop_slug was present on only about half. The slug is what shops/detail and shops/listings take, so on the rows that lack it you have to open the listing to get it. The numeric shop_id is the reliable identity; the slug is the convenient one.
Against us, our defect. Every listings/detail response begins its variations array with an entry called "Choose a reason…" whose options are "There's a problem with my order" and similar — that is Etsy's report-this-item dropdown, scraped as though it were a product choice. Three listings out of three. Skip that first block; the rest of the array is real and carries the per-option price ranges in its labels.
The headline price is the cheapest configuration. A journal listed at 34.80 had option labels reading 46.80 to 68.40 for laser engraving and 68.40 with a gift set — a listing whose real span is double its advertised price. If you are comparing sellers on price, compare the option matrix, not the grid figure.
Against us, and stated plainly so nobody builds on it: two listings, two rounds, 52 and 64 seconds each, returned 0 and 1 review with partial:true and a note in the payload saying deep review pagination is unavailable. reviews/shop works but is shallow — asking for 50 returned 6 on the shop we tried. Etsy reviews are the weak corner of this engine; listings and shops are not.
Search rows carry no rating and no review count at all — those live on listings/detail (rating, review_count_display) and on shops/detail. It is a structural difference from every other engine here, and it means a rating-filtered sweep is an enrichment job rather than a filter.
is_ad was null on all 59 search rows, and stock_left was null on all three listings we opened. original_price on the detail response was null even where the search row for the same listing carried a list_price — the two surfaces disagree, and the search row is the one that has the markdown.
Ten pages returned 112 unique listings in about thirty-two seconds, and a whole shop catalogue of 67 listings came back in two pages. listings/search, listings/detail, shops/detail, reviews/shop, reviews/listing and search/suggest are all priced per 25 rows — 2 credits per 25 on the first three, 1 per 25 on the rest — so a single listing detail costs 2 and a 112-row sweep costs 10. shops/listings and listings/category are flat at 1.
What people build with Etsy
The jobs this data is most often used for.
endpoints
credits per call
Marketplace researchers call listings/search to track prices and trends in a handmade category.
Seller-intelligence tools use shops/listings to audit a competitor shop's full catalog.
Product tools pull reviews/listing to gauge demand and sentiment for a listing.
What Etsy data costs
The cheapest call here is 1 credit, so $15/mo (Pro) buys 10,000 of them — $1.50 per 1,000 credits. Credits roll over and never expire, and failed or blocked calls are not charged.
Full pricing →- 1,000 free credits on signup, no card
- One key, all 185 APIs, one credit pool
- Failed and blocked calls are never charged
- Credits roll over and never expire
Call it in two lines
Sign up, get 1,000 credits and one key that works on every engine. Then this is the whole protocol.
curl -X POST https://api.reefapi.com/etsy/v1/listings/search \
-H "x-api-key: $REEF_KEY" \
-H "content-type: application/json" \
-d '{"query":"silver ring"}'import requests
r = requests.post(
"https://api.reefapi.com/etsy/v1/listings/search",
headers={"x-api-key": REEF_KEY},
json={
"query": "silver ring"
},
)
print(r.json()["data"])Have a question? We got answers.
The questions people actually ask before wiring up Etsy.
Get a free key →Where do I get the numeric shop_id that reviews/shop wants?▾
Three places, all cheap. Every listings/search row carries shop_id next to shop_slug; shops/detail returns it for a slug you already have; and it is the first path segment of any Etsy image URL, so i.etsystatic.com/7357402/r/il/... tells you the shop is 7357402 without another call. reviews/shop rejects the slug, so this step is not optional.
Which field is the sale price and which is the original?▾
In listings/search, shops/detail and shops/listings, price is the current price and list_price is the higher struck-through one: "12.90" against "42.99". listings/detail renames the pair to price and original_price, and original_price came back null with on_sale false on all three listings we pulled, including listing 4389097710 whose own shop page showed a 50 percent markdown. If you need the discount, take it from a search or shop row, not from detail.
Why is rating lower than the star rating in schema_product?▾
They round differently on the same underlying average. Listing 1509738931 returned rating 4.9 with schema_product.aggregateRating.ratingValue "5.0"; listing 1112702820 returned 4.7 against "4.8"; a listing whose true average is exactly 5.0 returned 5.0 in both. Treat rating as the truncated number and the schema value as the rounded one Etsy prints on the page. review_count_display and schema reviewCount agreed on every listing.
How many listings does one search page actually return?▾
About 12. Running the same query at max_pages 1, 2 and 3 returned 12, 24 and 35 rows, so budget roughly a dozen listings per page rather than the 48 the parameter text suggests. listings/category is far denser: category "jewelry/rings" returned 64 rows in a single page, and shops/listings returned 38 with total_listings 2202. If you want volume from a keyword, raise max_pages; if you want volume from a category, one page is usually enough.
What do the review timestamps look like?▾
reviews/shop returns created_at as Unix epoch seconds, so 1787400100 is a date in August 2026, not a date string. Each row also carries rating, text, language, photo_url (null when the buyer posted no photo) and the listing_id plus transaction_id the review belongs to, both as integers. reviewer was null on every row we pulled, so do not plan on a buyer name.
Does the API tell me how much a shop has sold?▾
shops/detail returns sales_count, the shop's lifetime order count, alongside followers_count, active_listings_count and rating. GlamAndGemsNY returned sales_count 2093, followers_count 7173, active_listings_count 2202 and rating 5.0. opened_year came back null on that shop, so treat the shop's age as optional. There is no per-listing sold count anywhere in the response.
What does search/suggest give me?▾
Plain keyword completions and nothing else. Query "silver ring" with limit 6 returned six suggestions, starting with the query itself and continuing "silver ring men", "silver rings for women", "silver ring set", "silver ring stack" and "silver ring with stone". The categories array on each suggestion was empty on all six, so use it for keyword expansion, not for category discovery.
Why did one listing come back with empty tags and a single image?▾
It happens on a page that renders thin, and the response still says ok true. Listing 4389097710 returned tags [], image_count 1 and shop_slug null on the first pull, while listing 1509738931 returned 30 tags, 8 images and a full shop slug. Price, listing_id, shop_id, description and the schema_product block were correct in both. If tags or images matter to you, check image_count before you trust the payload and retry, or take the image from the search row.
What is the Etsy API?▾
Etsy API is a ReefAPI endpoint group for handmade and vintage product listings and shops. It returns live JSON through POST requests under /etsy/v1.
Is the Etsy API free to try?▾
Yes. ReefAPI starts with 1,000 free credits, no card required. Etsy calls use the same shared credit balance as every other ReefAPI engine.
Do I need an Etsy login or account?▾
No login to Etsy is needed for the API response. You call ReefAPI with your x-api-key header, and the playground can run live examples before you create a production key.
How fresh is the Etsy data?▾
The page example is captured from a live listings/search call, and production requests fetch live data through ReefAPI rather than a static sample.
How many credits does the Etsy API use?▾
Etsy actions currently cost 1-2 credits per successful call. Failed or blocked calls are free, and all APIs draw from one credit pool.
Can I call Etsy from an AI assistant or MCP client?▾
Yes. Connect ReefAPI once through MCP and your assistant can call etsy actions with the same key, credit pool and JSON envelope used by normal REST requests.
37 E-commerce & Marketplaces APIs on the same key
One key, one credit pool, one response envelope. If you are pulling Etsy, you are one call away from the rest of the category — no second contract, no second integration.
Try it on your own data before you pay anything
The call above is the real endpoint, not a recording. A free key gives you 1,000 credits, the other 184 APIs, and the same envelope everywhere.
Endpoints, parameters and credit costs on this page are read from the live catalog and cannot drift from what the API accepts. Field notes were captured on 2026-08-27.