OfferUp API

US local classifieds as JSON, scoped to the metro you actually want

The OfferUp API returns the large US local classifieds marketplace as clean JSON, in two actions: search and product/detail.

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

2 active endpoints. Every call is 1 credit.

  • POST/offerup/v1/search
  • POST/offerup/v1/product/detail

What OfferUp endpoints does ReefAPI ship?

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

2 endpoints

search

1 cr

Search OfferUp listings near a US location by keyword, by category, or both.

required
optional
query, category, zip_code, latitude, longitude, radius, price_min, price_max, sort, cursor, max_rotations

product/detail

1 cr

The full OfferUp listing record by listing_id (or listing URL).

required
listing_id
optional
max_rotations

Every parameter, every allowed value →

OfferUp API

2 of 2 endpoints, ready to run

View docs ↗

The OfferUp feed near a US location: listing id and URL, title, the price as a number in USD with OfferUp's own formatted string, the town, the photo and the tile flags — about 44 to 50 rows, plus a cursor for the next page.

1 credit0 required · 7 optional
POST/offerup/v1/search
ok1046 ms · 44 records · sample
{
  "ok": true,
  "meta": {
    "api": "offerup",
    "endpoint": "search",
    "mode": "live",
    "latency_ms": 1045.9,
    "record_count": 44,
    "cache_hit": false
  },
  "data": {
    "results": [
      {
        "listing_id": "758a280b-44d6-343f-9604-04cff565d22b",
        "title": "Modular Sectional Sofa Couch",
        "price": 1350,
        "price_display": "$1,350",
        "currency": "USD",
        "call_for_price": false,
        "is_firm_price": null,
        "condition": null,
        "location": {
          "name": "South Gate, CA",
          "latitude": null,
          "longitude": null
        },
        "image": {
          "url": "https://images.offerup.com/WZiRf0hh3ZKxyp0yQxY_uiEHnt4=/250x250/339c/339cbc0403bc4506bf99fc9eb9ab945e.jpg",
          "width": 250,
          "height": 250
        },
        "vehicle_miles": null,
        "flags": [
          "LOCAL_PICKUP"
        ],
        "url": "https://offerup.com/item/detail/758a280b-44d6-343f-9604-04cff565d22b",
        "rating": null,
        "review_count": null,
        "rating_scale": null,
        "position": 1
      },
      {
        "listing_id": "8840afca-7efc-329c-b3ce-f716548fb181",
        "title": "Sofa couch, firm on price",
        "price": 140,
        "price_display": "$140",
        "currency": "USD",
        "call_for_price": false,
        "is_firm_price": null,
        "condition": null,
        "location": {
          "name": "Rosemead, CA",
          "latitude": null,
          "longitude": null
        },
        "image": {
          "url": "https://images.offerup.com/lcMUYZ7FhtI1hUkCRZzlS8ByY2I=/250x333/855e/855e090e8b424cb29ffbbf716913ae0c.jpg",
          "width": 250,
          "height": 333
        },
        "vehicle_miles": null,
        "flags": [
          "LOCAL_PICKUP"
        ],
        "url": "https://offerup.com/item/detail/8840afca-7efc-329c-b3ce-f716548fb181",
        "rating": null,
        "review_count": null,
        "rating_scale": null,
        "position": 2
      },
      {
        "listing_id": "4a9cae74-d161-3806-b101-4e53743759b2",
        "title": "Love seat and sofa",
        "price": 0,
        "price_display": "$0",
        "currency": "USD",
        "call_for_price": false,
        "is_firm_price": null,
        "condition": null,
        "location": {
          "name": "Garden Grove, CA",
          "latitude": null,
          "longitude": null
        },
        "image": {
          "url": "https://images.offerup.com/vCksVrKDX6E8l0y5YVHBU7fqZzc=/333x250/56ba/56ba6abcf1054e569fda47d47b3f4381.jpg",
          "width": 333,
          "height": 250
        },
        "vehicle_miles": null,
        "flags": [
          "LOCAL_PICKUP"
        ],
        "url": "https://offerup.com/item/detail/4a9cae74-d161-3806-b101-4e53743759b2",
        "rating": null,
        "review_count": null,
        "rating_scale": null,
        "position": 3
      }
    ],
    "count": 44,
    "next_cursor": "H4sIAAAAAAAAAI1W244ctxH9lWCeVQCvRXLfjFViCJAtIXYeDEtYFFnF1cDrncn0TGzF2H_34WidGIZh6GV3uru6yHMr9i-7zeQ0Pnxj27Y_PL7S3c1uw3UctbWpUpPkxL3V0Jlzc7jDoRfbvXh-8R9mens5bYcT3vzl3e4w52bnd7ublJ5QNPH4m7Oczrub7F7sjif7z_5w2d7Kvb3eb-f94_0r3XY33-9KrhKq65SSMsUUJzV2iVwac2bOGkJHv1qTkzmEis1BMbRBPQ6jWTznVGf31aMsSRtiJZF69hSrY-reeUqWY0mx5NYDyoqvObBH2WiTYtZJ3ThTSWEGdRxj51WWrWvxk4afKHONSUIu1NSHObyYhIQy1s6epVOMMeMPWtaujiQXLpVdbroWzcZDXSskrEqxi1CdI1Ewb9lKaVHiWlRqt-IL8NWwCIkkRRJVrdkpNpZHRZmbro4xInF06JZcRreZyOOmzdTzczfWUUeuFGbFBqtV6qOgNllV6UlUHcpU0Z2LEoN2itMCgXFPRSMXq6Ghz-pWUwkhCHUXCwgJlWRqIINtopbusiyxUgJLngepywsCZBORSXkyD25s3S1CzCzOooNCcJGiVA8IwjRGdxIG5OWlqTiwnaKjOjo0jZCiDs-Uy5hjqvbm2lIB_KVQPEHARLHBSFIGcESVyV00xLU3czpj4kkak1H0tUHTUJb-RS0F7HMuCBzbgL4kCX_iYKU2ADcWk-YZm-iLt5GdM00CkLb8pkYt1LIsVSzMPlK50ltD7d6wqEz_yW9NB5CGUnOKLelY9Ga16S02ApsOJvdKvaVAzo2QZmxhWkZZTOrijIF0VkDgoAukEXsFA0t9WbwF0-Z8auQFTo_ZGfUE8oqpCpoj4vG6aKtceqfWO6QvvsF5XLFVS8PVHKsvSwVw4L3p6gEjTR-xaHHEuboxo3mka-2tShq5JWo5Is6SkVObWFnUVQa_7Sq9b4krT1TMtCLTkQXOnZD2ab5NrLqQAo93MXuyYXAI97SShZbSpwQ_CibHEiswQHSkUzyk6CFSaxWGYXUCgjFJlqYRMcK6StN6WfQiBhZgP3F5pJnYzauR8NNNVFjwoHfp3zsGic9ADT2k1LEmkuU2Q4RnO2hAZADSY_L4DNvlEUHfImRiPAWEBtuqQOoR7Kpg0FobLtXmnS5bDu9dnR45lQxWGhSrFgEGLsRsqSBrQSiqGYKBi87QdHKAbOvXwNzmGJIFWSbPsXFF7EwM05KxqOQm5AyTDEqkrtcy4TYX7XNEaOoYZaFjDGLYjuKKclkqNEwtRn6or3jFWdds8kjWSN1CaUHzddTALTw7KBsLLjfQ6wDBAiTLLrt-dQjjMZfmSXpeQSlM8LhgVghG9NBSdWVhymyjiNJIABndqFQLuqmUmRNszbbKYIIowWEidYQqptmoIS7EmDS5NTeirUmOrSZe801yXuQJzNHZkQulN5w_M8iyJfAMJLLgMHLQ1BiWgssJI1dgTNWZ5-49wqDb3WYPD3b6Qrffn4KP9vP57ohD7m5c7-I8fLfzb1G1Tr7b53sv3l0PxM8r_EPNGFzDgHVxPjdKHgHDOZAB2AVz4BCT6PriX_VdJ_TCgN3a6VEePgfFl4fD_YO93G_HB_mIF56_HK5rid492vmnw-mH5zc2vIJG939459Pdz286DpfH9U3hcbl_VPvZVovv3funJ9y5Px0ux7vjaX847c8fP_WOR_xv7ek3hOPwuF1-NP3775Cupqvn7t8XO328lbPdo8N_5YyV0WR3_ng0EPH2n29e_uv227s3X7_-bn32HG3s535gKTy8ffPVV29evvr2-uTSV6e9XT9osOfx4W_jsn1Y7V48Xx_3Dw-Hn7b_XeNb6f-_D1N275_-dD-vD4cfLscvzmf78XiG42_Op4s9_Qq9w3g7vgkAAA",
    "total_results": null,
    "location": {
      "latitude": 34.0522,
      "longitude": -118.2437,
      "zip_code": null,
      "city": null,
      "state": null,
      "source": "coordinates",
      "radius_miles": 30
    },
    "query": "couch",
    "category": null,
    "sort": "best_match",
    "ad_tiles_dropped": 6,
    "duplicate_rows_dropped": 0
  }
}
Real response, fetched from the live endpoint with the parameters on the left — trimmed to the first few rows, with seller names left out. Press Try it for the untrimmed response.

How the OfferUp API works

OfferUp 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 192 engines.

02
Call
POST /offerup/v1/…

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

03
Pay
1 credit 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.

Search one metro, then read the listings that matter in full

The only thing that scopes an OfferUp search is the location you send with it. Get that right and the rest is two flat calls: the feed, then the record.

01search
POST/offerup/v1/search
{"query": "couch", "zip_code": "98101", "radius": 30}

One flat credit, about 44 rows at 24 KB. The response reports the coordinates it actually resolved and where they came from, so you can see the scope took. Take results[].listing_id.

02search
POST/offerup/v1/search
{"query": "couch", "zip_code": "98101", "cursor": "…"}

Pass the next_cursor from the previous response back as cursor. Measured over 4 pages: 184 rows, 184 distinct ids, zero overlap. The cursor belongs to the query that made it, so changing a filter starts a fresh walk.

03detail
POST/offerup/v1/product/detail
{"listing_id": "…"}

One flat credit, 3 KB. The description, the condition, the full gallery, the pickup terms and the seller's public sold count, join date and badges — plus the real price on the dealer rows where the tile hides it.

Three flat credits for a scoped local feed, its second page and a listing in full — and both actions are one upstream request each, so a sweep costs what you can count in advance.

request
curl -X POST https://api.reefapi.com/offerup/v1/search \
  -H "x-api-key: $REEF_KEY" \
  -H "content-type: application/json" \
  -d '{"query":"couch","latitude":34.0522,"longitude":-118.2437}'
response envelope
{
  "ok": true,
  "data": { … },
  "meta": {
    "api": "offerup",
    "endpoint": "search",
    "mode": "live",
    "latency_ms": …,
    "record_count": …
  },
  "error": null
}

What scopes a search is the coordinates you send - not your IP, and not a URL parameter

This is the single most important thing to know before you build against OfferUp, and it is the thing most callers get wrong first. OfferUp assigns EVERY exit the geographic centre of the United States as a fallback location, so an un-scoped search returns Kansas no matter where the call comes from. All five rows below were measured from ONE exit inside ONE minute on 2026-09-06 - the only thing that changed was the location sent with the query.

Location sent with the queryTowns that came back
nothingWichita KS, Pretty Praire KS - OfferUp's default US centre, not your location
40.7484 / -73.9857 (New York)Parlin NJ, Edison NJ, Union Beach NJ, Matawan NJ, New York NY
34.0522 / -118.2437 (Los Angeles)South Gate CA, Rosemead CA, South Pasadena CA, Garden Grove CA
25.7617 / -80.1918 (Miami)Miami FL, Ind Crk Vlg FL, Fort Lauderdale FL
47.6062 / -122.3321 (Seattle)Burien WA, Everett WA, Lynnwood WA, Fall City WA

A ZIP code works too and is resolved by OfferUp's own geocoder rather than by a table of ours, at the cost of one extra request - a live call on 98101 came back scoped to 47.6067 / -122.3354, Seattle WA, with 16 of 44 rows in Seattle itself. The response always reports which of the three happened, so you are never guessing whether your location took: the location block names the coordinates actually used and a source of zip_code, coordinates, or offerup_default_us_centre. Free-text place names are deliberately NOT offered, because OfferUp's geocoder refuses that arm without a bias position - it would have been a parameter that silently did nothing.

Which country, what scopes a search, which cursor pages, and what OfferUp does not publish

offerup.com only — one country, one currency, and a location that travels in the request rather than in your proxy. Measured on 2026-09-06 across 128 live engine calls in three runs with 0 unexpected failures, 704 search rows counted by value, 24 detail records and a 1,409-row regression. Four of these lines go against us.

One market: the United States, and prices in USD

OfferUp is a US marketplace and there is no country parameter because there is no other market. A request from outside the US is answered with a 403 page titled "Geolocation Unavailable", identically from every kind of exit — that is a country gate on the marketplace, not anti-bot behaviour, and the engine types it as MARKET_UNAVAILABLE so you know there is nothing to retry and no setting that opens it. Everything else about the surface is unusually open: OfferUp's own robots.txt names the data endpoint as allowed, and a call needs no cookie, no token, no account, no login and no browser.

🔴 Your IP does not scope the search. The coordinates you send do.

OfferUp assigns EVERY exit the geographic centre of the United States as a fallback location, so an un-scoped search returns Pretty Prairie and Wichita, Kansas — no matter where the call comes from. The lat and lon parameters on OfferUp's own search URL are ignored too. What works is the location sent with the query, and it was verified from one exit inside one minute: New York coordinates returned Parlin, Edison, Union Beach, Matawan and New York; Los Angeles returned South Gate, Rosemead, South Pasadena and Garden Grove; Miami returned Miami, Ind Crk Vlg and Fort Lauderdale; Seattle returned Burien, Everett, Lynnwood and Fall City. This is the practical upside as well as the trap: you sweep several metros from ONE exit, without buying an IP in each of them.

A ZIP is resolved by OfferUp's geocoder, and the response tells you what it used

Pass a ZIP and OfferUp's own geocoder turns it into coordinates at the cost of one extra request — a live call on 98101 came back scoped to 47.6067 / -122.3354, Seattle WA, with 16 of 44 rows in Seattle itself. The response always names the coordinates actually used and reports a source of zip_code, coordinates, or offerup_default_us_centre, so a mis-scoped search shows up in the payload rather than in the towns three days later. Free-text place names are deliberately not offered: OfferUp's geocoder refuses that arm without a bias position, so it would have been a parameter that silently did nothing.

Pagination turns, and it was checked by id rather than trusted

Pass the next_cursor from one response back as the cursor on the next call: 4 pages of one query gave 44 + 44 + 49 + 47 = 184 rows and 184 DISTINCT listing ids, with zero overlap against everything already seen. There is no page NUMBER — this feed is cursor-paged only — and no result total, so total_results is null rather than a guess. Two things not to assume: the page size is OfferUp's rather than yours, which is why a rows-per-call parameter is not offered at all (5, 10, 20, 50 and 100 all returned the same roughly 50-tile page upstream, so it would have been a parameter that does nothing), and the cursor belongs to the query that produced it, so changing a filter starts a fresh walk.

What one call costs, and how reliable it was

search is one upstream request at 23.7 to 24.7 KB, median 24.2 KB, with a median 875 ms; add a ZIP and it is two requests and about 1.7 seconds because of the geocode. product/detail is one request at 2.2 to 3.8 KB, median 3.0 KB, median 685 ms. Across 128 live engine calls in three runs there were 0 unexpected failures, p90 between 820 and 985 ms depending on the run, and 9 deliberate negative cases all returned the right error code. Both actions are flat-rated at one credit. The HTML page carries the same rows at 315 KB — thirteen times the bytes — and is deliberately not what this engine reads.

The price was cross-checked against the listing page itself

Fourteen listings were fetched twice, once through the engine and once as the page, and compared against the page's own structured-data price: 14 match, 0 mismatch, and no listing where the page carried no price. The set deliberately included a genuine 0.00 listing, kept as 0 rather than treated as missing, because a free item is a real thing on a classifieds site. Across 1,501 search rows, 24 detail payloads and a 1,409-row regression, the scan for raw HTML tags and HTML entities in any string found zero of each.

Against us: some vehicle rows have no price on the tile — traced to the exact mechanism

A dealer can ask OfferUp to hide the price on the feed tile, and OfferUp then sends an empty string rather than a number. Rather than shrug at the gap: the rows with no price are exactly the rows flagged CALL_FOR_PRICE — 7 of 1,062 in one run and 10 of 1,409 in the regression, and in BOTH runs the count of missing prices equalled the flag count exactly, so there are zero unexplained nulls. Every one was an auto-dealer vehicle. Those rows return price null with call_for_price true, never a misleading 0, and product/detail on the same ids returns the real numbers — 12,790, 22,290, 17,999 and 25,477 among them. OfferUp hides the figure on the tile, not on the listing.

Against us: there is no seller rating and no review count, anywhere

OfferUp's schema has a reviews object on a user profile and it measured null on 12 of 12 profiles — including a furniture seller with 10,769 items sold, and one whose own display name is "5 Star Seller". So the seller rating, the review count and the rating scale are all null rather than an invented number, and nothing on the surface states a rating maximum either. What OfferUp does publish is returned instead, and it is arguably the better reputation signal: items sold, items purchased, the join date, the stated response time, and the badge strip — "95% reply rate", "Confirmed phone", "Confirmed email" — as LABELS only, never as contact details.

Against us: a search row is thinner than a detail row, and there is no total

A feed tile has no owner field at all, so the seller is null on a search row and is filled by product/detail. The condition and the is-the-price-firm flag behave the same way: both measured 0 of 704 on search rows and both filled 24 of 24 on detail — the tile fields exist and OfferUp does not fill them, which is a source gap rather than a parse fault. And there is no result total anywhere on the feed, so total_results is null rather than a guess; the cursor is how you find out how much there is.

Against us: condition is not a search filter, because it did not work

OfferUp's own filter drawer names condition values, and three separate spellings of the parameter were tried against them. Not one changed a single row over 44, so condition is not published as a search filter at all — a parameter that is accepted and ignored is worse than no parameter. The filters that ARE offered were each proved to bite: a 100-to-200 price band returned 44 of 44 rows inside it; radius 5 kept 41 of 44 rows in Los Angeles itself across 4 towns while radius 50 spread over 30 towns; the descending price sort led with 1,000,000 and 999,999 where ascending led with five zero-priced rows; and each category id was verified by fetching the returned listing's own category back from product/detail. One interaction is documented on the parameter rather than hidden: a category plus a keyword lets the category win where the keyword has no local supply, so a phone keyword inside the vehicles category returns cars.

What is published about a person, and what is not

Public listings only, logged out, with no account and no captcha anywhere in the path. What comes back about a seller is what the public listing page shows anyone: their public display name, their public town, their join date, their sold and bought counts and their badge labels. The phone-number fields that exist on OfferUp's schema are never requested by this engine, so they cannot appear in a response even if OfferUp starts filling them.

What people build with OfferUp

The jobs this data is most often used for.

2

endpoints

1

credit per call

01

Local-market pricing tools scope a search to a metro with coordinates or a ZIP and read the whole 44-row feed at 24 KB a call.

02

Resale and arbitrage teams sweep a category across several US metros from one exit, since the location travels in the request rather than in the proxy.

03

Auto-listing aggregators pull dealer inventory from the vehicles categories and call product/detail for the mileage, transmission, title status and the real price on the rows where the tile hides it.

04

Marketplace research teams walk a query with the cursor - 184 distinct listings over 4 pages with zero overlap - and enrich each id with the seller's public sold count, join date and badges.

What OfferUp 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 →
$0.67–$1.50 / 1,000 credits
  • 1,000 free credits on signup, no card
  • One key, all 192 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/offerup/v1/search \
  -H "x-api-key: $REEF_KEY" \
  -H "content-type: application/json" \
  -d '{"query":"couch","latitude":34.0522,"longitude":-118.2437}'
python
import requests

r = requests.post(
    "https://api.reefapi.com/offerup/v1/search",
    headers={"x-api-key": REEF_KEY},
    json={
  "query": "couch",
  "latitude": 34.0522,
  "longitude": -118.2437
},
)
print(r.json()["data"])
FAQ

Have a question? We got answers.

The questions people actually ask before wiring up OfferUp.

Get a free key →
Why is my search returning results from Kansas?

Because you did not send a location, and OfferUp's fallback is the geographic centre of the United States - Pretty Prairie, Kansas. It applies that fallback to every exit, so the IP the call comes from does not scope anything, and neither do the lat and lon parameters on OfferUp's own search URL, which are ignored. Send zip_code, or latitude and longitude, on the search action. The response tells you which it used and what coordinates it resolved to, so a mis-scoped search is visible in the payload rather than something you discover from the towns three days later.

Does pagination actually return new listings?

Yes, and it was checked by comparing id sets rather than by trusting the cursor. Pass the next_cursor from one response back as the cursor on the next call: 4 pages of one query returned 44 + 44 + 49 + 47 = 184 rows and 184 DISTINCT listing ids, with zero overlap against everything already seen. There is no page NUMBER - OfferUp pages this feed by cursor only - and there is no result total either, so total_results is null rather than a guess. Two things not to assume: the page size is OfferUp's, not yours (a rows-per-call parameter is not offered because it does nothing upstream - 5, 10, 20, 50 and 100 all returned the same roughly 50-tile page), so read count; and the cursor belongs to the query that produced it, so change a filter and start a fresh walk.

Can I get a seller's rating or reviews?

No, and this one is worth stating plainly because it is the field people expect. OfferUp's schema has a reviews object on a user profile and it measured null on 12 of 12 profiles, including one furniture seller with 10,769 items sold and another whose own display name is "5 Star Seller". So the seller rating, the review count and the rating scale are all null rather than a fabricated number. What OfferUp does publish comes back instead, and it is a better reputation signal than an absent rating: items sold, items purchased, the join date, the stated response time, and the verification badge strip - "95% reply rate", "Confirmed phone", "Confirmed email" - as labels only, never as contact details.

Why do some vehicle listings have no price?

Because a dealer asked OfferUp to hide it on the tile, and OfferUp sends an empty string rather than a number. That was chased to the mechanism rather than shrugged off: the rows with no price are exactly the rows whose flags contain CALL_FOR_PRICE - 7 of 1,062 rows in one run and 10 of 1,409 in the regression, and in BOTH runs the count of missing prices equalled the flag count exactly, so there are zero unexplained nulls. Every one was an auto-dealer vehicle. Those rows come back with the price as null and call_for_price set to true, never as a misleading 0, and product/detail on the SAME listing ids returns the real numbers - 12,790, 22,290, 17,999 and 25,477 among them. OfferUp hides the figure on the tile, not on the listing.

Is the price the same number the page shows?

It was checked directly rather than assumed. Fourteen listings were fetched twice - once through the API and once as the listing page - and compared against the page's own structured-data price: 14 match, 0 mismatch, and no listing where the page had no price at all. The set deliberately included a genuine 0.00 listing, which is returned as 0 rather than being treated as missing, because a free item is a real thing on a classifieds site. Across 1,501 search rows, 24 detail payloads and a 1,409-row regression, the scan for raw HTML tags and HTML entities in any string found zero of each.

Which filters actually work?

The ones that were measured to change the result set, and only those. Price bounds bite exactly - a 100 to 200 band returned 44 of 44 rows inside it. Radius bites: at 5 miles a Los Angeles search kept 41 of 44 rows in Los Angeles across 4 towns, at 50 miles it spread over 30 towns. Sorting bites hard - a descending price sort led with 1,000,000 and 999,999 while ascending led with five zero-priced listings, and the distance and newest orderings shared 0 and 15 rows respectively with the default. Category ids bite, verified by fetching each returned listing's own category back from product/detail. Three condition parameter spellings were tried against OfferUp's own filter drawer and not one changed a single row over 44, so condition is NOT offered as a search filter - it is on product/detail instead. One interaction is worth knowing: a category plus a keyword lets the category win where the keyword has no local supply, so a phone keyword inside the vehicles category returns cars.

Does it work outside the United States?

No, and the failure is typed as a market limit rather than dressed up as a block. OfferUp is a US marketplace and answers a non-US request with a 403 page titled "Geolocation Unavailable", identically from every kind of exit, so it is a country gate rather than anti-bot behaviour. The engine returns MARKET_UNAVAILABLE for that, which tells you the truth: there is nothing to retry and no configuration that opens it. Everything else about the surface is unusually open - OfferUp's robots.txt names the data endpoint as allowed, and the call needs no cookie, no token, no account and no browser.

What does OfferUp NOT publish?

No seller rating, review count or rating scale anywhere. No total result count - the feed is cursor-paged and publishes no total, so total_results is null rather than an estimate. No seller at all on a search ROW: the feed tile has no owner field, so the seller comes back null there and is filled by product/detail. No condition and no is-the-price-firm flag on a search row either - both measured absent on 704 rows and both filled 24 of 24 on detail. And no per-listing rating or review count, because OfferUp has no product reviews: every listing is one second-hand object. The tile flag vocabulary observed over 1,062 rows was just two values, and one of them appeared on all 1,062 rows, so it is passed through verbatim rather than re-published as a boolean that would tell you nothing.

What is the OfferUp API?

OfferUp API is a ReefAPI endpoint group for us local classifieds: listings, prices and seller profiles near any zip. It returns live JSON through POST requests under /offerup/v1.

Is the OfferUp API free to try?

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

Do I need an OfferUp login or account?

No login to OfferUp 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 OfferUp 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 OfferUp API use?

OfferUp actions currently cost 1 credit per successful call. Failed or blocked calls are free, and all APIs draw from one credit pool.

Can I call OfferUp from an AI assistant or MCP client?

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

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 191 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-06.