Skip to content
Browsabledocs
Staging API reference · Requests use https://api-ingress-worker-staging.browsable-staging.workers.dev
Documentation OfferUp Search API
Markdown ↗
OfferUp APIs

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.

POST/v1/offerup/search
Authenticate every request

Send Authorization: Bearer YOUR_API_KEY. Get an API key →

Parameters

Send these fields in a flat JSON body. Add _run to choose execution options.

locationstringRequired

US city and state, such as Los Angeles, CA, or a 5-digit ZIP code. Coordinates are resolved automatically. Minimum length: 2. Maximum length: 200.

querystringRequired

Search words, such as iPhone 13 or Nintendo Switch. Minimum length: 1. Maximum length: 200.

limitintegerOptional

Maximum results in this response. Default: 25. Minimum: 1. Maximum: 50.

conditionstringOptional

Filter by an allowed product condition. Allowed: "new", "open_box", "refurbished", "used", "for_parts", "other".

cursorstringOptional

next_cursor from the previous response. Keep the other search inputs unchanged. Maximum length: 131072.

max_pricenumberOptional

Maximum price in the marketplace currency. Minimum: 0. Maximum: 1000000.

min_pricenumberOptional

Minimum price in the marketplace currency. Minimum: 0. Maximum: 1000000.

radius_milesintegerOptional

Search radius in miles around the resolved location. Default: 30. Allowed: 5, 10, 20, 30, 50, 80.

sortstringOptional

Sort order. Choose an allowed value below. Allowed: "best_match", "newest", "closest", "price_low", "price_high".

Advanced & compatibility inputs 1
category_idstringOptional

OfferUp 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
JSON
{
  "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
JSON
{
  "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 in errors before retrying.
  • 428Connect the requested website account using the returned sign-in link.
  • 429Wait for the duration in Retry-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.

Validation, pagination and recovery →

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
done
Wait-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.