Mudah.my API

Malaysia's classifieds market as JSON, by category, state and town

The Mudah API returns Malaysia's largest classifieds marketplace as clean JSON in eight actions.

no credit card1,000 free credits · instant API key · pay by card or crypto
Missing a Mudah.my endpoint, or need a source we don't have yet?Contact us real people · same-day reply.
M
/mudah/v1

8 active endpoints, on 0 and 1 credit tiers.

  • POST/mudah/v1/search
  • POST/mudah/v1/listing
  • POST/mudah/v1/seller_listings
  • POST/mudah/v1/similar
  • POST/mudah/v1/suggest
  • POST/mudah/v1/categories
  • POST/mudah/v1/locations
  • +1 more

What Mudah.my endpoints does ReefAPI ship?

8 live read endpoints. Read-only data API: no writes, no account actions, no dashboard access on the target site.

8 endpoints

search

1 cr

Search Mudah.my across every vertical.

required
—
optional
query, category, region, area, price_min, price_max, condition, ad_type, seller_type, sort, search_in, filters, limit, offset, include_description, include_images, include_pii

listing

1 cr

One ad in full, by its list id or URL.

required
listing_id
optional
include_pii

seller_listings

1 cr

Every live ad of one seller.

required
—
optional
store_id, user_id, query, category, region, sort, limit, offset, include_description, include_images, include_pii

similar

1 cr

Mudah's own 'similar ads' for one listing.

required
listing_id
optional
include_pii

suggest

1 cr

Mudah's keyword autocomplete.

required
query
optional
—

categories

0 cr

Mudah's whole category tree.

required
—
optional
—

locations

0 cr

Every Malaysian state and federal territory mudah lists, each with its towns and districts, i…

required
—
optional
—

filters

0 cr

Every filter one category publishes, with its key, label, kind (single, multi or range) and t…

required
category
optional
—

Every parameter, every allowed value →

Mudah.my API

5 of 8 endpoints, ready to run

View docs ↗

Malaysian classified ads across every vertical: listing id and URL, title, price in MYR with price_kind saying whether it is a sale price, a rent or a salary, condition, ad type, state and town, posting and bump dates, cover photo, private or business seller, and the fields the category itself publishes. Up to 200 a call.

1 credit0 required · 16 optional
POST/mudah/v1/search
idle
// 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 Mudah.my API works

Mudah.my is a normal ReefAPI surface — the same four rules that hold for every other engine on the key.

01
Authenticate
x-api-key header

No OAuth app, no request signing, no per-site account. One key covers all 294 engines.

02
Call
POST /mudah/v1/…

Every route is a POST with a JSON body. Parameters are validated against the published schema before anything is charged.

03
Pay
0 or 1 credits per call

Credits, not seats. Failed and blocked calls are never charged, and cache hits cost nothing.

04
Read
{ ok, data, meta, error }

One envelope everywhere. meta carries latency_ms, record_count and the endpoint that answered.

Read the filter schema first, because it is free and mudah will not tell you when a filter is wrong

Mudah answers an unknown filter key with the unfiltered set. rooms=3 left all 104,169 property ads in place, and it looked like a working query. The schema that says which key narrows costs nothing, so there is no reason to guess.

01categories
POST/mudah/v1/categories
{}

Zero credits. The whole category tree plus a flat index, so 1020 or cars is a value you read rather than a value you guess. Pair it with locations for the 16 states and their towns, also free.

02filters
POST/mudah/v1/filters
{"category": "cars"}

Zero credits. Every filter that category publishes, each with its kind and its complete value list, models nested under their make. This is the list a search filter is checked against.

03search
POST/mudah/v1/search
{"category": "1020", "filters": "make=Toyota;model=Hilux", "region": "selangor", "limit": 40}

1 credit for up to 200 rows. Read total_results before you page: make=Toyota alone was 19,549 of 89,804 car ads and adding the model took it to 1,051. A filter the schema does not publish is rejected here instead of being answered unfiltered.

04listing
POST/mudah/v1/listing
{"listing_id": "98625990"}

1 credit. The full description, every photo in standard and high resolution, the attribute table and the shop identity, none of which is on the results row.

05seller_listings
POST/mudah/v1/seller_listings
{"store_id": "1370561", "limit": 200}

1 credit a page for that dealer's or shop's entire live stock, in the same row shape as search.

A category and a filter set you can prove, a market count you can budget against, and a listing enriched with the description, photos and attributes the results row never carries.

request
curl -X POST https://api.reefapi.com/mudah/v1/search \
  -H "x-api-key: $REEF_KEY" \
  -H "content-type: application/json" \
  -d '{"category":"1020","limit":20}'
response envelope
{
  "ok": true,
  "data": { … },
  "meta": {
    "api": "mudah",
    "endpoint": "search",
    "mode": "live",
    "latency_ms": …,
    "record_count": …
  },
  "error": null
}

Six Mudah values that are not what they look like

Mudah answers a bad request with a plausible page rather than an error: a filter key it does not know comes back unfiltered, a page size it does not like comes back at its own default, and the end of its search window comes back as zero results. These were read from live searches and listing pages on 2026-09-24.

What you send or readLooks likeActually isWhat comes back
pricea sale price in MYRa sale price, a monthly rent or a job salary, all written into the same fieldthe number in price, plus price_kind reading price, rent or salary, and price_label exactly as mudah prints it
price on a services ada parse gapmudah publishes no price for that vertical: 200 of 200 service ads read Negotiableprice null and price_not_published true, never 0
rooms=3 on propertya filtera key mudah does not recognise, so it serves the unfiltered 104,169 adsrejected before anything is sent, with the keys and values mudah does publish; the key that narrows takes the same search to 67,675
limit=250250 rowsmudah's own default of 24 rows, with no error and no clampcapped at 200, which is the real maximum
offset past 10,000an empty marketthe end of mudah's search window: it reports 0 total results for a category holding tens of thousands of adsrefused, with a message to narrow the query rather than page deeper
condition on a property, job, service, pet, food or number-plate ada missing fieldthe category defines no condition at all, in its rows and in its filter schema alikeabsent, and said to be absent rather than filled in

Measured 2026-09-24 across 17 categories at 40 rows each and 40 listing pages. A sold or expired ad is not served at all, so a listing id that no longer exists comes back NOT_FOUND rather than as an empty success, and there is no sold-price history to read.

Malaysia only, priced in MYR, and the answers that look like data but are not

Measured 2026-09-24 on 171 live calls across all eight actions: 17 categories at 40 rows each, 40 listing pages, 24 filters against same-minute unfiltered controls. Every action returned 100 per cent. Three of these lines go against us.

One country, one currency, every vertical

Mudah.my is Malaysia only, so there is no country parameter and no other storefront. Verticals proven live at 40 of 40 rows each: cars, motorcycles, number plates, apartments and condos for sale and to rent, houses, mobile phones, TV and audio, computers, furniture, home appliances, clothes, sports, pets, food, business equipment, jobs and services. Search is by state and town, and the free locations action lists all 16 states and federal territories with their towns.

A filter mudah does not know comes back unfiltered, so filters are checked before they are sent

Measured against a same-run control: rooms=3 left property at 104,169, and property_type, job_cat, contract_type, pet_type and gender_type behaved the same way, while price_min with price_max went the other way and returned nothing. Every filter is resolved against mudah's own published schema, by id, slug or name, and rejected with the allowed values when it is not there. 24 filters were then run against controls and 24 narrowed, with 40 of 40 returned rows satisfying the one asked for.

The same field holds a sale price, a rent and a salary

price_kind says which of the three you are reading. Where an ad publishes no price mudah shows Negotiable, and price comes back null with price_not_published true rather than 0, because a zero would read as free. On 1,800 rows across nine categories, price was on 40 of 40 rows in 15 of 17 categories, 39 of 40 in jobs and 0 of 40 in services, where all 200 sampled service ads were Negotiable.

Two ceilings mudah answers with a plausible page instead of an error

limit above 200 silently returns 24 rows, mudah's own default, so 200 is enforced as the real maximum. offset plus limit past 10,000 makes mudah report zero total results for a category with tens of thousands of ads, so that request is refused with a message to narrow the query. An empty search is also asked a second time before it is reported empty, and carries empty_confirmed true when both reads agree.

Private sellers are withheld, businesses are not

Most mudah sellers are private individuals: in an 80-ad sample, 53 published a mobile number in the contact field, 43 repeated it inside a chat link and 48 typed one into the description. A private seller's name and number are off by default, with phone_masked showing that one exists and seller.pii_withheld saying it was withheld rather than missing, and include_pii restores them. Dealers, agencies and shops keep their details always: of the businesses in a 40-ad sample that publish a contact, 14 of 14 came back with it.

Against us: no unit price and no sold price

Mudah publishes no price per square foot and no price per unit anywhere, and none is worked out here: you get the advertised price and, on property, the floor size, as two separate fields. There is also no price history. Mudah stops serving an ad entirely once it goes, so a dead listing id is NOT_FOUND and there is no way to read what something finally sold for.

Against us: paging stops at 10,000 rows per query

That window is mudah's, not ours. A category with 89,804 car ads cannot be walked end to end in one query, so reaching the rest means partitioning by state, town, make or price band. total_results always reports the real count for the filter set, and the free locations and filters actions give you the axes to split on.

Against us: some categories publish less than others

Condition is not defined at all for property, jobs, services, pets, food and number plates, in the rows and in those categories' filter schemas alike. The vertical details block is empty on furniture and home appliances, 16 of 40 on business equipment and 3 of 40 on number plates and food. Job ads often have no photo, 24 of 40. On 40 listing pages, images and the attribute table were 38 of 40 and the vehicle specifications block 4 of 40, because only vehicles have one. Absent is returned as absent, never filled in.

Price

categories, locations and filters are free. search, listing, seller_listings, similar and suggest are 1 credit each. A 200-row search page and a single listing cost the same, so ask for the page.

What people build with Mudah.my

The jobs this data is most often used for.

8

endpoints

0/1

credits per call

01

Price a used car, phone or condo in Malaysia against what the market is asking this week, by category, make and state.

02

Track one dealer, agency or shop: pull its entire live stock by store_id and diff it daily to see what listed and what went.

03

Measure advertised rents by town or state from ad_type=let property rows, with bedrooms, bathrooms and floor size on each.

04

Feed a buyer-alert or comparison product: filter by category, price band and condition, sort by newest, and de-duplicate on listing_id.

What Mudah.my data costs

The cheapest call here is 0 credits, 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 →
$0.67–$1.50 / 1,000 credits
  • 1,000 free credits on signup, no card
  • One key, all 294 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
curl -X POST https://api.reefapi.com/mudah/v1/search \
  -H "x-api-key: $REEF_KEY" \
  -H "content-type: application/json" \
  -d '{"category":"1020","limit":20}'
python
import requests

r = requests.post(
    "https://api.reefapi.com/mudah/v1/search",
    headers={"x-api-key": REEF_KEY},
    json={
  "category": "1020",
  "limit": 20
},
)
print(r.json()["data"])
FAQ

Have a question? We got answers.

The questions people actually ask before wiring up Mudah.my.

Get a free key →
How do I tell Mudah what to search?▾

Any combination of a keyword and a place. query is the keyword, category is a category id, slug or name such as 1020, cars or Cars, region is a state or federal territory such as selangor or Kuala Lumpur, and area is a town or district inside it, where a comma list is allowed. A bare category with no keyword browses everything in it, and a parent category id includes its children. You do not have to guess any of those ids: categories and locations are free actions that list every one.

Do the Mudah filters actually filter?▾

They do here, and that is the point of the action. Mudah itself accepts a filter key it does not know and quietly returns the unfiltered set: rooms=3 left all 104,169 property ads in place, property_type, job_cat, contract_type, pet_type and gender_type did the same, and price_min with price_max went the other way and returned nothing at all. Every filter you send is resolved against mudah's own published schema first and rejected with the allowed values when it is not there. 24 filters were then run against a same-minute unfiltered control and all 24 narrowed: make=Toyota took 89,804 car ads to 19,549 and model=Hilux on top of it to 1,051 with 40 of 40 rows Hilux, condition=new took phones from 13,484 to 1,534 with 40 of 40 New, ad_type=let took property from 104,171 to 46,683 with 40 of 40 let, and seller_type private and company split 13,484 into 12,290 and 1,194 which add back to the total.

How many Mudah ads can one search return?▾

Up to 200 a call, and that ceiling is enforced because mudah does not enforce it: ask for 201 or more and it serves 24 rows with no error. Page with offset, and keep offset plus limit within 10,000, which is mudah's search window. Past it mudah reports zero total results for a category holding tens of thousands of ads, so a deeper request is refused here instead of being answered with that lie. total_results tells you how large the market really is, so partitioning by state, town, make or price band is how you reach the rest.

What does the price field mean on a rental or a job ad?▾

Mudah writes a sale price, a monthly rent and a job salary into the same field, so every row says which one it is in price_kind, reading price, rent or salary. Where an ad publishes no price at all mudah shows Negotiable, and price comes back null with price_not_published true rather than 0, because a zero there would read as free. Measured on 1,800 rows across nine categories: price is present on 40 of 40 rows in 15 of the 17 categories tested, 39 of 40 in jobs, and 0 of 40 in services, where all 200 sampled ads carried Negotiable.

Do I get the seller's phone number?▾

For a dealer, an agency or a shop, yes, always: those are business facts, and the shop identity, its verification and its registration number where one is published come with them. For a private individual the name and number are off by default, because on a classifieds site those belong to a person. You still see that a number exists, as a masked phone_masked, and seller.pii_withheld says plainly that it was withheld rather than absent. Set include_pii to true when you have a lawful reason and the full contact comes back. Every listing also publishes seller.business_evidence, so the private-or-business call is auditable rather than a hidden rule.

Is there a price per square foot, or what an item finally sold for?▾

No to both, and neither is invented. Mudah publishes no unit price anywhere, so there is no price per square foot on a property and no price per unit on anything else, and none is worked out here: what you get is the advertised price and, for property, the floor size, as two separate fields. There is also no sold price. Mudah stops serving an ad entirely when it goes, so a dead listing id is NOT_FOUND and there is no record of what it closed at.

Which Mudah fields are missing, and why?▾

Whatever the category does not publish, and it is left absent rather than guessed. listing_id, title, url, the cover image, state, town and posted_at came back on 40 of 40 rows in all 17 categories tested. Condition is not defined at all for property, jobs, services, pets, food and number plates. The vertical details block is full on cars, motorcycles, property, phones, clothes, pets and jobs, thin on business equipment at 16 of 40 and on number plates and food at 3 of 40, and empty on furniture and home appliances, which publish no extra row fields. Job ads often have no photo, 24 of 40. On the 40 listing pages measured, description and contacts were 40 of 40, images and the attribute table 38 of 40, and the specifications block 4 of 40, because only vehicles have one.

What happens when a Mudah search finds nothing?▾

It is checked before it is reported. A genuine no-match and a throttled read look identical from the outside, both a plain empty list, so an empty search is asked a second time and only reported empty when both reads agree. The answer then carries empty_confirmed true, which means mudah really has no ad matching the query.

What is the Mudah.my API?▾

Mudah.my API is a ReefAPI endpoint group for malaysia's largest classifieds: cars, property for sale and to rent, phones, appliances, fashion, pets, jobs and services, priced in myr. It returns live JSON through POST requests under /mudah/v1.

Is the Mudah.my API free to try?▾

Yes. ReefAPI starts with 1,000 free credits, no card required. Mudah.my calls use the same shared credit balance as every other ReefAPI engine.

Do I need a Mudah.my login or account?▾

No login to Mudah.my 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 Mudah.my data?▾

The page example is captured from a live search call, and production requests fetch live data through ReefAPI rather than a static sample.

How many credits does the Mudah.my API use?▾

Mudah.my actions currently cost 1 credit per successful call. Failed or blocked calls are free. All APIs draw from one credit pool.

Can I call Mudah.my from an AI assistant or MCP client?▾

Yes. Connect ReefAPI once through MCP and your assistant can call mudah actions with the same key, credit pool and JSON envelope used by normal REST requests.

122 E-commerce & Marketplaces APIs on the same key

One key, one credit pool, one response envelope. If you are pulling Mudah.my, you are one call away from the rest of the category — no second contract, no second integration.

Need something this API does not do?

Name the endpoint, the field, or a source we do not carry yet. We ship new APIs every week and you would be first to get the key. Real people read every message and reply the same day.

0/4000

No account needed · we reply from [email protected]

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 293 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-09-24.