# Carousell API — the Southeast Asian classifieds marketplace (Singapore, Malaysia, Hong Kong, Philippines, Taiwan, Indonesia): search listings, read the full listing and a seller's listings, in local currency. No account, no browser.

> Search Carousell listings in one country by keyword or category, 48 per page: listing id, title, price in local currency with the seller's earlier price when it was lowered, condition, status, posting time, whether the seller paid to bump it (and when), likes, seller username, photos, and for cars and property the card's key facts (mileage, registration, bedrooms, size). Filter by price range, condition and category; sort by best match, newest or price; page with a cursor.
> ReefAPI engine `carousell` · 4 endpoints · clean JSON, no scraping or browsers to manage.

## How to call
- **Endpoint:** `POST https://api.reefapi.com/carousell/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 /carousell/v1/search — 2 credits
Search Carousell listings in one country by keyword or category, 48 per page: listing id, title, price in local currency with the seller's earlier price when it was lowered, condition, status, posting time, whether the seller paid to bump it (and when), likes, seller username, photos, and for cars and property the card's key facts (mileage, registration, bedrooms, size). Filter by price range, condition and category; sort by best match, newest or price; page with a cursor.

**Parameters:**
- `query` (string, optional) — Keyword. Optional when `category_id` is given.
- `country` (enum, optional, default "sg") — Which Carousell storefront: sg, my, hk, ph, tw or id. Prices come back in that country's currency; listing ids and usernames belong to one storefront. [one of: sg, my, hk, ph, tw, id]
- `category_id` (string, optional) — Carousell category id — from `suggest` (suggestions[].categories[].id) or a listing's category.id (e.g. 1287 Sofas in Singapore).
- `sort` (enum, optional, default "best_match") — Order of results. [one of: best_match, newest, price_asc, price_desc]
- `price_min` (number, optional) — Lowest price in the country's currency.
- `price_max` (number, optional) — Highest price in the country's currency.
- `condition` (enum, optional) — Item condition on Carousell's five-step scale. [one of: brand_new, like_new, lightly_used, well_used, heavily_used]
- `cursor` (string, optional) — The `next_cursor` of the previous page. Omit for the first page.
- `exclude_bumped` (boolean, optional, default false) — Drop listings the seller paid to bump up the results (counted in bumped_dropped). Bumped listings still match your query.
- `autocorrect` (boolean, optional, default false) — Let Carousell correct a misspelled keyword ('iphnoe' → iPhone results). Off by default: a misspelled keyword then returns no results.
- `max_rotations` (integer, optional, default 4) — Advanced: how many fresh exits to try for a difficult request (1-6).

**Returns:** results[]{listing_id, title, url, price (number; null for free items and listings without a price), price_text, is_free, price_not_published, original_price + price_dropped (seller lowered the price), currency, condition (brand_new|like_new|lightly_used|well_used|heavily_used, or new|used in two-step categories, null for cars/property), condition_label, status (active|reserved|sold|…), posted_at (null on bumped cards), is_bumped, bumped_at, last_bumped_at, is_promoted, likes_count, seller{id, username, display_name}, card_type, vertical (cars|property|null), is_certified, buyer_protection_tag, deal_label, tags[], attributes[]{name, value} (cars: depreciation, registration date, mileage; property: bedrooms, bathrooms, size, MRT), card_lines[], image, images[], country}, count, total_results, total_is_lower_bound, has_more, next_cursor, bumped_count, bumped_dropped, non_listing_cards_dropped, sort_applied, filters_applied, query, country, currency

**Example request body:**
```json
{
  "query": "iphone",
  "country": "sg"
}
```

### POST /carousell/v1/listing — 2 credits
The full listing by id or URL: title, full description, price and currency (free items and no-price services marked), fixed price or open to offers, status (active, reserved, sold), condition, category, every attribute (model, storage, size…), car and property details (engine, COE, depreciation, bedrooms, lease, district), all photos, likes, posting / edit / expiry dates, meet-up points, mailing and Carousell shipping options, Buyer Protection, and the seller: username, business or private, verification, rating with review counts, followers, join date.

**Parameters:**
- `listing_id` (string, required) — Listing id (the number at the end of a carousell listing URL, …/p/iphone-15-pro-1459547251/) or the full URL — a URL also sets the country.
- `country` (enum, optional, default "sg") — Which Carousell storefront: sg, my, hk, ph, tw or id. Prices come back in that country's currency; listing ids and usernames belong to one storefront. [one of: sg, my, hk, ph, tw, id]
- `max_rotations` (integer, optional, default 4) — Advanced: how many fresh exits to try for a difficult request (1-6).

**Returns:** listing{listing_id, title, url, status, is_active, price (null for free items and services without a price), currency, is_free, price_not_published, fixed_price, condition, condition_label, description, category{id, name, slug}, attributes[]{name, value}, details[]{group, name, value} (specifications, financials, unit_details, location…), highlights[], images[], image_count, likes_count, posted_at, last_modified_at, expires_at, buyer_protection, delivery{meetup, meetups[]{name, address, latitude, longitude, note}, mailing, mailing_details, carousell_shipping, deal_options[], default_delivery_option}, seller{id, username, display_name, type (business|private|null), identity, is_official_partner, verified{id, mobile, email, facebook, gplus}, rating (0-5), rating_scale, review_count, positive_reviews, neutral_reviews, negative_reviews, followers_count, joined_at, response_rate, profile_url}, certified_product{product_id, variant_id}, country}

### POST /carousell/v1/seller_listings — 2 credits
A seller's listings on one storefront, newest first, 40 per page, including reserved and sold items: the same row fields as search, plus the seller's total listing count.

**Parameters:**
- `username` (string, required) — Seller username (search rows: seller.username), or the profile URL …/u/<username>/.
- `country` (enum, optional, default "sg") — Which Carousell storefront: sg, my, hk, ph, tw or id. Prices come back in that country's currency; listing ids and usernames belong to one storefront. [one of: sg, my, hk, ph, tw, id]
- `cursor` (string, optional) — The `next_cursor` of the previous page. Omit for the first page.
- `max_rotations` (integer, optional, default 4) — Advanced: how many fresh exits to try for a difficult request (1-6).

**Returns:** results[] (same row shape as search), count, total_results, has_more, next_cursor, username, country, currency

### POST /carousell/v1/suggest — 1 credit
Carousell's keyword autocomplete for one country, with the categories each suggestion maps to (their ids work as search category_id).

**Parameters:**
- `query` (string, required) — The beginning of a keyword.
- `country` (enum, optional, default "sg") — Which Carousell storefront: sg, my, hk, ph, tw or id. Prices come back in that country's currency; listing ids and usernames belong to one storefront. [one of: sg, my, hk, ph, tw, id]
- `max_rotations` (integer, optional, default 4) — Advanced: how many fresh exits to try for a difficult request (1-6).

**Returns:** suggestions[]{suggestion, categories[]{id, name}}, count, query, country

**Example request body:**
```json
{
  "query": "iph",
  "country": "sg"
}
```

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