OfferUp Search API
Search OfferUp listings near a US city and state or ZIP code. Location is resolved automatically. Returns prices, locations, images and pickup information with cursor pagination. Seller ratings and cancellations are not included in OfferUp's search feed.
/v1/offerup/searchSend Authorization: Bearer YOUR_API_KEY. Get an API key →
Parameters
Send these fields in a flat JSON body. Add _run to choose execution options.
locationstringRequiredUS city and state, such as Los Angeles, CA, or a 5-digit ZIP code. Coordinates are resolved automatically. Minimum length: 2. Maximum length: 200.
querystringRequiredSearch words, such as iPhone 13 or Nintendo Switch. Minimum length: 1. Maximum length: 200.
limitintegerOptionalMaximum results in this response. Default: 25. Minimum: 1. Maximum: 50.
conditionstringOptionalFilter by an allowed product condition. Allowed: "new", "open_box", "refurbished", "used", "for_parts", "other".
cursorstringOptionalnext_cursor from the previous response. Keep the other search inputs unchanged. Maximum length: 131072.
max_pricenumberOptionalMaximum price in the marketplace currency. Minimum: 0. Maximum: 1000000.
min_pricenumberOptionalMinimum price in the marketplace currency. Minimum: 0. Maximum: 1000000.
radius_milesintegerOptionalSearch radius in miles around the resolved location. Default: 30. Allowed: 5, 10, 20, 30, 50, 80.
sortstringOptionalSort order. Choose an allowed value below. Allowed: "best_match", "newest", "closest", "price_low", "price_high".
Advanced & compatibility inputs 1
category_idstringOptionalOfferUp category id, such as 1.2 for cell phones and accessories. Pattern: ^[0-9]{1,4}(?:\.[0-9]{1,4}){0,2}$.
Response
Every response describes a run. Read result once run_status is succeeded.
run_id- The run to track. Keep it when contacting support.
run_status- Queued, running, waiting for sign-in, succeeded, or failed. Check this even after an HTTP 200.
status_url- Poll this URL while the run is pending. Keep the same run instead of starting another request.
result- The endpoint’s returned data. The example is illustrative; actual fields may be empty or unavailable.
error- On failure, inspect its code, message, retryable and action fields.
View the complete output schema
{
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"required": [
"success",
"source",
"query",
"url",
"results",
"count",
"data",
"max_results_requested",
"pagination"
],
"properties": {
"url": {
"type": [
"string",
"null"
]
},
"data": {
"type": "object",
"required": [
"location",
"latitude",
"longitude",
"radius_miles",
"applied_query",
"seller_trust_available"
],
"properties": {
"latitude": {
"type": "number"
},
"location": {
"type": "string"
},
"longitude": {
"type": "number"
},
"radius_miles": {
"type": "integer"
},
"applied_query": {
"type": [
"string",
"null"
]
},
"seller_trust_available": {
"const": false
}
},
"additionalProperties": false
},
"count": {
"type": "integer",
"minimum": 0
},
"query": {
"type": [
"string",
"null"
]
},
"source": {
"const": "offerup-search"
},
"results": {
"type": "array",
"items": {
"type": "object",
"required": [
"id",
"title",
"url",
"price",
"currency",
"location",
"condition",
"image_url",
"firm_price",
"local_pickup"
],
"properties": {
"id": {
"type": "string"
},
"url": {
"type": "string"
},
"price": {
"type": [
"string",
"null"
]
},
"title": {
"type": "string"
},
"currency": {
"const": "USD"
},
"location": {
"type": [
"string",
"null"
]
},
"condition": {
"type": [
"string",
"null"
]
},
"image_url": {
"type": [
"string",
"null"
]
},
"firm_price": {
"type": [
"boolean",
"null"
]
},
"local_pickup": {
"type": [
"boolean",
"null"
]
}
},
"additionalProperties": false
}
},
"success": {
"const": true
},
"pagination": {
"type": "object",
"required": [
"cursor",
"next_cursor",
"has_next_page",
"count",
"strategy"
],
"properties": {
"count": {
"type": "integer"
},
"cursor": {
"type": [
"string",
"null"
]
},
"strategy": {
"const": "cursor"
},
"next_cursor": {
"type": [
"string",
"null"
]
},
"has_next_page": {
"type": "boolean"
}
},
"additionalProperties": false
},
"max_results_requested": {
"type": "integer"
}
},
"additionalProperties": false
}View a polled run response
{
"run_id": "00000000-0000-4000-8000-000000000001",
"task_key": "offerup-search",
"task_name": "OfferUp Search API",
"run_status": "succeeded",
"status_url": "/v1/runs/00000000-0000-4000-8000-000000000001",
"result": {
"url": "https://example.com/item-1",
"data": {
"latitude": 51.5074,
"location": "London",
"longitude": -0.1278,
"radius_miles": 1,
"applied_query": "London",
"seller_trust_available": false
},
"count": 1,
"query": "London",
"source": "offerup-search",
"results": [
{
"id": "id-1",
"url": "https://example.com/item-1",
"price": "180",
"title": "Stylish Shoreditch Loft with Balcony",
"currency": "USD",
"location": "London",
"condition": "sample",
"image_url": "https://example.com/item-1",
"firm_price": true,
"local_pickup": true
}
],
"success": true,
"pagination": {
"count": 1,
"cursor": "cursor-page-1",
"strategy": "cursor",
"next_cursor": "cursor-page-1",
"has_next_page": true
},
"max_results_requested": 1
},
"error": null
}Errors & retries
400Fix the fields listed inerrorsbefore retrying.428Connect the requested website account using the returned sign-in link.429Wait for the duration inRetry-After.5xxRetry transient failures with backoff. Keep the request ID.
A failed run has its own error inside the response. Retry it only when error.retryable is true.
More examples
Async request with polling
RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/offerup/search" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"query":"London","location":"London"}')
RUN_ID=$(echo "$RUN" | jq -er '.run_id // empty') || { echo "$RUN" >&2; exit 1; }
POLL_DELAY=3
while true; do
RESULT=$(curl -s -H "Authorization: Bearer YOUR_API_KEY" "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/$RUN_ID")
STATUS=$(echo "$RESULT" | jq -r '.run_status')
if [[ "$STATUS" =~ ^(succeeded|failed|errored|cancelled|canceled|expired)$ ]]; then
echo "$RESULT"
break
fi
sleep "$(awk "BEGIN { print $POLL_DELAY * (0.9 + ($RANDOM % 21) / 100) }")"
POLL_DELAY=$((POLL_DELAY < 30 ? POLL_DELAY * 2 : 30))
[ "$POLL_DELAY" -gt 30 ] && POLL_DELAY=30
doneWait-for-results request
curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/offerup/search" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"query":"London","location":"London","_run":{"async":false}}'Canonical & compatibility routes
You can also send the same JSON body to /v1/tasks/offerup-search/runs.