Read Yelp business data and reviews with one API
The Yelp API returns business search, reviews and ratings as clean JSON.
9 active endpoints. Every call is 1 credit.
- POST/yelp/v1/business/reviews
- POST/yelp/v1/business/details
- POST/yelp/v1/search
- POST/yelp/v1/popular_dishes
- POST/yelp/v1/menus
- POST/yelp/v1/business/photos
- POST/yelp/v1/review_highlights
- +2 more
What Yelp endpoints does ReefAPI ship?
9 live read endpoints. Read-only data API: no writes, no account actions, no dashboard access on the target site.
Yelp API
3 of 9 endpoints, ready to run
The keyword-in-a-city search: rating, review count, price level, categories and the business id for every hit.
{ "ok": true, "meta": { "api": "yelp", "endpoint": "search", "mode": "live", "latency_ms": 3440.1, "record_count": 10, "cache_hit": false }, "data": { "results": [ { "enc_biz_id": "wEzg_lla5jqAzIXokYnZJA", "name": "That's Amore Woodfire Pizza", "slug": "thats-amore-woodfire-pizza-san-francisco", "url": "https://www.yelp.com/biz/thats-amore-woodfire-pizza-san-francisco", "rating": 4.4, "review_count": 361, "price": "$$", "price_level": 2, "categories": [ "Pizza", "Beer, Wine & Spirits", "Italian" ], "address": "1901 Ocean Ave", "city": "San Francisco", "state": "CA", "neighborhoods": [ "Ingleside Terraces" ], "image": null }, { "enc_biz_id": "42gxakyqDMfiX9MW9T3tZQ", "name": "Mountain Mike's Pizza", "slug": "mountain-mikes-pizza-daly-city-2", "url": "https://www.yelp.com/biz/mountain-mikes-pizza-daly-city-2", "rating": 4.1, "review_count": 199, "price": "$$", "price_level": 2, "categories": [ "Pizza", "Chicken Wings" ], "address": "35 Skyline Plz", "city": "Daly City", "state": "CA", "neighborhoods": [], "image": null }, { "enc_biz_id": "JvSfQXeBKYQQpHMxF6sSww", "name": "Bollywood Pizza", "slug": "bollywood-pizza-san-francisco-2", "url": "https://www.yelp.com/biz/bollywood-pizza-san-francisco-2", "rating": 4.6, "review_count": 64, "price": null, "price_level": null, "categories": [ "Pizza", "Indian" ], "address": "215 Fremont St", "city": "San Francisco", "state": "CA", "neighborhoods": [ "Financial District", "SoMa" ], "image": null } ], "term": "Pizza", "location": "San Francisco, CA" } }
How the Yelp API works
Yelp 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.
Sort, do not stretch
Asking one call for more reviews has a ceiling. Asking two calls for opposite ends of the same feed does not — the newest-first and oldest-first windows on the same business shared no reviews at all on our run.
{"name": "Blue Bottle Coffee", "location": "San Francisco"}Take results[0].enc_biz_id. It is stable, so you only pay for this once per business.
{"encBizIds": ["..."], "sortBy": "DATE_DESC", "maxReviews": 500}The recent window, and the business profile with it — rating, categories, hours, amenities, photo.
{"encBizIds": ["..."], "sortBy": "DATE_ASC", "maxReviews": 500}The other end of the feed. Measured: 100 rows from each sort, zero shared review ids.
Two disjoint windows of the same business, plus a 1-star pass if you are after the complaints. Every result carries completeness_pct so you can see the share you hold.
curl -X POST https://api.reefapi.com/yelp/v1/search \
-H "x-api-key: $REEF_KEY" \
-H "content-type: application/json" \
-d '{"term":"Pizza","location":"San Francisco, CA","limit":10}'{
"ok": true,
"data": { … },
"meta": {
"api": "yelp",
"endpoint": "search",
"mode": "live",
"latency_ms": …,
"record_count": …
},
"error": null
}The business id is not the slug, and the price band changes field name per action
Two things send people in circles on Yelp. The identifier in a yelp.com/biz/ URL is a slug, not the id the API takes, and there is a dedicated action to convert one into the other. And the price band arrives under a different field name depending on which action returned it. Everything below is from measured calls on San Francisco and New York businesses.
| Field | Format | Measured |
|---|---|---|
| enc_biz_id | 22 characters, opaque, mixed case with - and _. This is what every action takes. | mSMZJj2pFvttWLpcDmgrEA for Tony's Pizza Napoletana, gZz9A8k8ORC_xl0aHxtY4w for Monkey Bar |
| slug / alias | The path segment in yelp.com/biz/<slug>. Never accepted where an id is required. | tonys-pizza-napoletana-san-francisco. business/url-to-id converts a URL into the id. |
| rating | One decimal, not a half-star. The half-star on the website is display rounding. | 4.1, 4.2, 4.3 and 4.6 all appeared on a single search page |
| rating_histogram | Keys "5" down to "1", integer counts. | Tony's returned 5:5442, 4:1770, 3:703, 2:399, 1:631, a weighted mean of 4.229 matching the reported 4.2 |
| price and price_level (search) | A band string and its integer, 1 through 4. Both null when Yelp has no band for that business. | "$$" with price_level 2, "$" on a budget listing, and null with null on another row |
| price_range (details, reviews) | The same band under a different field name, with no numeric twin. | "$$" on both business/details and business/reviews |
| price filter | Applied by the source. Verified in both directions. | price [4] returned eight $$$$ restaurants; price [1] returned six $ pizzerias |
| hours | Yelp's own GraphQL shape, passed through with its __typename keys. | hours[0].regularHoursMergedWithSpecialHoursForCurrentWeek[] of {dayOfWeekShort, dayOfWeek, regularHours[]}, e.g. "Mon", "Monday", ["11:45 AM - 10:30 PM"] |
| reviewer.elite_year | A two-digit string on elite reviewers, and the key is absent entirely otherwise. | "26" with is_elite true on one reviewer, and no elite_year key at all on the next |
| review reactions | A fixed four-key object, always present. | {HELPFUL, THANKS, LOVE_THIS, OH_NO}, alongside a separate useful_count |
The histogram and review_count can disagree slightly. Tony's histogram sums to 8945 against a review_count of 8942, because Yelp counts recommended reviews and builds the histogram at a different moment. Treat a difference of a few as normal, and do not use one to validate the other.
How much of a business's reviews you can hold
Measured on 2026-08-27 against one San Francisco restaurant that reports 8,945 reviews, by raising maxReviews until the call stopped answering.
Around 500. 20, 100 and 500 all came back exactly as asked, the last of them in just under a minute; 1,000 and 2,000 both ran out of time before answering. Treat 500 as the working size of one call and use more calls, not bigger ones.
In our favour, and it is not the norm in this vertical: oldest-first returned 100 rows with zero ids in common with newest-first, and ratings [1] returned 100 rows that were all 1-star. Slicing widens real coverage here instead of re-serving the same window.
Against us: 500 rows against a reported 8,945 is 5.6%, and the response says so — completeness_pct is in every result. No single strategy we measured gets a heavily-reviewed business anywhere near whole.
Every endpoint here is priced per call, so the credit figure on each endpoint card is the whole price of that call however many reviews it brings back. Failed and blocked calls are never charged.
Against us: useful_count came back 0 on all 20 rows we checked, and photos on 10 of 20. Review id, star rating, body, language and both date fields were filled on every row; an owner-reply flag on 18 of 20.
What people build with Yelp
The jobs this data is most often used for.
endpoints
credit per call
Reputation tools call business/reviews to monitor a business's Yelp rating and new reviews.
Lead-generation products use search to build lists of local businesses by category and city.
Local-data apps use business/details, menus and popular_dishes to enrich a restaurant listing.
What Yelp 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/yelp/v1/search \
-H "x-api-key: $REEF_KEY" \
-H "content-type: application/json" \
-d '{"term":"Pizza","location":"San Francisco, CA","limit":10}'import requests
r = requests.post(
"https://api.reefapi.com/yelp/v1/search",
headers={"x-api-key": REEF_KEY},
json={
"term": "Pizza",
"location": "San Francisco, CA",
"limit": 10
},
)
print(r.json()["data"])Have a question? We got answers.
The questions people actually ask before wiring up Yelp.
Get a free key →I have a yelp.com/biz/ URL. Why does the last part of it not work as a business id?▾
Because that is the slug, and the id is a separate 22-character encoded string. For Tony's Pizza Napoletana the slug is tonys-pizza-napoletana-san-francisco and the id is mSMZJj2pFvttWLpcDmgrEA. Pass a URL to business/url-to-id and it returns {enc_biz_id, name, slug, url} in one call. search and business/search also return enc_biz_id on every row, so if you are starting from a name you already have the id. A few actions (popular_dishes, menus, business/photos and review_highlights) accept the slug or the URL directly.
Is rating rounded to a half star?▾
No, that is a display convention on the website. The API returns one decimal: a single measured search page held 4.1, 4.2, 4.3 and 4.6, none of which is a half-step. You can check it against the histogram, since Tony's counts of 5442, 1770, 703, 399 and 631 give a weighted mean of 4.2289, which is exactly the 4.2 reported even though the page draws four and a half stars. Sort and threshold on rating directly, and round only when you draw the stars.
Why is price null on some businesses?▾
Because Yelp has no price band for them, usually a newer listing or a non-restaurant. A measured search returned one pizzeria with price "$$" and price_level 2 and another with both null on the same page. Note the field name changes by action: search returns price plus price_level (the integer 1 to 4), while business/details and business/reviews return price_range with no numeric twin. The price filter on search does work and was verified in both directions, with [4] returning only $$$$ and [1] only $.
A result came back with rating null and review_count 0. Is the record broken?▾
No, that is a listing with no reviews yet, and Yelp does show them in search results. A measured search for pizza in San Francisco returned a cafe with rating null and review_count 0 sitting among businesses with hundreds of reviews. Guard for it, because sorting on rating will either throw or push nulls to an arbitrary end depending on your language. It is the expected shape for a brand-new business rather than an error.
My search for San Francisco returned a business in Daly City. Why?▾
Yelp widens the radius when a query does not fill the page from inside the named location, exactly as the website does. A measured search for "Pizza" in "San Francisco, CA" returned Mountain Mike's Pizza in Daly City as the second result. Every row carries city, state and neighborhoods[], so filter on those yourself if you need a hard boundary. neighborhoods[] is empty for businesses outside a named Yelp neighborhood, which is another hint that a row is out of town.
completeness_pct says 0.1 but the profile looks complete. What is it measuring?▾
The share of the business's reviews this call actually harvested, not the completeness of the profile. A measured business/reviews call with maxReviews 5 against a business holding 8942 reviews returned scraped_review_count 5, claimed_review_count 8942 and completeness_pct 0.1. On business/details, which fetches no reviews at all, it sits near zero by definition even though every profile field came back populated. Read scraped_review_count against claimed_review_count if you want to know how much of the review body you hold.
What does the hours object look like, and why is __typename in it?▾
Hours arrive in Yelp's own GraphQL shape and we pass it through unflattened so nothing is lost in translation. You get hours[0].regularHoursMergedWithSpecialHoursForCurrentWeek, an array of seven entries of {dayOfWeekShort, dayOfWeek, regularHours, __typename}, measured as {"Mon", "Monday", ["11:45 AM - 10:30 PM"]}. regularHours is an array because a business can have split hours in one day, the times are 12-hour strings in the business's local time, and the field name says "merged with special hours", so a holiday can move a day with no separate flag. Ignore __typename.
What is on a review row besides the text?▾
Quite a lot. Measured: review_id, rating as an integer 1 to 5, text, language, localized_date ("2026-08-25") alongside created_at carrying the business's UTC offset ("2026-08-25T21:57:13-07:00"), useful_count, a reactions object with the four fixed keys HELPFUL, THANKS, LOVE_THIS and OH_NO, photos[] of full-size image URLs, is_not_recommended, and owner_reply_text with owner_reply_date whenever has_owner_reply is true. The nested reviewer object carries friend_count, review_count, photo_count and is_elite, with elite_year present as a two-digit string like "26" only on elite reviewers.
How do I pull only negative reviews?▾
Pass ratings, which takes an array of star values and defaults to all five. ratings [1, 2] gives you the complaints, and it combines with maxReviews and sortBy. sortBy takes RELEVANCE_DESC, DATE_DESC (the default here), DATE_ASC, RATING_DESC, RATING_ASC and ELITES_DESC. Also worth knowing: includeNotRecommended pulls Yelp's filtered reviews into a separate not_recommended_reviews[] array rather than mixing them into reviews[], with not_recommended_count reported beside it.
What is the Yelp API?▾
Yelp API is a ReefAPI endpoint group for local business reviews, ratings and details. It returns live JSON through POST requests under /yelp/v1.
Is the Yelp API free to try?▾
Yes. ReefAPI starts with 1,000 free credits, no card required. Yelp calls use the same shared credit balance as every other ReefAPI engine.
Do I need a Yelp login or account?▾
No login to Yelp 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 Yelp data?▾
The page example is captured from a live business/reviews call, and production requests fetch live data through ReefAPI rather than a static sample.
How many credits does the Yelp API use?▾
Yelp actions currently cost 1 credit per successful call. Failed or blocked calls are free, and all APIs draw from one credit pool.
14 Reputation & Reviews APIs on the same key
One key, one credit pool, one response envelope. If you are pulling Yelp, 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.