# Enjoei API — Brazil's biggest second-hand fashion & lifestyle marketplace

> Search Enjoei's live second-hand catalogue by keyword, brand, department, size, price, condition, discount or seller location. Returns the asking price and the seller's struck-through reference price on every row.
> ReefAPI engine `enjoei` · 8 endpoints · clean JSON, no scraping or browsers to manage.

## How to call
- **Endpoint:** `POST https://api.reefapi.com/enjoei/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, `Authorization: Bearer <key>`) and your assistant can call these actions directly.

## Endpoints

### POST /enjoei/v1/search — 1 credit
Search Enjoei's live second-hand catalogue by keyword, brand, department, size, price, condition, discount or seller location. Returns the asking price and the seller's struck-through reference price on every row.

**Parameters:**
- `query` (string, optional) — Free-text search, in Portuguese as the site indexes it (`tênis nike`, `vestido zara`). Optional when you are browsing a department, category or brand instead.
- `department` (string, optional) — Department slug, e.g. `mocas`, `rapazes`, `kids`, `casa`, `infoeletro`. Take the exact slug from a search row's `department`.
- `subcategory` (array, optional) — One or more sub-category slugs as they appear in a row's `subcategory` (`rapazes-roupas-bermudas`). Comma-separated is accepted.
- `brand` (array, optional) — One or more brand slugs, exactly as `filters` returns them (`nike`, `zara`, `off-white`).
- `price_min` (number, optional) — Lowest listing price, in BRL.
- `price_max` (number, optional) — Highest listing price, in BRL.
- `condition` (enum, optional) — Restrict to second-hand or to unused stock. [one of: used, new]
- `size_clothes` (array, optional) — Clothing sizes (`p`, `m`, `g`, `gg`) — shirts, tops, dresses.
- `size_shoes` (array, optional) — Shoe sizes, Brazilian numbering (`38`, `40`).
- `size_waist` (array, optional) — Waist sizes for trousers, shorts and skirts (`38`, `40`, `42`).
- `sort` (enum, optional, default "relevance") — Result order. Only the four orders Enjoei itself applies are offered — every other value the API accepts is ignored upstream and would silently not sort. [one of: relevance, price_asc, price_desc, discount_desc]
- `shipping_range` (enum, optional) — Limit to sellers near a place. Anything other than `same_country` needs `city` and/or `state`. [one of: same_city, same_state, near_regions, same_country]
- `city` (string, optional) — City the `shipping_range` is measured from.
- `state` (string, optional) — Two-letter Brazilian state the `shipping_range` is measured from.
- `published_within` (enum, optional) — Only listings published in this window. [one of: 24h, 7d, 14d, 30d]
- `discount_min` (integer, optional) — Only listings discounted by at least this percentage.
- `discount_max` (integer, optional) — Only listings discounted by at most this percentage.
- `store_kind` (enum, optional) — Restrict to a kind of shop. These are the only two kinds Enjoei tags, and both are small slices of the catalogue (measured on `nike`: pro 190, celebrity 33). [one of: pro, celebrity]
- `per_page` (integer, optional, default 30) — Rows per page. Enjoei clamps this at 50 — a larger number is silently reduced, so the engine caps it too.
- `cursor` (string, optional) — `next_cursor` from the previous page. Enjoei pages by cursor, not by page number.
- `max_rotations` (integer, optional, default 3) — How many times to retry a failed upstream attempt before giving up.

**Returns:** results[] with listing_id, slug, url, title, price, original_price, discount_percent, currency, condition, size, sizes[], variants[], brand, department, category, subcategory, image, free_shipping, shipping_type, bundle_allowed, promo_tags[], seller{username,display_name,url,avatar}; plus count, total_results, total_results_capped, next_cursor, has_more, filters{}, query

**Example request body:**
```json
{
  "query": "nike",
  "per_page": 30
}
```

### POST /enjoei/v1/product/detail — 2 credits
One listing in full: the LIVE price (read from Enjoei's own pricing route, not the search index), description, every photo, weight, size, brand, category path, the offer range the seller will consider, and whether it is still on sale.

**Parameters:**
- `listing` (string, required) — Listing id, slug or full product URL — `151426712`, `shorts-nike-nba-chicago-bulls-151426712` or the whole `/p/...` link.
- `max_rotations` (integer, optional, default 3) — How many times to retry a failed upstream attempt before giving up.

**Returns:** listing{listing_id, url, title, description, price, original_price, discount_percent, currency, status, is_sold, condition, size, variants[], brand, brand_verified, category_path[], google_product_category, weight_kg, images[], image_count, offer{accepted,min_price,max_price}, payment{}, seller_id, similar_query}

**Example request body:**
```json
{
  "listing": "151426712"
}
```

### POST /enjoei/v1/product/similar — 2 credits
Listings comparable to a given one — same sub-category, same brand and a price band around it, which is the recipe Enjoei's own page uses. Useful for pricing a second-hand item against live competition.

**Parameters:**
- `listing` (string, required) — Listing id, slug or full product URL — `151426712`, `shorts-nike-nba-chicago-bulls-151426712` or the whole `/p/...` link.
- `per_page` (integer, optional, default 30) — Rows per page. Enjoei clamps this at 50 — a larger number is silently reduced, so the engine caps it too.
- `sort` (enum, optional, default "relevance") — Result order. Only the four orders Enjoei itself applies are offered — every other value the API accepts is ignored upstream and would silently not sort. [one of: relevance, price_asc, price_desc, discount_desc]
- `condition` (enum, optional) — Restrict to second-hand or to unused stock. [one of: used, new]
- `max_rotations` (integer, optional, default 3) — How many times to retry a failed upstream attempt before giving up.

**Returns:** results[] with listing_id, slug, url, title, price, original_price, discount_percent, currency, condition, size, sizes[], variants[], brand, department, category, subcategory, image, free_shipping, shipping_type, bundle_allowed, promo_tags[], seller{username,display_name,url,avatar}; plus count, total_results, source_listing_id, filters{}

**Example request body:**
```json
{
  "listing": "151426712"
}
```

### POST /enjoei/v1/seller/listings — 2 credits
Everything a shop currently has for sale, with the same row shape as search and the same filters.

**Parameters:**
- `seller` (string, required) — Shop handle (`@diego-a02c80` or `diego-a02c80`) or the shop URL.
- `seller_id` (string, optional) — Numeric shop id, as `seller_id` on a listing detail. Faster than the handle because it needs no lookup.
- `query` (string, optional) — Free-text search, in Portuguese as the site indexes it (`tênis nike`, `vestido zara`). Optional when you are browsing a department, category or brand instead.
- `brand` (array, optional) — One or more brand slugs, exactly as `filters` returns them (`nike`, `zara`, `off-white`).
- `subcategory` (array, optional) — One or more sub-category slugs as they appear in a row's `subcategory` (`rapazes-roupas-bermudas`). Comma-separated is accepted.
- `price_min` (number, optional) — Lowest listing price, in BRL.
- `price_max` (number, optional) — Highest listing price, in BRL.
- `condition` (enum, optional) — Restrict to second-hand or to unused stock. [one of: used, new]
- `sort` (enum, optional, default "relevance") — Result order. Only the four orders Enjoei itself applies are offered — every other value the API accepts is ignored upstream and would silently not sort. [one of: relevance, price_asc, price_desc, discount_desc]
- `per_page` (integer, optional, default 30) — Rows per page. Enjoei clamps this at 50 — a larger number is silently reduced, so the engine caps it too.
- `cursor` (string, optional) — `next_cursor` from the previous page. Enjoei pages by cursor, not by page number.
- `max_rotations` (integer, optional, default 3) — How many times to retry a failed upstream attempt before giving up.

**Returns:** results[] with listing_id, slug, url, title, price, original_price, discount_percent, currency, condition, size, sizes[], variants[], brand, department, category, subcategory, image, free_shipping, shipping_type, bundle_allowed, promo_tags[], seller{username,display_name,url,avatar}; plus count, total_results, next_cursor, has_more, seller{}

### POST /enjoei/v1/seller/sold — 1 credit
A shop's completed sales: what the item was listed at AND what it actually sold for. Enjoei publishes both, which makes this the price-comparison surface for second-hand goods in Brazil.

**Parameters:**
- `seller` (string, required) — Shop handle (`@diego-a02c80` or `diego-a02c80`) or the shop URL.
- `page` (integer, optional, default 1) — 1-based page of the sold shelf (40 rows per page).
- `max_rotations` (integer, optional, default 3) — How many times to retry a failed upstream attempt before giving up.

**Returns:** results[] with listing_id, slug, url, title, price, sold_price, discount_percent, currency, is_sold, image; plus count, total_results, page, page_size, has_more, seller

### POST /enjoei/v1/seller/profile — 1 credit
A shop's public page: handle, display name, city/state, bio, avatar, the date it joined, and its public counters — items for sale, items sold, likes received, followers and following.

**Parameters:**
- `seller` (string, required) — Shop handle (`@diego-a02c80` or `diego-a02c80`) or the shop URL.
- `max_rotations` (integer, optional, default 3) — How many times to retry a failed upstream attempt before giving up.

**Returns:** seller{seller_id, username, display_name, url, location, badge, description, avatar, cover_image, member_since, is_business, on_vacation, listings_count, sold_count, liked_count, followers, following}. `location` is 'City, UF' and is null on a shop whose display line carries a merchandising badge instead (8 of 25 measured); that badge is returned as `badge`.

### POST /enjoei/v1/filters — 1 credit
The brand and sub-category facets Enjoei itself offers for a query, each with its live listing count — the slugs you feed back into `search`.

**Parameters:**
- `query` (string, optional) — Free-text search, in Portuguese as the site indexes it (`tênis nike`, `vestido zara`). Optional when you are browsing a department, category or brand instead.
- `department` (string, optional) — Department slug, e.g. `mocas`, `rapazes`, `kids`, `casa`, `infoeletro`. Take the exact slug from a search row's `department`.
- `subcategory` (array, optional) — One or more sub-category slugs as they appear in a row's `subcategory` (`rapazes-roupas-bermudas`). Comma-separated is accepted.
- `brand` (array, optional) — One or more brand slugs, exactly as `filters` returns them (`nike`, `zara`, `off-white`).
- `price_min` (number, optional) — Lowest listing price, in BRL.
- `price_max` (number, optional) — Highest listing price, in BRL.
- `condition` (enum, optional) — Restrict to second-hand or to unused stock. [one of: used, new]
- `size_clothes` (array, optional) — Clothing sizes (`p`, `m`, `g`, `gg`) — shirts, tops, dresses.
- `size_shoes` (array, optional) — Shoe sizes, Brazilian numbering (`38`, `40`).
- `size_waist` (array, optional) — Waist sizes for trousers, shorts and skirts (`38`, `40`, `42`).
- `sort` (enum, optional, default "relevance") — Result order. Only the four orders Enjoei itself applies are offered — every other value the API accepts is ignored upstream and would silently not sort. [one of: relevance, price_asc, price_desc, discount_desc]
- `shipping_range` (enum, optional) — Limit to sellers near a place. Anything other than `same_country` needs `city` and/or `state`. [one of: same_city, same_state, near_regions, same_country]
- `city` (string, optional) — City the `shipping_range` is measured from.
- `state` (string, optional) — Two-letter Brazilian state the `shipping_range` is measured from.
- `published_within` (enum, optional) — Only listings published in this window. [one of: 24h, 7d, 14d, 30d]
- `discount_min` (integer, optional) — Only listings discounted by at least this percentage.
- `discount_max` (integer, optional) — Only listings discounted by at most this percentage.
- `store_kind` (enum, optional) — Restrict to a kind of shop. These are the only two kinds Enjoei tags, and both are small slices of the catalogue (measured on `nike`: pro 190, celebrity 33). [one of: pro, celebrity]
- `max_rotations` (integer, optional, default 3) — How many times to retry a failed upstream attempt before giving up.

**Returns:** brands[]{name,slug,count}, subcategories[]{name,slug,count}, store_kinds[]{name,slug,count}, query. No result count: Enjoei zeroes `total` on any query that asks for facets, so ask `search` for the count.

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

### POST /enjoei/v1/suggest — 0 credits
Enjoei's own search typeahead: completed search terms and matching shops.

**Parameters:**
- `term` (string, required) — Partial search text to complete, as typed into Enjoei's search box.
- `max_rotations` (integer, optional, default 3) — How many times to retry a failed upstream attempt before giving up.

**Returns:** terms[]{text}, shops[]{text,username,url}, term

**Example request body:**
```json
{
  "term": "nik"
}
```

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