# Browsable documentation Static documentation snapshot. Prefer the linked per-page Markdown when your context is limited. Prices and account access should be checked with the live API. # API Key Management Programmatically manage your API keys. ## List API Keys GET `/admin/list-keys` ```bash curl -X GET "https://api-ingress-worker-staging.browsable-staging.workers.dev/admin/list-keys" \ -H "Authorization: Bearer YOUR_API_KEY" ``` ## Create API Key POST `/admin/create-key` ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/admin/create-key" \ -H "Authorization: Bearer YOUR_API_KEY" ``` ## Revoke API Key POST `/admin/revoke-key` ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/admin/revoke-key" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"key_id": "key_abc123"}' ``` ## Get Usage Statistics GET `/admin/usage` ```bash curl -X GET "https://api-ingress-worker-staging.browsable-staging.workers.dev/admin/usage" \ -H "Authorization: Bearer YOUR_API_KEY" ``` --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/admin/api-keys # Amazon Product Search API Search Amazon and return structured product results. This endpoint uses the standard Browsable run envelope, so synchronous requests return `result` and asynchronous requests return a monitorable `run_id`. POST `/v1/amazon/search` Canonical execution route: `/v1/tasks/amazon-search/runs`. Live schema, examples, and credit cost are also available from `GET /v1/tasks/amazon-search`. For all current parameters, limits and response fields, see the [complete endpoint reference](/docs/api/endpoints/post-amazon-search.md) . This guide shows a basic request. ## Parameters | Parameter | Type | Required | Description | | --- | --- | --- | --- | | query | string | Yes | Amazon search query. | | marketplace | string | No | Amazon domain, such as amazon.com, amazon.co.uk or amazon.de. Defaults to amazon.com. | | postal_code | string | No | Delivery postal code used to check local prices and availability. | | limit | integer | No | Maximum results to return, from 1 to 100. Defaults to 100. | | cursor | string | No | Use result.pagination.next_cursor to continue with the same query and filters. | | min_price, max_price | number | No | Price range in the marketplace currency. | | min_rating | integer | No | Minimum star rating: 1, 2, 3 or 4. | | brand, category | string | No | Filter by a single brand or a supported department. Use category_id for a specific browse node. | | sort | string | No | relevance, price_asc, price_desc, rating or newest. | Continue while `result.pagination.next_cursor` is present, even if a filtered page is empty. Keep the query, marketplace, delivery postal code and filters unchanged between requests. You can change the limit. Prices include their currency and a decimal `price_amount`. Product fields are null when Amazon does not expose them. A delivery postal code must be accepted by Amazon for the request to succeed. ## More Amazon endpoints - `/v1/amazon/product/offers`: compare sellers, condition, item price and shipping. - `/v1/amazon/product/variations`: get child ASINs and size, colour or style options. Use `include_details: true` for up to 10 variants’ prices and availability. - `/v1/amazon/products/batch`: fetch up to 10 ASINs, with individual errors for unavailable products. - `/v1/amazon/movers-and-shakers` and `/v1/amazon/new-releases`: discover products by category. Lists may be empty when Amazon has no entries. - `/v1/amazon/seller/products`: browse a seller’s products using its merchant ID. ## Response A synchronous request returns a standard run envelope with Amazon products in `result.results`. ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "amazon-search", "task_name": "Amazon Search", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "count": 1, "results": [ { "name": "Apple AirPods Max - Silver", "link": "https://www.amazon.com/dp/B08N5WRWNW", "price": "$549.00", "images": [ "https://m.media-amazon.com/images/..." ], "rating": 4.6, "numberOfReviews": 12543, "tags": ["Best Seller"] } ] }, "error": null } ``` ### Result Fields `name` - Product title. `link` - Direct product page URL. `price` - Display price string. `images` - Product image URLs. `rating` - Average customer rating. `numberOfReviews` - Review count. `tags` - Visible badges or labels. ## Code Examples ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/search" \n -H "Authorization: Bearer YOUR_API_KEY" \n -H "Content-Type: application/json" \n -d '{"query":"laptop","_run":{"async":false}}' ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "laptop", "_run": {"async": False}, }, ) payload = response.json() print(payload["run_status"]) print(payload["result"]["count"]) for product in payload["result"]["results"][:5]: print(product["name"]) ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json" }, body: JSON.stringify({ query: "laptop", _run: { async: false } }) }); const payload = await response.json(); console.log(payload.run_status); console.log(payload.result.count); payload.result.results.slice(0, 5).forEach((product) => { console.log(product.name); }); ``` ## Try it Out ### API Playground API Key Stored locally only query * Product search query marketplace Amazon marketplace domain limit Maximum products to return (1–100) cursor Continuation cursor from a previous result ## Error Codes 400 Bad Request The JSON body does not match the task input schema. 401 Unauthorized Missing or invalid API key. 403 Forbidden Your account cannot execute the task, usually because of access or credits. 500 Internal Server Error Amazon search failed upstream. --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/amazon/search # Compatibility and supporting endpoints These routes support existing integrations. Use the [catalogue reference](/docs/api.md) to choose a scraping API. All routes below require a Browsable API key and access to the owning team. ## Legacy Instagram requests `POST /v1/instagram/scrape` is a compatibility route. For new integrations, use [Instagram public profile](/docs/api/endpoints/post-instagram-public-profile.md) or [Instagram feed](/docs/api/endpoints/post-instagram-feed.md) . The feed API uses a connected website account. The legacy route accepts either `username` for a public profile, or `sessionId` plus `csrfToken` and optional `userId` for an authenticated feed. It accepts `count` (default 12) and `after`. Supplying both modes, or neither, returns HTTP 400. It uses a legacy response format rather than the standard task run envelope. Keep credentials on your server; migrate to the connected-account API for new work. ## Authentication-flow status `GET /v1/auth/invocations/{id}` requires `website_logins.manage`. Pass an invocation ID from an authentication flow, rather than an account or task ID. It returns an `invocation` object with `id`, `status`, `provider`, `domain`, `platform`, `hosted_url`, `live_view_url`, `expires_at`, `flow_status`, `step`, `failure_code` and `failure_message`. Links and failure fields may be null. A missing or inaccessible invocation returns 404. For account connection setup and cancellation, see [website logins](/docs/api/website-logins.md) , including `/v1/website-logins/invocations/{id}`. ## Integration image assets `POST /v1/integration-assets` requires `tasks.run`. Send PNG, JPEG or WebP bytes with the matching `Content-Type`. The maximum size is 20 MiB, and the file contents must match the declared type. Alternatively send `application/json` with a `url` from an allowed import origin; arbitrary external URLs are not accepted. Invalid images and unavailable imports return HTTP 400 with `error.code` and `error.message`. A successful upload returns HTTP 201 with `assetId`, `mimeType`, `sizeBytes`, `url` and `expiresAt`. Default retention is 30 days; use the returned expiry as authoritative. Assets are private to the team. `GET /v1/integration-assets/{id}` requires `runs.read` and returns the image bytes. Add `?download=1` to request an attachment, or `?format=json` for a signed asset reference. An expired or unavailable asset cannot be loaded; upload a replacement. ## Cancel a supported integration run `POST /v1/runs/{id}/cancel` requires `tasks.run`. Supply the run UUID in the URL; no request body is required. This route supports integration runs with cancellation support. It is not a universal cancel route for every scraper or downloader. Success returns `run_id`, `status`, `run_status` and `cancelled`. Invalid run identities return 400. Missing/inaccessible runs return 404; an unsupported cancellation returns 409. Inspect the returned state rather than assuming the work stopped immediately. --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/compatibility [Airbnb APIs](/docs/api.md#airbnb) # Airbnb calendar Read public calendar availability and exposed stay restrictions. Unavailable does not mean booked; prices are displayed calendar prices, not stay quotes. POST `/v1/airbnb/calendar` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`url` string Required** Public HTTPS Airbnb listing URL. Minimum length: 1. Maximum length: 2000. Format: uri. Pattern: ^https://([a-z0-9-]+\.)?airbnb\.(com|co\.uk|fr|de|es|it|ca|com\.au)/rooms/[0-9]+/?([?].*)?$. - **`currency` string Optional** Three-letter currency code, such as USD. Default: "USD". Pattern: ^[A-Z]{3}$. - **`locale` string Optional** Language code for source content, such as en. Default: "en". - **`months` integer Optional** Number of calendar months to retrieve. Default: 3. Minimum: 1. Maximum: 24. - **`start_month` integer Optional** First calendar month, from 1 (January) to 12 (December); defaults to the current month. Minimum: 1. Maximum: 12. - **`start_year` integer Optional** First calendar year to retrieve; defaults to the current year. Minimum: 2000. Maximum: 2100. ## 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", "required": [ "success", "fetched_at", "listing_id", "listing_url", "currency", "months", "request", "availability_note" ], "properties": { "months": { "type": "array", "items": { "type": "object", "required": [ "month", "year", "days" ], "properties": { "days": { "type": "array", "items": { "type": "object", "required": [ "date", "available", "available_for_checkin", "available_for_checkout", "bookable", "min_nights", "max_nights", "local_price" ], "properties": { "date": { "type": "string", "format": "date" }, "bookable": { "type": [ "boolean", "null" ] }, "available": { "type": [ "boolean", "null" ] }, "max_nights": { "type": [ "number", "null" ] }, "min_nights": { "type": [ "number", "null" ] }, "local_price": { "type": [ "string", "null" ] }, "available_for_checkin": { "type": [ "boolean", "null" ] }, "available_for_checkout": { "type": [ "boolean", "null" ] } }, "additionalProperties": false } }, "year": { "type": "integer" }, "month": { "type": "integer" } }, "additionalProperties": false } }, "request": { "type": "object", "required": [ "months", "start_month", "start_year" ], "properties": { "months": { "type": "integer" }, "start_year": { "type": "integer" }, "start_month": { "type": "integer" } }, "additionalProperties": false }, "success": { "type": "boolean", "const": true }, "currency": { "type": "string" }, "fetched_at": { "type": "string", "format": "date-time" }, "listing_id": { "type": "string" }, "listing_url": { "type": "string" }, "availability_note": { "type": "string" } }, "additionalProperties": false } ``` ### View a polled run response ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "airbnb-calendar", "task_name": "Airbnb calendar", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "months": [ { "days": [ { "date": "sample", "bookable": true, "available": true, "max_nights": 1.5, "min_nights": 1.5, "local_price": "180", "available_for_checkin": true, "available_for_checkout": true } ], "year": 1, "month": 1 } ], "request": { "months": 1, "start_year": 1, "start_month": 1 }, "success": true, "currency": "USD", "fetched_at": "sample", "listing_id": "id-1", "listing_url": "https://example.com/item-1", "availability_note": "sample" }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/airbnb/calendar" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.airbnb.com/rooms/21944286"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/airbnb/calendar", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.airbnb.com/rooms/21944286" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/airbnb/calendar", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.airbnb.com/rooms/21944286" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/airbnb/calendar" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.airbnb.com/rooms/21944286","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/airbnb/calendar", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.airbnb.com/rooms/21944286", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/airbnb/calendar", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.airbnb.com/rooms/21944286", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/airbnb-calendar/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/airbnb/calendar" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.airbnb.com/rooms/21944286","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/airbnb/calendar", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.airbnb.com/rooms/21944286", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/airbnb/calendar", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.airbnb.com/rooms/21944286", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "airbnb-calendar", "task_name": "Airbnb calendar", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "months": [ { "days": [ { "date": "sample", "bookable": true, "available": true, "max_nights": 1.5, "min_nights": 1.5, "local_price": "180", "available_for_checkin": true, "available_for_checkout": true } ], "year": 1, "month": 1 } ], "request": { "months": 1, "start_year": 1, "start_month": 1 }, "success": true, "currency": "USD", "fetched_at": "sample", "listing_id": "id-1", "listing_url": "https://example.com/item-1", "availability_note": "sample" }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-airbnb-calendar [Airbnb APIs](/docs/api.md#airbnb) # Airbnb host listings Read publicly exposed stays on an Airbnb host profile, with explicit pagination and completeness. Does not infer hidden listings. POST `/v1/airbnb/host/listings` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`url` string Required** Public Airbnb host profile URL. Minimum length: 1. Maximum length: 2000. Format: uri. Pattern: ^https://([a-z0-9-]+\.)?airbnb\.(com|co\.uk|fr|de|es|it|ca|com\.au)/users/(show|profile)/[^/?#]+/?([?].*)?$. - **`limit` integer Optional** Maximum results in this response. Default: 20. Minimum: 1. Maximum: 50. - **`currency` string Optional** Three-letter currency code, such as USD. Default: "USD". Pattern: ^[A-Z]{3}$. - **`locale` string Optional** Language code for source content, such as en. Default: "en". - **`offset` integer Optional** Number of results to skip. Start at 0. Default: 0. Minimum: 0. Maximum: 10000. ## 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", "required": [ "success", "fetched_at", "host_id", "profile_url", "listings", "pagination", "completeness" ], "properties": { "host_id": { "type": "string" }, "success": { "type": "boolean", "const": true }, "listings": { "type": "array", "items": { "type": "object", "required": [ "listing_id", "url", "title", "picture_url", "room_type" ], "properties": { "url": { "type": "string" }, "title": { "type": [ "string", "null" ] }, "room_type": { "type": [ "string", "null" ] }, "listing_id": { "type": "string" }, "picture_url": { "type": [ "string", "null" ] } }, "additionalProperties": false } }, "fetched_at": { "type": "string", "format": "date-time" }, "pagination": { "type": "object", "required": [ "total_count", "offset", "limit", "has_more", "next_offset" ], "properties": { "limit": { "type": "integer" }, "offset": { "type": "integer" }, "has_more": { "type": "boolean" }, "next_offset": { "type": [ "integer", "null" ] }, "total_count": { "type": [ "number", "null" ] } }, "additionalProperties": false }, "profile_url": { "type": "string" }, "completeness": { "type": "object", "required": [ "status", "reason" ], "properties": { "reason": { "type": [ "string", "null" ] }, "status": { "enum": [ "complete", "partial", "unknown" ], "type": "string" } }, "additionalProperties": false }, "host_id_type": { "enum": [ "legacy", "contextual" ], "type": "string" } }, "additionalProperties": false } ``` ### View a polled run response ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "airbnb-host-listings", "task_name": "Airbnb host listings", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "host_id": "id-1", "success": true, "listings": [ { "url": "https://example.com/item-1", "title": "Stylish Shoreditch Loft with Balcony", "room_type": "sample", "listing_id": "id-1", "picture_url": "https://example.com/item-1" } ], "fetched_at": "sample", "pagination": { "limit": 1, "offset": 1, "has_more": true, "next_offset": 1, "total_count": 1 }, "profile_url": "https://example.com/item-1", "completeness": { "reason": "sample", "status": "complete" }, "host_id_type": "legacy" }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/airbnb/host/listings" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.airbnb.com/users/show/123456"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/airbnb/host/listings", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.airbnb.com/users/show/123456" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/airbnb/host/listings", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.airbnb.com/users/show/123456" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/airbnb/host/listings" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.airbnb.com/users/show/123456","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/airbnb/host/listings", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.airbnb.com/users/show/123456", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/airbnb/host/listings", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.airbnb.com/users/show/123456", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/airbnb-host-listings/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/airbnb/host/listings" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.airbnb.com/users/show/123456","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/airbnb/host/listings", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.airbnb.com/users/show/123456", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/airbnb/host/listings", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.airbnb.com/users/show/123456", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "airbnb-host-listings", "task_name": "Airbnb host listings", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "host_id": "id-1", "success": true, "listings": [ { "url": "https://example.com/item-1", "title": "Stylish Shoreditch Loft with Balcony", "room_type": "sample", "listing_id": "id-1", "picture_url": "https://example.com/item-1" } ], "fetched_at": "sample", "pagination": { "limit": 1, "offset": 1, "has_more": true, "next_offset": 1, "total_count": 1 }, "profile_url": "https://example.com/item-1", "completeness": { "reason": "sample", "status": "complete" }, "host_id_type": "legacy" }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-airbnb-host-listings [Airbnb APIs](/docs/api.md#airbnb) # Airbnb host Read a public Airbnb host profile. Only publicly exposed attributes are returned; unknown fields remain null. POST `/v1/airbnb/host` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`url` string Required** Public Airbnb host profile URL. Minimum length: 1. Maximum length: 2000. Format: uri. Pattern: ^https://([a-z0-9-]+\.)?airbnb\.(com|co\.uk|fr|de|es|it|ca|com\.au)/users/(show|profile)/[^/?#]+/?([?].*)?$. - **`currency` string Optional** Three-letter currency code, such as USD. Default: "USD". Pattern: ^[A-Z]{3}$. - **`locale` string Optional** Language code for source content, such as en. Default: "en". ## 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", "required": [ "success", "fetched_at", "host_id", "profile_url", "profile" ], "properties": { "host_id": { "type": "string" }, "profile": { "type": "object", "required": [ "name", "about", "picture_url", "is_superhost", "hosting_years", "review_count", "rating", "details" ], "properties": { "name": { "type": [ "string", "null" ] }, "about": { "type": [ "string", "null" ] }, "rating": { "type": [ "number", "null" ] }, "details": { "type": "array", "items": { "type": "object", "required": [ "label", "value" ], "properties": { "label": { "type": [ "string", "null" ] }, "value": { "type": [ "string", "null" ] } }, "additionalProperties": false } }, "picture_url": { "type": [ "string", "null" ] }, "is_superhost": { "type": [ "boolean", "null" ] }, "review_count": { "type": [ "number", "null" ] }, "hosting_years": { "type": [ "number", "null" ] } }, "additionalProperties": false }, "success": { "type": "boolean", "const": true }, "fetched_at": { "type": "string", "format": "date-time" }, "profile_url": { "type": "string" }, "host_id_type": { "enum": [ "legacy", "contextual" ], "type": "string" } }, "additionalProperties": false } ``` ### View a polled run response ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "airbnb-host", "task_name": "Airbnb host", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "host_id": "id-1", "profile": { "name": "Stylish Shoreditch Loft with Balcony", "about": "sample", "rating": 4.91, "details": [ { "label": "Stylish Shoreditch Loft with Balcony", "value": "180" } ], "picture_url": "https://example.com/item-1", "is_superhost": true, "review_count": 1, "hosting_years": 1.5 }, "success": true, "fetched_at": "sample", "profile_url": "https://example.com/item-1", "host_id_type": "legacy" }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/airbnb/host" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.airbnb.com/users/show/123456"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/airbnb/host", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.airbnb.com/users/show/123456" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/airbnb/host", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.airbnb.com/users/show/123456" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/airbnb/host" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.airbnb.com/users/show/123456","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/airbnb/host", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.airbnb.com/users/show/123456", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/airbnb/host", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.airbnb.com/users/show/123456", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/airbnb-host/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/airbnb/host" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.airbnb.com/users/show/123456","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/airbnb/host", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.airbnb.com/users/show/123456", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/airbnb/host", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.airbnb.com/users/show/123456", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "airbnb-host", "task_name": "Airbnb host", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "host_id": "id-1", "profile": { "name": "Stylish Shoreditch Loft with Balcony", "about": "sample", "rating": 4.91, "details": [ { "label": "Stylish Shoreditch Loft with Balcony", "value": "180" } ], "picture_url": "https://example.com/item-1", "is_superhost": true, "review_count": 1, "hosting_years": 1.5 }, "success": true, "fetched_at": "sample", "profile_url": "https://example.com/item-1", "host_id_type": "legacy" }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-airbnb-host [Airbnb APIs](/docs/api.md#airbnb) # Airbnb reviews Read paginated public listing reviews, rating summary and host responses. Missing upstream review data fails explicitly. POST `/v1/airbnb/reviews` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`url` string Required** Public HTTPS Airbnb listing URL. Minimum length: 1. Maximum length: 2000. Format: uri. Pattern: ^https://([a-z0-9-]+\.)?airbnb\.(com|co\.uk|fr|de|es|it|ca|com\.au)/rooms/[0-9]+/?([?].*)?$. - **`limit` integer Optional** Maximum results in this response. Default: 24. Minimum: 1. Maximum: 100. - **`currency` string Optional** Three-letter currency code, such as USD. Default: "USD". Pattern: ^[A-Z]{3}$. - **`locale` string Optional** Language code for source content, such as en. Default: "en". - **`offset` integer Optional** Number of results to skip. Start at 0. Default: 0. Minimum: 0. Maximum: 10000. - **`sort` string Optional** Sort order. Choose an allowed value below. Default: "most_recent". Allowed: "most_recent", "most_relevant", "highest_rated", "lowest_rated". - **`tag` string Optional** Optional review category tag. ## 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", "required": [ "success", "fetched_at", "listing_id", "listing_url", "summary", "reviews", "pagination", "request" ], "properties": { "request": { "type": "object", "required": [ "limit", "offset", "sort", "tag_name", "tag_label" ], "properties": { "sort": { "type": "string" }, "limit": { "type": "integer" }, "offset": { "type": "integer" }, "tag_name": { "type": [ "string", "null" ] }, "tag_label": { "type": [ "string", "null" ] } }, "additionalProperties": false }, "reviews": { "type": "array", "items": { "type": "object", "required": [ "id", "highlight_mentions", "review_photo_urls" ], "properties": { "id": { "type": "string" }, "rating": { "type": [ "number", "null" ] }, "comments": { "type": [ "string", "null" ] }, "language": { "type": [ "string", "null" ] }, "response": { "type": [ "string", "null" ] }, "reviewee": { "type": "object", "required": [], "properties": { "name": { "type": [ "string", "null" ] }, "picture_url": { "type": [ "string", "null" ] }, "profile_url": { "type": [ "string", "null" ] } }, "additionalProperties": false }, "reviewer": { "type": "object", "required": [], "properties": { "name": { "type": [ "string", "null" ] }, "picture_url": { "type": [ "string", "null" ] }, "profile_url": { "type": [ "string", "null" ] } }, "additionalProperties": false }, "created_at": { "type": [ "string", "null" ] }, "highlight_type": { "type": [ "string", "null" ] }, "localized_date": { "type": [ "string", "null" ] }, "review_photo_urls": { "type": "array", "items": { "type": "string" } }, "reviewer_location": { "type": [ "string", "null" ] }, "highlight_mentions": { "type": "array", "items": { "type": "string" } }, "localized_responded_date": { "type": [ "string", "null" ] } }, "additionalProperties": false } }, "success": { "type": "boolean", "const": true }, "summary": { "type": "object", "required": [ "overall_rating", "overall_count", "heading_title", "heading_subtitle_html", "heading_subtitle_text", "categories", "rating_distribution", "available_tags", "available_sorts" ], "properties": { "categories": { "type": "array", "items": { "type": "object", "required": [], "properties": { "type": { "type": [ "string", "null" ] }, "label": { "type": [ "string", "null" ] }, "rating": { "type": [ "number", "null" ] }, "formatted_rating": { "type": [ "string", "null" ] } }, "additionalProperties": false } }, "heading_title": { "type": [ "string", "null" ] }, "overall_count": { "type": [ "number", "null" ] }, "available_tags": { "type": "array", "items": { "type": "object", "required": [ "name" ], "properties": { "name": { "type": "string" }, "count": { "type": [ "number", "null" ] }, "label": { "type": [ "string", "null" ] }, "icon_url": { "type": [ "string", "null" ] } }, "additionalProperties": false } }, "overall_rating": { "type": [ "number", "null" ] }, "available_sorts": { "type": "array", "items": { "type": "object", "required": [ "value" ], "properties": { "title": { "type": [ "string", "null" ] }, "value": { "type": "string" } }, "additionalProperties": false } }, "rating_distribution": { "type": "array", "items": { "type": "object", "required": [], "properties": { "label": { "type": [ "string", "null" ] }, "percentage": { "type": [ "number", "null" ] }, "formatted_percentage": { "type": [ "string", "null" ] } }, "additionalProperties": false } }, "heading_subtitle_html": { "type": [ "string", "null" ] }, "heading_subtitle_text": { "type": [ "string", "null" ] } }, "additionalProperties": false }, "fetched_at": { "type": "string", "format": "date-time" }, "listing_id": { "type": "string" }, "pagination": { "type": "object", "required": [ "total_count", "offset", "limit", "has_more", "next_offset" ], "properties": { "limit": { "type": "integer" }, "offset": { "type": "integer" }, "has_more": { "type": "boolean" }, "next_offset": { "type": [ "integer", "null" ] }, "total_count": { "type": [ "number", "null" ] } }, "additionalProperties": false }, "listing_url": { "type": "string" } }, "additionalProperties": false } ``` ### View a polled run response ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "airbnb-reviews", "task_name": "Airbnb reviews", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "request": { "sort": "sample", "limit": 1, "offset": 1, "tag_name": "Stylish Shoreditch Loft with Balcony", "tag_label": "Stylish Shoreditch Loft with Balcony" }, "reviews": [ { "id": "id-1", "rating": 4.91, "comments": "sample", "language": "sample", "response": "sample", "reviewee": { "name": "Stylish Shoreditch Loft with Balcony", "picture_url": "https://example.com/item-1", "profile_url": "https://example.com/item-1" }, "reviewer": { "name": "Stylish Shoreditch Loft with Balcony", "picture_url": "https://example.com/item-1", "profile_url": "https://example.com/item-1" }, "created_at": "2026-06-14T15:30:00Z", "highlight_type": "sample", "localized_date": "sample", "review_photo_urls": [ "https://images.example.com/review_photo_urls-1.jpg" ], "reviewer_location": "London", "highlight_mentions": [ "sample" ], "localized_responded_date": "sample" } ], "success": true, "summary": { "categories": [ { "type": "sample", "label": "Stylish Shoreditch Loft with Balcony", "rating": 4.91, "formatted_rating": "sample" } ], "heading_title": "Stylish Shoreditch Loft with Balcony", "overall_count": 1, "available_tags": [ { "name": "Stylish Shoreditch Loft with Balcony", "count": 1, "label": "Stylish Shoreditch Loft with Balcony", "icon_url": "https://images.example.com/icon_url-1.jpg" } ], "overall_rating": 4.91, "available_sorts": [ { "title": "Stylish Shoreditch Loft with Balcony", "value": "180" } ], "rating_distribution": [ { "label": "Stylish Shoreditch Loft with Balcony", "percentage": 1.5, "formatted_percentage": "Featured" } ], "heading_subtitle_html": "Stylish Shoreditch Loft with Balcony", "heading_subtitle_text": "Stylish Shoreditch Loft with Balcony" }, "fetched_at": "sample", "listing_id": "id-1", "pagination": { "limit": 1, "offset": 1, "has_more": true, "next_offset": 1, "total_count": 1 }, "listing_url": "https://example.com/item-1" }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/airbnb/reviews" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.airbnb.com/rooms/21944286"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/airbnb/reviews", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.airbnb.com/rooms/21944286" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/airbnb/reviews", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.airbnb.com/rooms/21944286" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/airbnb/reviews" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.airbnb.com/rooms/21944286","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/airbnb/reviews", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.airbnb.com/rooms/21944286", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/airbnb/reviews", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.airbnb.com/rooms/21944286", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/airbnb-reviews/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/airbnb/reviews" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.airbnb.com/rooms/21944286","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/airbnb/reviews", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.airbnb.com/rooms/21944286", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/airbnb/reviews", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.airbnb.com/rooms/21944286", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "airbnb-reviews", "task_name": "Airbnb reviews", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "request": { "sort": "sample", "limit": 1, "offset": 1, "tag_name": "Stylish Shoreditch Loft with Balcony", "tag_label": "Stylish Shoreditch Loft with Balcony" }, "reviews": [ { "id": "id-1", "rating": 4.91, "comments": "sample", "language": "sample", "response": "sample", "reviewee": { "name": "Stylish Shoreditch Loft with Balcony", "picture_url": "https://example.com/item-1", "profile_url": "https://example.com/item-1" }, "reviewer": { "name": "Stylish Shoreditch Loft with Balcony", "picture_url": "https://example.com/item-1", "profile_url": "https://example.com/item-1" }, "created_at": "2026-06-14T15:30:00Z", "highlight_type": "sample", "localized_date": "sample", "review_photo_urls": [ "https://images.example.com/review_photo_urls-1.jpg" ], "reviewer_location": "London", "highlight_mentions": [ "sample" ], "localized_responded_date": "sample" } ], "success": true, "summary": { "categories": [ { "type": "sample", "label": "Stylish Shoreditch Loft with Balcony", "rating": 4.91, "formatted_rating": "sample" } ], "heading_title": "Stylish Shoreditch Loft with Balcony", "overall_count": 1, "available_tags": [ { "name": "Stylish Shoreditch Loft with Balcony", "count": 1, "label": "Stylish Shoreditch Loft with Balcony", "icon_url": "https://images.example.com/icon_url-1.jpg" } ], "overall_rating": 4.91, "available_sorts": [ { "title": "Stylish Shoreditch Loft with Balcony", "value": "180" } ], "rating_distribution": [ { "label": "Stylish Shoreditch Loft with Balcony", "percentage": 1.5, "formatted_percentage": "Featured" } ], "heading_subtitle_html": "Stylish Shoreditch Loft with Balcony", "heading_subtitle_text": "Stylish Shoreditch Loft with Balcony" }, "fetched_at": "sample", "listing_id": "id-1", "pagination": { "limit": 1, "offset": 1, "has_more": true, "next_offset": 1, "total_count": 1 }, "listing_url": "https://example.com/item-1" }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-airbnb-reviews [Airbnb APIs](/docs/api.md#airbnb) # Airbnb room Fetch an Airbnb room/listing page and return normalized details, photos, host info, amenities, reviews, policies, and availability. POST `/v1/airbnb/room` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`url` string Required** Full Airbnb room URL. Minimum length: 1. Maximum length: 2000. - **`adults` integer Optional** Number of adult guests or travellers. Minimum: 1. Maximum: 16. - **`checkin` string Optional** Check-in date. Overrides check_in in the URL; supply with checkout. Format: date. - **`checkout` string Optional** Check-out date. Overrides check_out in the URL. Format: date. - **`children` integer Optional** Number of child guests. Minimum: 0. Maximum: 16. - **`currency` string Optional** Display currency; defaults to URL currency or site default. Pattern: ^[A-Z]{3}$. - **`include_quote` boolean Optional** Fetch a read-only tax-inclusive quote and full attributes for the room identified by the URL. Requires dates. Does not book. - **`infants` integer Optional** Number of infant guests. Minimum: 0. Maximum: 16. - **`pets` integer Optional** Number of pets. Minimum: 0. Maximum: 16. ### Advanced & compatibility inputs 1 - **`rate_plan_id` string Optional** Optional rate plan from hotel.offers; used with include_quote. Pattern: ^[0-9]+$. ## 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", "listing_id", "listing_url", "locale", "currency", "requested_stay", "review_request", "calendar_request", "photos", "reviews" ], "properties": { "host": { "anyOf": [ { "type": "object" }, { "type": "null" } ] }, "hotel": { "type": "object", "properties": { "title": { "type": [ "string", "null" ] }, "offers": { "type": "array", "items": { "type": "object", "properties": { "room_id": { "type": [ "string", "null" ] }, "capacity": { "type": [ "number", "null" ] }, "currency": { "type": [ "string", "null" ] }, "room_url": { "type": [ "string", "null" ] }, "available": { "type": [ "boolean", "null" ] }, "breakdown": { "type": "array", "items": { "type": "object", "properties": { "label": { "type": [ "string", "null" ] }, "amount": { "type": [ "number", "null" ] }, "display_price": { "type": [ "string", "null" ] } }, "additionalProperties": true } }, "room_name": { "type": [ "string", "null" ] }, "attributes": { "type": "array", "items": { "type": "string" } }, "rate_plans": { "type": "array", "items": { "type": "object", "properties": { "add_ons": { "type": "array", "items": {} }, "selected": { "type": "boolean" }, "refundable": { "type": [ "boolean", "null" ] }, "cancellation": { "type": [ "string", "null" ] }, "rate_plan_id": { "type": [ "string", "null" ] }, "price_adjustment": { "type": [ "number", "null" ] }, "cancellation_details": { "type": [ "string", "null" ] }, "price_adjustment_type": { "type": [ "string", "null" ] } }, "additionalProperties": true } }, "tax_status": { "type": [ "string", "null" ] }, "disclaimers": { "type": "array", "items": { "type": "string" } }, "price_basis": { "type": [ "string", "null" ] }, "credit_offer": { "type": [ "string", "null" ] }, "display_price": { "type": [ "string", "null" ] }, "selected_dates": { "type": [ "string", "null" ] }, "displayed_total": { "type": [ "number", "null" ] }, "price_qualifier": { "type": [ "string", "null" ] }, "selected_rate_plan_id": { "type": [ "string", "null" ] }, "total_including_taxes": { "type": [ "number", "null" ] } }, "additionalProperties": true } }, "address": { "type": [ "string", "null" ] }, "coverage": { "type": [ "string", "null" ] }, "returned_rooms": { "type": [ "number", "null" ] }, "advertised_rooms": { "type": [ "number", "null" ] } }, "additionalProperties": true }, "title": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "locale": { "type": "string" }, "photos": { "type": "object" }, "pricing": { "anyOf": [ { "type": "object" }, { "type": "null" } ] }, "reviews": { "type": "object" }, "success": { "type": "boolean" }, "calendar": { "anyOf": [ { "type": "object" }, { "type": "null" } ] }, "currency": { "type": "string" }, "location": { "anyOf": [ { "type": "object" }, { "type": "null" } ] }, "overview": { "type": "object" }, "policies": { "anyOf": [ { "type": "object" }, { "type": "null" } ] }, "amenities": { "type": "object" }, "share_url": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "highlights": { "type": "array", "items": { "type": "object", "properties": { "icon": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "type": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "title": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "subtitle": { "anyOf": [ { "type": "string" }, { "type": "null" } ] } }, "additionalProperties": false } }, "listing_id": { "type": "string" }, "description": { "type": "object" }, "hotel_quote": { "type": "object", "properties": { "reason": { "type": [ "string", "null" ] }, "source": { "type": [ "string", "null" ] }, "currency": { "type": [ "string", "null" ] }, "available": { "type": "boolean" }, "meal_plan": { "type": "object", "properties": { "evidence": { "type": [ "string", "null" ] }, "rate_add_ons": { "type": "array", "items": {} }, "breakfast_included": { "type": [ "boolean", "null" ] } }, "additionalProperties": true }, "room_name": { "type": [ "string", "null" ] }, "hotel_name": { "type": [ "string", "null" ] }, "observed_at": { "type": [ "string", "null" ] }, "price_items": { "type": "array", "items": { "type": "object", "properties": { "type": { "type": [ "string", "null" ] }, "label": { "type": [ "string", "null" ] }, "amount": { "type": [ "number", "null" ] }, "details": { "type": "array", "items": { "type": "object" } }, "display": { "type": [ "string", "null" ] }, "currency": { "type": [ "string", "null" ] } }, "additionalProperties": true } }, "cancellation": { "type": [ "string", "null" ] }, "rate_plan_id": { "type": [ "string", "null" ] }, "room_details": { "type": "object", "properties": { "amenities": { "type": "array", "items": { "type": "object", "properties": { "title": { "type": [ "string", "null" ] }, "subtitle": { "type": [ "string", "null" ] } }, "additionalProperties": true } }, "attributes": { "type": "array", "items": { "type": "string" } }, "photo_urls": { "type": "array", "items": { "type": "string" } }, "description": { "type": [ "string", "null" ] } }, "additionalProperties": true }, "source_total": { "type": [ "number", "null" ] }, "tax_evidence": { "type": [ "string", "null" ] }, "observed_stay": { "type": "object", "properties": { "pets": { "type": [ "number", "null" ] }, "adults": { "type": [ "number", "null" ] }, "checkin": { "type": [ "string", "null" ] }, "infants": { "type": [ "number", "null" ] }, "room_id": { "type": [ "string", "null" ] }, "checkout": { "type": [ "string", "null" ] }, "children": { "type": [ "number", "null" ] } }, "additionalProperties": true }, "stay_verified": { "type": "boolean" }, "quote_complete": { "type": "boolean" }, "rate_selection": { "type": [ "string", "null" ] }, "payment_options": { "type": "array", "items": { "type": "object", "properties": { "type": { "type": [ "string", "null" ] }, "title": { "type": [ "string", "null" ] }, "subtitle": { "type": [ "string", "null" ] }, "disclaimer": { "type": [ "string", "null" ] } }, "additionalProperties": true } }, "amounts_reconcile": { "type": "boolean" }, "rate_plan_verified": { "type": "boolean" }, "total_including_taxes": { "type": [ "number", "null" ] }, "cancellation_milestones": { "type": "array", "items": { "type": "object" } } }, "additionalProperties": true }, "listing_url": { "type": "string" }, "canonical_url": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "property_type": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "summary_title": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "requested_stay": { "type": "object" }, "review_request": { "type": "object" }, "person_capacity": { "anyOf": [ { "type": "number" }, { "type": "null" } ] }, "calendar_request": { "type": "object" }, "location_summary": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "sleeping_arrangements": { "type": "array", "items": { "type": "object", "properties": { "title": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "images": { "type": "array", "items": { "type": "object", "required": [ "url" ], "properties": { "id": { "type": "string" }, "url": { "type": "string" }, "caption": { "anyOf": [ { "type": "string" }, { "type": "null" } ] } }, "additionalProperties": false } }, "subtitle": { "anyOf": [ { "type": "string" }, { "type": "null" } ] } }, "additionalProperties": false } } }, "additionalProperties": true } ``` ### View a polled run response ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "airbnb-room", "task_name": "Airbnb room", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "host": {}, "hotel": { "title": "Stylish Shoreditch Loft with Balcony", "offers": [ { "room_id": "id-1", "capacity": 1.5, "currency": "USD", "room_url": "https://example.com/item-1", "available": true, "breakdown": [ { "label": "Stylish Shoreditch Loft with Balcony", "amount": 180, "display_price": "GBP 210 total" } ], "room_name": "Stylish Shoreditch Loft with Balcony", "attributes": [ "sample" ], "rate_plans": [ { "add_ons": [ "sample" ], "selected": true, "refundable": true, "cancellation": "sample", "rate_plan_id": "id-1", "price_adjustment": 180, "cancellation_details": "2 guests", "price_adjustment_type": "180" } ], "tax_status": "sample", "disclaimers": [ "sample" ], "price_basis": "180", "credit_offer": "sample", "display_price": "GBP 210 total", "selected_dates": "sample", "displayed_total": 180, "price_qualifier": "for 1 night", "selected_rate_plan_id": "id-1", "total_including_taxes": 180 } ], "address": "sample", "coverage": "sample", "returned_rooms": 1.5, "advertised_rooms": 1.5 }, "title": "Stylish Shoreditch Loft with Balcony", "locale": "sample", "photos": {}, "pricing": {}, "reviews": {}, "success": true, "calendar": {}, "currency": "USD", "location": {}, "overview": {}, "policies": {}, "amenities": {}, "share_url": "https://example.com/item-1", "highlights": [ { "icon": "https://images.example.com/icon-1.jpg", "type": "sample", "title": "Stylish Shoreditch Loft with Balcony", "subtitle": "Stylish Shoreditch Loft with Balcony" } ], "listing_id": "id-1", "description": {}, "hotel_quote": { "reason": "sample", "source": "sample", "currency": "USD", "available": true, "meal_plan": { "evidence": "id-1", "rate_add_ons": [ "sample" ], "breakfast_included": true }, "room_name": "Stylish Shoreditch Loft with Balcony", "hotel_name": "Stylish Shoreditch Loft with Balcony", "observed_at": "sample", "price_items": [ { "type": "sample", "label": "Stylish Shoreditch Loft with Balcony", "amount": 180, "details": [ {} ], "display": "sample", "currency": "USD" } ], "cancellation": "sample", "rate_plan_id": "id-1", "room_details": { "amenities": [ { "title": "Stylish Shoreditch Loft with Balcony", "subtitle": "Stylish Shoreditch Loft with Balcony" } ], "attributes": [ "sample" ], "photo_urls": [ "https://images.example.com/photo_urls-1.jpg" ], "description": "Sample description 1" }, "source_total": 180, "tax_evidence": "id-1", "observed_stay": { "pets": 1.5, "adults": 1, "checkin": "2026-06-14", "infants": 1.5, "room_id": "id-1", "checkout": "2026-06-21", "children": 1 }, "stay_verified": true, "quote_complete": true, "rate_selection": "sample", "payment_options": [ { "type": "sample", "title": "Stylish Shoreditch Loft with Balcony", "subtitle": "Stylish Shoreditch Loft with Balcony", "disclaimer": "sample" } ], "amounts_reconcile": true, "rate_plan_verified": true, "total_including_taxes": 180, "cancellation_milestones": [ {} ] }, "listing_url": "https://example.com/item-1", "canonical_url": "https://example.com/item-1", "property_type": "sample", "summary_title": "Stylish Shoreditch Loft with Balcony", "requested_stay": {}, "review_request": {}, "person_capacity": 1.5, "calendar_request": {}, "location_summary": "Sample location_summary 1", "sleeping_arrangements": [ { "title": "Stylish Shoreditch Loft with Balcony", "images": [ { "id": "id-1", "url": "https://example.com/item-1", "caption": "sample" } ], "subtitle": "Stylish Shoreditch Loft with Balcony" } ] }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/airbnb/room" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.airbnb.com/rooms/21944286"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/airbnb/room", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.airbnb.com/rooms/21944286" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/airbnb/room", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.airbnb.com/rooms/21944286" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/airbnb/room" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.airbnb.com/rooms/21944286","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/airbnb/room", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.airbnb.com/rooms/21944286", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/airbnb/room", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.airbnb.com/rooms/21944286", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/airbnb-room/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/airbnb/room" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.airbnb.com/rooms/21944286","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/airbnb/room", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.airbnb.com/rooms/21944286", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/airbnb/room", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.airbnb.com/rooms/21944286", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "airbnb-room", "task_name": "Airbnb room", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "host": {}, "hotel": { "title": "Stylish Shoreditch Loft with Balcony", "offers": [ { "room_id": "id-1", "capacity": 1.5, "currency": "USD", "room_url": "https://example.com/item-1", "available": true, "breakdown": [ { "label": "Stylish Shoreditch Loft with Balcony", "amount": 180, "display_price": "GBP 210 total" } ], "room_name": "Stylish Shoreditch Loft with Balcony", "attributes": [ "sample" ], "rate_plans": [ { "add_ons": [ "sample" ], "selected": true, "refundable": true, "cancellation": "sample", "rate_plan_id": "id-1", "price_adjustment": 180, "cancellation_details": "2 guests", "price_adjustment_type": "180" } ], "tax_status": "sample", "disclaimers": [ "sample" ], "price_basis": "180", "credit_offer": "sample", "display_price": "GBP 210 total", "selected_dates": "sample", "displayed_total": 180, "price_qualifier": "for 1 night", "selected_rate_plan_id": "id-1", "total_including_taxes": 180 } ], "address": "sample", "coverage": "sample", "returned_rooms": 1.5, "advertised_rooms": 1.5 }, "title": "Stylish Shoreditch Loft with Balcony", "locale": "sample", "photos": {}, "pricing": {}, "reviews": {}, "success": true, "calendar": {}, "currency": "USD", "location": {}, "overview": {}, "policies": {}, "amenities": {}, "share_url": "https://example.com/item-1", "highlights": [ { "icon": "https://images.example.com/icon-1.jpg", "type": "sample", "title": "Stylish Shoreditch Loft with Balcony", "subtitle": "Stylish Shoreditch Loft with Balcony" } ], "listing_id": "id-1", "description": {}, "hotel_quote": { "reason": "sample", "source": "sample", "currency": "USD", "available": true, "meal_plan": { "evidence": "id-1", "rate_add_ons": [ "sample" ], "breakfast_included": true }, "room_name": "Stylish Shoreditch Loft with Balcony", "hotel_name": "Stylish Shoreditch Loft with Balcony", "observed_at": "sample", "price_items": [ { "type": "sample", "label": "Stylish Shoreditch Loft with Balcony", "amount": 180, "details": [ {} ], "display": "sample", "currency": "USD" } ], "cancellation": "sample", "rate_plan_id": "id-1", "room_details": { "amenities": [ { "title": "Stylish Shoreditch Loft with Balcony", "subtitle": "Stylish Shoreditch Loft with Balcony" } ], "attributes": [ "sample" ], "photo_urls": [ "https://images.example.com/photo_urls-1.jpg" ], "description": "Sample description 1" }, "source_total": 180, "tax_evidence": "id-1", "observed_stay": { "pets": 1.5, "adults": 1, "checkin": "2026-06-14", "infants": 1.5, "room_id": "id-1", "checkout": "2026-06-21", "children": 1 }, "stay_verified": true, "quote_complete": true, "rate_selection": "sample", "payment_options": [ { "type": "sample", "title": "Stylish Shoreditch Loft with Balcony", "subtitle": "Stylish Shoreditch Loft with Balcony", "disclaimer": "sample" } ], "amounts_reconcile": true, "rate_plan_verified": true, "total_including_taxes": 180, "cancellation_milestones": [ {} ] }, "listing_url": "https://example.com/item-1", "canonical_url": "https://example.com/item-1", "property_type": "sample", "summary_title": "Stylish Shoreditch Loft with Balcony", "requested_stay": {}, "review_request": {}, "person_capacity": 1.5, "calendar_request": {}, "location_summary": "Sample location_summary 1", "sleeping_arrangements": [ { "title": "Stylish Shoreditch Loft with Balcony", "images": [ { "id": "id-1", "url": "https://example.com/item-1", "caption": "sample" } ], "subtitle": "Stylish Shoreditch Loft with Balcony" } ] }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-airbnb-room [Airbnb APIs](/docs/api.md#airbnb) # Airbnb search Search Airbnb stay results for a destination/date combination and return normalized listings with cursor pagination. POST `/v1/airbnb/search` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`query` string Required** Airbnb destination query, such as a city or neighborhood name. Minimum length: 1. Maximum length: 2000. - **`checkin` string Required** Check-in date in YYYY-MM-DD format. Pattern: ^\d{4}-\d{2}-\d{2}$. - **`checkout` string Required** Check-out date in YYYY-MM-DD format. Pattern: ^\d{4}-\d{2}-\d{2}$. - **`accessibility_features` string | array Optional** Accessibility feature labels from Airbnb such as "Step-free access" or "Disabled parking spot". Accepts a comma-separated string or an array. - **`adults` integer Optional** Number of adult guests. Default: 1. Minimum: 1. Maximum: 16. - **`amenities` string | array Optional** Amenity labels from Airbnb such as "Wifi", "Kitchen", or "Free parking". Raw Airbnb amenity IDs are also accepted. - **`bathroom_privacy` string | array Optional** Bathroom privacy labels or raw values such as "Private attached bathroom" or "ENSUITE". Accepts a comma-separated string or an array. - **`bathrooms` string | number Optional** Minimum number of bathrooms. - **`bedrooms` string | number Optional** Minimum number of bedrooms. - **`beds` string | number Optional** Minimum number of beds. - **`booking_options` string | array Optional** Booking option labels from Airbnb such as "Instant Book", "Self check-in", "Free cancellation", or "Allows pets". Accepts a comma-separated string or an array. - **`children` integer Optional** Number of child guests. Default: 0. Minimum: 0. Maximum: 16. - **`cursor` string Optional** Optional Airbnb pagination cursor from a search URL or previous response to start from a later result page. - **`flexible_cancellation` boolean | string | number Optional** Flexible cancellation filter. Accepts true/false or 1/0. - **`guest_favorite` boolean | string | number Optional** Guest favorite filter. Accepts true/false or 1/0. - **`host_languages` string | array Optional** Host language labels such as "English", "French", or "Sign Language". Raw language codes like en and fr are also accepted. - **`instant_book` boolean | string | number Optional** Instant Book filter. Accepts true/false or 1/0. - **`pages` integer Optional** Number of paginated Airbnb result pages to fetch (1-20). Default: 1. Minimum: 1. Maximum: 20. - **`pets` string | number Optional** Pet-friendly filter as a positive count, typically 1. - **`price_max` string | number Optional** Maximum nightly price filter from an Airbnb search URL. - **`price_min` string | number Optional** Minimum nightly price filter from an Airbnb search URL. - **`property_types` string | array Optional** Property type labels from Airbnb such as "House", "Apartment", or "Guesthouse". Accepts a comma-separated string or an array. - **`room_types` string | array Optional** Room type labels such as "Room" or "Entire home". Raw Airbnb values like "Private room" are also accepted. - **`standout_stays` string | array Optional** Standout stay labels from Airbnb such as "Guest favorite" or "Luxe". Accepts a comma-separated string or an array. - **`type_of_place` string | array Optional** Type of place labels from Airbnb such as "Room" or "Entire home". Accepts a comma-separated string or an array. ### Advanced & compatibility inputs 2 - **`property_type_ids` string | array Optional** Raw Airbnb property type IDs. Prefer property_types for human-readable labels. - **`tier_ids` string | array Optional** Raw Airbnb tier IDs, or labels such as "Luxe" when the option is available. ## 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", "query", "checkin", "checkout", "adults", "children", "applied_filters", "pages_requested", "pages_fetched", "count", "results", "pagination" ], "properties": { "count": { "type": "number" }, "query": { "type": "string" }, "adults": { "type": "number" }, "checkin": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "required": [ "id", "page", "link", "badges", "payment_messages", "image_urls", "details", "price" ], "properties": { "id": { "type": "string" }, "link": { "type": "string" }, "name": { "type": "string" }, "page": { "type": "number" }, "price": { "anyOf": [ { "type": "object", "required": [ "display", "amount_numeric", "currency", "qualifier" ], "properties": { "display": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "currency": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "qualifier": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "amount_numeric": { "anyOf": [ { "type": "number" }, { "type": "null" } ] }, "original_display": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "accessibility_label": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "original_amount_numeric": { "anyOf": [ { "type": "number" }, { "type": "null" } ] } }, "additionalProperties": false }, { "type": "null" } ] }, "title": { "type": "string" }, "badges": { "type": "array", "items": { "type": "string" } }, "rating": { "anyOf": [ { "type": "number" }, { "type": "null" } ] }, "details": { "type": "array", "items": { "type": "string" } }, "location": { "anyOf": [ { "type": "object", "required": [ "lat", "lng" ], "properties": { "lat": { "anyOf": [ { "type": "number" }, { "type": "null" } ] }, "lng": { "anyOf": [ { "type": "number" }, { "type": "null" } ] } }, "additionalProperties": false }, { "type": "null" } ] }, "subtitle": { "type": "string" }, "image_urls": { "type": "array", "items": { "type": "string" } }, "rating_text": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "review_count": { "anyOf": [ { "type": "number" }, { "type": "null" } ] }, "payment_messages": { "type": "array", "items": { "type": "string" } } }, "additionalProperties": true } }, "success": { "type": "boolean" }, "checkout": { "type": "string" }, "children": { "type": "number" }, "pagination": { "type": "object", "required": [ "has_next_page", "next_page", "next_page_cursor", "previous_page_cursor", "page_cursors" ], "properties": { "next_page": { "anyOf": [ { "type": "number" }, { "type": "null" } ] }, "total_pages": { "anyOf": [ { "type": "number" }, { "type": "null" } ] }, "current_page": { "anyOf": [ { "type": "number" }, { "type": "null" } ] }, "page_cursors": { "type": "array", "items": { "type": "string" } }, "has_next_page": { "type": "boolean" }, "next_page_cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "previous_page_cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] } }, "additionalProperties": false }, "section_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "pages_fetched": { "type": "number" }, "applied_filters": { "type": "object", "properties": { "beds": { "type": "number" }, "pets": { "type": "number" }, "bedrooms": { "type": "number" }, "tier_ids": { "type": "array", "items": { "type": "string" } }, "amenities": { "type": "array", "items": { "type": "string" } }, "bathrooms": { "type": "number" }, "price_max": { "type": "number" }, "price_min": { "type": "number" }, "room_types": { "type": "array", "items": { "type": "string" } }, "instant_book": { "type": "boolean" }, "type_of_place": { "type": "array", "items": { "type": "string" } }, "guest_favorite": { "type": "boolean" }, "host_languages": { "type": "array", "items": { "type": "string" } }, "property_types": { "type": "array", "items": { "type": "string" } }, "standout_stays": { "type": "array", "items": { "type": "string" } }, "booking_options": { "type": "array", "items": { "type": "string" } }, "bathroom_privacy": { "type": "array", "items": { "type": "string" } }, "property_type_ids": { "type": "array", "items": { "type": "string" } }, "flexible_cancellation": { "type": "boolean" }, "accessibility_features": { "type": "array", "items": { "type": "string" } } }, "additionalProperties": false }, "pages_requested": { "type": "number" }, "search_session_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ] } }, "additionalProperties": true } ``` ### View a polled run response ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "airbnb-search", "task_name": "Airbnb search", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "success": true, "query": "London", "checkin": "2027-06-14", "checkout": "2027-06-21", "adults": 2, "children": 1, "applied_filters": { "amenities": [ "Wifi", "Kitchen" ], "room_types": [ "Entire home" ], "instant_book": true, "guest_favorite": true, "price_min": 180, "price_max": 350 }, "pages_requested": 2, "pages_fetched": 2, "count": 2, "search_session_id": "search-session-1", "section_id": "EXPLORE_SEARCH_RESULTS", "results": [ { "id": "101", "page": 1, "link": "https://www.airbnb.com/rooms/101", "name": "Stylish Shoreditch Loft with Balcony", "title": "Stylish Shoreditch Loft with Balcony", "subtitle": "Entire rental unit in Greater London", "badges": [ "Guest favorite" ], "payment_messages": [ "Free cancellation" ], "image_urls": [ "https://images.example.com/airbnb/101-1.jpg", "https://images.example.com/airbnb/101-2.jpg" ], "details": [ "2 guests", "1 bedroom", "1 bed", "1 bath" ], "price": { "display": "GBP 210 total", "amount_numeric": 210, "currency": "GBP", "qualifier": "for 1 night", "original_display": "GBP 240 total", "accessibility_label": "GBP 210 total for 1 night", "original_amount_numeric": 240 }, "rating": 4.91, "location": { "lat": 51.5246, "lng": -0.0759 }, "rating_text": "4.91 · 128 reviews", "review_count": 128 }, { "id": "202", "page": 2, "link": "https://www.airbnb.com/rooms/202", "name": "Bright Notting Hill Apartment Near Tube", "title": "Bright Notting Hill Apartment Near Tube", "subtitle": "Private room in Kensington", "badges": [ "Superhost" ], "payment_messages": [ "Reserve now, pay later" ], "image_urls": [ "https://images.example.com/airbnb/202-1.jpg", "https://images.example.com/airbnb/202-2.jpg" ], "details": [ "2 guests", "1 bedroom", "1 bed", "Shared bath" ], "price": { "display": "GBP 245 total", "amount_numeric": 245, "currency": "GBP", "qualifier": "for 1 night", "original_display": "GBP 280 total", "accessibility_label": "GBP 245 total for 1 night", "original_amount_numeric": 280 }, "rating": 4.84, "location": { "lat": 51.5092, "lng": -0.1964 }, "rating_text": "4.84 · 76 reviews", "review_count": 76 } ], "pagination": { "current_page": 2, "total_pages": 2, "page_cursors": [ "cursor-page-1", "cursor-page-2" ], "has_next_page": false, "next_page": null, "next_page_cursor": null, "previous_page_cursor": "cursor-page-1" } }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/airbnb/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"London","checkin":"2027-06-14","checkout":"2027-06-21"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/airbnb/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "London", "checkin": "2027-06-14", "checkout": "2027-06-21" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/airbnb/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "London", "checkin": "2027-06-14", "checkout": "2027-06-21" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/airbnb/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"London","checkin":"2027-06-14","checkout":"2027-06-21","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/airbnb/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "London", "checkin": "2027-06-14", "checkout": "2027-06-21", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/airbnb/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "London", "checkin": "2027-06-14", "checkout": "2027-06-21", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/airbnb-search/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/airbnb/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"London","checkin":"2027-06-14","checkout":"2027-06-21","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/airbnb/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "London", "checkin": "2027-06-14", "checkout": "2027-06-21", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/airbnb/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "London", "checkin": "2027-06-14", "checkout": "2027-06-21", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "airbnb-search", "task_name": "Airbnb search", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "success": true, "query": "London", "checkin": "2027-06-14", "checkout": "2027-06-21", "adults": 2, "children": 1, "applied_filters": { "amenities": [ "Wifi", "Kitchen" ], "room_types": [ "Entire home" ], "instant_book": true, "guest_favorite": true, "price_min": 180, "price_max": 350 }, "pages_requested": 2, "pages_fetched": 2, "count": 2, "search_session_id": "search-session-1", "section_id": "EXPLORE_SEARCH_RESULTS", "results": [ { "id": "101", "page": 1, "link": "https://www.airbnb.com/rooms/101", "name": "Stylish Shoreditch Loft with Balcony", "title": "Stylish Shoreditch Loft with Balcony", "subtitle": "Entire rental unit in Greater London", "badges": [ "Guest favorite" ], "payment_messages": [ "Free cancellation" ], "image_urls": [ "https://images.example.com/airbnb/101-1.jpg", "https://images.example.com/airbnb/101-2.jpg" ], "details": [ "2 guests", "1 bedroom", "1 bed", "1 bath" ], "price": { "display": "GBP 210 total", "amount_numeric": 210, "currency": "GBP", "qualifier": "for 1 night", "original_display": "GBP 240 total", "accessibility_label": "GBP 210 total for 1 night", "original_amount_numeric": 240 }, "rating": 4.91, "location": { "lat": 51.5246, "lng": -0.0759 }, "rating_text": "4.91 · 128 reviews", "review_count": 128 }, { "id": "202", "page": 2, "link": "https://www.airbnb.com/rooms/202", "name": "Bright Notting Hill Apartment Near Tube", "title": "Bright Notting Hill Apartment Near Tube", "subtitle": "Private room in Kensington", "badges": [ "Superhost" ], "payment_messages": [ "Reserve now, pay later" ], "image_urls": [ "https://images.example.com/airbnb/202-1.jpg", "https://images.example.com/airbnb/202-2.jpg" ], "details": [ "2 guests", "1 bedroom", "1 bed", "Shared bath" ], "price": { "display": "GBP 245 total", "amount_numeric": 245, "currency": "GBP", "qualifier": "for 1 night", "original_display": "GBP 280 total", "accessibility_label": "GBP 245 total for 1 night", "original_amount_numeric": 280 }, "rating": 4.84, "location": { "lat": 51.5092, "lng": -0.1964 }, "rating_text": "4.84 · 76 reviews", "review_count": 76 } ], "pagination": { "current_page": 2, "total_pages": 2, "page_cursors": [ "cursor-page-1", "cursor-page-2" ], "has_next_page": false, "next_page": null, "next_page_cursor": null, "previous_page_cursor": "cursor-page-1" } }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-airbnb-search [Alibaba APIs](/docs/api.md#alibaba) # Alibaba Product API Scrape a public Alibaba product detail page from a search result URL. POST `/v1/alibaba/product` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`url` string Required** Alibaba product URL returned by alibaba/search. Minimum length: 1. Maximum length: 2000. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "alibaba-product", "task_name": "Alibaba Product API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/alibaba/product" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.alibaba.com/product-detail/custom-packaging-boxes_1600000000000.html"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/alibaba/product", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.alibaba.com/product-detail/custom-packaging-boxes_1600000000000.html" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/alibaba/product", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.alibaba.com/product-detail/custom-packaging-boxes_1600000000000.html" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/alibaba/product" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.alibaba.com/product-detail/custom-packaging-boxes_1600000000000.html","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/alibaba/product", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.alibaba.com/product-detail/custom-packaging-boxes_1600000000000.html", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/alibaba/product", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.alibaba.com/product-detail/custom-packaging-boxes_1600000000000.html", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/alibaba-product/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/alibaba/product" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.alibaba.com/product-detail/custom-packaging-boxes_1600000000000.html","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/alibaba/product", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.alibaba.com/product-detail/custom-packaging-boxes_1600000000000.html", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/alibaba/product", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.alibaba.com/product-detail/custom-packaging-boxes_1600000000000.html", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "alibaba-product", "task_name": "Alibaba Product API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-alibaba-product [Alibaba APIs](/docs/api.md#alibaba) # Alibaba API Scrape public Alibaba showroom product pages by query. POST `/v1/alibaba/search` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`query` string Required** Search query. Minimum length: 1. Maximum length: 2000. - **`limit` integer Optional** Maximum number of results to return. Default: 25. Minimum: 1. Maximum: 100. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "alibaba-search", "task_name": "Alibaba API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/alibaba/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"custom packaging boxes"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/alibaba/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "custom packaging boxes" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/alibaba/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "custom packaging boxes" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/alibaba/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"custom packaging boxes","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/alibaba/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "custom packaging boxes", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/alibaba/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "custom packaging boxes", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/alibaba-search/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/alibaba/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"custom packaging boxes","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/alibaba/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "custom packaging boxes", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/alibaba/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "custom packaging boxes", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "alibaba-search", "task_name": "Alibaba API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-alibaba-search [AliExpress APIs](/docs/api.md#aliexpress) # AliExpress Item API Scrape a public AliExpress item detail page from a search result URL or item id. POST `/v1/aliexpress/item` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. Provide at least one of: url; id. - **`url` string Optional** AliExpress item URL returned by aliexpress/search. Minimum length: 1. Maximum length: 2000. - **`id` string Optional** AliExpress item id, or the id value returned by aliexpress/search. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "aliexpress-item", "task_name": "AliExpress Item API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/aliexpress/item" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.aliexpress.com/item/1005010149274942.html"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/aliexpress/item", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.aliexpress.com/item/1005010149274942.html" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/aliexpress/item", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.aliexpress.com/item/1005010149274942.html" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/aliexpress/item" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.aliexpress.com/item/1005010149274942.html","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/aliexpress/item", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.aliexpress.com/item/1005010149274942.html", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/aliexpress/item", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.aliexpress.com/item/1005010149274942.html", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/aliexpress-item/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/aliexpress/item" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.aliexpress.com/item/1005010149274942.html","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/aliexpress/item", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.aliexpress.com/item/1005010149274942.html", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/aliexpress/item", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.aliexpress.com/item/1005010149274942.html", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "aliexpress-item", "task_name": "AliExpress Item API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-aliexpress-item [AliExpress APIs](/docs/api.md#aliexpress) # AliExpress API Scrape public AliExpress search result pages by query with page pagination. POST `/v1/aliexpress/search` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`query` string Required** Search query. Minimum length: 1. Maximum length: 2000. - **`limit` integer Optional** Maximum number of results to return. Default: 25. Minimum: 1. Maximum: 100. - **`cursor` string Optional** Cursor returned as next_cursor from the previous response. - **`page` integer Optional** Page number for sources that support page-based pagination. Default: 1. Minimum: 1. Maximum: 10000. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "aliexpress-search", "task_name": "AliExpress API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/aliexpress/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"phone case"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/aliexpress/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "phone case" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/aliexpress/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "phone case" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/aliexpress/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"phone case","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/aliexpress/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "phone case", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/aliexpress/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "phone case", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/aliexpress-search/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/aliexpress/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"phone case","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/aliexpress/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "phone case", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/aliexpress/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "phone case", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "aliexpress-search", "task_name": "AliExpress API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-aliexpress-search [Amazon APIs](/docs/api.md#amazon) # Amazon ASIN Lookup API Fetch product details, specifications, images, price and availability by ASIN or URL. No Amazon sign-in required. Prices and availability reflect the marketplace and delivery location; unavailable fields are null. POST `/v1/amazon/asin` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. Provide at least one of: asin; url. - **`url` string Optional** Product URL on a supported Amazon marketplace. Minimum length: 1. Maximum length: 2000. Format: uri. Pattern: ^https://. - **`asin` string Optional** Amazon product ASIN. Pattern: ^[a-zA-Z0-9]{10}$. - **`marketplace` string Optional** Amazon marketplace. Defaults to the product URL's marketplace, or amazon.com. Allowed: "amazon.com", "amazon.co.uk", "amazon.ca", "amazon.de", "amazon.fr", "amazon.it", "amazon.es", "amazon.co.jp", "amazon.in", "amazon.com.au". - **`postal_code` string Optional** Delivery postal code. The request fails if Amazon cannot apply it; responses include the displayed delivery location. Minimum length: 2. Maximum length: 16. Pattern: ^[a-zA-Z0-9][a-zA-Z0-9 -]+$. ## 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": [ "id", "asin", "url", "title", "description", "price", "price_amount", "price_currency", "availability", "availability_text", "rating", "review_count", "image_url", "image_urls", "details", "marketplace", "delivery_location" ], "properties": { "id": { "type": "string" }, "url": { "type": "string" }, "asin": { "type": "string" }, "price": { "type": [ "string", "null" ] }, "title": { "type": "string" }, "rating": { "type": [ "number", "null" ] }, "details": { "type": "object", "additionalProperties": { "type": "string" } }, "image_url": { "type": [ "string", "null" ] }, "image_urls": { "type": "array", "items": { "type": "string" } }, "description": { "type": [ "string", "null" ] }, "marketplace": { "enum": [ "amazon.com", "amazon.co.uk", "amazon.ca", "amazon.de", "amazon.fr", "amazon.it", "amazon.es", "amazon.co.jp", "amazon.in", "amazon.com.au" ], "type": "string" }, "availability": { "type": [ "string", "null" ] }, "price_amount": { "type": [ "string", "null" ], "description": "Decimal amount in the marketplace currency, without grouping separators; null when unavailable." }, "review_count": { "type": [ "integer", "null" ] }, "price_currency": { "type": [ "string", "null" ] }, "availability_text": { "type": [ "string", "null" ] }, "delivery_location": { "type": "object", "required": [ "postal_code", "applied", "displayed" ], "properties": { "applied": { "type": "boolean" }, "displayed": { "type": [ "string", "null" ] }, "postal_code": { "type": [ "string", "null" ] } }, "additionalProperties": false } }, "additionalProperties": false }, "count": { "type": "integer", "minimum": 0 }, "query": { "type": [ "string", "null" ] }, "source": { "const": "amazon-asin" }, "results": { "type": "array", "items": { "type": "object", "required": [ "id", "asin", "url", "title", "description", "price", "price_amount", "price_currency", "availability", "availability_text", "rating", "review_count", "image_url", "image_urls", "details", "marketplace", "delivery_location" ], "properties": { "id": { "type": "string" }, "url": { "type": "string" }, "asin": { "type": "string" }, "price": { "type": [ "string", "null" ] }, "title": { "type": "string" }, "rating": { "type": [ "number", "null" ] }, "details": { "type": "object", "additionalProperties": { "type": "string" } }, "image_url": { "type": [ "string", "null" ] }, "image_urls": { "type": "array", "items": { "type": "string" } }, "description": { "type": [ "string", "null" ] }, "marketplace": { "enum": [ "amazon.com", "amazon.co.uk", "amazon.ca", "amazon.de", "amazon.fr", "amazon.it", "amazon.es", "amazon.co.jp", "amazon.in", "amazon.com.au" ], "type": "string" }, "availability": { "type": [ "string", "null" ] }, "price_amount": { "type": [ "string", "null" ], "description": "Decimal amount in the marketplace currency, without grouping separators; null when unavailable." }, "review_count": { "type": [ "integer", "null" ] }, "price_currency": { "type": [ "string", "null" ] }, "availability_text": { "type": [ "string", "null" ] }, "delivery_location": { "type": "object", "required": [ "postal_code", "applied", "displayed" ], "properties": { "applied": { "type": "boolean" }, "displayed": { "type": [ "string", "null" ] }, "postal_code": { "type": [ "string", "null" ] } }, "additionalProperties": false } }, "additionalProperties": false } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer", "minimum": 0 }, "cursor": { "type": [ "string", "null" ] }, "strategy": { "enum": [ "none", "cursor" ], "type": "string" }, "next_cursor": { "type": [ "string", "null" ] }, "has_next_page": { "type": "boolean" } }, "additionalProperties": false }, "max_results_requested": { "type": "integer", "minimum": 1 } }, "additionalProperties": false } ``` ### View a polled run response ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "amazon-asin", "task_name": "Amazon ASIN Lookup API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": { "id": "id-1", "url": "https://example.com/item-1", "asin": "sample", "price": "180", "title": "Stylish Shoreditch Loft with Balcony", "rating": 4.91, "details": {}, "image_url": "https://example.com/item-1", "image_urls": [ "https://images.example.com/image_urls-1.jpg" ], "description": "Sample description 1", "marketplace": "amazon.com", "availability": "sample", "price_amount": "180", "review_count": 1, "price_currency": "GBP", "availability_text": "Sample availability_text 1", "delivery_location": { "applied": true, "displayed": "sample", "postal_code": "sample" } }, "count": 1, "query": "London", "source": "amazon-asin", "results": [ { "id": "id-1", "url": "https://example.com/item-1", "asin": "sample", "price": "180", "title": "Stylish Shoreditch Loft with Balcony", "rating": 4.91, "details": {}, "image_url": "https://example.com/item-1", "image_urls": [ "https://images.example.com/image_urls-1.jpg" ], "description": "Sample description 1", "marketplace": "amazon.com", "availability": "sample", "price_amount": "180", "review_count": 1, "price_currency": "GBP", "availability_text": "Sample availability_text 1", "delivery_location": { "applied": true, "displayed": "sample", "postal_code": "sample" } } ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "none", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/asin" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.amazon.com/dp/B0C3HCD34R"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/asin", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.amazon.com/dp/B0C3HCD34R" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/asin", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.amazon.com/dp/B0C3HCD34R" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/asin" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.amazon.com/dp/B0C3HCD34R","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/asin", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.amazon.com/dp/B0C3HCD34R", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/asin", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.amazon.com/dp/B0C3HCD34R", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/amazon-asin/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/asin" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.amazon.com/dp/B0C3HCD34R","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/asin", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.amazon.com/dp/B0C3HCD34R", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/asin", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.amazon.com/dp/B0C3HCD34R", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "amazon-asin", "task_name": "Amazon ASIN Lookup API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": { "id": "id-1", "url": "https://example.com/item-1", "asin": "sample", "price": "180", "title": "Stylish Shoreditch Loft with Balcony", "rating": 4.91, "details": {}, "image_url": "https://example.com/item-1", "image_urls": [ "https://images.example.com/image_urls-1.jpg" ], "description": "Sample description 1", "marketplace": "amazon.com", "availability": "sample", "price_amount": "180", "review_count": 1, "price_currency": "GBP", "availability_text": "Sample availability_text 1", "delivery_location": { "applied": true, "displayed": "sample", "postal_code": "sample" } }, "count": 1, "query": "London", "source": "amazon-asin", "results": [ { "id": "id-1", "url": "https://example.com/item-1", "asin": "sample", "price": "180", "title": "Stylish Shoreditch Loft with Balcony", "rating": 4.91, "details": {}, "image_url": "https://example.com/item-1", "image_urls": [ "https://images.example.com/image_urls-1.jpg" ], "description": "Sample description 1", "marketplace": "amazon.com", "availability": "sample", "price_amount": "180", "review_count": 1, "price_currency": "GBP", "availability_text": "Sample availability_text 1", "delivery_location": { "applied": true, "displayed": "sample", "postal_code": "sample" } } ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "none", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-amazon-asin [Amazon APIs](/docs/api.md#amazon) # Amazon Best Sellers API Fetch Amazon Best Sellers by category with continuation cursors. Empty lists are returned when Amazon explicitly reports no entries. No Amazon sign-in required. Prices and availability reflect the marketplace and delivery location; unavailable fields are null. POST `/v1/amazon/best-sellers` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`limit` integer Optional** Maximum results in this response. Default: 25. Minimum: 1. Maximum: 100. - **`category` string Optional** Department such as electronics, kitchen, books, beauty or pet supplies. Unsupported departments fail explicitly. Minimum length: 1. Maximum length: 100. - **`cursor` string Optional** next_cursor from a prior response using the same filters and marketplace. Maximum length: 131072. - **`marketplace` string Optional** Amazon marketplace. Defaults to the product URL's marketplace, or amazon.com. Allowed: "amazon.com", "amazon.co.uk", "amazon.ca", "amazon.de", "amazon.fr", "amazon.it", "amazon.es", "amazon.co.jp", "amazon.in", "amazon.com.au". - **`page` integer Optional** Starting upstream page. Prefer cursor to retain unused results and avoid duplicates. Minimum: 1. Maximum: 1000. - **`postal_code` string Optional** Delivery postal code. The request fails if Amazon cannot apply it; responses include the displayed delivery location. Minimum length: 2. Maximum length: 16. Pattern: ^[a-zA-Z0-9][a-zA-Z0-9 -]+$. ## 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": [ "marketplace", "delivery_location" ], "properties": { "notice": { "type": "string" }, "marketplace": { "enum": [ "amazon.com", "amazon.co.uk", "amazon.ca", "amazon.de", "amazon.fr", "amazon.it", "amazon.es", "amazon.co.jp", "amazon.in", "amazon.com.au" ], "type": "string" }, "delivery_location": { "type": "object", "required": [ "postal_code", "applied", "displayed" ], "properties": { "applied": { "type": "boolean" }, "displayed": { "type": [ "string", "null" ] }, "postal_code": { "type": [ "string", "null" ] } }, "additionalProperties": false } }, "additionalProperties": false }, "count": { "type": "integer", "minimum": 0 }, "query": { "type": [ "string", "null" ] }, "source": { "const": "amazon-best-sellers" }, "results": { "type": "array", "items": { "type": "object", "required": [ "id", "asin", "title", "url", "price", "price_amount", "price_currency", "list_price", "rating", "image_url", "deal_badge", "rank", "sales_rank", "previous_sales_rank", "rank_change_percent", "is_sponsored", "name", "link", "images", "tags", "numberOfReviews" ], "properties": { "id": { "type": "string" }, "url": { "type": "string" }, "asin": { "type": "string" }, "link": { "type": "string" }, "name": { "type": "string" }, "rank": { "type": [ "integer", "null" ] }, "tags": { "type": "array", "items": { "type": "string" } }, "price": { "type": [ "string", "null" ] }, "title": { "type": "string" }, "images": { "type": "array", "items": { "type": "string" } }, "rating": { "type": [ "number", "null" ] }, "image_url": { "type": [ "string", "null" ] }, "deal_badge": { "type": [ "string", "null" ] }, "list_price": { "type": [ "string", "null" ] }, "sales_rank": { "type": [ "integer", "null" ] }, "is_sponsored": { "type": "boolean" }, "price_amount": { "type": [ "string", "null" ], "description": "Decimal amount in the marketplace currency, without grouping separators; null when unavailable." }, "price_currency": { "type": [ "string", "null" ] }, "numberOfReviews": { "type": [ "integer", "null" ] }, "previous_sales_rank": { "type": [ "integer", "null" ] }, "rank_change_percent": { "type": [ "number", "null" ] } }, "additionalProperties": false } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer", "minimum": 0 }, "cursor": { "type": [ "string", "null" ] }, "strategy": { "enum": [ "none", "cursor" ], "type": "string" }, "next_cursor": { "type": [ "string", "null" ] }, "has_next_page": { "type": "boolean" } }, "additionalProperties": false }, "max_results_requested": { "type": "integer", "minimum": 1 } }, "additionalProperties": false } ``` ### View a polled run response ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "amazon-best-sellers", "task_name": "Amazon Best Sellers API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": { "notice": "sample", "marketplace": "amazon.com", "delivery_location": { "applied": true, "displayed": "sample", "postal_code": "sample" } }, "count": 1, "query": "London", "source": "amazon-best-sellers", "results": [ { "id": "id-1", "url": "https://example.com/item-1", "asin": "sample", "link": "https://example.com/item-1", "name": "Stylish Shoreditch Loft with Balcony", "rank": 1, "tags": [ "Featured" ], "price": "180", "title": "Stylish Shoreditch Loft with Balcony", "images": [ "https://images.example.com/images-1.jpg" ], "rating": 4.91, "image_url": "https://example.com/item-1", "deal_badge": "sample", "list_price": "180", "sales_rank": 1, "is_sponsored": true, "price_amount": "180", "price_currency": "GBP", "numberOfReviews": 1, "previous_sales_rank": 1, "rank_change_percent": 1.5 } ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "none", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/best-sellers" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/best-sellers", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({}), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/best-sellers", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={}, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/best-sellers" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/best-sellers", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/best-sellers", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/amazon-best-sellers/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/best-sellers" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/best-sellers", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/best-sellers", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "amazon-best-sellers", "task_name": "Amazon Best Sellers API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": { "notice": "sample", "marketplace": "amazon.com", "delivery_location": { "applied": true, "displayed": "sample", "postal_code": "sample" } }, "count": 1, "query": "London", "source": "amazon-best-sellers", "results": [ { "id": "id-1", "url": "https://example.com/item-1", "asin": "sample", "link": "https://example.com/item-1", "name": "Stylish Shoreditch Loft with Balcony", "rank": 1, "tags": [ "Featured" ], "price": "180", "title": "Stylish Shoreditch Loft with Balcony", "images": [ "https://images.example.com/images-1.jpg" ], "rating": 4.91, "image_url": "https://example.com/item-1", "deal_badge": "sample", "list_price": "180", "sales_rank": 1, "is_sponsored": true, "price_amount": "180", "price_currency": "GBP", "numberOfReviews": 1, "previous_sales_rank": 1, "rank_change_percent": 1.5 } ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "none", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-amazon-best-sellers [Amazon APIs](/docs/api.md#amazon) # Amazon Deals API Fetch public deals, or search for products with active deal badges. Query pages can be empty after filtering; continue while next_cursor is present. No Amazon sign-in required. Prices and availability reflect the marketplace and delivery location; unavailable fields are null. POST `/v1/amazon/deals` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`query` string Optional** Search text. Minimum length: 1. Maximum length: 500. - **`limit` integer Optional** Maximum results in this response. Default: 25. Minimum: 1. Maximum: 100. - **`brand` string Optional** Single brand name. Minimum length: 1. Maximum length: 100. Pattern: ^[^:,]+$. - **`category` string Optional** Department such as electronics, kitchen, books, beauty or pet supplies. Unsupported departments fail explicitly. Minimum length: 1. Maximum length: 100. - **`cursor` string Optional** next_cursor from a prior response using the same filters and marketplace. Maximum length: 131072. - **`marketplace` string Optional** Amazon marketplace. Defaults to the product URL's marketplace, or amazon.com. Allowed: "amazon.com", "amazon.co.uk", "amazon.ca", "amazon.de", "amazon.fr", "amazon.it", "amazon.es", "amazon.co.jp", "amazon.in", "amazon.com.au". - **`max_price` number Optional** Maximum item price in the marketplace currency. Minimum: 0. - **`min_price` number Optional** Minimum item price in the marketplace currency. Minimum: 0. - **`min_rating` integer Optional** Minimum product star rating. Allowed: 1, 2, 3, 4. - **`page` integer Optional** Starting upstream page. Prefer cursor to retain unused results and avoid duplicates. Minimum: 1. Maximum: 1000. - **`postal_code` string Optional** Delivery postal code. The request fails if Amazon cannot apply it; responses include the displayed delivery location. Minimum length: 2. Maximum length: 16. Pattern: ^[a-zA-Z0-9][a-zA-Z0-9 -]+$. - **`sort` string Optional** Sort order. Choose an allowed value below. Default: "relevance". Allowed: "relevance", "price_asc", "price_desc", "rating", "newest". ### Advanced & compatibility inputs 1 - **`category_id` string Optional** Amazon browse node ID for a more specific category. Pattern: ^[0-9]{1,20}$. ## 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": [ "marketplace", "delivery_location" ], "properties": { "notice": { "type": "string" }, "marketplace": { "enum": [ "amazon.com", "amazon.co.uk", "amazon.ca", "amazon.de", "amazon.fr", "amazon.it", "amazon.es", "amazon.co.jp", "amazon.in", "amazon.com.au" ], "type": "string" }, "delivery_location": { "type": "object", "required": [ "postal_code", "applied", "displayed" ], "properties": { "applied": { "type": "boolean" }, "displayed": { "type": [ "string", "null" ] }, "postal_code": { "type": [ "string", "null" ] } }, "additionalProperties": false } }, "additionalProperties": false }, "count": { "type": "integer", "minimum": 0 }, "query": { "type": [ "string", "null" ] }, "source": { "const": "amazon-deals" }, "results": { "type": "array", "items": { "type": "object", "required": [ "id", "asin", "title", "url", "price", "price_amount", "price_currency", "list_price", "rating", "image_url", "deal_badge", "rank", "sales_rank", "previous_sales_rank", "rank_change_percent", "is_sponsored", "name", "link", "images", "tags", "numberOfReviews" ], "properties": { "id": { "type": "string" }, "url": { "type": "string" }, "asin": { "type": "string" }, "link": { "type": "string" }, "name": { "type": "string" }, "rank": { "type": [ "integer", "null" ] }, "tags": { "type": "array", "items": { "type": "string" } }, "price": { "type": [ "string", "null" ] }, "title": { "type": "string" }, "images": { "type": "array", "items": { "type": "string" } }, "rating": { "type": [ "number", "null" ] }, "image_url": { "type": [ "string", "null" ] }, "deal_badge": { "type": [ "string", "null" ] }, "list_price": { "type": [ "string", "null" ] }, "sales_rank": { "type": [ "integer", "null" ] }, "is_sponsored": { "type": "boolean" }, "price_amount": { "type": [ "string", "null" ], "description": "Decimal amount in the marketplace currency, without grouping separators; null when unavailable." }, "price_currency": { "type": [ "string", "null" ] }, "numberOfReviews": { "type": [ "integer", "null" ] }, "previous_sales_rank": { "type": [ "integer", "null" ] }, "rank_change_percent": { "type": [ "number", "null" ] } }, "additionalProperties": false } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer", "minimum": 0 }, "cursor": { "type": [ "string", "null" ] }, "strategy": { "enum": [ "none", "cursor" ], "type": "string" }, "next_cursor": { "type": [ "string", "null" ] }, "has_next_page": { "type": "boolean" } }, "additionalProperties": false }, "max_results_requested": { "type": "integer", "minimum": 1 } }, "additionalProperties": false } ``` ### View a polled run response ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "amazon-deals", "task_name": "Amazon Deals API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": { "notice": "sample", "marketplace": "amazon.com", "delivery_location": { "applied": true, "displayed": "sample", "postal_code": "sample" } }, "count": 1, "query": "London", "source": "amazon-deals", "results": [ { "id": "id-1", "url": "https://example.com/item-1", "asin": "sample", "link": "https://example.com/item-1", "name": "Stylish Shoreditch Loft with Balcony", "rank": 1, "tags": [ "Featured" ], "price": "180", "title": "Stylish Shoreditch Loft with Balcony", "images": [ "https://images.example.com/images-1.jpg" ], "rating": 4.91, "image_url": "https://example.com/item-1", "deal_badge": "sample", "list_price": "180", "sales_rank": 1, "is_sponsored": true, "price_amount": "180", "price_currency": "GBP", "numberOfReviews": 1, "previous_sales_rank": 1, "rank_change_percent": 1.5 } ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "none", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/deals" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/deals", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({}), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/deals", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={}, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/deals" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/deals", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/deals", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/amazon-deals/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/deals" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/deals", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/deals", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "amazon-deals", "task_name": "Amazon Deals API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": { "notice": "sample", "marketplace": "amazon.com", "delivery_location": { "applied": true, "displayed": "sample", "postal_code": "sample" } }, "count": 1, "query": "London", "source": "amazon-deals", "results": [ { "id": "id-1", "url": "https://example.com/item-1", "asin": "sample", "link": "https://example.com/item-1", "name": "Stylish Shoreditch Loft with Balcony", "rank": 1, "tags": [ "Featured" ], "price": "180", "title": "Stylish Shoreditch Loft with Balcony", "images": [ "https://images.example.com/images-1.jpg" ], "rating": 4.91, "image_url": "https://example.com/item-1", "deal_badge": "sample", "list_price": "180", "sales_rank": 1, "is_sponsored": true, "price_amount": "180", "price_currency": "GBP", "numberOfReviews": 1, "previous_sales_rank": 1, "rank_change_percent": 1.5 } ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "none", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-amazon-deals [Amazon APIs](/docs/api.md#amazon) # Amazon Movers and Shakers API Fetch Amazon Movers and Shakers by category with continuation cursors. Empty lists are returned when Amazon explicitly reports no entries. No Amazon sign-in required. Prices and availability reflect the marketplace and delivery location; unavailable fields are null. POST `/v1/amazon/movers-and-shakers` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`limit` integer Optional** Maximum results in this response. Default: 25. Minimum: 1. Maximum: 100. - **`category` string Optional** Department such as electronics, kitchen, books, beauty or pet supplies. Unsupported departments fail explicitly. Minimum length: 1. Maximum length: 100. - **`cursor` string Optional** next_cursor from a prior response using the same filters and marketplace. Maximum length: 131072. - **`marketplace` string Optional** Amazon marketplace. Defaults to the product URL's marketplace, or amazon.com. Allowed: "amazon.com", "amazon.co.uk", "amazon.ca", "amazon.de", "amazon.fr", "amazon.it", "amazon.es", "amazon.co.jp", "amazon.in", "amazon.com.au". - **`page` integer Optional** Starting upstream page. Prefer cursor to retain unused results and avoid duplicates. Minimum: 1. Maximum: 1000. - **`postal_code` string Optional** Delivery postal code. The request fails if Amazon cannot apply it; responses include the displayed delivery location. Minimum length: 2. Maximum length: 16. Pattern: ^[a-zA-Z0-9][a-zA-Z0-9 -]+$. ## 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": [ "marketplace", "delivery_location" ], "properties": { "notice": { "type": "string" }, "marketplace": { "enum": [ "amazon.com", "amazon.co.uk", "amazon.ca", "amazon.de", "amazon.fr", "amazon.it", "amazon.es", "amazon.co.jp", "amazon.in", "amazon.com.au" ], "type": "string" }, "delivery_location": { "type": "object", "required": [ "postal_code", "applied", "displayed" ], "properties": { "applied": { "type": "boolean" }, "displayed": { "type": [ "string", "null" ] }, "postal_code": { "type": [ "string", "null" ] } }, "additionalProperties": false } }, "additionalProperties": false }, "count": { "type": "integer", "minimum": 0 }, "query": { "type": [ "string", "null" ] }, "source": { "const": "amazon-movers-and-shakers" }, "results": { "type": "array", "items": { "type": "object", "required": [ "id", "asin", "title", "url", "price", "price_amount", "price_currency", "list_price", "rating", "image_url", "deal_badge", "rank", "sales_rank", "previous_sales_rank", "rank_change_percent", "is_sponsored", "name", "link", "images", "tags", "numberOfReviews" ], "properties": { "id": { "type": "string" }, "url": { "type": "string" }, "asin": { "type": "string" }, "link": { "type": "string" }, "name": { "type": "string" }, "rank": { "type": [ "integer", "null" ] }, "tags": { "type": "array", "items": { "type": "string" } }, "price": { "type": [ "string", "null" ] }, "title": { "type": "string" }, "images": { "type": "array", "items": { "type": "string" } }, "rating": { "type": [ "number", "null" ] }, "image_url": { "type": [ "string", "null" ] }, "deal_badge": { "type": [ "string", "null" ] }, "list_price": { "type": [ "string", "null" ] }, "sales_rank": { "type": [ "integer", "null" ] }, "is_sponsored": { "type": "boolean" }, "price_amount": { "type": [ "string", "null" ], "description": "Decimal amount in the marketplace currency, without grouping separators; null when unavailable." }, "price_currency": { "type": [ "string", "null" ] }, "numberOfReviews": { "type": [ "integer", "null" ] }, "previous_sales_rank": { "type": [ "integer", "null" ] }, "rank_change_percent": { "type": [ "number", "null" ] } }, "additionalProperties": false } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer", "minimum": 0 }, "cursor": { "type": [ "string", "null" ] }, "strategy": { "enum": [ "none", "cursor" ], "type": "string" }, "next_cursor": { "type": [ "string", "null" ] }, "has_next_page": { "type": "boolean" } }, "additionalProperties": false }, "max_results_requested": { "type": "integer", "minimum": 1 } }, "additionalProperties": false } ``` ### View a polled run response ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "amazon-movers-and-shakers", "task_name": "Amazon Movers and Shakers API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": { "notice": "sample", "marketplace": "amazon.com", "delivery_location": { "applied": true, "displayed": "sample", "postal_code": "sample" } }, "count": 1, "query": "London", "source": "amazon-movers-and-shakers", "results": [ { "id": "id-1", "url": "https://example.com/item-1", "asin": "sample", "link": "https://example.com/item-1", "name": "Stylish Shoreditch Loft with Balcony", "rank": 1, "tags": [ "Featured" ], "price": "180", "title": "Stylish Shoreditch Loft with Balcony", "images": [ "https://images.example.com/images-1.jpg" ], "rating": 4.91, "image_url": "https://example.com/item-1", "deal_badge": "sample", "list_price": "180", "sales_rank": 1, "is_sponsored": true, "price_amount": "180", "price_currency": "GBP", "numberOfReviews": 1, "previous_sales_rank": 1, "rank_change_percent": 1.5 } ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "none", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/movers-and-shakers" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/movers-and-shakers", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({}), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/movers-and-shakers", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={}, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/movers-and-shakers" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/movers-and-shakers", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/movers-and-shakers", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/amazon-movers-and-shakers/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/movers-and-shakers" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/movers-and-shakers", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/movers-and-shakers", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "amazon-movers-and-shakers", "task_name": "Amazon Movers and Shakers API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": { "notice": "sample", "marketplace": "amazon.com", "delivery_location": { "applied": true, "displayed": "sample", "postal_code": "sample" } }, "count": 1, "query": "London", "source": "amazon-movers-and-shakers", "results": [ { "id": "id-1", "url": "https://example.com/item-1", "asin": "sample", "link": "https://example.com/item-1", "name": "Stylish Shoreditch Loft with Balcony", "rank": 1, "tags": [ "Featured" ], "price": "180", "title": "Stylish Shoreditch Loft with Balcony", "images": [ "https://images.example.com/images-1.jpg" ], "rating": 4.91, "image_url": "https://example.com/item-1", "deal_badge": "sample", "list_price": "180", "sales_rank": 1, "is_sponsored": true, "price_amount": "180", "price_currency": "GBP", "numberOfReviews": 1, "previous_sales_rank": 1, "rank_change_percent": 1.5 } ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "none", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-amazon-movers-and-shakers [Amazon APIs](/docs/api.md#amazon) # Amazon New Releases API Fetch Amazon New Releases by category with continuation cursors. Empty lists are returned when Amazon explicitly reports no entries. No Amazon sign-in required. Prices and availability reflect the marketplace and delivery location; unavailable fields are null. POST `/v1/amazon/new-releases` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`limit` integer Optional** Maximum results in this response. Default: 25. Minimum: 1. Maximum: 100. - **`category` string Optional** Department such as electronics, kitchen, books, beauty or pet supplies. Unsupported departments fail explicitly. Minimum length: 1. Maximum length: 100. - **`cursor` string Optional** next_cursor from a prior response using the same filters and marketplace. Maximum length: 131072. - **`marketplace` string Optional** Amazon marketplace. Defaults to the product URL's marketplace, or amazon.com. Allowed: "amazon.com", "amazon.co.uk", "amazon.ca", "amazon.de", "amazon.fr", "amazon.it", "amazon.es", "amazon.co.jp", "amazon.in", "amazon.com.au". - **`page` integer Optional** Starting upstream page. Prefer cursor to retain unused results and avoid duplicates. Minimum: 1. Maximum: 1000. - **`postal_code` string Optional** Delivery postal code. The request fails if Amazon cannot apply it; responses include the displayed delivery location. Minimum length: 2. Maximum length: 16. Pattern: ^[a-zA-Z0-9][a-zA-Z0-9 -]+$. ## 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": [ "marketplace", "delivery_location" ], "properties": { "notice": { "type": "string" }, "marketplace": { "enum": [ "amazon.com", "amazon.co.uk", "amazon.ca", "amazon.de", "amazon.fr", "amazon.it", "amazon.es", "amazon.co.jp", "amazon.in", "amazon.com.au" ], "type": "string" }, "delivery_location": { "type": "object", "required": [ "postal_code", "applied", "displayed" ], "properties": { "applied": { "type": "boolean" }, "displayed": { "type": [ "string", "null" ] }, "postal_code": { "type": [ "string", "null" ] } }, "additionalProperties": false } }, "additionalProperties": false }, "count": { "type": "integer", "minimum": 0 }, "query": { "type": [ "string", "null" ] }, "source": { "const": "amazon-new-releases" }, "results": { "type": "array", "items": { "type": "object", "required": [ "id", "asin", "title", "url", "price", "price_amount", "price_currency", "list_price", "rating", "image_url", "deal_badge", "rank", "sales_rank", "previous_sales_rank", "rank_change_percent", "is_sponsored", "name", "link", "images", "tags", "numberOfReviews" ], "properties": { "id": { "type": "string" }, "url": { "type": "string" }, "asin": { "type": "string" }, "link": { "type": "string" }, "name": { "type": "string" }, "rank": { "type": [ "integer", "null" ] }, "tags": { "type": "array", "items": { "type": "string" } }, "price": { "type": [ "string", "null" ] }, "title": { "type": "string" }, "images": { "type": "array", "items": { "type": "string" } }, "rating": { "type": [ "number", "null" ] }, "image_url": { "type": [ "string", "null" ] }, "deal_badge": { "type": [ "string", "null" ] }, "list_price": { "type": [ "string", "null" ] }, "sales_rank": { "type": [ "integer", "null" ] }, "is_sponsored": { "type": "boolean" }, "price_amount": { "type": [ "string", "null" ], "description": "Decimal amount in the marketplace currency, without grouping separators; null when unavailable." }, "price_currency": { "type": [ "string", "null" ] }, "numberOfReviews": { "type": [ "integer", "null" ] }, "previous_sales_rank": { "type": [ "integer", "null" ] }, "rank_change_percent": { "type": [ "number", "null" ] } }, "additionalProperties": false } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer", "minimum": 0 }, "cursor": { "type": [ "string", "null" ] }, "strategy": { "enum": [ "none", "cursor" ], "type": "string" }, "next_cursor": { "type": [ "string", "null" ] }, "has_next_page": { "type": "boolean" } }, "additionalProperties": false }, "max_results_requested": { "type": "integer", "minimum": 1 } }, "additionalProperties": false } ``` ### View a polled run response ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "amazon-new-releases", "task_name": "Amazon New Releases API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": { "notice": "sample", "marketplace": "amazon.com", "delivery_location": { "applied": true, "displayed": "sample", "postal_code": "sample" } }, "count": 1, "query": "London", "source": "amazon-new-releases", "results": [ { "id": "id-1", "url": "https://example.com/item-1", "asin": "sample", "link": "https://example.com/item-1", "name": "Stylish Shoreditch Loft with Balcony", "rank": 1, "tags": [ "Featured" ], "price": "180", "title": "Stylish Shoreditch Loft with Balcony", "images": [ "https://images.example.com/images-1.jpg" ], "rating": 4.91, "image_url": "https://example.com/item-1", "deal_badge": "sample", "list_price": "180", "sales_rank": 1, "is_sponsored": true, "price_amount": "180", "price_currency": "GBP", "numberOfReviews": 1, "previous_sales_rank": 1, "rank_change_percent": 1.5 } ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "none", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/new-releases" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/new-releases", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({}), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/new-releases", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={}, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/new-releases" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/new-releases", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/new-releases", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/amazon-new-releases/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/new-releases" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/new-releases", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/new-releases", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "amazon-new-releases", "task_name": "Amazon New Releases API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": { "notice": "sample", "marketplace": "amazon.com", "delivery_location": { "applied": true, "displayed": "sample", "postal_code": "sample" } }, "count": 1, "query": "London", "source": "amazon-new-releases", "results": [ { "id": "id-1", "url": "https://example.com/item-1", "asin": "sample", "link": "https://example.com/item-1", "name": "Stylish Shoreditch Loft with Balcony", "rank": 1, "tags": [ "Featured" ], "price": "180", "title": "Stylish Shoreditch Loft with Balcony", "images": [ "https://images.example.com/images-1.jpg" ], "rating": 4.91, "image_url": "https://example.com/item-1", "deal_badge": "sample", "list_price": "180", "sales_rank": 1, "is_sponsored": true, "price_amount": "180", "price_currency": "GBP", "numberOfReviews": 1, "previous_sales_rank": 1, "rank_change_percent": 1.5 } ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "none", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-amazon-new-releases [Amazon APIs](/docs/api.md#amazon) # Amazon Product Price API Fetch the current product price and availability by ASIN or URL. No Amazon sign-in required. Prices and availability reflect the marketplace and delivery location; unavailable fields are null. POST `/v1/amazon/price` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. Provide at least one of: asin; url. - **`url` string Optional** Product URL on a supported Amazon marketplace. Minimum length: 1. Maximum length: 2000. Format: uri. Pattern: ^https://. - **`asin` string Optional** Amazon product ASIN. Pattern: ^[a-zA-Z0-9]{10}$. - **`marketplace` string Optional** Amazon marketplace. Defaults to the product URL's marketplace, or amazon.com. Allowed: "amazon.com", "amazon.co.uk", "amazon.ca", "amazon.de", "amazon.fr", "amazon.it", "amazon.es", "amazon.co.jp", "amazon.in", "amazon.com.au". - **`postal_code` string Optional** Delivery postal code. The request fails if Amazon cannot apply it; responses include the displayed delivery location. Minimum length: 2. Maximum length: 16. Pattern: ^[a-zA-Z0-9][a-zA-Z0-9 -]+$. ## 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": [ "id", "asin", "url", "title", "description", "price", "price_amount", "price_currency", "availability", "availability_text", "rating", "review_count", "image_url", "image_urls", "details", "marketplace", "delivery_location" ], "properties": { "id": { "type": "string" }, "url": { "type": "string" }, "asin": { "type": "string" }, "price": { "type": [ "string", "null" ] }, "title": { "type": "string" }, "rating": { "type": [ "number", "null" ] }, "details": { "type": "object", "additionalProperties": { "type": "string" } }, "image_url": { "type": [ "string", "null" ] }, "image_urls": { "type": "array", "items": { "type": "string" } }, "description": { "type": [ "string", "null" ] }, "marketplace": { "enum": [ "amazon.com", "amazon.co.uk", "amazon.ca", "amazon.de", "amazon.fr", "amazon.it", "amazon.es", "amazon.co.jp", "amazon.in", "amazon.com.au" ], "type": "string" }, "availability": { "type": [ "string", "null" ] }, "price_amount": { "type": [ "string", "null" ], "description": "Decimal amount in the marketplace currency, without grouping separators; null when unavailable." }, "review_count": { "type": [ "integer", "null" ] }, "price_currency": { "type": [ "string", "null" ] }, "availability_text": { "type": [ "string", "null" ] }, "delivery_location": { "type": "object", "required": [ "postal_code", "applied", "displayed" ], "properties": { "applied": { "type": "boolean" }, "displayed": { "type": [ "string", "null" ] }, "postal_code": { "type": [ "string", "null" ] } }, "additionalProperties": false } }, "additionalProperties": false }, "count": { "type": "integer", "minimum": 0 }, "query": { "type": [ "string", "null" ] }, "source": { "const": "amazon-price" }, "results": { "type": "array", "items": { "type": "object", "required": [ "id", "asin", "url", "title", "description", "price", "price_amount", "price_currency", "availability", "availability_text", "rating", "review_count", "image_url", "image_urls", "details", "marketplace", "delivery_location" ], "properties": { "id": { "type": "string" }, "url": { "type": "string" }, "asin": { "type": "string" }, "price": { "type": [ "string", "null" ] }, "title": { "type": "string" }, "rating": { "type": [ "number", "null" ] }, "details": { "type": "object", "additionalProperties": { "type": "string" } }, "image_url": { "type": [ "string", "null" ] }, "image_urls": { "type": "array", "items": { "type": "string" } }, "description": { "type": [ "string", "null" ] }, "marketplace": { "enum": [ "amazon.com", "amazon.co.uk", "amazon.ca", "amazon.de", "amazon.fr", "amazon.it", "amazon.es", "amazon.co.jp", "amazon.in", "amazon.com.au" ], "type": "string" }, "availability": { "type": [ "string", "null" ] }, "price_amount": { "type": [ "string", "null" ], "description": "Decimal amount in the marketplace currency, without grouping separators; null when unavailable." }, "review_count": { "type": [ "integer", "null" ] }, "price_currency": { "type": [ "string", "null" ] }, "availability_text": { "type": [ "string", "null" ] }, "delivery_location": { "type": "object", "required": [ "postal_code", "applied", "displayed" ], "properties": { "applied": { "type": "boolean" }, "displayed": { "type": [ "string", "null" ] }, "postal_code": { "type": [ "string", "null" ] } }, "additionalProperties": false } }, "additionalProperties": false } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer", "minimum": 0 }, "cursor": { "type": [ "string", "null" ] }, "strategy": { "enum": [ "none", "cursor" ], "type": "string" }, "next_cursor": { "type": [ "string", "null" ] }, "has_next_page": { "type": "boolean" } }, "additionalProperties": false }, "max_results_requested": { "type": "integer", "minimum": 1 } }, "additionalProperties": false } ``` ### View a polled run response ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "amazon-price", "task_name": "Amazon Product Price API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": { "id": "id-1", "url": "https://example.com/item-1", "asin": "sample", "price": "180", "title": "Stylish Shoreditch Loft with Balcony", "rating": 4.91, "details": {}, "image_url": "https://example.com/item-1", "image_urls": [ "https://images.example.com/image_urls-1.jpg" ], "description": "Sample description 1", "marketplace": "amazon.com", "availability": "sample", "price_amount": "180", "review_count": 1, "price_currency": "GBP", "availability_text": "Sample availability_text 1", "delivery_location": { "applied": true, "displayed": "sample", "postal_code": "sample" } }, "count": 1, "query": "London", "source": "amazon-price", "results": [ { "id": "id-1", "url": "https://example.com/item-1", "asin": "sample", "price": "180", "title": "Stylish Shoreditch Loft with Balcony", "rating": 4.91, "details": {}, "image_url": "https://example.com/item-1", "image_urls": [ "https://images.example.com/image_urls-1.jpg" ], "description": "Sample description 1", "marketplace": "amazon.com", "availability": "sample", "price_amount": "180", "review_count": 1, "price_currency": "GBP", "availability_text": "Sample availability_text 1", "delivery_location": { "applied": true, "displayed": "sample", "postal_code": "sample" } } ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "none", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/price" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.amazon.com/dp/B0C3HCD34R"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/price", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.amazon.com/dp/B0C3HCD34R" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/price", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.amazon.com/dp/B0C3HCD34R" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/price" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.amazon.com/dp/B0C3HCD34R","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/price", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.amazon.com/dp/B0C3HCD34R", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/price", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.amazon.com/dp/B0C3HCD34R", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/amazon-price/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/price" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.amazon.com/dp/B0C3HCD34R","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/price", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.amazon.com/dp/B0C3HCD34R", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/price", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.amazon.com/dp/B0C3HCD34R", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "amazon-price", "task_name": "Amazon Product Price API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": { "id": "id-1", "url": "https://example.com/item-1", "asin": "sample", "price": "180", "title": "Stylish Shoreditch Loft with Balcony", "rating": 4.91, "details": {}, "image_url": "https://example.com/item-1", "image_urls": [ "https://images.example.com/image_urls-1.jpg" ], "description": "Sample description 1", "marketplace": "amazon.com", "availability": "sample", "price_amount": "180", "review_count": 1, "price_currency": "GBP", "availability_text": "Sample availability_text 1", "delivery_location": { "applied": true, "displayed": "sample", "postal_code": "sample" } }, "count": 1, "query": "London", "source": "amazon-price", "results": [ { "id": "id-1", "url": "https://example.com/item-1", "asin": "sample", "price": "180", "title": "Stylish Shoreditch Loft with Balcony", "rating": 4.91, "details": {}, "image_url": "https://example.com/item-1", "image_urls": [ "https://images.example.com/image_urls-1.jpg" ], "description": "Sample description 1", "marketplace": "amazon.com", "availability": "sample", "price_amount": "180", "review_count": 1, "price_currency": "GBP", "availability_text": "Sample availability_text 1", "delivery_location": { "applied": true, "displayed": "sample", "postal_code": "sample" } } ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "none", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-amazon-price [Amazon APIs](/docs/api.md#amazon) # Amazon Product Offers API Compare public seller offers, item condition, shipping and Featured Offer status for a product. Total prices are null when shipping cannot be determined. No Amazon sign-in required. Prices and availability reflect the marketplace and delivery location; unavailable fields are null. POST `/v1/amazon/product/offers` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. Provide at least one of: asin; url. - **`url` string Optional** Product URL on a supported Amazon marketplace. Minimum length: 1. Maximum length: 2000. Format: uri. Pattern: ^https://. - **`limit` integer Optional** Maximum results in this response. Default: 25. Minimum: 1. Maximum: 100. - **`asin` string Optional** Amazon product ASIN. Pattern: ^[a-zA-Z0-9]{10}$. - **`condition` string Optional** Filter by an allowed product condition. Default: "all". Allowed: "all", "new", "used", "renewed". - **`cursor` string Optional** next_cursor from a prior response using the same filters and marketplace. Maximum length: 131072. - **`marketplace` string Optional** Amazon marketplace. Defaults to the product URL's marketplace, or amazon.com. Allowed: "amazon.com", "amazon.co.uk", "amazon.ca", "amazon.de", "amazon.fr", "amazon.it", "amazon.es", "amazon.co.jp", "amazon.in", "amazon.com.au". - **`page` integer Optional** Starting upstream page. Prefer cursor to retain unused results and avoid duplicates. Minimum: 1. Maximum: 1000. - **`postal_code` string Optional** Delivery postal code. The request fails if Amazon cannot apply it; responses include the displayed delivery location. Minimum length: 2. Maximum length: 16. Pattern: ^[a-zA-Z0-9][a-zA-Z0-9 -]+$. ## 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": [ "marketplace", "delivery_location", "asin", "total_offers" ], "properties": { "asin": { "type": "string" }, "marketplace": { "enum": [ "amazon.com", "amazon.co.uk", "amazon.ca", "amazon.de", "amazon.fr", "amazon.it", "amazon.es", "amazon.co.jp", "amazon.in", "amazon.com.au" ], "type": "string" }, "total_offers": { "type": [ "integer", "null" ] }, "delivery_location": { "type": "object", "required": [ "postal_code", "applied", "displayed" ], "properties": { "applied": { "type": "boolean" }, "displayed": { "type": [ "string", "null" ] }, "postal_code": { "type": [ "string", "null" ] } }, "additionalProperties": false } }, "additionalProperties": false }, "count": { "type": "integer", "minimum": 0 }, "query": { "type": [ "string", "null" ] }, "source": { "const": "amazon-product-offers" }, "results": { "type": "array", "items": { "type": "object", "required": [ "id", "asin", "seller_id", "seller_name", "seller_url", "ships_from", "condition", "condition_notes", "price", "price_amount", "price_currency", "shipping_price", "shipping_amount", "shipping_text", "total_amount", "is_featured_offer", "seller_rating_text", "marketplace" ], "properties": { "id": { "type": "string" }, "asin": { "type": "string" }, "price": { "type": [ "string", "null" ] }, "condition": { "type": [ "string", "null" ] }, "seller_id": { "type": [ "string", "null" ] }, "seller_url": { "type": [ "string", "null" ] }, "ships_from": { "type": [ "string", "null" ] }, "marketplace": { "enum": [ "amazon.com", "amazon.co.uk", "amazon.ca", "amazon.de", "amazon.fr", "amazon.it", "amazon.es", "amazon.co.jp", "amazon.in", "amazon.com.au" ], "type": "string" }, "seller_name": { "type": [ "string", "null" ] }, "price_amount": { "type": [ "string", "null" ], "description": "Decimal amount in the marketplace currency, without grouping separators; null when unavailable." }, "total_amount": { "type": [ "string", "null" ] }, "shipping_text": { "type": [ "string", "null" ] }, "price_currency": { "type": [ "string", "null" ] }, "shipping_price": { "type": [ "string", "null" ] }, "condition_notes": { "type": [ "string", "null" ] }, "shipping_amount": { "type": [ "string", "null" ] }, "is_featured_offer": { "type": "boolean" }, "seller_rating_text": { "type": [ "string", "null" ] } }, "additionalProperties": false } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer", "minimum": 0 }, "cursor": { "type": [ "string", "null" ] }, "strategy": { "enum": [ "none", "cursor" ], "type": "string" }, "next_cursor": { "type": [ "string", "null" ] }, "has_next_page": { "type": "boolean" } }, "additionalProperties": false }, "max_results_requested": { "type": "integer", "minimum": 1 } }, "additionalProperties": false } ``` ### View a polled run response ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "amazon-product-offers", "task_name": "Amazon Product Offers API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": { "asin": "sample", "marketplace": "amazon.com", "total_offers": 180, "delivery_location": { "applied": true, "displayed": "sample", "postal_code": "sample" } }, "count": 1, "query": "London", "source": "amazon-product-offers", "results": [ { "id": "id-1", "asin": "sample", "price": "180", "condition": "sample", "seller_id": "id-1", "seller_url": "https://example.com/item-1", "ships_from": "sample", "marketplace": "amazon.com", "seller_name": "Stylish Shoreditch Loft with Balcony", "price_amount": "180", "total_amount": "180", "shipping_text": "Sample shipping_text 1", "price_currency": "GBP", "shipping_price": "180", "condition_notes": "sample", "shipping_amount": "180", "is_featured_offer": true, "seller_rating_text": "4.91 · 128 reviews" } ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "none", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/product/offers" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.amazon.com/dp/B0C3HCD34R"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/product/offers", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.amazon.com/dp/B0C3HCD34R" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/product/offers", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.amazon.com/dp/B0C3HCD34R" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/product/offers" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.amazon.com/dp/B0C3HCD34R","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/product/offers", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.amazon.com/dp/B0C3HCD34R", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/product/offers", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.amazon.com/dp/B0C3HCD34R", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/amazon-product-offers/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/product/offers" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.amazon.com/dp/B0C3HCD34R","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/product/offers", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.amazon.com/dp/B0C3HCD34R", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/product/offers", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.amazon.com/dp/B0C3HCD34R", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "amazon-product-offers", "task_name": "Amazon Product Offers API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": { "asin": "sample", "marketplace": "amazon.com", "total_offers": 180, "delivery_location": { "applied": true, "displayed": "sample", "postal_code": "sample" } }, "count": 1, "query": "London", "source": "amazon-product-offers", "results": [ { "id": "id-1", "asin": "sample", "price": "180", "condition": "sample", "seller_id": "id-1", "seller_url": "https://example.com/item-1", "ships_from": "sample", "marketplace": "amazon.com", "seller_name": "Stylish Shoreditch Loft with Balcony", "price_amount": "180", "total_amount": "180", "shipping_text": "Sample shipping_text 1", "price_currency": "GBP", "shipping_price": "180", "condition_notes": "sample", "shipping_amount": "180", "is_featured_offer": true, "seller_rating_text": "4.91 · 128 reviews" } ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "none", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-amazon-product-offers [Amazon APIs](/docs/api.md#amazon) # Amazon Reviews POST `/v1/amazon/product/reviews` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) **Connected website account required** Requires a connected amazon.com account. Browsable automatically uses a saved connection on your team when one is available. If none is available, HTTP `428` includes a `hosted_url`. Complete sign-in there, then retry. [Connect an account →](/docs/api/website-logins.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`url` string Optional** Amazon product URL (alternative to ASIN) Minimum length: 1. Maximum length: 2000. - **`limit` integer Optional** Maximum number of reviews to scrape (omit for all reviews) Preferred name; maxReviews remains supported. - **`asin` string Optional** Amazon product ASIN (10-character alphanumeric code) - **`domain` string Optional** Amazon domain (e.g., amazon.com, amazon.co.uk) Default: "amazon.com". ### Advanced & compatibility inputs 1 - **`maxReviews` integer Optional** Maximum number of reviews to scrape (omit for all reviews) You can also use limit. ## 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": [ "results", "count" ], "properties": { "count": { "type": "integer" }, "results": { "type": "array", "items": { "type": "object", "properties": { "date": { "type": [ "string", "null" ] }, "title": { "type": [ "string", "null" ] }, "avatar": { "type": [ "string", "null" ] }, "images": { "type": "array", "items": { "type": "string" } }, "rating": { "type": [ "number", "null" ] }, "content": { "type": [ "string", "null" ] }, "location": { "type": [ "string", "null" ] }, "username": { "type": [ "string", "null" ] }, "styleName": { "type": [ "string", "null" ] }, "helpfulCount": { "type": [ "integer", "null" ] }, "verifiedPurchase": { "type": "boolean" } } } } } } ``` ### View a polled run response ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "amazon-product-reviews", "task_name": "Amazon Reviews", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "count": 1, "results": [ { "date": "sample", "title": "Stylish Shoreditch Loft with Balcony", "avatar": "https://images.example.com/avatar-1.jpg", "images": [ "https://images.example.com/images-1.jpg" ], "rating": 4.91, "content": "Sample content 1", "location": "London", "username": "Stylish Shoreditch Loft with Balcony", "styleName": "Stylish Shoreditch Loft with Balcony", "helpfulCount": 1, "verifiedPurchase": true } ] }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/product/reviews" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/product/reviews", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({}), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/product/reviews", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={}, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/product/reviews" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/product/reviews", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/product/reviews", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/amazon-product-reviews/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/product/reviews" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/product/reviews", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/product/reviews", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "amazon-product-reviews", "task_name": "Amazon Reviews", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "count": 1, "results": [ { "date": "sample", "title": "Stylish Shoreditch Loft with Balcony", "avatar": "https://images.example.com/avatar-1.jpg", "images": [ "https://images.example.com/images-1.jpg" ], "rating": 4.91, "content": "Sample content 1", "location": "London", "username": "Stylish Shoreditch Loft with Balcony", "styleName": "Stylish Shoreditch Loft with Balcony", "helpfulCount": 1, "verifiedPurchase": true } ] }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-amazon-product-reviews [Amazon APIs](/docs/api.md#amazon) # Amazon Product Variations API List related child ASINs and their size, colour and style attributes. Set include_details to fetch each variant's current price and availability (maximum 10 per request). Without it, only the selected variant has product details. Costs 10 credits. No Amazon sign-in required. Prices and availability reflect the marketplace and delivery location; unavailable fields are null. POST `/v1/amazon/product/variations` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. Provide at least one of: asin; url. - **`url` string Optional** Product URL on a supported Amazon marketplace. Minimum length: 1. Maximum length: 2000. Format: uri. Pattern: ^https://. - **`limit` integer Optional** Maximum results in this response. Default: 25. Minimum: 1. Maximum: 100. - **`asin` string Optional** Amazon product ASIN. Pattern: ^[a-zA-Z0-9]{10}$. - **`cursor` string Optional** next_cursor from a prior response using the same filters and marketplace. Maximum length: 131072. - **`include_details` boolean Optional** Include price and availability details for variants; limited to 10 variants per request. Default: false. - **`marketplace` string Optional** Amazon marketplace. Defaults to the product URL's marketplace, or amazon.com. Allowed: "amazon.com", "amazon.co.uk", "amazon.ca", "amazon.de", "amazon.fr", "amazon.it", "amazon.es", "amazon.co.jp", "amazon.in", "amazon.com.au". - **`page` integer Optional** Starting upstream page. Prefer cursor to retain unused results and avoid duplicates. Minimum: 1. Maximum: 1000. - **`postal_code` string Optional** Delivery postal code. The request fails if Amazon cannot apply it; responses include the displayed delivery location. Minimum length: 2. Maximum length: 16. Pattern: ^[a-zA-Z0-9][a-zA-Z0-9 -]+$. ## 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": [ "marketplace", "delivery_location", "parent_asin", "dimensions", "has_variations", "total_variations", "errors" ], "properties": { "errors": { "type": "array", "items": { "type": "object", "required": [ "asin", "message" ], "properties": { "asin": { "type": "string" }, "message": { "type": "string" } }, "additionalProperties": false } }, "dimensions": { "type": "array", "items": { "type": "string" } }, "marketplace": { "enum": [ "amazon.com", "amazon.co.uk", "amazon.ca", "amazon.de", "amazon.fr", "amazon.it", "amazon.es", "amazon.co.jp", "amazon.in", "amazon.com.au" ], "type": "string" }, "parent_asin": { "type": [ "string", "null" ] }, "has_variations": { "type": "boolean" }, "total_variations": { "type": "integer", "minimum": 0 }, "delivery_location": { "type": "object", "required": [ "postal_code", "applied", "displayed" ], "properties": { "applied": { "type": "boolean" }, "displayed": { "type": [ "string", "null" ] }, "postal_code": { "type": [ "string", "null" ] } }, "additionalProperties": false } }, "additionalProperties": false }, "count": { "type": "integer", "minimum": 0 }, "query": { "type": [ "string", "null" ] }, "source": { "const": "amazon-product-variations" }, "results": { "type": "array", "items": { "type": "object", "required": [ "id", "asin", "url", "parent_asin", "attributes", "is_selected", "title", "price", "price_amount", "price_currency", "availability", "image_url" ], "properties": { "id": { "type": "string" }, "url": { "type": "string" }, "asin": { "type": "string" }, "price": { "type": [ "string", "null" ] }, "title": { "type": [ "string", "null" ] }, "image_url": { "type": [ "string", "null" ] }, "attributes": { "type": "object", "additionalProperties": { "type": "string" } }, "is_selected": { "type": "boolean" }, "parent_asin": { "type": [ "string", "null" ] }, "availability": { "type": [ "string", "null" ] }, "price_amount": { "type": [ "string", "null" ], "description": "Decimal amount in the marketplace currency, without grouping separators; null when unavailable." }, "price_currency": { "type": [ "string", "null" ] } }, "additionalProperties": false } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer", "minimum": 0 }, "cursor": { "type": [ "string", "null" ] }, "strategy": { "enum": [ "none", "cursor" ], "type": "string" }, "next_cursor": { "type": [ "string", "null" ] }, "has_next_page": { "type": "boolean" } }, "additionalProperties": false }, "max_results_requested": { "type": "integer", "minimum": 1 } }, "additionalProperties": false } ``` ### View a polled run response ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "amazon-product-variations", "task_name": "Amazon Product Variations API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": { "errors": [ { "asin": "sample", "message": "sample" } ], "dimensions": [ "sample" ], "marketplace": "amazon.com", "parent_asin": "180", "has_variations": true, "total_variations": 180, "delivery_location": { "applied": true, "displayed": "sample", "postal_code": "sample" } }, "count": 1, "query": "London", "source": "amazon-product-variations", "results": [ { "id": "id-1", "url": "https://example.com/item-1", "asin": "sample", "price": "180", "title": "Stylish Shoreditch Loft with Balcony", "image_url": "https://example.com/item-1", "attributes": {}, "is_selected": true, "parent_asin": "180", "availability": "sample", "price_amount": "180", "price_currency": "GBP" } ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "none", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/product/variations" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.amazon.com/dp/B0C3HCD34R"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/product/variations", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.amazon.com/dp/B0C3HCD34R" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/product/variations", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.amazon.com/dp/B0C3HCD34R" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/product/variations" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.amazon.com/dp/B0C3HCD34R","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/product/variations", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.amazon.com/dp/B0C3HCD34R", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/product/variations", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.amazon.com/dp/B0C3HCD34R", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/amazon-product-variations/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/product/variations" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.amazon.com/dp/B0C3HCD34R","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/product/variations", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.amazon.com/dp/B0C3HCD34R", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/product/variations", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.amazon.com/dp/B0C3HCD34R", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "amazon-product-variations", "task_name": "Amazon Product Variations API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": { "errors": [ { "asin": "sample", "message": "sample" } ], "dimensions": [ "sample" ], "marketplace": "amazon.com", "parent_asin": "180", "has_variations": true, "total_variations": 180, "delivery_location": { "applied": true, "displayed": "sample", "postal_code": "sample" } }, "count": 1, "query": "London", "source": "amazon-product-variations", "results": [ { "id": "id-1", "url": "https://example.com/item-1", "asin": "sample", "price": "180", "title": "Stylish Shoreditch Loft with Balcony", "image_url": "https://example.com/item-1", "attributes": {}, "is_selected": true, "parent_asin": "180", "availability": "sample", "price_amount": "180", "price_currency": "GBP" } ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "none", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-amazon-product-variations [Amazon APIs](/docs/api.md#amazon) # Amazon Products Batch API Fetch up to 10 products by ASIN. Duplicate ASINs are fetched once. Partial batches include per-product errors; all-failed batches fail. Costs 10 credits. No Amazon sign-in required. Prices and availability reflect the marketplace and delivery location; unavailable fields are null. POST `/v1/amazon/products/batch` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`asins` array Required** Between 1 and 10 Amazon product ASINs. Each ASIN has 10 letters or digits. Errors are reported per product. Minimum items: 1. Maximum items: 10. - **`marketplace` string Optional** Amazon marketplace. Defaults to the product URL's marketplace, or amazon.com. Allowed: "amazon.com", "amazon.co.uk", "amazon.ca", "amazon.de", "amazon.fr", "amazon.it", "amazon.es", "amazon.co.jp", "amazon.in", "amazon.com.au". - **`postal_code` string Optional** Delivery postal code. The request fails if Amazon cannot apply it; responses include the displayed delivery location. Minimum length: 2. Maximum length: 16. Pattern: ^[a-zA-Z0-9][a-zA-Z0-9 -]+$. ## 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": [ "marketplace", "delivery_location", "requested", "succeeded", "failed", "errors" ], "properties": { "errors": { "type": "array", "items": { "type": "object", "required": [ "asin", "code", "message" ], "properties": { "asin": { "type": "string" }, "code": { "type": "string" }, "message": { "type": "string" } }, "additionalProperties": false } }, "failed": { "type": "integer", "minimum": 0 }, "requested": { "type": "integer", "minimum": 0 }, "succeeded": { "type": "integer", "minimum": 0 }, "marketplace": { "enum": [ "amazon.com", "amazon.co.uk", "amazon.ca", "amazon.de", "amazon.fr", "amazon.it", "amazon.es", "amazon.co.jp", "amazon.in", "amazon.com.au" ], "type": "string" }, "delivery_location": { "type": "object", "required": [ "postal_code", "applied", "displayed" ], "properties": { "applied": { "type": "boolean" }, "displayed": { "type": [ "string", "null" ] }, "postal_code": { "type": [ "string", "null" ] } }, "additionalProperties": false } }, "additionalProperties": false }, "count": { "type": "integer", "minimum": 0 }, "query": { "type": [ "string", "null" ] }, "source": { "const": "amazon-products-batch" }, "results": { "type": "array", "items": { "type": "object", "required": [ "id", "asin", "url", "title", "description", "price", "price_amount", "price_currency", "availability", "availability_text", "rating", "review_count", "image_url", "image_urls", "details", "marketplace", "delivery_location" ], "properties": { "id": { "type": "string" }, "url": { "type": "string" }, "asin": { "type": "string" }, "price": { "type": [ "string", "null" ] }, "title": { "type": "string" }, "rating": { "type": [ "number", "null" ] }, "details": { "type": "object", "additionalProperties": { "type": "string" } }, "image_url": { "type": [ "string", "null" ] }, "image_urls": { "type": "array", "items": { "type": "string" } }, "description": { "type": [ "string", "null" ] }, "marketplace": { "enum": [ "amazon.com", "amazon.co.uk", "amazon.ca", "amazon.de", "amazon.fr", "amazon.it", "amazon.es", "amazon.co.jp", "amazon.in", "amazon.com.au" ], "type": "string" }, "availability": { "type": [ "string", "null" ] }, "price_amount": { "type": [ "string", "null" ], "description": "Decimal amount in the marketplace currency, without grouping separators; null when unavailable." }, "review_count": { "type": [ "integer", "null" ] }, "price_currency": { "type": [ "string", "null" ] }, "availability_text": { "type": [ "string", "null" ] }, "delivery_location": { "type": "object", "required": [ "postal_code", "applied", "displayed" ], "properties": { "applied": { "type": "boolean" }, "displayed": { "type": [ "string", "null" ] }, "postal_code": { "type": [ "string", "null" ] } }, "additionalProperties": false } }, "additionalProperties": false } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer", "minimum": 0 }, "cursor": { "type": [ "string", "null" ] }, "strategy": { "enum": [ "none", "cursor" ], "type": "string" }, "next_cursor": { "type": [ "string", "null" ] }, "has_next_page": { "type": "boolean" } }, "additionalProperties": false }, "max_results_requested": { "type": "integer", "minimum": 1 } }, "additionalProperties": false } ``` ### View a polled run response ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "amazon-products-batch", "task_name": "Amazon Products Batch API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": { "errors": [ { "asin": "sample", "code": "sample", "message": "sample" } ], "failed": 1, "requested": 1, "succeeded": 1, "marketplace": "amazon.com", "delivery_location": { "applied": true, "displayed": "sample", "postal_code": "sample" } }, "count": 1, "query": "London", "source": "amazon-products-batch", "results": [ { "id": "id-1", "url": "https://example.com/item-1", "asin": "sample", "price": "180", "title": "Stylish Shoreditch Loft with Balcony", "rating": 4.91, "details": {}, "image_url": "https://example.com/item-1", "image_urls": [ "https://images.example.com/image_urls-1.jpg" ], "description": "Sample description 1", "marketplace": "amazon.com", "availability": "sample", "price_amount": "180", "review_count": 1, "price_currency": "GBP", "availability_text": "Sample availability_text 1", "delivery_location": { "applied": true, "displayed": "sample", "postal_code": "sample" } } ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "none", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/products/batch" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"asins":["B0C3HCD34R","B085DV8T75"]}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/products/batch", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "asins": [ "B0C3HCD34R", "B085DV8T75" ] }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/products/batch", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "asins": [ "B0C3HCD34R", "B085DV8T75" ] }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/products/batch" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"asins":["B0C3HCD34R","B085DV8T75"],"_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/products/batch", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "asins": [ "B0C3HCD34R", "B085DV8T75" ], "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/products/batch", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "asins": [ "B0C3HCD34R", "B085DV8T75" ], "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/amazon-products-batch/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/products/batch" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"asins":["B0C3HCD34R","B085DV8T75"],"_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/products/batch", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "asins": [ "B0C3HCD34R", "B085DV8T75" ], "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/products/batch", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "asins": [ "B0C3HCD34R", "B085DV8T75" ], "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "amazon-products-batch", "task_name": "Amazon Products Batch API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": { "errors": [ { "asin": "sample", "code": "sample", "message": "sample" } ], "failed": 1, "requested": 1, "succeeded": 1, "marketplace": "amazon.com", "delivery_location": { "applied": true, "displayed": "sample", "postal_code": "sample" } }, "count": 1, "query": "London", "source": "amazon-products-batch", "results": [ { "id": "id-1", "url": "https://example.com/item-1", "asin": "sample", "price": "180", "title": "Stylish Shoreditch Loft with Balcony", "rating": 4.91, "details": {}, "image_url": "https://example.com/item-1", "image_urls": [ "https://images.example.com/image_urls-1.jpg" ], "description": "Sample description 1", "marketplace": "amazon.com", "availability": "sample", "price_amount": "180", "review_count": 1, "price_currency": "GBP", "availability_text": "Sample availability_text 1", "delivery_location": { "applied": true, "displayed": "sample", "postal_code": "sample" } } ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "none", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-amazon-products-batch [Amazon APIs](/docs/api.md#amazon) # Amazon Search API Search Amazon products with price, rating, brand and category filters, sorting, and continuation cursors. No Amazon sign-in required. Prices and availability reflect the marketplace and delivery location; unavailable fields are null. POST `/v1/amazon/search` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`query` string Required** Search text. Minimum length: 1. Maximum length: 500. - **`limit` integer Optional** Maximum results in this response. Default: 100. Minimum: 1. Maximum: 100. - **`brand` string Optional** Single brand name. Minimum length: 1. Maximum length: 100. Pattern: ^[^:,]+$. - **`category` string Optional** Department such as electronics, kitchen, books, beauty or pet supplies. Unsupported departments fail explicitly. Minimum length: 1. Maximum length: 100. - **`cursor` string Optional** next_cursor from a prior response using the same filters and marketplace. Maximum length: 131072. - **`domain` string Optional** Compatibility alias for marketplace. Allowed: "amazon.com", "amazon.co.uk", "amazon.ca", "amazon.de", "amazon.fr", "amazon.it", "amazon.es", "amazon.co.jp", "amazon.in", "amazon.com.au". - **`marketplace` string Optional** Amazon marketplace. Defaults to the product URL's marketplace, or amazon.com. Allowed: "amazon.com", "amazon.co.uk", "amazon.ca", "amazon.de", "amazon.fr", "amazon.it", "amazon.es", "amazon.co.jp", "amazon.in", "amazon.com.au". - **`max_price` number Optional** Maximum item price in the marketplace currency. Minimum: 0. - **`maxResults` integer Optional** Compatibility alias for limit. Minimum: 1. Maximum: 100. - **`min_price` number Optional** Minimum item price in the marketplace currency. Minimum: 0. - **`min_rating` integer Optional** Minimum product star rating. Allowed: 1, 2, 3, 4. - **`page` integer Optional** Starting upstream page. Prefer cursor to retain unused results and avoid duplicates. Minimum: 1. Maximum: 1000. - **`postal_code` string Optional** Delivery postal code. The request fails if Amazon cannot apply it; responses include the displayed delivery location. Minimum length: 2. Maximum length: 16. Pattern: ^[a-zA-Z0-9][a-zA-Z0-9 -]+$. - **`sort` string Optional** Sort order. Choose an allowed value below. Default: "relevance". Allowed: "relevance", "price_asc", "price_desc", "rating", "newest". ### Advanced & compatibility inputs 1 - **`category_id` string Optional** Amazon browse node ID for a more specific category. Pattern: ^[0-9]{1,20}$. ## 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": [ "marketplace", "delivery_location" ], "properties": { "notice": { "type": "string" }, "marketplace": { "enum": [ "amazon.com", "amazon.co.uk", "amazon.ca", "amazon.de", "amazon.fr", "amazon.it", "amazon.es", "amazon.co.jp", "amazon.in", "amazon.com.au" ], "type": "string" }, "delivery_location": { "type": "object", "required": [ "postal_code", "applied", "displayed" ], "properties": { "applied": { "type": "boolean" }, "displayed": { "type": [ "string", "null" ] }, "postal_code": { "type": [ "string", "null" ] } }, "additionalProperties": false } }, "additionalProperties": false }, "count": { "type": "integer", "minimum": 0 }, "query": { "type": [ "string", "null" ] }, "source": { "const": "amazon-search" }, "results": { "type": "array", "items": { "type": "object", "required": [ "id", "asin", "title", "url", "price", "price_amount", "price_currency", "list_price", "rating", "image_url", "deal_badge", "rank", "sales_rank", "previous_sales_rank", "rank_change_percent", "is_sponsored", "name", "link", "images", "tags", "numberOfReviews" ], "properties": { "id": { "type": "string" }, "url": { "type": "string" }, "asin": { "type": "string" }, "link": { "type": "string" }, "name": { "type": "string" }, "rank": { "type": [ "integer", "null" ] }, "tags": { "type": "array", "items": { "type": "string" } }, "price": { "type": [ "string", "null" ] }, "title": { "type": "string" }, "images": { "type": "array", "items": { "type": "string" } }, "rating": { "type": [ "number", "null" ] }, "image_url": { "type": [ "string", "null" ] }, "deal_badge": { "type": [ "string", "null" ] }, "list_price": { "type": [ "string", "null" ] }, "sales_rank": { "type": [ "integer", "null" ] }, "is_sponsored": { "type": "boolean" }, "price_amount": { "type": [ "string", "null" ], "description": "Decimal amount in the marketplace currency, without grouping separators; null when unavailable." }, "price_currency": { "type": [ "string", "null" ] }, "numberOfReviews": { "type": [ "integer", "null" ] }, "previous_sales_rank": { "type": [ "integer", "null" ] }, "rank_change_percent": { "type": [ "number", "null" ] } }, "additionalProperties": false } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer", "minimum": 0 }, "cursor": { "type": [ "string", "null" ] }, "strategy": { "enum": [ "none", "cursor" ], "type": "string" }, "next_cursor": { "type": [ "string", "null" ] }, "has_next_page": { "type": "boolean" } }, "additionalProperties": false }, "max_results_requested": { "type": "integer", "minimum": 1 } }, "additionalProperties": false } ``` ### View a polled run response ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "amazon-search", "task_name": "Amazon Search API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": { "notice": "sample", "marketplace": "amazon.com", "delivery_location": { "applied": true, "displayed": "sample", "postal_code": "sample" } }, "count": 1, "query": "London", "source": "amazon-search", "results": [ { "id": "id-1", "url": "https://example.com/item-1", "asin": "sample", "link": "https://example.com/item-1", "name": "Stylish Shoreditch Loft with Balcony", "rank": 1, "tags": [ "Featured" ], "price": "180", "title": "Stylish Shoreditch Loft with Balcony", "images": [ "https://images.example.com/images-1.jpg" ], "rating": 4.91, "image_url": "https://example.com/item-1", "deal_badge": "sample", "list_price": "180", "sales_rank": 1, "is_sponsored": true, "price_amount": "180", "price_currency": "GBP", "numberOfReviews": 1, "previous_sales_rank": 1, "rank_change_percent": 1.5 } ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "none", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"wireless headphones"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "wireless headphones" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "wireless headphones" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"wireless headphones","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "wireless headphones", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "wireless headphones", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/amazon-search/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"wireless headphones","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "wireless headphones", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "wireless headphones", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "amazon-search", "task_name": "Amazon Search API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": { "notice": "sample", "marketplace": "amazon.com", "delivery_location": { "applied": true, "displayed": "sample", "postal_code": "sample" } }, "count": 1, "query": "London", "source": "amazon-search", "results": [ { "id": "id-1", "url": "https://example.com/item-1", "asin": "sample", "link": "https://example.com/item-1", "name": "Stylish Shoreditch Loft with Balcony", "rank": 1, "tags": [ "Featured" ], "price": "180", "title": "Stylish Shoreditch Loft with Balcony", "images": [ "https://images.example.com/images-1.jpg" ], "rating": 4.91, "image_url": "https://example.com/item-1", "deal_badge": "sample", "list_price": "180", "sales_rank": 1, "is_sponsored": true, "price_amount": "180", "price_currency": "GBP", "numberOfReviews": 1, "previous_sales_rank": 1, "rank_change_percent": 1.5 } ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "none", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-amazon-search [Amazon APIs](/docs/api.md#amazon) # Amazon Seller Products API Browse a public seller's product catalogue by merchant ID, with optional search, filters, sorting and continuation cursors. No Amazon sign-in required. Prices and availability reflect the marketplace and delivery location; unavailable fields are null. POST `/v1/amazon/seller/products` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. Provide at least one of: seller_url; seller_id. - **`seller_url` string Optional** Public Amazon seller URL containing seller= or me=. The merchant ID and marketplace are resolved automatically. Minimum length: 1. Maximum length: 500. Format: uri. - **`query` string Optional** Search text. Minimum length: 1. Maximum length: 500. - **`limit` integer Optional** Maximum results in this response. Default: 25. Minimum: 1. Maximum: 100. - **`brand` string Optional** Single brand name. Minimum length: 1. Maximum length: 100. Pattern: ^[^:,]+$. - **`category` string Optional** Department such as electronics, kitchen, books, beauty or pet supplies. Unsupported departments fail explicitly. Minimum length: 1. Maximum length: 100. - **`cursor` string Optional** next_cursor from a prior response using the same filters and marketplace. Maximum length: 131072. - **`marketplace` string Optional** Amazon marketplace. Defaults to the product URL's marketplace, or amazon.com. Allowed: "amazon.com", "amazon.co.uk", "amazon.ca", "amazon.de", "amazon.fr", "amazon.it", "amazon.es", "amazon.co.jp", "amazon.in", "amazon.com.au". - **`max_price` number Optional** Maximum item price in the marketplace currency. Minimum: 0. - **`min_price` number Optional** Minimum item price in the marketplace currency. Minimum: 0. - **`min_rating` integer Optional** Minimum product star rating. Allowed: 1, 2, 3, 4. - **`page` integer Optional** Starting upstream page. Prefer cursor to retain unused results and avoid duplicates. Minimum: 1. Maximum: 1000. - **`postal_code` string Optional** Delivery postal code. The request fails if Amazon cannot apply it; responses include the displayed delivery location. Minimum length: 2. Maximum length: 16. Pattern: ^[a-zA-Z0-9][a-zA-Z0-9 -]+$. - **`sort` string Optional** Sort order. Choose an allowed value below. Default: "relevance". Allowed: "relevance", "price_asc", "price_desc", "rating", "newest". ### Advanced & compatibility inputs 2 - **`category_id` string Optional** Amazon browse node ID for a more specific category. Pattern: ^[0-9]{1,20}$. - **`seller_id` string Optional** Merchant ID from a public Amazon seller URL or product offer. Pattern: ^[A-Z0-9]{8,32}$. ## 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": [ "marketplace", "delivery_location" ], "properties": { "notice": { "type": "string" }, "marketplace": { "enum": [ "amazon.com", "amazon.co.uk", "amazon.ca", "amazon.de", "amazon.fr", "amazon.it", "amazon.es", "amazon.co.jp", "amazon.in", "amazon.com.au" ], "type": "string" }, "delivery_location": { "type": "object", "required": [ "postal_code", "applied", "displayed" ], "properties": { "applied": { "type": "boolean" }, "displayed": { "type": [ "string", "null" ] }, "postal_code": { "type": [ "string", "null" ] } }, "additionalProperties": false } }, "additionalProperties": false }, "count": { "type": "integer", "minimum": 0 }, "query": { "type": [ "string", "null" ] }, "source": { "const": "amazon-seller-products" }, "results": { "type": "array", "items": { "type": "object", "required": [ "id", "asin", "title", "url", "price", "price_amount", "price_currency", "list_price", "rating", "image_url", "deal_badge", "rank", "sales_rank", "previous_sales_rank", "rank_change_percent", "is_sponsored", "name", "link", "images", "tags", "numberOfReviews" ], "properties": { "id": { "type": "string" }, "url": { "type": "string" }, "asin": { "type": "string" }, "link": { "type": "string" }, "name": { "type": "string" }, "rank": { "type": [ "integer", "null" ] }, "tags": { "type": "array", "items": { "type": "string" } }, "price": { "type": [ "string", "null" ] }, "title": { "type": "string" }, "images": { "type": "array", "items": { "type": "string" } }, "rating": { "type": [ "number", "null" ] }, "image_url": { "type": [ "string", "null" ] }, "deal_badge": { "type": [ "string", "null" ] }, "list_price": { "type": [ "string", "null" ] }, "sales_rank": { "type": [ "integer", "null" ] }, "is_sponsored": { "type": "boolean" }, "price_amount": { "type": [ "string", "null" ], "description": "Decimal amount in the marketplace currency, without grouping separators; null when unavailable." }, "price_currency": { "type": [ "string", "null" ] }, "numberOfReviews": { "type": [ "integer", "null" ] }, "previous_sales_rank": { "type": [ "integer", "null" ] }, "rank_change_percent": { "type": [ "number", "null" ] } }, "additionalProperties": false } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer", "minimum": 0 }, "cursor": { "type": [ "string", "null" ] }, "strategy": { "enum": [ "none", "cursor" ], "type": "string" }, "next_cursor": { "type": [ "string", "null" ] }, "has_next_page": { "type": "boolean" } }, "additionalProperties": false }, "max_results_requested": { "type": "integer", "minimum": 1 } }, "additionalProperties": false } ``` ### View a polled run response ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "amazon-seller-products", "task_name": "Amazon Seller Products API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": { "notice": "sample", "marketplace": "amazon.com", "delivery_location": { "applied": true, "displayed": "sample", "postal_code": "sample" } }, "count": 1, "query": "London", "source": "amazon-seller-products", "results": [ { "id": "id-1", "url": "https://example.com/item-1", "asin": "sample", "link": "https://example.com/item-1", "name": "Stylish Shoreditch Loft with Balcony", "rank": 1, "tags": [ "Featured" ], "price": "180", "title": "Stylish Shoreditch Loft with Balcony", "images": [ "https://images.example.com/images-1.jpg" ], "rating": 4.91, "image_url": "https://example.com/item-1", "deal_badge": "sample", "list_price": "180", "sales_rank": 1, "is_sponsored": true, "price_amount": "180", "price_currency": "GBP", "numberOfReviews": 1, "previous_sales_rank": 1, "rank_change_percent": 1.5 } ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "none", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/seller/products" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"seller_url":"https://www.amazon.com/sp?seller=A294P4X9EWVXLJ"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/seller/products", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "seller_url": "https://www.amazon.com/sp?seller=A294P4X9EWVXLJ" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/seller/products", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "seller_url": "https://www.amazon.com/sp?seller=A294P4X9EWVXLJ" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/seller/products" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"seller_url":"https://www.amazon.com/sp?seller=A294P4X9EWVXLJ","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/seller/products", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "seller_url": "https://www.amazon.com/sp?seller=A294P4X9EWVXLJ", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/seller/products", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "seller_url": "https://www.amazon.com/sp?seller=A294P4X9EWVXLJ", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/amazon-seller-products/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/seller/products" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"seller_url":"https://www.amazon.com/sp?seller=A294P4X9EWVXLJ","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/seller/products", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "seller_url": "https://www.amazon.com/sp?seller=A294P4X9EWVXLJ", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/amazon/seller/products", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "seller_url": "https://www.amazon.com/sp?seller=A294P4X9EWVXLJ", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "amazon-seller-products", "task_name": "Amazon Seller Products API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": { "notice": "sample", "marketplace": "amazon.com", "delivery_location": { "applied": true, "displayed": "sample", "postal_code": "sample" } }, "count": 1, "query": "London", "source": "amazon-seller-products", "results": [ { "id": "id-1", "url": "https://example.com/item-1", "asin": "sample", "link": "https://example.com/item-1", "name": "Stylish Shoreditch Loft with Balcony", "rank": 1, "tags": [ "Featured" ], "price": "180", "title": "Stylish Shoreditch Loft with Balcony", "images": [ "https://images.example.com/images-1.jpg" ], "rating": 4.91, "image_url": "https://example.com/item-1", "deal_badge": "sample", "list_price": "180", "sales_rank": 1, "is_sponsored": true, "price_amount": "180", "price_currency": "GBP", "numberOfReviews": 1, "previous_sales_rank": 1, "rank_change_percent": 1.5 } ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "none", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-amazon-seller-products [Bandcamp APIs](/docs/api.md#bandcamp) # Bandcamp Page API Scrape a public Bandcamp artist, album, or track page. POST `/v1/bandcamp/page` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`url` string Required** URL returned by the matching search endpoint. Minimum length: 1. Maximum length: 2000. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "bandcamp-page", "task_name": "Bandcamp Page API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/bandcamp/page" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://artist.bandcamp.com/album/example"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/bandcamp/page", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://artist.bandcamp.com/album/example" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/bandcamp/page", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://artist.bandcamp.com/album/example" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/bandcamp/page" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://artist.bandcamp.com/album/example","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/bandcamp/page", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://artist.bandcamp.com/album/example", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/bandcamp/page", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://artist.bandcamp.com/album/example", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/bandcamp-page/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/bandcamp/page" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://artist.bandcamp.com/album/example","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/bandcamp/page", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://artist.bandcamp.com/album/example", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/bandcamp/page", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://artist.bandcamp.com/album/example", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "bandcamp-page", "task_name": "Bandcamp Page API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-bandcamp-page [Bandcamp APIs](/docs/api.md#bandcamp) # Bandcamp API Scrape public Bandcamp search results. POST `/v1/bandcamp/search` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`query` string Required** Search query. Minimum length: 1. Maximum length: 2000. - **`limit` integer Optional** Maximum number of results to return. Default: 25. Minimum: 1. Maximum: 100. - **`cursor` string Optional** Cursor returned as next_cursor from the previous response. - **`page` integer Optional** Page number for sources that support page-based pagination. Default: 1. Minimum: 1. Maximum: 10000. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "bandcamp-search", "task_name": "Bandcamp API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/bandcamp/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"ambient techno"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/bandcamp/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "ambient techno" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/bandcamp/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "ambient techno" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/bandcamp/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"ambient techno","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/bandcamp/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "ambient techno", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/bandcamp/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "ambient techno", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/bandcamp-search/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/bandcamp/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"ambient techno","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/bandcamp/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "ambient techno", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/bandcamp/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "ambient techno", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "bandcamp-search", "task_name": "Bandcamp API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-bandcamp-search [BBC News APIs](/docs/api.md#bbc-news) # BBC News Article API Scrape a public BBC article page. POST `/v1/bbc-news/article` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`url` string Required** URL returned by the matching search endpoint. Minimum length: 1. Maximum length: 2000. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "bbc-news-article", "task_name": "BBC News Article API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/bbc-news/article" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.bbc.com/news/articles/example"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/bbc-news/article", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.bbc.com/news/articles/example" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/bbc-news/article", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.bbc.com/news/articles/example" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/bbc-news/article" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.bbc.com/news/articles/example","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/bbc-news/article", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.bbc.com/news/articles/example", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/bbc-news/article", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.bbc.com/news/articles/example", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/bbc-news-article/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/bbc-news/article" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.bbc.com/news/articles/example","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/bbc-news/article", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.bbc.com/news/articles/example", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/bbc-news/article", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.bbc.com/news/articles/example", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "bbc-news-article", "task_name": "BBC News Article API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-bbc-news-article [BBC News APIs](/docs/api.md#bbc-news) # BBC News API Scrape public BBC search results. POST `/v1/bbc-news/search` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`query` string Required** Search query. Minimum length: 1. Maximum length: 2000. - **`limit` integer Optional** Maximum number of results to return. Default: 25. Minimum: 1. Maximum: 100. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "bbc-news-search", "task_name": "BBC News API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/bbc-news/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"climate policy"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/bbc-news/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "climate policy" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/bbc-news/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "climate policy" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/bbc-news/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"climate policy","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/bbc-news/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "climate policy", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/bbc-news/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "climate policy", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/bbc-news-search/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/bbc-news/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"climate policy","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/bbc-news/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "climate policy", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/bbc-news/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "climate policy", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "bbc-news-search", "task_name": "BBC News API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-bbc-news-search [Bluesky APIs](/docs/api.md#bluesky) # Bluesky Profile API Fetch a public Bluesky profile by handle, DID, or profile URL. POST `/v1/bluesky/profile` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`username` string Required** Bluesky handle or DID. Minimum length: 1. Maximum length: 2000. - **`limit` integer Optional** Maximum number of results to return. Default: 25. Minimum: 1. Maximum: 100. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "bluesky-profile", "task_name": "Bluesky Profile API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/bluesky/profile" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"username":"bsky.app"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/bluesky/profile", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "username": "bsky.app" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/bluesky/profile", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "username": "bsky.app" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/bluesky/profile" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"username":"bsky.app","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/bluesky/profile", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "username": "bsky.app", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/bluesky/profile", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "username": "bsky.app", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/bluesky-profile/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/bluesky/profile" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"username":"bsky.app","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/bluesky/profile", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "username": "bsky.app", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/bluesky/profile", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "username": "bsky.app", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "bluesky-profile", "task_name": "Bluesky Profile API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-bluesky-profile [Bluesky APIs](/docs/api.md#bluesky) # Bluesky API Search public Bluesky profiles through the public AppView API. POST `/v1/bluesky/search` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`query` string Required** Search query. Minimum length: 1. Maximum length: 2000. - **`limit` integer Optional** Maximum number of results to return. Default: 25. Minimum: 1. Maximum: 100. - **`cursor` string Optional** Cursor returned as next_cursor from the previous response. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "bluesky-search", "task_name": "Bluesky API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/bluesky/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"design"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/bluesky/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "design" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/bluesky/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "design" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/bluesky/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"design","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/bluesky/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "design", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/bluesky/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "design", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/bluesky-search/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/bluesky/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"design","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/bluesky/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "design", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/bluesky/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "design", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "bluesky-search", "task_name": "Bluesky API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-bluesky-search [Booking.com APIs](/docs/api.md#booking-com) # Booking.com Hotel API Scrape hotel details and dated room offers with occupancy, cancellation, meals, payment and tax text. Supply checkin, checkout, group_adults, group_children, no_rooms and selected_currency in the URL. Displayed prices may exclude taxes. Returns public discovery metadata; undated prices are not stay-specific quotes. This endpoint does not accept stay dates or occupancy; check a dated search on the source website for stay-specific prices. POST `/v1/booking/hotel` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`url` string Required** URL returned by the matching search endpoint. Minimum length: 1. Maximum length: 2000. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "type": "object", "properties": { "price": { "type": [ "string", "null" ] }, "currency": { "type": [ "string", "null" ] }, "price_basis": { "type": [ "string", "null" ] }, "price_value": { "type": [ "number", "null" ] }, "room_offers": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": [ "string", "null" ] }, "beds": { "type": [ "string", "null" ] }, "price": { "type": [ "string", "null" ] }, "taxes": { "type": [ "string", "null" ] }, "nights": { "type": [ "number", "null" ] }, "payment": { "type": [ "string", "null" ] }, "room_id": { "type": [ "string", "null" ] }, "capacity": { "type": [ "number", "null" ] }, "currency": { "type": [ "string", "null" ] }, "breakfast": { "type": [ "string", "null" ] }, "meal_plan": { "type": [ "string", "null" ] }, "occupancy": { "type": [ "string", "null" ] }, "room_name": { "type": [ "string", "null" ] }, "conditions": { "type": [ "string", "null" ] }, "refundable": { "type": [ "boolean", "null" ] }, "tax_status": { "type": [ "string", "null" ] }, "price_basis": { "type": [ "string", "null" ] }, "cancellation": { "type": [ "string", "null" ] }, "quote_source": { "type": [ "string", "null" ] }, "room_details": { "type": [ "object", "null" ], "properties": { "source": { "type": "string" }, "room_id": { "type": "string" }, "capacity": { "type": [ "number", "null" ] }, "facilities": { "type": "array", "items": { "type": "object" } }, "descriptions": {}, "room_area_m2": { "type": [ "number", "null" ] }, "bed_configurations": { "type": "array", "items": { "type": "object" } } } }, "source_total": { "type": [ "number", "null" ] }, "quote_room_id": { "type": [ "string", "null" ] }, "room_features": { "type": "array", "items": { "type": "string" } }, "hotel_currency": { "type": [ "string", "null" ] }, "policy_details": { "type": [ "string", "null" ] }, "quote_complete": { "type": "boolean" }, "quote_currency": { "type": [ "string", "null" ] }, "rate_is_genius": { "type": "boolean" }, "tax_exceptions": { "type": "array", "items": {} }, "displayed_total": { "type": [ "number", "null" ] }, "quote_room_name": { "type": [ "string", "null" ] }, "source_capacity": { "type": [ "number", "null" ] }, "source_subtotal": { "type": [ "number", "null" ] }, "excluded_charges": { "type": "array", "items": { "type": "object" } }, "included_charges": { "type": "array", "items": { "type": "object" } }, "optional_charges": { "type": "array", "items": { "type": "object" } }, "breakfast_included": { "type": [ "boolean", "null" ] }, "source_hotel_total": { "type": [ "number", "null" ] }, "conditional_charges": { "type": "array", "items": { "type": "object" } }, "max_selectable_rooms": { "type": [ "number", "null" ] }, "source_payment_terms": { "type": "object" }, "source_hotel_subtotal": { "type": [ "number", "null" ] }, "total_including_taxes": { "type": [ "number", "null" ] }, "matches_requested_stay": { "type": [ "boolean", "null" ] }, "observed_stay_verified": { "type": "boolean" }, "matches_requested_occupancy": { "type": [ "boolean", "null" ] } }, "additionalProperties": true } }, "observed_stay": { "type": "object", "properties": { "checkin": { "type": [ "string", "null" ] }, "checkout": { "type": [ "string", "null" ] } }, "additionalProperties": true }, "offers_status": { "type": [ "string", "null" ] }, "price_offer_id": { "type": [ "string", "null" ] }, "requested_stay": { "type": "object", "properties": { "rooms": { "type": [ "number", "null" ] }, "adults": { "type": [ "number", "null" ] }, "nights": { "type": [ "number", "null" ] }, "checkin": { "type": [ "string", "null" ] }, "checkout": { "type": [ "string", "null" ] }, "children": { "type": [ "number", "null" ] } }, "additionalProperties": true }, "room_details_status": { "type": [ "string", "null" ] }, "quote_display_currency": { "type": [ "string", "null" ] } }, "additionalProperties": true }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "properties": { "price": { "type": [ "string", "null" ] }, "currency": { "type": [ "string", "null" ] }, "price_basis": { "type": [ "string", "null" ] }, "price_value": { "type": [ "number", "null" ] }, "room_offers": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": [ "string", "null" ] }, "beds": { "type": [ "string", "null" ] }, "price": { "type": [ "string", "null" ] }, "taxes": { "type": [ "string", "null" ] }, "nights": { "type": [ "number", "null" ] }, "payment": { "type": [ "string", "null" ] }, "room_id": { "type": [ "string", "null" ] }, "capacity": { "type": [ "number", "null" ] }, "currency": { "type": [ "string", "null" ] }, "breakfast": { "type": [ "string", "null" ] }, "meal_plan": { "type": [ "string", "null" ] }, "occupancy": { "type": [ "string", "null" ] }, "room_name": { "type": [ "string", "null" ] }, "conditions": { "type": [ "string", "null" ] }, "refundable": { "type": [ "boolean", "null" ] }, "tax_status": { "type": [ "string", "null" ] }, "price_basis": { "type": [ "string", "null" ] }, "cancellation": { "type": [ "string", "null" ] }, "quote_source": { "type": [ "string", "null" ] }, "room_details": { "type": [ "object", "null" ], "properties": { "source": { "type": "string" }, "room_id": { "type": "string" }, "capacity": { "type": [ "number", "null" ] }, "facilities": { "type": "array", "items": { "type": "object" } }, "descriptions": {}, "room_area_m2": { "type": [ "number", "null" ] }, "bed_configurations": { "type": "array", "items": { "type": "object" } } } }, "source_total": { "type": [ "number", "null" ] }, "quote_room_id": { "type": [ "string", "null" ] }, "room_features": { "type": "array", "items": { "type": "string" } }, "hotel_currency": { "type": [ "string", "null" ] }, "policy_details": { "type": [ "string", "null" ] }, "quote_complete": { "type": "boolean" }, "quote_currency": { "type": [ "string", "null" ] }, "rate_is_genius": { "type": "boolean" }, "tax_exceptions": { "type": "array", "items": {} }, "displayed_total": { "type": [ "number", "null" ] }, "quote_room_name": { "type": [ "string", "null" ] }, "source_capacity": { "type": [ "number", "null" ] }, "source_subtotal": { "type": [ "number", "null" ] }, "excluded_charges": { "type": "array", "items": { "type": "object" } }, "included_charges": { "type": "array", "items": { "type": "object" } }, "optional_charges": { "type": "array", "items": { "type": "object" } }, "breakfast_included": { "type": [ "boolean", "null" ] }, "source_hotel_total": { "type": [ "number", "null" ] }, "conditional_charges": { "type": "array", "items": { "type": "object" } }, "max_selectable_rooms": { "type": [ "number", "null" ] }, "source_payment_terms": { "type": "object" }, "source_hotel_subtotal": { "type": [ "number", "null" ] }, "total_including_taxes": { "type": [ "number", "null" ] }, "matches_requested_stay": { "type": [ "boolean", "null" ] }, "observed_stay_verified": { "type": "boolean" }, "matches_requested_occupancy": { "type": [ "boolean", "null" ] } }, "additionalProperties": true } }, "observed_stay": { "type": "object", "properties": { "checkin": { "type": [ "string", "null" ] }, "checkout": { "type": [ "string", "null" ] } }, "additionalProperties": true }, "offers_status": { "type": [ "string", "null" ] }, "price_offer_id": { "type": [ "string", "null" ] }, "requested_stay": { "type": "object", "properties": { "rooms": { "type": [ "number", "null" ] }, "adults": { "type": [ "number", "null" ] }, "nights": { "type": [ "number", "null" ] }, "checkin": { "type": [ "string", "null" ] }, "checkout": { "type": [ "string", "null" ] }, "children": { "type": [ "number", "null" ] } }, "additionalProperties": true }, "room_details_status": { "type": [ "string", "null" ] }, "quote_display_currency": { "type": [ "string", "null" ] } }, "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "booking-hotel", "task_name": "Booking.com Hotel API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": { "price": "180", "currency": "USD", "price_basis": "180", "price_value": 180, "room_offers": [ { "id": "id-1", "beds": "sample", "price": "180", "taxes": "sample", "nights": 1.5, "payment": "sample", "room_id": "id-1", "capacity": 1.5, "currency": "USD", "breakfast": "sample", "meal_plan": "sample", "occupancy": "sample", "room_name": "Stylish Shoreditch Loft with Balcony", "conditions": "sample", "refundable": true, "tax_status": "sample", "price_basis": "180", "cancellation": "sample", "quote_source": "sample", "room_details": { "source": "sample", "room_id": "id-1", "capacity": 1.5, "facilities": [ {} ], "descriptions": "sample", "room_area_m2": 1.5, "bed_configurations": [ {} ] }, "source_total": 180, "quote_room_id": "id-1", "room_features": [ "sample" ], "hotel_currency": "USD", "policy_details": "2 guests", "quote_complete": true, "quote_currency": "USD", "rate_is_genius": true, "tax_exceptions": [ "sample" ], "displayed_total": 180, "quote_room_name": "Stylish Shoreditch Loft with Balcony", "source_capacity": 1.5, "source_subtotal": 180, "excluded_charges": [ {} ], "included_charges": [ {} ], "optional_charges": [ {} ], "breakfast_included": true, "source_hotel_total": 180, "conditional_charges": [ {} ], "max_selectable_rooms": 1.5, "source_payment_terms": {}, "source_hotel_subtotal": 180, "total_including_taxes": 180, "matches_requested_stay": true, "observed_stay_verified": true, "matches_requested_occupancy": true } ], "observed_stay": { "checkin": "2026-06-14", "checkout": "2026-06-21" }, "offers_status": "sample", "price_offer_id": "180", "requested_stay": { "rooms": 1.5, "adults": 1, "nights": 1.5, "checkin": "2026-06-14", "checkout": "2026-06-21", "children": 1 }, "room_details_status": "2 guests", "quote_display_currency": "USD" }, "count": 1, "query": "London", "source": "sample", "results": [ { "price": "180", "currency": "USD", "price_basis": "180", "price_value": 180, "room_offers": [ { "id": "id-1", "beds": "sample", "price": "180", "taxes": "sample", "nights": 1.5, "payment": "sample", "room_id": "id-1", "capacity": 1.5, "currency": "USD", "breakfast": "sample", "meal_plan": "sample", "occupancy": "sample", "room_name": "Stylish Shoreditch Loft with Balcony", "conditions": "sample", "refundable": true, "tax_status": "sample", "price_basis": "180", "cancellation": "sample", "quote_source": "sample", "room_details": { "source": "sample", "room_id": "id-1", "capacity": 1.5, "facilities": [ {} ], "descriptions": "sample", "room_area_m2": 1.5, "bed_configurations": [ {} ] }, "source_total": 180, "quote_room_id": "id-1", "room_features": [ "sample" ], "hotel_currency": "USD", "policy_details": "2 guests", "quote_complete": true, "quote_currency": "USD", "rate_is_genius": true, "tax_exceptions": [ "sample" ], "displayed_total": 180, "quote_room_name": "Stylish Shoreditch Loft with Balcony", "source_capacity": 1.5, "source_subtotal": 180, "excluded_charges": [ {} ], "included_charges": [ {} ], "optional_charges": [ {} ], "breakfast_included": true, "source_hotel_total": 180, "conditional_charges": [ {} ], "max_selectable_rooms": 1.5, "source_payment_terms": {}, "source_hotel_subtotal": 180, "total_including_taxes": 180, "matches_requested_stay": true, "observed_stay_verified": true, "matches_requested_occupancy": true } ], "observed_stay": { "checkin": "2026-06-14", "checkout": "2026-06-21" }, "offers_status": "sample", "price_offer_id": "180", "requested_stay": { "rooms": 1.5, "adults": 1, "nights": 1.5, "checkin": "2026-06-14", "checkout": "2026-06-21", "children": 1 }, "room_details_status": "2 guests", "quote_display_currency": "USD" } ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/booking/hotel" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.booking.com/hotel/gb/example.html"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/booking/hotel", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.booking.com/hotel/gb/example.html" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/booking/hotel", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.booking.com/hotel/gb/example.html" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/booking/hotel" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.booking.com/hotel/gb/example.html","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/booking/hotel", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.booking.com/hotel/gb/example.html", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/booking/hotel", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.booking.com/hotel/gb/example.html", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/booking-hotel/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/booking/hotel" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.booking.com/hotel/gb/example.html","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/booking/hotel", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.booking.com/hotel/gb/example.html", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/booking/hotel", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.booking.com/hotel/gb/example.html", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "booking-hotel", "task_name": "Booking.com Hotel API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": { "price": "180", "currency": "USD", "price_basis": "180", "price_value": 180, "room_offers": [ { "id": "id-1", "beds": "sample", "price": "180", "taxes": "sample", "nights": 1.5, "payment": "sample", "room_id": "id-1", "capacity": 1.5, "currency": "USD", "breakfast": "sample", "meal_plan": "sample", "occupancy": "sample", "room_name": "Stylish Shoreditch Loft with Balcony", "conditions": "sample", "refundable": true, "tax_status": "sample", "price_basis": "180", "cancellation": "sample", "quote_source": "sample", "room_details": { "source": "sample", "room_id": "id-1", "capacity": 1.5, "facilities": [ {} ], "descriptions": "sample", "room_area_m2": 1.5, "bed_configurations": [ {} ] }, "source_total": 180, "quote_room_id": "id-1", "room_features": [ "sample" ], "hotel_currency": "USD", "policy_details": "2 guests", "quote_complete": true, "quote_currency": "USD", "rate_is_genius": true, "tax_exceptions": [ "sample" ], "displayed_total": 180, "quote_room_name": "Stylish Shoreditch Loft with Balcony", "source_capacity": 1.5, "source_subtotal": 180, "excluded_charges": [ {} ], "included_charges": [ {} ], "optional_charges": [ {} ], "breakfast_included": true, "source_hotel_total": 180, "conditional_charges": [ {} ], "max_selectable_rooms": 1.5, "source_payment_terms": {}, "source_hotel_subtotal": 180, "total_including_taxes": 180, "matches_requested_stay": true, "observed_stay_verified": true, "matches_requested_occupancy": true } ], "observed_stay": { "checkin": "2026-06-14", "checkout": "2026-06-21" }, "offers_status": "sample", "price_offer_id": "180", "requested_stay": { "rooms": 1.5, "adults": 1, "nights": 1.5, "checkin": "2026-06-14", "checkout": "2026-06-21", "children": 1 }, "room_details_status": "2 guests", "quote_display_currency": "USD" }, "count": 1, "query": "London", "source": "sample", "results": [ { "price": "180", "currency": "USD", "price_basis": "180", "price_value": 180, "room_offers": [ { "id": "id-1", "beds": "sample", "price": "180", "taxes": "sample", "nights": 1.5, "payment": "sample", "room_id": "id-1", "capacity": 1.5, "currency": "USD", "breakfast": "sample", "meal_plan": "sample", "occupancy": "sample", "room_name": "Stylish Shoreditch Loft with Balcony", "conditions": "sample", "refundable": true, "tax_status": "sample", "price_basis": "180", "cancellation": "sample", "quote_source": "sample", "room_details": { "source": "sample", "room_id": "id-1", "capacity": 1.5, "facilities": [ {} ], "descriptions": "sample", "room_area_m2": 1.5, "bed_configurations": [ {} ] }, "source_total": 180, "quote_room_id": "id-1", "room_features": [ "sample" ], "hotel_currency": "USD", "policy_details": "2 guests", "quote_complete": true, "quote_currency": "USD", "rate_is_genius": true, "tax_exceptions": [ "sample" ], "displayed_total": 180, "quote_room_name": "Stylish Shoreditch Loft with Balcony", "source_capacity": 1.5, "source_subtotal": 180, "excluded_charges": [ {} ], "included_charges": [ {} ], "optional_charges": [ {} ], "breakfast_included": true, "source_hotel_total": 180, "conditional_charges": [ {} ], "max_selectable_rooms": 1.5, "source_payment_terms": {}, "source_hotel_subtotal": 180, "total_including_taxes": 180, "matches_requested_stay": true, "observed_stay_verified": true, "matches_requested_occupancy": true } ], "observed_stay": { "checkin": "2026-06-14", "checkout": "2026-06-21" }, "offers_status": "sample", "price_offer_id": "180", "requested_stay": { "rooms": 1.5, "adults": 1, "nights": 1.5, "checkin": "2026-06-14", "checkout": "2026-06-21", "children": 1 }, "room_details_status": "2 guests", "quote_display_currency": "USD" } ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-booking-hotel [Booking.com APIs](/docs/api.md#booking-com) # Booking.com API Scrape public Booking.com accommodation search results by destination. Returns public discovery metadata; undated prices are not stay-specific quotes. This endpoint does not accept stay dates or occupancy; check a dated search on the source website for stay-specific prices. POST `/v1/booking/search` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`query` string Required** Search query. Minimum length: 1. Maximum length: 2000. - **`limit` integer Optional** Maximum number of results to return. Default: 25. Minimum: 1. Maximum: 100. - **`cursor` string Optional** Cursor returned as next_cursor from the previous response. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "booking-search", "task_name": "Booking.com API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/booking/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/booking/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "London" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/booking/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "London" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/booking/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"London","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/booking/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "London", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/booking/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "London", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/booking-search/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/booking/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"London","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/booking/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "London", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/booking/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "London", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "booking-search", "task_name": "Booking.com API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-booking-search [Capterra APIs](/docs/api.md#capterra) # Capterra Product API Scrape a public Capterra product page. POST `/v1/capterra/product` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`url` string Required** URL returned by the matching search endpoint. Minimum length: 1. Maximum length: 2000. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "capterra-product", "task_name": "Capterra Product API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/capterra/product" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.capterra.com/p/123456/example/"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/capterra/product", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.capterra.com/p/123456/example/" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/capterra/product", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.capterra.com/p/123456/example/" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/capterra/product" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.capterra.com/p/123456/example/","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/capterra/product", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.capterra.com/p/123456/example/", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/capterra/product", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.capterra.com/p/123456/example/", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/capterra-product/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/capterra/product" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.capterra.com/p/123456/example/","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/capterra/product", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.capterra.com/p/123456/example/", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/capterra/product", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.capterra.com/p/123456/example/", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "capterra-product", "task_name": "Capterra Product API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-capterra-product [Capterra APIs](/docs/api.md#capterra) # Capterra API Scrape public Capterra software search results. POST `/v1/capterra/search` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`query` string Required** Search query. Minimum length: 1. Maximum length: 2000. - **`limit` integer Optional** Maximum number of results to return. Default: 25. Minimum: 1. Maximum: 100. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "capterra-search", "task_name": "Capterra API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/capterra/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"project management"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/capterra/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "project management" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/capterra/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "project management" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/capterra/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"project management","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/capterra/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "project management", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/capterra/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "project management", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/capterra-search/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/capterra/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"project management","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/capterra/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "project management", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/capterra/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "project management", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "capterra-search", "task_name": "Capterra API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-capterra-search [Costco APIs](/docs/api.md#costco) # Costco Product API Scrape a public Costco product detail page from a search result URL. POST `/v1/costco/product` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`url` string Required** Costco product URL returned by costco/search. Minimum length: 1. Maximum length: 2000. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "costco-product", "task_name": "Costco Product API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/costco/product" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.costco.com/example.product.1234567.html"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/costco/product", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.costco.com/example.product.1234567.html" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/costco/product", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.costco.com/example.product.1234567.html" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/costco/product" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.costco.com/example.product.1234567.html","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/costco/product", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.costco.com/example.product.1234567.html", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/costco/product", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.costco.com/example.product.1234567.html", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/costco-product/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/costco/product" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.costco.com/example.product.1234567.html","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/costco/product", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.costco.com/example.product.1234567.html", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/costco/product", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.costco.com/example.product.1234567.html", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "costco-product", "task_name": "Costco Product API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-costco-product [Costco APIs](/docs/api.md#costco) # Costco API Scrape public Costco search result pages by query. POST `/v1/costco/search` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`query` string Required** Search query. Minimum length: 1. Maximum length: 2000. - **`limit` integer Optional** Maximum number of results to return. Default: 25. Minimum: 1. Maximum: 100. - **`cursor` string Optional** Cursor returned as next_cursor from the previous response. - **`page` integer Optional** Page number for sources that support page-based pagination. Default: 1. Minimum: 1. Maximum: 10000. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "costco-search", "task_name": "Costco API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/costco/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"paper towels"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/costco/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "paper towels" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/costco/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "paper towels" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/costco/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"paper towels","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/costco/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "paper towels", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/costco/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "paper towels", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/costco-search/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/costco/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"paper towels","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/costco/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "paper towels", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/costco/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "paper towels", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "costco-search", "task_name": "Costco API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-costco-search [Craigslist APIs](/docs/api.md#craigslist) # Craigslist Post API Scrape a public Craigslist result detail page from a search result URL or post id. POST `/v1/craigslist/post` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. Provide at least one of: url; id. - **`url` string Optional** Craigslist result URL returned by craigslist/search. Minimum length: 1. Maximum length: 2000. - **`id` string Optional** Craigslist post id or search result id. URL is preferred when available. - **`site` string Optional** Craigslist subdomain to use when resolving an id without a URL. Default: "sfbay". ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "craigslist-post", "task_name": "Craigslist Post API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/craigslist/post" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://sfbay.craigslist.org/scz/tls/d/santa-cruz-electric-lawnmower/7933608346.html"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/craigslist/post", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://sfbay.craigslist.org/scz/tls/d/santa-cruz-electric-lawnmower/7933608346.html" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/craigslist/post", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://sfbay.craigslist.org/scz/tls/d/santa-cruz-electric-lawnmower/7933608346.html" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/craigslist/post" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://sfbay.craigslist.org/scz/tls/d/santa-cruz-electric-lawnmower/7933608346.html","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/craigslist/post", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://sfbay.craigslist.org/scz/tls/d/santa-cruz-electric-lawnmower/7933608346.html", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/craigslist/post", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://sfbay.craigslist.org/scz/tls/d/santa-cruz-electric-lawnmower/7933608346.html", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/craigslist-post/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/craigslist/post" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://sfbay.craigslist.org/scz/tls/d/santa-cruz-electric-lawnmower/7933608346.html","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/craigslist/post", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://sfbay.craigslist.org/scz/tls/d/santa-cruz-electric-lawnmower/7933608346.html", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/craigslist/post", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://sfbay.craigslist.org/scz/tls/d/santa-cruz-electric-lawnmower/7933608346.html", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "craigslist-post", "task_name": "Craigslist Post API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-craigslist-post [Craigslist APIs](/docs/api.md#craigslist) # Craigslist API Scrape public Craigslist search results by query and site with offset pagination. POST `/v1/craigslist/search` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. Provide at least one of: location; site. - **`query` string Required** Search query. Minimum length: 1. Maximum length: 2000. - **`location` string Optional** City or region name, such as San Francisco, CA or New York, NY. No region is assumed. Minimum length: 1. Maximum length: 500. - **`limit` integer Optional** Maximum number of results to return. Default: 25. Minimum: 1. Maximum: 100. - **`cursor` string Optional** Cursor returned as next_cursor from the previous response. ### Advanced & compatibility inputs 1 - **`site` string Optional** Advanced regional Craigslist subdomain, such as sfbay. Use location for a city name. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "craigslist-search", "task_name": "Craigslist API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/craigslist/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"lawnmower","location":"San Francisco, CA"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/craigslist/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "lawnmower", "location": "San Francisco, CA" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/craigslist/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "lawnmower", "location": "San Francisco, CA" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/craigslist/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"lawnmower","location":"San Francisco, CA","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/craigslist/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "lawnmower", "location": "San Francisco, CA", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/craigslist/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "lawnmower", "location": "San Francisco, CA", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/craigslist-search/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/craigslist/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"lawnmower","location":"San Francisco, CA","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/craigslist/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "lawnmower", "location": "San Francisco, CA", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/craigslist/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "lawnmower", "location": "San Francisco, CA", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "craigslist-search", "task_name": "Craigslist API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-craigslist-search [Crunchbase APIs](/docs/api.md#crunchbase) # Crunchbase Organization API Scrape a public Crunchbase organization profile. POST `/v1/crunchbase/organization` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`url` string Required** URL returned by the matching search endpoint. Minimum length: 1. Maximum length: 2000. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "crunchbase-organization", "task_name": "Crunchbase Organization API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/crunchbase/organization" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.crunchbase.com/organization/stripe"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/crunchbase/organization", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.crunchbase.com/organization/stripe" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/crunchbase/organization", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.crunchbase.com/organization/stripe" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/crunchbase/organization" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.crunchbase.com/organization/stripe","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/crunchbase/organization", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.crunchbase.com/organization/stripe", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/crunchbase/organization", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.crunchbase.com/organization/stripe", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/crunchbase-organization/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/crunchbase/organization" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.crunchbase.com/organization/stripe","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/crunchbase/organization", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.crunchbase.com/organization/stripe", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/crunchbase/organization", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.crunchbase.com/organization/stripe", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "crunchbase-organization", "task_name": "Crunchbase Organization API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-crunchbase-organization [Crunchbase APIs](/docs/api.md#crunchbase) # Crunchbase API Scrape public Crunchbase organization search results. POST `/v1/crunchbase/search` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`query` string Required** Search query. Minimum length: 1. Maximum length: 2000. - **`limit` integer Optional** Maximum number of results to return. Default: 25. Minimum: 1. Maximum: 100. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "crunchbase-search", "task_name": "Crunchbase API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/crunchbase/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"Stripe"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/crunchbase/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "Stripe" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/crunchbase/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "Stripe" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/crunchbase/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"Stripe","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/crunchbase/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "Stripe", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/crunchbase/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "Stripe", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/crunchbase-search/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/crunchbase/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"Stripe","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/crunchbase/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "Stripe", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/crunchbase/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "Stripe", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "crunchbase-search", "task_name": "Crunchbase API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-crunchbase-search [Depop APIs](/docs/api.md#depop) # Depop Listing API Scrape a public Depop product page. POST `/v1/depop/listing` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`url` string Required** URL returned by the matching search endpoint. Minimum length: 1. Maximum length: 2000. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "depop-listing", "task_name": "Depop Listing API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/depop/listing" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.depop.com/products/seller-example-item/"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/depop/listing", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.depop.com/products/seller-example-item/" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/depop/listing", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.depop.com/products/seller-example-item/" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/depop/listing" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.depop.com/products/seller-example-item/","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/depop/listing", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.depop.com/products/seller-example-item/", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/depop/listing", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.depop.com/products/seller-example-item/", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/depop-listing/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/depop/listing" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.depop.com/products/seller-example-item/","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/depop/listing", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.depop.com/products/seller-example-item/", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/depop/listing", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.depop.com/products/seller-example-item/", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "depop-listing", "task_name": "Depop Listing API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-depop-listing [Depop APIs](/docs/api.md#depop) # Depop API Scrape public Depop listing search results. POST `/v1/depop/search` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`query` string Required** Search query. Minimum length: 1. Maximum length: 2000. - **`limit` integer Optional** Maximum number of results to return. Default: 25. Minimum: 1. Maximum: 100. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "depop-search", "task_name": "Depop API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/depop/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"leather boots"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/depop/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "leather boots" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/depop/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "leather boots" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/depop/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"leather boots","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/depop/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "leather boots", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/depop/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "leather boots", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/depop-search/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/depop/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"leather boots","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/depop/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "leather boots", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/depop/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "leather boots", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "depop-search", "task_name": "Depop API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-depop-search [Discogs APIs](/docs/api.md#discogs) # Discogs Release API Scrape a public Discogs release, master, or artist page. POST `/v1/discogs/release` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`url` string Required** URL returned by the matching search endpoint. Minimum length: 1. Maximum length: 2000. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "discogs-release", "task_name": "Discogs Release API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/discogs/release" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.discogs.com/release/123456-example"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/discogs/release", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.discogs.com/release/123456-example" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/discogs/release", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.discogs.com/release/123456-example" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/discogs/release" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.discogs.com/release/123456-example","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/discogs/release", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.discogs.com/release/123456-example", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/discogs/release", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.discogs.com/release/123456-example", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/discogs-release/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/discogs/release" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.discogs.com/release/123456-example","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/discogs/release", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.discogs.com/release/123456-example", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/discogs/release", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.discogs.com/release/123456-example", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "discogs-release", "task_name": "Discogs Release API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-discogs-release [Discogs APIs](/docs/api.md#discogs) # Discogs API Scrape public Discogs marketplace and catalog search results. POST `/v1/discogs/search` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`query` string Required** Search query. Minimum length: 1. Maximum length: 2000. - **`limit` integer Optional** Maximum number of results to return. Default: 25. Minimum: 1. Maximum: 100. - **`cursor` string Optional** Cursor returned as next_cursor from the previous response. - **`page` integer Optional** Page number for sources that support page-based pagination. Default: 1. Minimum: 1. Maximum: 10000. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "discogs-search", "task_name": "Discogs API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/discogs/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"Miles Davis Kind of Blue"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/discogs/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "Miles Davis Kind of Blue" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/discogs/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "Miles Davis Kind of Blue" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/discogs/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"Miles Davis Kind of Blue","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/discogs/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "Miles Davis Kind of Blue", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/discogs/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "Miles Davis Kind of Blue", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/discogs-search/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/discogs/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"Miles Davis Kind of Blue","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/discogs/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "Miles Davis Kind of Blue", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/discogs/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "Miles Davis Kind of Blue", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "discogs-search", "task_name": "Discogs API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-discogs-search [eBay APIs](/docs/api.md#ebay) # eBay Item API Read the exact public ebay.com listing by item URL or id, including displayed price, condition, images and seller feedback. Listing sold counters are not a transaction history. eBay may restrict anonymous access. POST `/v1/ebay/item` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. Provide at least one of: url; id. - **`url` string Optional** HTTPS ebay.com item URL returned by search. Minimum length: 1. Maximum length: 2000. Pattern: ^https://(?:www\.)?ebay\.com/itm/(?:[^/?#]+/)?[0-9]{8,20}/?(?:[?#].*)?$. - **`id` string Optional** Numeric eBay item id returned by search. Older Browsable item ids remain supported. Pattern: ^(?:[0-9]{8,20}|(?:www-)?ebay-com-itm-(?:[a-zA-Z0-9-]+-)?[0-9]{8,20})$. - **`marketplace` string Optional** Public endpoints currently support ebay.com. Allowed: "ebay.com". ## 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": [ "id", "item_id", "variation_id", "url", "title", "price", "price_amount", "price_currency", "condition", "availability", "availability_text", "quantity_text", "sold_count_text", "watchers_text", "brand", "gtin13", "description", "image_url", "seller", "seller_url", "seller_positive_feedback", "shipping", "delivery", "returns", "payments", "location", "category", "sold_count", "watchers_count", "rating", "review_count", "seller_feedback_score", "image_urls", "breadcrumbs", "item_specifics", "shipping_cost" ], "properties": { "id": { "type": "string" }, "url": { "type": "string" }, "brand": { "type": [ "string", "null" ] }, "price": { "type": [ "string", "null" ] }, "title": { "type": "string" }, "gtin13": { "type": [ "string", "null" ] }, "rating": { "type": [ "number", "null" ] }, "seller": { "type": [ "string", "null" ] }, "item_id": { "type": "string" }, "returns": { "type": [ "string", "null" ] }, "category": { "type": [ "string", "null" ] }, "delivery": { "type": [ "string", "null" ] }, "location": { "type": [ "string", "null" ] }, "payments": { "type": [ "string", "null" ] }, "shipping": { "type": [ "string", "null" ] }, "condition": { "type": [ "string", "null" ] }, "image_url": { "type": [ "string", "null" ] }, "image_urls": { "type": "array", "items": { "type": "string" } }, "seller_url": { "type": [ "string", "null" ] }, "sold_count": { "type": [ "number", "null" ] }, "breadcrumbs": { "type": "array", "items": { "type": "string" } }, "description": { "type": [ "string", "null" ] }, "availability": { "type": [ "string", "null" ] }, "price_amount": { "type": [ "string", "null" ] }, "review_count": { "type": [ "number", "null" ] }, "variation_id": { "type": [ "string", "null" ] }, "quantity_text": { "type": [ "string", "null" ] }, "shipping_cost": { "anyOf": [ { "type": "null" }, { "type": "object", "required": [ "value", "currency" ], "properties": { "value": { "type": [ "string", "null" ] }, "currency": { "type": [ "string", "null" ] } }, "additionalProperties": false } ] }, "watchers_text": { "type": [ "string", "null" ] }, "item_specifics": { "type": "object", "additionalProperties": { "type": "string" } }, "price_currency": { "type": [ "string", "null" ] }, "watchers_count": { "type": [ "number", "null" ] }, "sold_count_text": { "type": [ "string", "null" ] }, "availability_text": { "type": [ "string", "null" ] }, "seller_description": { "type": [ "string", "null" ] }, "seller_feedback_score": { "type": [ "number", "null" ] }, "seller_positive_feedback": { "type": [ "string", "null" ] } }, "additionalProperties": false }, "count": { "type": "integer", "minimum": 0 }, "query": { "type": [ "string", "null" ] }, "source": { "const": "ebay-item" }, "results": { "type": "array", "items": { "type": "object", "required": [ "id", "item_id", "variation_id", "url", "title", "price", "price_amount", "price_currency", "condition", "availability", "availability_text", "quantity_text", "sold_count_text", "watchers_text", "brand", "gtin13", "description", "image_url", "seller", "seller_url", "seller_positive_feedback", "shipping", "delivery", "returns", "payments", "location", "category", "sold_count", "watchers_count", "rating", "review_count", "seller_feedback_score", "image_urls", "breadcrumbs", "item_specifics", "shipping_cost" ], "properties": { "id": { "type": "string" }, "url": { "type": "string" }, "brand": { "type": [ "string", "null" ] }, "price": { "type": [ "string", "null" ] }, "title": { "type": "string" }, "gtin13": { "type": [ "string", "null" ] }, "rating": { "type": [ "number", "null" ] }, "seller": { "type": [ "string", "null" ] }, "item_id": { "type": "string" }, "returns": { "type": [ "string", "null" ] }, "category": { "type": [ "string", "null" ] }, "delivery": { "type": [ "string", "null" ] }, "location": { "type": [ "string", "null" ] }, "payments": { "type": [ "string", "null" ] }, "shipping": { "type": [ "string", "null" ] }, "condition": { "type": [ "string", "null" ] }, "image_url": { "type": [ "string", "null" ] }, "image_urls": { "type": "array", "items": { "type": "string" } }, "seller_url": { "type": [ "string", "null" ] }, "sold_count": { "type": [ "number", "null" ] }, "breadcrumbs": { "type": "array", "items": { "type": "string" } }, "description": { "type": [ "string", "null" ] }, "availability": { "type": [ "string", "null" ] }, "price_amount": { "type": [ "string", "null" ] }, "review_count": { "type": [ "number", "null" ] }, "variation_id": { "type": [ "string", "null" ] }, "quantity_text": { "type": [ "string", "null" ] }, "shipping_cost": { "anyOf": [ { "type": "null" }, { "type": "object", "required": [ "value", "currency" ], "properties": { "value": { "type": [ "string", "null" ] }, "currency": { "type": [ "string", "null" ] } }, "additionalProperties": false } ] }, "watchers_text": { "type": [ "string", "null" ] }, "item_specifics": { "type": "object", "additionalProperties": { "type": "string" } }, "price_currency": { "type": [ "string", "null" ] }, "watchers_count": { "type": [ "number", "null" ] }, "sold_count_text": { "type": [ "string", "null" ] }, "availability_text": { "type": [ "string", "null" ] }, "seller_description": { "type": [ "string", "null" ] }, "seller_feedback_score": { "type": [ "number", "null" ] }, "seller_positive_feedback": { "type": [ "string", "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": { "type": [ "string", "null" ] }, "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": "ebay-item", "task_name": "eBay Item API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": { "id": "id-1", "url": "https://example.com/item-1", "brand": "sample", "price": "180", "title": "Stylish Shoreditch Loft with Balcony", "gtin13": "sample", "rating": 4.91, "seller": "sample", "item_id": "id-1", "returns": "sample", "category": "sample", "delivery": "sample", "location": "London", "payments": "sample", "shipping": "sample", "condition": "sample", "image_url": "https://example.com/item-1", "image_urls": [ "https://images.example.com/image_urls-1.jpg" ], "seller_url": "https://example.com/item-1", "sold_count": 1, "breadcrumbs": [ "sample" ], "description": "Sample description 1", "availability": "sample", "price_amount": "180", "review_count": 1, "variation_id": "id-1", "quantity_text": "Sample quantity_text 1", "shipping_cost": null, "watchers_text": "Sample watchers_text 1", "item_specifics": {}, "price_currency": "GBP", "watchers_count": 1, "sold_count_text": "Sample sold_count_text 1", "availability_text": "Sample availability_text 1", "seller_description": "Sample seller_description 1", "seller_feedback_score": 1.5, "seller_positive_feedback": "sample" }, "count": 1, "query": "London", "source": "ebay-item", "results": [ { "id": "id-1", "url": "https://example.com/item-1", "brand": "sample", "price": "180", "title": "Stylish Shoreditch Loft with Balcony", "gtin13": "sample", "rating": 4.91, "seller": "sample", "item_id": "id-1", "returns": "sample", "category": "sample", "delivery": "sample", "location": "London", "payments": "sample", "shipping": "sample", "condition": "sample", "image_url": "https://example.com/item-1", "image_urls": [ "https://images.example.com/image_urls-1.jpg" ], "seller_url": "https://example.com/item-1", "sold_count": 1, "breadcrumbs": [ "sample" ], "description": "Sample description 1", "availability": "sample", "price_amount": "180", "review_count": 1, "variation_id": "id-1", "quantity_text": "Sample quantity_text 1", "shipping_cost": null, "watchers_text": "Sample watchers_text 1", "item_specifics": {}, "price_currency": "GBP", "watchers_count": 1, "sold_count_text": "Sample sold_count_text 1", "availability_text": "Sample availability_text 1", "seller_description": "Sample seller_description 1", "seller_feedback_score": 1.5, "seller_positive_feedback": "sample" } ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/ebay/item" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.ebay.com/itm/389640259363"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/ebay/item", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.ebay.com/itm/389640259363" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/ebay/item", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.ebay.com/itm/389640259363" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/ebay/item" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.ebay.com/itm/389640259363","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/ebay/item", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.ebay.com/itm/389640259363", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/ebay/item", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.ebay.com/itm/389640259363", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/ebay-item/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/ebay/item" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.ebay.com/itm/389640259363","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/ebay/item", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.ebay.com/itm/389640259363", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/ebay/item", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.ebay.com/itm/389640259363", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "ebay-item", "task_name": "eBay Item API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": { "id": "id-1", "url": "https://example.com/item-1", "brand": "sample", "price": "180", "title": "Stylish Shoreditch Loft with Balcony", "gtin13": "sample", "rating": 4.91, "seller": "sample", "item_id": "id-1", "returns": "sample", "category": "sample", "delivery": "sample", "location": "London", "payments": "sample", "shipping": "sample", "condition": "sample", "image_url": "https://example.com/item-1", "image_urls": [ "https://images.example.com/image_urls-1.jpg" ], "seller_url": "https://example.com/item-1", "sold_count": 1, "breadcrumbs": [ "sample" ], "description": "Sample description 1", "availability": "sample", "price_amount": "180", "review_count": 1, "variation_id": "id-1", "quantity_text": "Sample quantity_text 1", "shipping_cost": null, "watchers_text": "Sample watchers_text 1", "item_specifics": {}, "price_currency": "GBP", "watchers_count": 1, "sold_count_text": "Sample sold_count_text 1", "availability_text": "Sample availability_text 1", "seller_description": "Sample seller_description 1", "seller_feedback_score": 1.5, "seller_positive_feedback": "sample" }, "count": 1, "query": "London", "source": "ebay-item", "results": [ { "id": "id-1", "url": "https://example.com/item-1", "brand": "sample", "price": "180", "title": "Stylish Shoreditch Loft with Balcony", "gtin13": "sample", "rating": 4.91, "seller": "sample", "item_id": "id-1", "returns": "sample", "category": "sample", "delivery": "sample", "location": "London", "payments": "sample", "shipping": "sample", "condition": "sample", "image_url": "https://example.com/item-1", "image_urls": [ "https://images.example.com/image_urls-1.jpg" ], "seller_url": "https://example.com/item-1", "sold_count": 1, "breadcrumbs": [ "sample" ], "description": "Sample description 1", "availability": "sample", "price_amount": "180", "review_count": 1, "variation_id": "id-1", "quantity_text": "Sample quantity_text 1", "shipping_cost": null, "watchers_text": "Sample watchers_text 1", "item_specifics": {}, "price_currency": "GBP", "watchers_count": 1, "sold_count_text": "Sample sold_count_text 1", "availability_text": "Sample availability_text 1", "seller_description": "Sample seller_description 1", "seller_feedback_score": 1.5, "seller_positive_feedback": "sample" } ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-ebay-item [eBay APIs](/docs/api.md#ebay) # eBay Search API Search public active ebay.com listings, including displayed prices and seller feedback when available. Does not search sold/completed listings. eBay may restrict anonymous access. POST `/v1/ebay/search` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`query` string Required** Search text. Minimum length: 1. Maximum length: 500. Pattern: \S. - **`limit` integer Optional** Maximum results in this response. Default: 25. Minimum: 1. Maximum: 100. - **`condition` string Optional** Listing condition. for_parts selects For parts or not working. Allowed: "new", "used", "for_parts". - **`cursor` string Optional** next_cursor from the previous response. Keep query, marketplace and limit unchanged. Expires after 30 minutes. Maximum length: 131072. Pattern: ^(?:[0-9]+|[A-Za-z0-9_-]+\.[A-Za-z0-9_-]{43})$. - **`marketplace` string Optional** Public endpoints currently support ebay.com. Default: "ebay.com". Allowed: "ebay.com". - **`max_price` number Optional** Maximum displayed listing price in USD. Minimum: 0. Maximum: 1000000000. - **`min_price` number Optional** Minimum displayed listing price in USD. Minimum: 0. Maximum: 1000000000. - **`page` integer Optional** Starting page; omit when continuing with a cursor. Minimum: 1. Maximum: 10000. - **`sort` string Optional** Sort order. Choose an allowed value below. Allowed: "best_match", "newest", "price_low", "price_high", "ending_soon". ### Advanced & compatibility inputs 1 - **`category_id` string Optional** Numeric eBay category id, such as 9355 for cell phones. Pattern: ^[0-9]{1,12}$. ## 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": [ "marketplace" ], "properties": { "marketplace": { "type": "string" } }, "additionalProperties": false }, "count": { "type": "integer", "minimum": 0 }, "query": { "type": [ "string", "null" ] }, "source": { "const": "ebay-search" }, "results": { "type": "array", "items": { "type": "object", "required": [ "id", "title", "url", "rating", "summary", "image_url", "price", "condition", "shipping", "seller" ], "properties": { "id": { "type": "string" }, "url": { "type": "string" }, "price": { "type": [ "string", "null" ] }, "title": { "type": "string" }, "rating": { "type": [ "string", "null" ] }, "seller": { "type": "object", "required": [ "username", "feedback_count", "positive_feedback_percent" ], "properties": { "username": { "type": [ "string", "null" ] }, "feedback_count": { "type": [ "number", "null" ] }, "positive_feedback_percent": { "type": [ "number", "null" ] } }, "additionalProperties": false }, "summary": { "type": [ "string", "null" ] }, "shipping": { "type": [ "string", "null" ] }, "condition": { "type": [ "string", "null" ] }, "image_url": { "type": [ "string", "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": { "type": [ "string", "null" ] }, "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": "ebay-search", "task_name": "eBay Search API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": { "marketplace": "sample" }, "count": 1, "query": "London", "source": "ebay-search", "results": [ { "id": "id-1", "url": "https://example.com/item-1", "price": "180", "title": "Stylish Shoreditch Loft with Balcony", "rating": "sample", "seller": { "username": "Stylish Shoreditch Loft with Balcony", "feedback_count": 1, "positive_feedback_percent": 1.5 }, "summary": "Sample summary 1", "shipping": "sample", "condition": "sample", "image_url": "https://example.com/item-1" } ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/ebay/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"iphone 13"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/ebay/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "iphone 13" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/ebay/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "iphone 13" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/ebay/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"iphone 13","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/ebay/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "iphone 13", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/ebay/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "iphone 13", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/ebay-search/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/ebay/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"iphone 13","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/ebay/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "iphone 13", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/ebay/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "iphone 13", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "ebay-search", "task_name": "eBay Search API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": { "marketplace": "sample" }, "count": 1, "query": "London", "source": "ebay-search", "results": [ { "id": "id-1", "url": "https://example.com/item-1", "price": "180", "title": "Stylish Shoreditch Loft with Balcony", "rating": "sample", "seller": { "username": "Stylish Shoreditch Loft with Balcony", "feedback_count": 1, "positive_feedback_percent": 1.5 }, "summary": "Sample summary 1", "shipping": "sample", "condition": "sample", "image_url": "https://example.com/item-1" } ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-ebay-search [eBay APIs](/docs/api.md#ebay) # eBay Seller Feedback API Read paginated feedback received as an ebay.com seller, including comments, rating, displayed date, item reference and available seller replies. Supports positive, neutral or negative feedback filters; filtered pages may contain fewer results, so follow next_cursor even when count is zero. Feedback prices are displayed references, not a sold-listings price history. POST `/v1/ebay/seller-feedback` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. Provide at least one of: username; url. - **`url` string Optional** Public page URL. Minimum length: 1. Maximum length: 2000. Pattern: ^https://(?:www\.)?ebay\.com/(?:usr|fdbk/feedback_profile)/[a-zA-Z0-9_.-]{1,64}/?(?:[?#].*)?$. - **`username` string Optional** Public username, without a profile URL. Minimum length: 1. Maximum length: 2000. Pattern: ^[a-zA-Z0-9_.-]{1,64}$. - **`limit` integer Optional** Maximum results in this response. Default: 25. Minimum: 1. Maximum: 50. - **`cursor` string Optional** next_cursor from the previous response. Keep all other inputs unchanged. Expires after 30 minutes. Maximum length: 131072. - **`rating` string Optional** Filter by the allowed feedback rating below. Default: "all". Allowed: "all", "positive", "neutral", "negative". - **`sort` string Optional** Sort order. Choose an allowed value below. Default: "recent". Allowed: "recent", "relevant". ## 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": [ "seller" ], "properties": { "seller": { "type": "object", "required": [ "username", "url", "feedback_score", "positive_feedback_percent", "member_since", "country", "top_rated", "feedback_ratings", "detailed_ratings" ], "properties": { "url": { "type": [ "string", "null" ] }, "country": { "type": [ "string", "null" ] }, "username": { "type": [ "string", "null" ] }, "top_rated": { "type": [ "boolean", "null" ] }, "member_since": { "type": [ "string", "null" ] }, "feedback_score": { "type": [ "number", "null" ] }, "detailed_ratings": { "type": "array", "items": { "type": "object", "required": [ "label", "rating", "count" ], "properties": { "count": { "type": [ "number", "null" ] }, "label": { "type": [ "string", "null" ] }, "rating": { "type": [ "number", "null" ] } }, "additionalProperties": false } }, "feedback_ratings": { "type": "array", "items": { "type": "object", "required": [ "rating", "one_month", "six_months", "twelve_months" ], "properties": { "rating": { "type": [ "string", "null" ] }, "one_month": { "type": [ "number", "null" ] }, "six_months": { "type": [ "number", "null" ] }, "twelve_months": { "type": [ "number", "null" ] } }, "additionalProperties": false } }, "positive_feedback_percent": { "type": [ "number", "null" ] } }, "additionalProperties": false } }, "additionalProperties": false }, "count": { "type": "integer", "minimum": 0 }, "query": { "type": [ "string", "null" ] }, "source": { "const": "ebay-seller-feedback" }, "results": { "type": "array", "items": { "type": "object", "required": [ "id", "rating", "comment", "item_id", "item_title", "item_url", "buyer", "price", "when", "verified_purchase", "automated", "seller_response" ], "properties": { "id": { "type": "string" }, "when": { "type": [ "string", "null" ] }, "buyer": { "type": [ "string", "null" ] }, "price": { "type": [ "string", "null" ] }, "rating": { "enum": [ "positive", "neutral", "negative", null ] }, "comment": { "type": [ "string", "null" ] }, "item_id": { "type": [ "string", "null" ] }, "item_url": { "type": [ "string", "null" ] }, "automated": { "type": "boolean" }, "item_title": { "type": [ "string", "null" ] }, "seller_response": { "type": [ "string", "null" ] }, "verified_purchase": { "type": "boolean" } }, "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": { "type": [ "string", "null" ] }, "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": "ebay-seller-feedback", "task_name": "eBay Seller Feedback API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": { "seller": { "url": "https://example.com/item-1", "country": "London", "username": "Stylish Shoreditch Loft with Balcony", "top_rated": true, "member_since": "sample", "feedback_score": 1.5, "detailed_ratings": [ { "count": 1, "label": "Stylish Shoreditch Loft with Balcony", "rating": 4.91 } ], "feedback_ratings": [ { "rating": "sample", "one_month": 1.5, "six_months": 1.5, "twelve_months": 1.5 } ], "positive_feedback_percent": 1.5 } }, "count": 1, "query": "London", "source": "ebay-seller-feedback", "results": [ { "id": "id-1", "when": "sample", "buyer": "sample", "price": "180", "rating": "positive", "comment": "sample", "item_id": "id-1", "item_url": "https://example.com/item-1", "automated": true, "item_title": "Stylish Shoreditch Loft with Balcony", "seller_response": "sample", "verified_purchase": true } ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/ebay/seller-feedback" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.ebay.com/usr/example-seller"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/ebay/seller-feedback", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.ebay.com/usr/example-seller" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/ebay/seller-feedback", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.ebay.com/usr/example-seller" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/ebay/seller-feedback" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.ebay.com/usr/example-seller","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/ebay/seller-feedback", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.ebay.com/usr/example-seller", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/ebay/seller-feedback", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.ebay.com/usr/example-seller", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/ebay-seller-feedback/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/ebay/seller-feedback" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.ebay.com/usr/example-seller","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/ebay/seller-feedback", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.ebay.com/usr/example-seller", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/ebay/seller-feedback", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.ebay.com/usr/example-seller", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "ebay-seller-feedback", "task_name": "eBay Seller Feedback API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": { "seller": { "url": "https://example.com/item-1", "country": "London", "username": "Stylish Shoreditch Loft with Balcony", "top_rated": true, "member_since": "sample", "feedback_score": 1.5, "detailed_ratings": [ { "count": 1, "label": "Stylish Shoreditch Loft with Balcony", "rating": 4.91 } ], "feedback_ratings": [ { "rating": "sample", "one_month": 1.5, "six_months": 1.5, "twelve_months": 1.5 } ], "positive_feedback_percent": 1.5 } }, "count": 1, "query": "London", "source": "ebay-seller-feedback", "results": [ { "id": "id-1", "when": "sample", "buyer": "sample", "price": "180", "rating": "positive", "comment": "sample", "item_id": "id-1", "item_url": "https://example.com/item-1", "automated": true, "item_title": "Stylish Shoreditch Loft with Balcony", "seller_response": "sample", "verified_purchase": true } ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-ebay-seller-feedback [eBay APIs](/docs/api.md#ebay) # eBay Seller Listings API Search an ebay.com seller's active listings, optionally filtered by keywords, condition, price and category, with cursor pagination. Does not return sold/completed history. POST `/v1/ebay/seller-listings` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. Provide at least one of: username; url. - **`url` string Optional** Public page URL. Minimum length: 1. Maximum length: 2000. Pattern: ^https://(?:www\.)?ebay\.com/(?:usr|fdbk/feedback_profile)/[a-zA-Z0-9_.-]{1,64}/?(?:[?#].*)?$. - **`username` string Optional** Public username, without a profile URL. Minimum length: 1. Maximum length: 2000. Pattern: ^[a-zA-Z0-9_.-]{1,64}$. - **`query` string Optional** Search text. Minimum length: 1. Maximum length: 500. Pattern: \S. - **`limit` integer Optional** Maximum results in this response. Default: 25. Minimum: 1. Maximum: 50. - **`condition` string Optional** Listing condition. for_parts selects For parts or not working. Allowed: "new", "used", "for_parts". - **`cursor` string Optional** next_cursor from the previous response. Keep all other inputs unchanged. Expires after 30 minutes. Maximum length: 131072. - **`max_price` number Optional** Maximum displayed listing price in USD. Minimum: 0. Maximum: 1000000000. - **`min_price` number Optional** Minimum displayed listing price in USD. Minimum: 0. Maximum: 1000000000. - **`sort` string Optional** Sort order. Choose an allowed value below. Allowed: "best_match", "newest", "price_low", "price_high", "ending_soon". ### Advanced & compatibility inputs 1 - **`category_id` string Optional** Numeric eBay category id, such as 9355 for cell phones. Pattern: ^[0-9]{1,12}$. ## 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": [ "marketplace", "username" ], "properties": { "username": { "type": "string" }, "marketplace": { "const": "ebay.com" } }, "additionalProperties": false }, "count": { "type": "integer", "minimum": 0 }, "query": { "type": [ "string", "null" ] }, "source": { "const": "ebay-seller-listings" }, "results": { "type": "array", "items": { "type": "object", "required": [ "id", "title", "url", "rating", "summary", "image_url", "price", "condition", "shipping", "seller" ], "properties": { "id": { "type": "string" }, "url": { "type": "string" }, "price": { "type": [ "string", "null" ] }, "title": { "type": "string" }, "rating": { "type": [ "string", "null" ] }, "seller": { "type": "object", "required": [ "username", "feedback_count", "positive_feedback_percent" ], "properties": { "username": { "type": [ "string", "null" ] }, "feedback_count": { "type": [ "number", "null" ] }, "positive_feedback_percent": { "type": [ "number", "null" ] } }, "additionalProperties": false }, "summary": { "type": [ "string", "null" ] }, "shipping": { "type": [ "string", "null" ] }, "condition": { "type": [ "string", "null" ] }, "image_url": { "type": [ "string", "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": { "type": [ "string", "null" ] }, "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": "ebay-seller-listings", "task_name": "eBay Seller Listings API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": { "username": "Stylish Shoreditch Loft with Balcony", "marketplace": "ebay.com" }, "count": 1, "query": "London", "source": "ebay-seller-listings", "results": [ { "id": "id-1", "url": "https://example.com/item-1", "price": "180", "title": "Stylish Shoreditch Loft with Balcony", "rating": "sample", "seller": { "username": "Stylish Shoreditch Loft with Balcony", "feedback_count": 1, "positive_feedback_percent": 1.5 }, "summary": "Sample summary 1", "shipping": "sample", "condition": "sample", "image_url": "https://example.com/item-1" } ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/ebay/seller-listings" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.ebay.com/usr/example-seller"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/ebay/seller-listings", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.ebay.com/usr/example-seller" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/ebay/seller-listings", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.ebay.com/usr/example-seller" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/ebay/seller-listings" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.ebay.com/usr/example-seller","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/ebay/seller-listings", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.ebay.com/usr/example-seller", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/ebay/seller-listings", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.ebay.com/usr/example-seller", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/ebay-seller-listings/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/ebay/seller-listings" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.ebay.com/usr/example-seller","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/ebay/seller-listings", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.ebay.com/usr/example-seller", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/ebay/seller-listings", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.ebay.com/usr/example-seller", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "ebay-seller-listings", "task_name": "eBay Seller Listings API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": { "username": "Stylish Shoreditch Loft with Balcony", "marketplace": "ebay.com" }, "count": 1, "query": "London", "source": "ebay-seller-listings", "results": [ { "id": "id-1", "url": "https://example.com/item-1", "price": "180", "title": "Stylish Shoreditch Loft with Balcony", "rating": "sample", "seller": { "username": "Stylish Shoreditch Loft with Balcony", "feedback_count": 1, "positive_feedback_percent": 1.5 }, "summary": "Sample summary 1", "shipping": "sample", "condition": "sample", "image_url": "https://example.com/item-1" } ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-ebay-seller-listings [eBay APIs](/docs/api.md#ebay) # eBay Seller API Read an ebay.com seller's public feedback score, positive percentage, registration date, rating counts and detailed seller ratings. No website login required; eBay may restrict anonymous access. POST `/v1/ebay/seller` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. Provide at least one of: username; url. - **`url` string Optional** Public page URL. Minimum length: 1. Maximum length: 2000. Pattern: ^https://(?:www\.)?ebay\.com/(?:usr|fdbk/feedback_profile)/[a-zA-Z0-9_.-]{1,64}/?(?:[?#].*)?$. - **`username` string Optional** Public username, without a profile URL. Minimum length: 1. Maximum length: 2000. Pattern: ^[a-zA-Z0-9_.-]{1,64}$. ## 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": [ "username", "url", "feedback_score", "positive_feedback_percent", "member_since", "country", "top_rated", "feedback_ratings", "detailed_ratings" ], "properties": { "url": { "type": [ "string", "null" ] }, "country": { "type": [ "string", "null" ] }, "username": { "type": [ "string", "null" ] }, "top_rated": { "type": [ "boolean", "null" ] }, "member_since": { "type": [ "string", "null" ] }, "feedback_score": { "type": [ "number", "null" ] }, "detailed_ratings": { "type": "array", "items": { "type": "object", "required": [ "label", "rating", "count" ], "properties": { "count": { "type": [ "number", "null" ] }, "label": { "type": [ "string", "null" ] }, "rating": { "type": [ "number", "null" ] } }, "additionalProperties": false } }, "feedback_ratings": { "type": "array", "items": { "type": "object", "required": [ "rating", "one_month", "six_months", "twelve_months" ], "properties": { "rating": { "type": [ "string", "null" ] }, "one_month": { "type": [ "number", "null" ] }, "six_months": { "type": [ "number", "null" ] }, "twelve_months": { "type": [ "number", "null" ] } }, "additionalProperties": false } }, "positive_feedback_percent": { "type": [ "number", "null" ] } }, "additionalProperties": false }, "count": { "type": "integer", "minimum": 0 }, "query": { "type": [ "string", "null" ] }, "source": { "const": "ebay-seller" }, "results": { "type": "array", "items": { "type": "object", "required": [ "username", "url", "feedback_score", "positive_feedback_percent", "member_since", "country", "top_rated", "feedback_ratings", "detailed_ratings" ], "properties": { "url": { "type": [ "string", "null" ] }, "country": { "type": [ "string", "null" ] }, "username": { "type": [ "string", "null" ] }, "top_rated": { "type": [ "boolean", "null" ] }, "member_since": { "type": [ "string", "null" ] }, "feedback_score": { "type": [ "number", "null" ] }, "detailed_ratings": { "type": "array", "items": { "type": "object", "required": [ "label", "rating", "count" ], "properties": { "count": { "type": [ "number", "null" ] }, "label": { "type": [ "string", "null" ] }, "rating": { "type": [ "number", "null" ] } }, "additionalProperties": false } }, "feedback_ratings": { "type": "array", "items": { "type": "object", "required": [ "rating", "one_month", "six_months", "twelve_months" ], "properties": { "rating": { "type": [ "string", "null" ] }, "one_month": { "type": [ "number", "null" ] }, "six_months": { "type": [ "number", "null" ] }, "twelve_months": { "type": [ "number", "null" ] } }, "additionalProperties": false } }, "positive_feedback_percent": { "type": [ "number", "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": { "type": [ "string", "null" ] }, "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": "ebay-seller", "task_name": "eBay Seller API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": { "url": "https://example.com/item-1", "country": "London", "username": "Stylish Shoreditch Loft with Balcony", "top_rated": true, "member_since": "sample", "feedback_score": 1.5, "detailed_ratings": [ { "count": 1, "label": "Stylish Shoreditch Loft with Balcony", "rating": 4.91 } ], "feedback_ratings": [ { "rating": "sample", "one_month": 1.5, "six_months": 1.5, "twelve_months": 1.5 } ], "positive_feedback_percent": 1.5 }, "count": 1, "query": "London", "source": "ebay-seller", "results": [ { "url": "https://example.com/item-1", "country": "London", "username": "Stylish Shoreditch Loft with Balcony", "top_rated": true, "member_since": "sample", "feedback_score": 1.5, "detailed_ratings": [ { "count": 1, "label": "Stylish Shoreditch Loft with Balcony", "rating": 4.91 } ], "feedback_ratings": [ { "rating": "sample", "one_month": 1.5, "six_months": 1.5, "twelve_months": 1.5 } ], "positive_feedback_percent": 1.5 } ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/ebay/seller" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.ebay.com/usr/example-seller"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/ebay/seller", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.ebay.com/usr/example-seller" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/ebay/seller", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.ebay.com/usr/example-seller" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/ebay/seller" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.ebay.com/usr/example-seller","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/ebay/seller", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.ebay.com/usr/example-seller", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/ebay/seller", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.ebay.com/usr/example-seller", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/ebay-seller/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/ebay/seller" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.ebay.com/usr/example-seller","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/ebay/seller", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.ebay.com/usr/example-seller", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/ebay/seller", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.ebay.com/usr/example-seller", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "ebay-seller", "task_name": "eBay Seller API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": { "url": "https://example.com/item-1", "country": "London", "username": "Stylish Shoreditch Loft with Balcony", "top_rated": true, "member_since": "sample", "feedback_score": 1.5, "detailed_ratings": [ { "count": 1, "label": "Stylish Shoreditch Loft with Balcony", "rating": 4.91 } ], "feedback_ratings": [ { "rating": "sample", "one_month": 1.5, "six_months": 1.5, "twelve_months": 1.5 } ], "positive_feedback_percent": 1.5 }, "count": 1, "query": "London", "source": "ebay-seller", "results": [ { "url": "https://example.com/item-1", "country": "London", "username": "Stylish Shoreditch Loft with Balcony", "top_rated": true, "member_since": "sample", "feedback_score": 1.5, "detailed_ratings": [ { "count": 1, "label": "Stylish Shoreditch Loft with Balcony", "rating": 4.91 } ], "feedback_ratings": [ { "rating": "sample", "one_month": 1.5, "six_months": 1.5, "twelve_months": 1.5 } ], "positive_feedback_percent": 1.5 } ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-ebay-seller [Etsy APIs](/docs/api.md#etsy) # Etsy Listing API Scrape a public Etsy listing detail page from a search result URL. POST `/v1/etsy/listing` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`url` string Required** Etsy listing URL returned by etsy/search. Minimum length: 1. Maximum length: 2000. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "etsy-listing", "task_name": "Etsy Listing API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/etsy/listing" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.etsy.com/listing/123456789/handmade-necklace"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/etsy/listing", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.etsy.com/listing/123456789/handmade-necklace" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/etsy/listing", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.etsy.com/listing/123456789/handmade-necklace" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/etsy/listing" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.etsy.com/listing/123456789/handmade-necklace","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/etsy/listing", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.etsy.com/listing/123456789/handmade-necklace", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/etsy/listing", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.etsy.com/listing/123456789/handmade-necklace", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/etsy-listing/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/etsy/listing" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.etsy.com/listing/123456789/handmade-necklace","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/etsy/listing", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.etsy.com/listing/123456789/handmade-necklace", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/etsy/listing", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.etsy.com/listing/123456789/handmade-necklace", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "etsy-listing", "task_name": "Etsy Listing API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-etsy-listing [Etsy APIs](/docs/api.md#etsy) # Etsy API Scrape public Etsy search result pages by query with page pagination. POST `/v1/etsy/search` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`query` string Required** Search query. Minimum length: 1. Maximum length: 2000. - **`limit` integer Optional** Maximum number of results to return. Default: 25. Minimum: 1. Maximum: 100. - **`cursor` string Optional** Cursor returned as next_cursor from the previous response. - **`page` integer Optional** Page number for sources that support page-based pagination. Default: 1. Minimum: 1. Maximum: 10000. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "etsy-search", "task_name": "Etsy API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/etsy/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"handmade necklace"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/etsy/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "handmade necklace" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/etsy/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "handmade necklace" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/etsy/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"handmade necklace","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/etsy/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "handmade necklace", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/etsy/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "handmade necklace", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/etsy-search/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/etsy/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"handmade necklace","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/etsy/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "handmade necklace", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/etsy/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "handmade necklace", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "etsy-search", "task_name": "Etsy API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-etsy-search [Facebook APIs](/docs/api.md#facebook) # Facebook group Scrape public metadata and public initial-page posts from a Facebook group URL or group id. POST `/v1/facebook/group` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. Provide at least one of: url; group_id. - **`url` string Optional** Facebook group URL. Minimum length: 1. Maximum length: 2000. - **`cursor` string Optional** Offset cursor returned as next_cursor from the previous response. - **`group_id` string Optional** Facebook group id or public group slug. Use this instead of url when you only have the identifier. - **`max_posts` integer Optional** Maximum number of public posts to return from the initial group page payload. Default: 20. Minimum: 0. Maximum: 100. ## 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", "group", "posts", "count", "max_posts_requested", "pagination" ], "properties": { "count": { "type": "integer" }, "group": { "type": "object", "required": [ "id", "url", "mobile_url", "name", "description", "privacy", "privacy_description", "visibility", "visibility_description", "member_count_text", "member_count", "location", "profile_picture_url", "cover_photo_url", "tabs", "recent_media" ], "properties": { "id": { "type": "string" }, "url": { "type": "string" }, "name": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "tabs": { "type": "array", "items": { "type": "object", "required": [ "title", "type", "url" ], "properties": { "url": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "type": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "title": { "type": "string" } }, "additionalProperties": false } }, "privacy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "location": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "mobile_url": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "visibility": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "description": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "member_count": { "anyOf": [ { "type": "number" }, { "type": "null" } ] }, "recent_media": { "type": "array", "items": { "type": "object", "required": [ "id", "type", "url", "image_url", "accessibility_caption" ], "properties": { "id": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "url": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "type": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "image_url": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "accessibility_caption": { "anyOf": [ { "type": "string" }, { "type": "null" } ] } }, "additionalProperties": false } }, "cover_photo_url": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "member_count_text": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "privacy_description": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "profile_picture_url": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "visibility_description": { "anyOf": [ { "type": "string" }, { "type": "null" } ] } }, "additionalProperties": false }, "posts": { "type": "array", "items": { "type": "object", "required": [ "id", "post_id", "url", "author_id", "author_name", "author_profile_picture_url", "message", "created_time", "created_at", "reaction_count", "comment_count", "attachments", "comments" ], "properties": { "id": { "type": "string" }, "url": { "type": "string" }, "message": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "post_id": { "type": "string" }, "comments": { "type": "array", "items": { "type": "object", "required": [ "id", "legacy_fbid", "url", "message", "author_id", "author_name", "author_profile_picture_url", "created_time", "created_at", "reaction_count", "reply_count" ], "properties": { "id": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "url": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "message": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "author_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "created_at": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "author_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "legacy_fbid": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "reply_count": { "anyOf": [ { "type": "number" }, { "type": "null" } ] }, "created_time": { "anyOf": [ { "type": "number" }, { "type": "null" } ] }, "reaction_count": { "anyOf": [ { "type": "number" }, { "type": "null" } ] }, "author_profile_picture_url": { "anyOf": [ { "type": "string" }, { "type": "null" } ] } }, "additionalProperties": false } }, "author_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "created_at": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "attachments": { "type": "array", "items": { "type": "object", "required": [ "type", "title", "source", "url", "image_url", "description" ], "properties": { "url": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "type": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "title": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "image_url": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "description": { "anyOf": [ { "type": "string" }, { "type": "null" } ] } }, "additionalProperties": false } }, "author_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "created_time": { "anyOf": [ { "type": "number" }, { "type": "null" } ] }, "comment_count": { "anyOf": [ { "type": "number" }, { "type": "null" } ] }, "reaction_count": { "anyOf": [ { "type": "number" }, { "type": "null" } ] }, "author_profile_picture_url": { "anyOf": [ { "type": "string" }, { "type": "null" } ] } }, "additionalProperties": false } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "total_available", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "const": "public_page_offset" }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "has_next_page": { "type": "boolean" }, "total_available": { "type": "integer" } }, "additionalProperties": false }, "max_posts_requested": { "type": "integer" } }, "additionalProperties": false } ``` ### View a polled run response ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "facebook-group", "task_name": "Facebook group", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "count": 1, "group": { "id": "id-1", "url": "https://example.com/item-1", "name": "Stylish Shoreditch Loft with Balcony", "tabs": [ { "url": "https://example.com/item-1", "type": "sample", "title": "Stylish Shoreditch Loft with Balcony" } ], "privacy": "sample", "location": "London", "mobile_url": "https://example.com/item-1", "visibility": "sample", "description": "Sample description 1", "member_count": 1, "recent_media": [ { "id": "id-1", "url": "https://example.com/item-1", "type": "sample", "image_url": "https://example.com/item-1", "accessibility_caption": "sample" } ], "cover_photo_url": "https://images.example.com/cover_photo_url-1.jpg", "member_count_text": "Sample member_count_text 1", "privacy_description": "Sample privacy_description 1", "profile_picture_url": "https://example.com/item-1", "visibility_description": "Sample visibility_description 1" }, "posts": [ { "id": "id-1", "url": "https://example.com/item-1", "message": "sample", "post_id": "id-1", "comments": [ { "id": "id-1", "url": "https://example.com/item-1", "message": "sample", "author_id": "user_1", "created_at": "2026-06-14T15:30:00Z", "author_name": "Stylish Shoreditch Loft with Balcony", "legacy_fbid": "id-1", "reply_count": 1, "created_time": 1.5, "reaction_count": 1, "author_profile_picture_url": "https://example.com/item-1" } ], "author_id": "user_1", "created_at": "2026-06-14T15:30:00Z", "attachments": [ { "url": "https://example.com/item-1", "type": "sample", "title": "Stylish Shoreditch Loft with Balcony", "source": "sample", "image_url": "https://example.com/item-1", "description": "Sample description 1" } ], "author_name": "Stylish Shoreditch Loft with Balcony", "created_time": 1.5, "comment_count": 1, "reaction_count": 1, "author_profile_picture_url": "https://example.com/item-1" } ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "public_page_offset", "next_cursor": "cursor-page-1", "has_next_page": true, "total_available": 180 }, "max_posts_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/facebook/group" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.facebook.com/groups/2379328805667854/"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/facebook/group", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.facebook.com/groups/2379328805667854/" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/facebook/group", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.facebook.com/groups/2379328805667854/" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/facebook/group" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.facebook.com/groups/2379328805667854/","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/facebook/group", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.facebook.com/groups/2379328805667854/", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/facebook/group", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.facebook.com/groups/2379328805667854/", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/facebook-group/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/facebook/group" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.facebook.com/groups/2379328805667854/","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/facebook/group", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.facebook.com/groups/2379328805667854/", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/facebook/group", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.facebook.com/groups/2379328805667854/", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "facebook-group", "task_name": "Facebook group", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "count": 1, "group": { "id": "id-1", "url": "https://example.com/item-1", "name": "Stylish Shoreditch Loft with Balcony", "tabs": [ { "url": "https://example.com/item-1", "type": "sample", "title": "Stylish Shoreditch Loft with Balcony" } ], "privacy": "sample", "location": "London", "mobile_url": "https://example.com/item-1", "visibility": "sample", "description": "Sample description 1", "member_count": 1, "recent_media": [ { "id": "id-1", "url": "https://example.com/item-1", "type": "sample", "image_url": "https://example.com/item-1", "accessibility_caption": "sample" } ], "cover_photo_url": "https://images.example.com/cover_photo_url-1.jpg", "member_count_text": "Sample member_count_text 1", "privacy_description": "Sample privacy_description 1", "profile_picture_url": "https://example.com/item-1", "visibility_description": "Sample visibility_description 1" }, "posts": [ { "id": "id-1", "url": "https://example.com/item-1", "message": "sample", "post_id": "id-1", "comments": [ { "id": "id-1", "url": "https://example.com/item-1", "message": "sample", "author_id": "user_1", "created_at": "2026-06-14T15:30:00Z", "author_name": "Stylish Shoreditch Loft with Balcony", "legacy_fbid": "id-1", "reply_count": 1, "created_time": 1.5, "reaction_count": 1, "author_profile_picture_url": "https://example.com/item-1" } ], "author_id": "user_1", "created_at": "2026-06-14T15:30:00Z", "attachments": [ { "url": "https://example.com/item-1", "type": "sample", "title": "Stylish Shoreditch Loft with Balcony", "source": "sample", "image_url": "https://example.com/item-1", "description": "Sample description 1" } ], "author_name": "Stylish Shoreditch Loft with Balcony", "created_time": 1.5, "comment_count": 1, "reaction_count": 1, "author_profile_picture_url": "https://example.com/item-1" } ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "public_page_offset", "next_cursor": "cursor-page-1", "has_next_page": true, "total_available": 180 }, "max_posts_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-facebook-group [Fantasy Premier League APIs](/docs/api.md#fantasy-premier-league) # Fantasy Premier League Dataset Get public FPL players and summaries of teams and gameweek events. POST `/v1/fantasy-premier-league/bootstrap` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`query` string Optional** Optional text filter for player names or team codes. Does not filter teams or events. Minimum length: 1. Maximum length: 2000. - **`limit` integer Optional** Maximum player records in results, and maximum teams/events included in data. Default: 25. Minimum: 1. Maximum: 100. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "fantasy-premier-league-bootstrap", "task_name": "Fantasy Premier League Dataset", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/fantasy-premier-league/bootstrap" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/fantasy-premier-league/bootstrap", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({}), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/fantasy-premier-league/bootstrap", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={}, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/fantasy-premier-league/bootstrap" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/fantasy-premier-league/bootstrap", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/fantasy-premier-league/bootstrap", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/fantasy-premier-league-bootstrap/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/fantasy-premier-league/bootstrap" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/fantasy-premier-league/bootstrap", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/fantasy-premier-league/bootstrap", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "fantasy-premier-league-bootstrap", "task_name": "Fantasy Premier League Dataset", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-fantasy-premier-league-bootstrap [G2 APIs](/docs/api.md#g2) # G2 Product API Scrape a public G2 product page. POST `/v1/g2/product` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`url` string Required** URL returned by the matching search endpoint. Minimum length: 1. Maximum length: 2000. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "g2-product", "task_name": "G2 Product API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/g2/product" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.g2.com/products/salesforce-sales-cloud/reviews"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/g2/product", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.g2.com/products/salesforce-sales-cloud/reviews" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/g2/product", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.g2.com/products/salesforce-sales-cloud/reviews" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/g2/product" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.g2.com/products/salesforce-sales-cloud/reviews","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/g2/product", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.g2.com/products/salesforce-sales-cloud/reviews", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/g2/product", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.g2.com/products/salesforce-sales-cloud/reviews", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/g2-product/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/g2/product" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.g2.com/products/salesforce-sales-cloud/reviews","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/g2/product", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.g2.com/products/salesforce-sales-cloud/reviews", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/g2/product", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.g2.com/products/salesforce-sales-cloud/reviews", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "g2-product", "task_name": "G2 Product API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-g2-product [G2 APIs](/docs/api.md#g2) # G2 API Scrape public G2 software search results. POST `/v1/g2/search` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`query` string Required** Search query. Minimum length: 1. Maximum length: 2000. - **`limit` integer Optional** Maximum number of results to return. Default: 25. Minimum: 1. Maximum: 100. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "g2-search", "task_name": "G2 API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/g2/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"CRM software"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/g2/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "CRM software" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/g2/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "CRM software" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/g2/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"CRM software","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/g2/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "CRM software", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/g2/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "CRM software", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/g2-search/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/g2/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"CRM software","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/g2/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "CRM software", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/g2/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "CRM software", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "g2-search", "task_name": "G2 API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-g2-search [Glassdoor APIs](/docs/api.md#glassdoor) # Glassdoor Interviews API Scrape public Glassdoor interview question pages. POST `/v1/glassdoor/interviews` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`query` string Required** Search query. Minimum length: 1. Maximum length: 2000. - **`limit` integer Optional** Maximum number of results to return. Default: 25. Minimum: 1. Maximum: 100. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "glassdoor-interviews", "task_name": "Glassdoor Interviews API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/glassdoor/interviews" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"product manager"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/glassdoor/interviews", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "product manager" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/glassdoor/interviews", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "product manager" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/glassdoor/interviews" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"product manager","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/glassdoor/interviews", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "product manager", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/glassdoor/interviews", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "product manager", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/glassdoor-interviews/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/glassdoor/interviews" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"product manager","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/glassdoor/interviews", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "product manager", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/glassdoor/interviews", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "product manager", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "glassdoor-interviews", "task_name": "Glassdoor Interviews API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-glassdoor-interviews [Glassdoor APIs](/docs/api.md#glassdoor) # Glassdoor Salaries API Scrape public Glassdoor salary search pages. POST `/v1/glassdoor/salaries` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`query` string Required** Search query. Minimum length: 1. Maximum length: 2000. - **`limit` integer Optional** Maximum number of results to return. Default: 25. Minimum: 1. Maximum: 100. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "glassdoor-salaries", "task_name": "Glassdoor Salaries API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/glassdoor/salaries" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"software engineer"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/glassdoor/salaries", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "software engineer" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/glassdoor/salaries", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "software engineer" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/glassdoor/salaries" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"software engineer","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/glassdoor/salaries", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "software engineer", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/glassdoor/salaries", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "software engineer", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/glassdoor-salaries/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/glassdoor/salaries" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"software engineer","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/glassdoor/salaries", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "software engineer", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/glassdoor/salaries", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "software engineer", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "glassdoor-salaries", "task_name": "Glassdoor Salaries API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-glassdoor-salaries [Goodreads APIs](/docs/api.md#goodreads) # Goodreads Book API Scrape a public Goodreads book page. POST `/v1/goodreads/book` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`url` string Required** URL returned by the matching search endpoint. Minimum length: 1. Maximum length: 2000. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "goodreads-book", "task_name": "Goodreads Book API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/goodreads/book" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.goodreads.com/book/show/44767458-dune"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/goodreads/book", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.goodreads.com/book/show/44767458-dune" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/goodreads/book", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.goodreads.com/book/show/44767458-dune" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/goodreads/book" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.goodreads.com/book/show/44767458-dune","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/goodreads/book", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.goodreads.com/book/show/44767458-dune", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/goodreads/book", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.goodreads.com/book/show/44767458-dune", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/goodreads-book/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/goodreads/book" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.goodreads.com/book/show/44767458-dune","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/goodreads/book", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.goodreads.com/book/show/44767458-dune", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/goodreads/book", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.goodreads.com/book/show/44767458-dune", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "goodreads-book", "task_name": "Goodreads Book API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-goodreads-book [Goodreads APIs](/docs/api.md#goodreads) # Goodreads API Scrape public Goodreads book search results. POST `/v1/goodreads/search` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`query` string Required** Search query. Minimum length: 1. Maximum length: 2000. - **`limit` integer Optional** Maximum number of results to return. Default: 25. Minimum: 1. Maximum: 100. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "goodreads-search", "task_name": "Goodreads API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/goodreads/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"Dune"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/goodreads/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "Dune" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/goodreads/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "Dune" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/goodreads/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"Dune","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/goodreads/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "Dune", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/goodreads/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "Dune", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/goodreads-search/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/goodreads/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"Dune","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/goodreads/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "Dune", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/goodreads/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "Dune", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "goodreads-search", "task_name": "Goodreads API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-goodreads-search [Google Maps APIs](/docs/api.md#google-maps) # Google Maps area search Search Google Maps for businesses near a specific latitude/longitude. Useful for exhaustive geographic coverage where IP-based location guessing would be unreliable. POST `/v1/googlemaps/area` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. Provide at least one of: location; latitude + longitude. - **`query` string Required** Search query (e.g. 'dentists', 'coffee shops'). Combined with latitude/longitude to search a specific area. Minimum length: 1. Maximum length: 500. - **`location` string Optional** City, neighbourhood or address to search around. Coordinates are optional advanced inputs. Minimum length: 1. Maximum length: 500. - **`limit` integer Optional** Maximum results to return. Defaults to 100. Preferred name; maxResults remains supported. Default: 100. Minimum: 1. Maximum: 500. ### Advanced & compatibility inputs 4 - **`latitude` number Optional** Center latitude (-90 to 90). Minimum: -90. Maximum: 90. - **`longitude` number Optional** Center longitude (-180 to 180). Minimum: -180. Maximum: 180. - **`maxResults` integer Optional** Maximum results to return. Defaults to 100. You can also use limit. Default: 100. Minimum: 1. Maximum: 500. - **`zoom` number Optional** Map zoom level (3 to 21). Higher values search a tighter area. Defaults to 14 (~city block scale). Default: 14. Minimum: 3. Maximum: 21. ## 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": [ "results", "count" ], "properties": { "count": { "type": "number" }, "results": { "type": "array", "items": { "type": "object", "required": [ "name", "rating", "reviewsCount", "category", "address", "description", "status", "hours", "link", "placeId", "latitude", "longitude" ], "properties": { "link": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "name": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "hours": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "rating": { "anyOf": [ { "type": "number" }, { "type": "null" } ] }, "status": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "address": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "placeId": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "category": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "latitude": { "anyOf": [ { "type": "number" }, { "type": "null" } ] }, "longitude": { "anyOf": [ { "type": "number" }, { "type": "null" } ] }, "description": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "reviewsCount": { "anyOf": [ { "type": "number" }, { "type": "null" } ] } }, "additionalProperties": false } } }, "additionalProperties": false } ``` ### View a polled run response ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "googlemaps-area", "task_name": "Google Maps area search", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "count": 1, "results": [ { "link": "https://example.com/item-1", "name": "Stylish Shoreditch Loft with Balcony", "hours": "sample", "rating": 4.91, "status": "sample", "address": "sample", "placeId": "id-1", "category": "sample", "latitude": 51.5074, "longitude": -0.1278, "description": "Sample description 1", "reviewsCount": 1 } ] }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/googlemaps/area" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"London","location":"Brooklyn, NY"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/googlemaps/area", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "London", "location": "Brooklyn, NY" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/googlemaps/area", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "London", "location": "Brooklyn, NY" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/googlemaps/area" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"London","location":"Brooklyn, NY","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/googlemaps/area", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "London", "location": "Brooklyn, NY", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/googlemaps/area", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "London", "location": "Brooklyn, NY", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/googlemaps-area/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/googlemaps/area" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"London","location":"Brooklyn, NY","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/googlemaps/area", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "London", "location": "Brooklyn, NY", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/googlemaps/area", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "London", "location": "Brooklyn, NY", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "googlemaps-area", "task_name": "Google Maps area search", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "count": 1, "results": [ { "link": "https://example.com/item-1", "name": "Stylish Shoreditch Loft with Balcony", "hours": "sample", "rating": 4.91, "status": "sample", "address": "sample", "placeId": "id-1", "category": "sample", "latitude": 51.5074, "longitude": -0.1278, "description": "Sample description 1", "reviewsCount": 1 } ] }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-googlemaps-area [Google Maps APIs](/docs/api.md#google-maps) # Google Maps Autocomplete API Fetch public Google Maps autocomplete suggestions. POST `/v1/googlemaps/autocomplete` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`query` string Required** Search query. Minimum length: 1. Maximum length: 2000. - **`location` string Optional** Location filter. Minimum length: 1. Maximum length: 2000. - **`limit` integer Optional** Maximum number of results to return. Default: 25. Minimum: 1. Maximum: 100. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "googlemaps-autocomplete", "task_name": "Google Maps Autocomplete API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/googlemaps/autocomplete" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"pizza near Shoreditch"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/googlemaps/autocomplete", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "pizza near Shoreditch" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/googlemaps/autocomplete", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "pizza near Shoreditch" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/googlemaps/autocomplete" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"pizza near Shoreditch","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/googlemaps/autocomplete", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "pizza near Shoreditch", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/googlemaps/autocomplete", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "pizza near Shoreditch", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/googlemaps-autocomplete/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/googlemaps/autocomplete" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"pizza near Shoreditch","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/googlemaps/autocomplete", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "pizza near Shoreditch", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/googlemaps/autocomplete", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "pizza near Shoreditch", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "googlemaps-autocomplete", "task_name": "Google Maps Autocomplete API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-googlemaps-autocomplete [Google Maps APIs](/docs/api.md#google-maps) # Google Maps place Fetch full details for a single Google Maps place — name, rating, category, description, address, phone, website, plus code, opening hours, and coordinates. POST `/v1/googlemaps/place` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. Provide at least one of: placeUrl; query. - **`url` string Optional** Full Google Maps place URL (e.g. https://www.google.com/maps/place/...). Preferred — supply from a prior search result. Preferred name; placeUrl remains supported. - **`query` string Optional** Search query if no placeUrl. The first matching result is used. Minimum length: 1. Maximum length: 500. ### Advanced & compatibility inputs 1 - **`placeUrl` string Optional** Full Google Maps place URL (e.g. https://www.google.com/maps/place/...). Preferred — supply from a prior search result. You can also use url. ## 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": [ "name", "rating", "reviewsCount", "category", "description", "address", "phone", "website", "plusCode", "hours", "status", "link", "placeId", "latitude", "longitude" ], "properties": { "link": { "type": "string" }, "name": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "hours": { "anyOf": [ { "type": "array", "items": { "type": "object", "required": [ "day", "hours" ], "properties": { "day": { "type": "string" }, "hours": { "type": "string" } }, "additionalProperties": false } }, { "type": "null" } ] }, "phone": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "rating": { "anyOf": [ { "type": "number" }, { "type": "null" } ] }, "status": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "address": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "placeId": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "website": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "category": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "latitude": { "anyOf": [ { "type": "number" }, { "type": "null" } ] }, "plusCode": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "longitude": { "anyOf": [ { "type": "number" }, { "type": "null" } ] }, "description": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "reviewsCount": { "anyOf": [ { "type": "number" }, { "type": "null" } ] } }, "additionalProperties": false } ``` ### View a polled run response ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "googlemaps-place", "task_name": "Google Maps place", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "link": "https://example.com/item-1", "name": "Stylish Shoreditch Loft with Balcony", "hours": [ { "day": "sample", "hours": "sample" } ], "phone": "sample", "rating": 4.91, "status": "sample", "address": "sample", "placeId": "id-1", "website": "sample", "category": "sample", "latitude": 51.5074, "plusCode": "sample", "longitude": -0.1278, "description": "Sample description 1", "reviewsCount": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/googlemaps/place" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"placeUrl":"https://example.com/item-1"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/googlemaps/place", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "placeUrl": "https://example.com/item-1" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/googlemaps/place", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "placeUrl": "https://example.com/item-1" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/googlemaps/place" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"placeUrl":"https://example.com/item-1","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/googlemaps/place", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "placeUrl": "https://example.com/item-1", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/googlemaps/place", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "placeUrl": "https://example.com/item-1", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/googlemaps-place/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/googlemaps/place" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"placeUrl":"https://example.com/item-1","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/googlemaps/place", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "placeUrl": "https://example.com/item-1", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/googlemaps/place", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "placeUrl": "https://example.com/item-1", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "googlemaps-place", "task_name": "Google Maps place", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "link": "https://example.com/item-1", "name": "Stylish Shoreditch Loft with Balcony", "hours": [ { "day": "sample", "hours": "sample" } ], "phone": "sample", "rating": 4.91, "status": "sample", "address": "sample", "placeId": "id-1", "website": "sample", "category": "sample", "latitude": 51.5074, "plusCode": "sample", "longitude": -0.1278, "description": "Sample description 1", "reviewsCount": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-googlemaps-place [Google Maps APIs](/docs/api.md#google-maps) # Google Maps reviews Fetch reviews for a Google Maps place — author, rating, date, text, owner response, plus an overall rating breakdown. POST `/v1/googlemaps/reviews` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. Provide at least one of: url; placeUrl. - **`url` string Optional** Full Google Maps place URL — pass the `link` field from a `googlemaps/search`, `googlemaps/area`, or `googlemaps/place` response. Preferred name; placeUrl remains supported. - **`limit` integer Optional** Maximum reviews to extract. Defaults to 50. Preferred name; maxReviews remains supported. Default: 50. Minimum: 1. Maximum: 2000. ### Advanced & compatibility inputs 2 - **`maxReviews` integer Optional** Maximum reviews to extract. Defaults to 50. You can also use limit. Default: 50. Minimum: 1. Maximum: 2000. - **`placeUrl` string Optional** Full Google Maps place URL — pass the `link` field from a `googlemaps/search`, `googlemaps/area`, or `googlemaps/place` response. You can also use url. ## 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": [ "placeName", "rating", "reviewsCount", "ratingBreakdown", "reviews" ], "properties": { "rating": { "anyOf": [ { "type": "number" }, { "type": "null" } ] }, "reviews": { "type": "array", "items": { "type": "object", "required": [ "reviewId", "author", "rating", "relativeDate", "text", "ownerResponse", "photoCount" ], "properties": { "text": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "author": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "rating": { "anyOf": [ { "type": "number" }, { "type": "null" } ] }, "reviewId": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "photoCount": { "type": "number" }, "relativeDate": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "ownerResponse": { "anyOf": [ { "type": "string" }, { "type": "null" } ] } }, "additionalProperties": false } }, "placeName": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "reviewsCount": { "anyOf": [ { "type": "number" }, { "type": "null" } ] }, "ratingBreakdown": { "type": "array", "items": { "type": "object", "required": [ "stars", "count" ], "properties": { "count": { "type": "number" }, "stars": { "type": "number" } }, "additionalProperties": false } } }, "additionalProperties": false } ``` ### View a polled run response ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "googlemaps-reviews", "task_name": "Google Maps reviews", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "rating": 4.91, "reviews": [ { "text": "Sample text 1", "author": "user_1", "rating": 4.91, "reviewId": "id-1", "photoCount": 1, "relativeDate": "sample", "ownerResponse": "sample" } ], "placeName": "Stylish Shoreditch Loft with Balcony", "reviewsCount": 1, "ratingBreakdown": [ { "count": 1, "stars": 1.5 } ] }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/googlemaps/reviews" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://example.com/item-1"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/googlemaps/reviews", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://example.com/item-1" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/googlemaps/reviews", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://example.com/item-1" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/googlemaps/reviews" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://example.com/item-1","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/googlemaps/reviews", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://example.com/item-1", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/googlemaps/reviews", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://example.com/item-1", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/googlemaps-reviews/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/googlemaps/reviews" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://example.com/item-1","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/googlemaps/reviews", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://example.com/item-1", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/googlemaps/reviews", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://example.com/item-1", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "googlemaps-reviews", "task_name": "Google Maps reviews", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "rating": 4.91, "reviews": [ { "text": "Sample text 1", "author": "user_1", "rating": 4.91, "reviewId": "id-1", "photoCount": 1, "relativeDate": "sample", "ownerResponse": "sample" } ], "placeName": "Stylish Shoreditch Loft with Balcony", "reviewsCount": 1, "ratingBreakdown": [ { "count": 1, "stars": 1.5 } ] }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-googlemaps-reviews [Google Maps APIs](/docs/api.md#google-maps) # Google Maps search Search Google Maps for businesses or places matching a query and return each result's name, rating, category, address, hours, place ID, and coordinates. POST `/v1/googlemaps/search` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`query` string Required** Search query — typically a business type plus a location (e.g. 'coffee shops in San Francisco', 'dentists Austin TX'). Minimum length: 1. Maximum length: 500. - **`limit` integer Optional** Maximum results to return. Google Maps loads ~20 at a time; the scraper scrolls until enough cards appear or the feed stops growing. Preferred name; maxResults remains supported. Default: 100. Minimum: 1. Maximum: 500. ### Advanced & compatibility inputs 1 - **`maxResults` integer Optional** Maximum results to return. Google Maps loads ~20 at a time; the scraper scrolls until enough cards appear or the feed stops growing. You can also use limit. Default: 100. Minimum: 1. Maximum: 500. ## 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": [ "results", "count" ], "properties": { "count": { "type": "number" }, "results": { "type": "array", "items": { "type": "object", "required": [ "name", "rating", "reviewsCount", "category", "address", "description", "status", "hours", "link", "placeId", "latitude", "longitude" ], "properties": { "link": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "name": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "hours": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "rating": { "anyOf": [ { "type": "number" }, { "type": "null" } ] }, "status": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "address": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "placeId": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "category": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "latitude": { "anyOf": [ { "type": "number" }, { "type": "null" } ] }, "longitude": { "anyOf": [ { "type": "number" }, { "type": "null" } ] }, "description": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "reviewsCount": { "anyOf": [ { "type": "number" }, { "type": "null" } ] } }, "additionalProperties": false } } }, "additionalProperties": false } ``` ### View a polled run response ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "googlemaps-search", "task_name": "Google Maps search", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "count": 1, "results": [ { "link": "https://example.com/item-1", "name": "Stylish Shoreditch Loft with Balcony", "hours": "sample", "rating": 4.91, "status": "sample", "address": "sample", "placeId": "id-1", "category": "sample", "latitude": 51.5074, "longitude": -0.1278, "description": "Sample description 1", "reviewsCount": 1 } ] }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/googlemaps/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/googlemaps/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "London" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/googlemaps/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "London" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/googlemaps/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"London","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/googlemaps/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "London", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/googlemaps/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "London", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/googlemaps-search/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/googlemaps/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"London","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/googlemaps/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "London", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/googlemaps/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "London", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "googlemaps-search", "task_name": "Google Maps search", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "count": 1, "results": [ { "link": "https://example.com/item-1", "name": "Stylish Shoreditch Loft with Balcony", "hours": "sample", "rating": 4.91, "status": "sample", "address": "sample", "placeId": "id-1", "category": "sample", "latitude": 51.5074, "longitude": -0.1278, "description": "Sample description 1", "reviewsCount": 1 } ] }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-googlemaps-search [Gumtree APIs](/docs/api.md#gumtree) # Gumtree Listing API Scrape a public Gumtree listing detail page from a search result URL. POST `/v1/gumtree/listing` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`url` string Required** Gumtree listing URL returned by gumtree/search. Minimum length: 1. Maximum length: 2000. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "gumtree-listing", "task_name": "Gumtree Listing API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/gumtree/listing" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.gumtree.com/p/bicycles/example-listing/1234567890"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/gumtree/listing", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.gumtree.com/p/bicycles/example-listing/1234567890" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/gumtree/listing", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.gumtree.com/p/bicycles/example-listing/1234567890" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/gumtree/listing" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.gumtree.com/p/bicycles/example-listing/1234567890","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/gumtree/listing", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.gumtree.com/p/bicycles/example-listing/1234567890", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/gumtree/listing", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.gumtree.com/p/bicycles/example-listing/1234567890", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/gumtree-listing/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/gumtree/listing" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.gumtree.com/p/bicycles/example-listing/1234567890","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/gumtree/listing", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.gumtree.com/p/bicycles/example-listing/1234567890", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/gumtree/listing", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.gumtree.com/p/bicycles/example-listing/1234567890", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "gumtree-listing", "task_name": "Gumtree Listing API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-gumtree-listing [Gumtree APIs](/docs/api.md#gumtree) # Gumtree API Scrape public Gumtree search result pages by query with page pagination. POST `/v1/gumtree/search` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`query` string Required** Search query. Minimum length: 1. Maximum length: 2000. - **`limit` integer Optional** Maximum number of results to return. Default: 25. Minimum: 1. Maximum: 100. - **`cursor` string Optional** Cursor returned as next_cursor from the previous response. - **`page` integer Optional** Page number for sources that support page-based pagination. Default: 1. Minimum: 1. Maximum: 10000. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "gumtree-search", "task_name": "Gumtree API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/gumtree/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"bicycle"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/gumtree/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "bicycle" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/gumtree/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "bicycle" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/gumtree/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"bicycle","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/gumtree/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "bicycle", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/gumtree/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "bicycle", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/gumtree-search/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/gumtree/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"bicycle","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/gumtree/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "bicycle", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/gumtree/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "bicycle", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "gumtree-search", "task_name": "Gumtree API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-gumtree-search [Hacker News APIs](/docs/api.md#hacker-news) # Hacker News Item API Fetch a public Hacker News item by URL or item id. POST `/v1/hacker-news/item` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. Provide at least one of: url; id. - **`url` string Optional** Hacker News item URL. Minimum length: 1. Maximum length: 2000. - **`id` string Optional** Hacker News item id. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "hacker-news-item", "task_name": "Hacker News Item API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/hacker-news/item" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://news.ycombinator.com/item?id=8863"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/hacker-news/item", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://news.ycombinator.com/item?id=8863" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/hacker-news/item", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://news.ycombinator.com/item?id=8863" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/hacker-news/item" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://news.ycombinator.com/item?id=8863","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/hacker-news/item", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://news.ycombinator.com/item?id=8863", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/hacker-news/item", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://news.ycombinator.com/item?id=8863", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/hacker-news-item/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/hacker-news/item" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://news.ycombinator.com/item?id=8863","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/hacker-news/item", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://news.ycombinator.com/item?id=8863", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/hacker-news/item", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://news.ycombinator.com/item?id=8863", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "hacker-news-item", "task_name": "Hacker News Item API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-hacker-news-item [Hacker News APIs](/docs/api.md#hacker-news) # Hacker News API Search Hacker News stories through public Algolia data with page pagination. POST `/v1/hacker-news/search` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`query` string Required** Search query. Minimum length: 1. Maximum length: 2000. - **`limit` integer Optional** Maximum number of results to return. Default: 25. Minimum: 1. Maximum: 100. - **`cursor` string Optional** Cursor returned as next_cursor from the previous response. - **`page` integer Optional** Page number for sources that support page-based pagination. Default: 1. Minimum: 1. Maximum: 10000. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "hacker-news-search", "task_name": "Hacker News API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/hacker-news/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"postgres"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/hacker-news/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "postgres" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/hacker-news/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "postgres" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/hacker-news/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"postgres","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/hacker-news/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "postgres", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/hacker-news/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "postgres", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/hacker-news-search/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/hacker-news/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"postgres","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/hacker-news/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "postgres", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/hacker-news/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "postgres", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "hacker-news-search", "task_name": "Hacker News API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-hacker-news-search [Home Depot APIs](/docs/api.md#home-depot) # Home Depot Product API Scrape a public Home Depot product detail page from a search result URL. POST `/v1/homedepot/product` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`url` string Required** Home Depot product URL returned by homedepot/search. Minimum length: 1. Maximum length: 2000. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "homedepot-product", "task_name": "Home Depot Product API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/homedepot/product" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.homedepot.com/p/example-product/123456789"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/homedepot/product", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.homedepot.com/p/example-product/123456789" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/homedepot/product", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.homedepot.com/p/example-product/123456789" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/homedepot/product" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.homedepot.com/p/example-product/123456789","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/homedepot/product", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.homedepot.com/p/example-product/123456789", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/homedepot/product", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.homedepot.com/p/example-product/123456789", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/homedepot-product/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/homedepot/product" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.homedepot.com/p/example-product/123456789","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/homedepot/product", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.homedepot.com/p/example-product/123456789", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/homedepot/product", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.homedepot.com/p/example-product/123456789", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "homedepot-product", "task_name": "Home Depot Product API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-homedepot-product [Home Depot APIs](/docs/api.md#home-depot) # Home Depot API Scrape public Home Depot search result pages by query with offset pagination. POST `/v1/homedepot/search` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`query` string Required** Search query. Minimum length: 1. Maximum length: 2000. - **`limit` integer Optional** Maximum number of results to return. Default: 25. Minimum: 1. Maximum: 100. - **`cursor` string Optional** Cursor returned as next_cursor from the previous response. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "homedepot-search", "task_name": "Home Depot API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/homedepot/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"cordless drill"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/homedepot/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "cordless drill" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/homedepot/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "cordless drill" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/homedepot/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"cordless drill","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/homedepot/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "cordless drill", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/homedepot/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "cordless drill", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/homedepot-search/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/homedepot/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"cordless drill","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/homedepot/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "cordless drill", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/homedepot/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "cordless drill", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "homedepot-search", "task_name": "Home Depot API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-homedepot-search [Hotels.com APIs](/docs/api.md#hotels-com) # Hotels.com Property API Get public Hotels.com property details. If stay dates are unavailable, returns an undated property summary without prices or availability. Returns public discovery metadata; undated prices are not stay-specific quotes. This endpoint does not accept stay dates or occupancy; check a dated search on the source website for stay-specific prices. POST `/v1/hotels/property` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`url` string Required** URL returned by the matching search endpoint. Minimum length: 1. Maximum length: 2000. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "hotels-property", "task_name": "Hotels.com Property API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/hotels/property" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.hotels.com/ho123456/example-hotel/"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/hotels/property", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.hotels.com/ho123456/example-hotel/" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/hotels/property", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.hotels.com/ho123456/example-hotel/" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/hotels/property" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.hotels.com/ho123456/example-hotel/","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/hotels/property", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.hotels.com/ho123456/example-hotel/", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/hotels/property", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.hotels.com/ho123456/example-hotel/", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/hotels-property/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/hotels/property" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.hotels.com/ho123456/example-hotel/","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/hotels/property", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.hotels.com/ho123456/example-hotel/", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/hotels/property", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.hotels.com/ho123456/example-hotel/", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "hotels-property", "task_name": "Hotels.com Property API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-hotels-property [Hotels.com APIs](/docs/api.md#hotels-com) # Hotels.com API Scrape public Hotels.com accommodation search results by destination. Returns public discovery metadata; undated prices are not stay-specific quotes. This endpoint does not accept stay dates or occupancy; check a dated search on the source website for stay-specific prices. POST `/v1/hotels/search` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`query` string Required** City, region, airport or neighborhood. Minimum length: 1. Maximum length: 2000. - **`limit` integer Optional** Maximum number of results to return. Default: 25. Minimum: 1. Maximum: 100. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "hotels-search", "task_name": "Hotels.com API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/hotels/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"Miami Beach"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/hotels/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "Miami Beach" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/hotels/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "Miami Beach" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/hotels/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"Miami Beach","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/hotels/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "Miami Beach", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/hotels/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "Miami Beach", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/hotels-search/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/hotels/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"Miami Beach","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/hotels/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "Miami Beach", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/hotels/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "Miami Beach", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "hotels-search", "task_name": "Hotels.com API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-hotels-search [IMDb APIs](/docs/api.md#imdb) # IMDb Detail API Scrape a public IMDb title, name, or series detail page from a search result URL. POST `/v1/imdb/detail` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`url` string Required** IMDb URL returned by imdb/search. Minimum length: 1. Maximum length: 2000. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "imdb-detail", "task_name": "IMDb Detail API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/imdb/detail" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.imdb.com/title/tt0133093/"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/imdb/detail", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.imdb.com/title/tt0133093/" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/imdb/detail", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.imdb.com/title/tt0133093/" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/imdb/detail" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.imdb.com/title/tt0133093/","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/imdb/detail", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.imdb.com/title/tt0133093/", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/imdb/detail", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.imdb.com/title/tt0133093/", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/imdb-detail/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/imdb/detail" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.imdb.com/title/tt0133093/","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/imdb/detail", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.imdb.com/title/tt0133093/", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/imdb/detail", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.imdb.com/title/tt0133093/", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "imdb-detail", "task_name": "IMDb Detail API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-imdb-detail [IMDb APIs](/docs/api.md#imdb) # IMDb API Search IMDb public suggestion data by query. POST `/v1/imdb/search` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`query` string Required** Movie, TV show, or person to search for. Minimum length: 1. Maximum length: 2000. - **`limit` integer Optional** Maximum number of results to return. Default: 25. Minimum: 1. Maximum: 100. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "imdb-search", "task_name": "IMDb API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/imdb/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"The Matrix"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/imdb/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "The Matrix" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/imdb/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "The Matrix" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/imdb/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"The Matrix","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/imdb/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "The Matrix", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/imdb/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "The Matrix", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/imdb-search/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/imdb/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"The Matrix","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/imdb/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "The Matrix", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/imdb/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "The Matrix", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "imdb-search", "task_name": "IMDb API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-imdb-search [Indeed APIs](/docs/api.md#indeed) # Indeed Company Reviews API Scrape public Indeed company review pages. POST `/v1/indeed/company-reviews` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`query` string Required** Search query. Minimum length: 1. Maximum length: 2000. - **`limit` integer Optional** Maximum number of results to return. Default: 25. Minimum: 1. Maximum: 100. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "indeed-company-reviews", "task_name": "Indeed Company Reviews API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/indeed/company-reviews" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"Starbucks"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/indeed/company-reviews", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "Starbucks" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/indeed/company-reviews", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "Starbucks" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/indeed/company-reviews" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"Starbucks","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/indeed/company-reviews", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "Starbucks", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/indeed/company-reviews", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "Starbucks", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/indeed-company-reviews/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/indeed/company-reviews" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"Starbucks","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/indeed/company-reviews", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "Starbucks", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/indeed/company-reviews", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "Starbucks", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "indeed-company-reviews", "task_name": "Indeed Company Reviews API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-indeed-company-reviews [Indeed APIs](/docs/api.md#indeed) # Indeed job details Fetch full details for a single Indeed job posting — title, company, location, salary, employment type, full description, benefits, posted date, and apply URL. Pass either a job URL or a job key. POST `/v1/indeed/job` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. Provide at least one of: url; jobKey. - **`url` string Optional** Full Indeed job URL — typically the `link` from a prior `indeed/search` response. Minimum length: 1. Maximum length: 2000. - **`domain` string Optional** Indeed regional domain (default www.indeed.com). Only used when jobKey is provided. Pattern: ^[a-z0-9.-]+\.indeed\.com$. - **`jobKey` string Optional** Indeed job key (e.g. `a61c6e343c845e92`) — the `jobKey` field from `indeed/search`. Use instead of url. ## 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": [ "jobKey", "title", "url", "company", "location", "salary", "employmentType", "description", "descriptionText", "benefits", "datePosted", "validThrough", "directApply", "applyUrl" ], "properties": { "url": { "type": "string" }, "title": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "jobKey": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "salary": { "type": "object", "required": [ "min", "max", "currency", "type", "text", "source" ], "properties": { "max": { "anyOf": [ { "type": "number" }, { "type": "null" } ] }, "min": { "anyOf": [ { "type": "number" }, { "type": "null" } ] }, "text": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "type": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "currency": { "anyOf": [ { "type": "string" }, { "type": "null" } ] } }, "additionalProperties": false }, "company": { "type": "object", "required": [ "name", "url", "logo" ], "properties": { "url": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "logo": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "name": { "anyOf": [ { "type": "string" }, { "type": "null" } ] } }, "additionalProperties": false }, "applyUrl": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "benefits": { "type": "array", "items": { "type": "string" } }, "location": { "type": "object", "required": [ "formatted", "city", "region", "postalCode", "country", "remote", "jobLocationType" ], "properties": { "city": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "region": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "remote": { "type": "boolean" }, "country": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "formatted": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "postalCode": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "jobLocationType": { "anyOf": [ { "type": "string" }, { "type": "null" } ] } }, "additionalProperties": false }, "datePosted": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "description": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "directApply": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ] }, "validThrough": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "employmentType": { "type": "array", "items": { "type": "string" } }, "descriptionText": { "anyOf": [ { "type": "string" }, { "type": "null" } ] } }, "additionalProperties": false } ``` ### View a polled run response ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "indeed-job", "task_name": "Indeed job details", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "title": "Stylish Shoreditch Loft with Balcony", "jobKey": "sample", "salary": { "max": 1.5, "min": 1.5, "text": "Sample text 1", "type": "sample", "source": "sample", "currency": "USD" }, "company": { "url": "https://example.com/item-1", "logo": "https://images.example.com/logo-1.jpg", "name": "Stylish Shoreditch Loft with Balcony" }, "applyUrl": "https://example.com/item-1", "benefits": [ "sample" ], "location": { "city": "London", "region": "London", "remote": true, "country": "London", "formatted": "sample", "postalCode": "sample", "jobLocationType": "London" }, "datePosted": "sample", "description": "Sample description 1", "directApply": true, "validThrough": "id-1", "employmentType": [ "sample" ], "descriptionText": "Sample descriptiontext 1" }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/indeed/job" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://example.com/item-1"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/indeed/job", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://example.com/item-1" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/indeed/job", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://example.com/item-1" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/indeed/job" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://example.com/item-1","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/indeed/job", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://example.com/item-1", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/indeed/job", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://example.com/item-1", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/indeed-job/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/indeed/job" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://example.com/item-1","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/indeed/job", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://example.com/item-1", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/indeed/job", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://example.com/item-1", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "indeed-job", "task_name": "Indeed job details", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "title": "Stylish Shoreditch Loft with Balcony", "jobKey": "sample", "salary": { "max": 1.5, "min": 1.5, "text": "Sample text 1", "type": "sample", "source": "sample", "currency": "USD" }, "company": { "url": "https://example.com/item-1", "logo": "https://images.example.com/logo-1.jpg", "name": "Stylish Shoreditch Loft with Balcony" }, "applyUrl": "https://example.com/item-1", "benefits": [ "sample" ], "location": { "city": "London", "region": "London", "remote": true, "country": "London", "formatted": "sample", "postalCode": "sample", "jobLocationType": "London" }, "datePosted": "sample", "description": "Sample description 1", "directApply": true, "validThrough": "id-1", "employmentType": [ "sample" ], "descriptionText": "Sample descriptiontext 1" }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-indeed-job [Indeed APIs](/docs/api.md#indeed) # Indeed Salaries API Scrape public Indeed company salary pages. POST `/v1/indeed/salaries` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`query` string Required** Search query. Minimum length: 1. Maximum length: 2000. - **`limit` integer Optional** Maximum number of results to return. Default: 25. Minimum: 1. Maximum: 100. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "indeed-salaries", "task_name": "Indeed Salaries API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/indeed/salaries" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"Google"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/indeed/salaries", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "Google" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/indeed/salaries", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "Google" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/indeed/salaries" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"Google","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/indeed/salaries", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "Google", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/indeed/salaries", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "Google", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/indeed-salaries/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/indeed/salaries" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"Google","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/indeed/salaries", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "Google", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/indeed/salaries", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "Google", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "indeed-salaries", "task_name": "Indeed Salaries API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-indeed-salaries [Indeed APIs](/docs/api.md#indeed) # Indeed job search Search Indeed for job postings matching a query (and optional location), returning normalized listings with title, company, location, salary, snippet, posted-date, and the canonical Indeed job URL. POST `/v1/indeed/search` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`query` string Required** Job search query — title, skill, or keywords (e.g. 'software engineer', 'nurse'). Minimum length: 1. Maximum length: 200. - **`location` string Optional** Location filter — city, state, postcode, or 'Remote'. Leave empty to search everywhere on the chosen domain. Minimum length: 1. Maximum length: 2000. - **`domain` string Optional** Indeed regional domain (default www.indeed.com). Examples: 'uk.indeed.com', 'ca.indeed.com', 'de.indeed.com'. Pattern: ^[a-z0-9.-]+\.indeed\.com$. - **`pages` integer Optional** How many result pages to fetch (each ~15 jobs). Defaults to 1. Default: 1. Minimum: 1. Maximum: 20. ## 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": [ "results", "count" ], "properties": { "count": { "type": "number" }, "results": { "type": "array", "items": { "type": "object", "required": [ "jobKey", "title", "company", "companyRating", "companyReviewCount", "location", "city", "region", "postalCode", "remote", "salary", "salaryMin", "salaryMax", "salaryType", "jobTypes", "snippet", "postedRelative", "postedAt", "link", "sponsored", "urgentlyHiring", "indeedApplyable", "thirdPartyApplyUrl" ], "properties": { "city": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "link": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "title": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "jobKey": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "region": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "remote": { "type": "boolean" }, "salary": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "company": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "snippet": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "jobTypes": { "type": "array", "items": { "type": "string" } }, "location": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "postedAt": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "salaryMax": { "anyOf": [ { "type": "number" }, { "type": "null" } ] }, "salaryMin": { "anyOf": [ { "type": "number" }, { "type": "null" } ] }, "sponsored": { "type": "boolean" }, "postalCode": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "salaryType": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "companyRating": { "anyOf": [ { "type": "number" }, { "type": "null" } ] }, "postedRelative": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "urgentlyHiring": { "type": "boolean" }, "indeedApplyable": { "type": "boolean" }, "companyReviewCount": { "anyOf": [ { "type": "number" }, { "type": "null" } ] }, "thirdPartyApplyUrl": { "anyOf": [ { "type": "string" }, { "type": "null" } ] } }, "additionalProperties": false } } }, "additionalProperties": false } ``` ### View a polled run response ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "indeed-search", "task_name": "Indeed job search", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "count": 1, "results": [ { "city": "London", "link": "https://example.com/item-1", "title": "Stylish Shoreditch Loft with Balcony", "jobKey": "sample", "region": "London", "remote": true, "salary": "180", "company": "sample", "snippet": "sample", "jobTypes": [ "sample" ], "location": "London", "postedAt": "sample", "salaryMax": 180, "salaryMin": 180, "sponsored": true, "postalCode": "sample", "salaryType": "180", "companyRating": 4.91, "postedRelative": "sample", "urgentlyHiring": true, "indeedApplyable": true, "companyReviewCount": 1, "thirdPartyApplyUrl": "https://example.com/item-1" } ] }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/indeed/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/indeed/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "London" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/indeed/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "London" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/indeed/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"London","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/indeed/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "London", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/indeed/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "London", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/indeed-search/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/indeed/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"London","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/indeed/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "London", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/indeed/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "London", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "indeed-search", "task_name": "Indeed job search", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "count": 1, "results": [ { "city": "London", "link": "https://example.com/item-1", "title": "Stylish Shoreditch Loft with Balcony", "jobKey": "sample", "region": "London", "remote": true, "salary": "180", "company": "sample", "snippet": "sample", "jobTypes": [ "sample" ], "location": "London", "postedAt": "sample", "salaryMax": 180, "salaryMin": 180, "sponsored": true, "postalCode": "sample", "salaryType": "180", "companyRating": 4.91, "postedRelative": "sample", "urgentlyHiring": true, "indeedApplyable": true, "companyReviewCount": 1, "thirdPartyApplyUrl": "https://example.com/item-1" } ] }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-indeed-search [Instagram APIs](/docs/api.md#instagram) # Instagram Authenticated Feed Fetch your Instagram home feed using a managed website login for instagram.com. POST `/v1/instagram/feed` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) **Connected website account required** Requires a connected instagram.com account. Browsable automatically uses a saved connection on your team when one is available. If none is available, HTTP `428` includes a `hosted_url`. Complete sign-in there, then retry. [Connect an account →](/docs/api/website-logins.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`limit` integer Optional** Number of feed posts to fetch. Preferred name; count remains supported. - **`after` string Optional** Pagination cursor from a previous feed response. ### Advanced & compatibility inputs 1 - **`count` integer Optional** Number of feed posts to fetch. You can also use limit. ## 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 {} ``` ### View a polled run response ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "instagram-feed", "task_name": "Instagram Authenticated Feed", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": "sample", "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/instagram/feed" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/instagram/feed", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({}), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/instagram/feed", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={}, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/instagram/feed" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/instagram/feed", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/instagram/feed", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/instagram-feed/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/instagram/feed" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/instagram/feed", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/instagram/feed", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "instagram-feed", "task_name": "Instagram Authenticated Feed", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": "sample", "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-instagram-feed [Instagram APIs](/docs/api.md#instagram) # Instagram Hashtag Posts Retrieve public Instagram posts for a hashtag. This endpoint does not retrieve posts tagging a user. POST `/v1/instagram/hashtag-posts` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. Provide at least one of: hashtag; query. - **`query` string Optional** Compatibility input for hashtag. Prefer hashtag. Minimum length: 1. Maximum length: 2000. - **`hashtag` string Optional** Hashtag, with or without the leading #. Minimum length: 1. Maximum length: 500. - **`limit` integer Optional** Maximum number of results to return. Default: 25. Minimum: 1. Maximum: 100. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "instagram-hashtag-posts", "task_name": "Instagram Hashtag Posts", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/instagram/hashtag-posts" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"hashtag":"streetphotography"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/instagram/hashtag-posts", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "hashtag": "streetphotography" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/instagram/hashtag-posts", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "hashtag": "streetphotography" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/instagram/hashtag-posts" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"hashtag":"streetphotography","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/instagram/hashtag-posts", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "hashtag": "streetphotography", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/instagram/hashtag-posts", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "hashtag": "streetphotography", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/instagram-hashtag-posts/runs`. Compatibility route: `/v1/instagram/tagged-posts`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/instagram/hashtag-posts" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"hashtag":"streetphotography","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/instagram/hashtag-posts", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "hashtag": "streetphotography", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/instagram/hashtag-posts", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "hashtag": "streetphotography", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "instagram-hashtag-posts", "task_name": "Instagram Hashtag Posts", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-instagram-hashtag-posts [Instagram APIs](/docs/api.md#instagram) # Instagram Profile Download Export a full public Instagram profile as a ZIP file with media, captions, post metadata, manifest.json, and posts.csv. Authenticated runs are recommended in async mode. Pricing depends on account eligibility and profile size. See the Instagram profile downloader in your dashboard for your starting price. POST `/v1/instagram/profile-download` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`profile` string Required** Instagram username, @handle, or profile URL to export as a ZIP file. Minimum length: 1. Maximum length: 2000. - **`limit` integer Optional** Optional maximum number of posts to include. Omit this field to export the full public profile. Preferred name; maxPosts remains supported. Minimum: 1. Maximum: 100000. ### Advanced & compatibility inputs 1 - **`maxPosts` integer Optional** Optional maximum number of posts to include. Omit this field to export the full public profile. You can also use limit. Minimum: 1. Maximum: 100000. ## 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 { "$schema": "https://json-schema.org/draft/2020-12/schema", "description": "The result begins with an export ID. A completed run returns artifact details, download expiry and collection statistics. partial_success means some media could not be downloaded; inspect failed_media.", "anyOf": [ { "type": "object", "properties": { "success": { "type": "boolean", "const": true }, "export_id": { "type": "string", "description": "Export identifier. Poll the run until it succeeds before downloading." }, "status": { "type": "string", "enum": [ "completed", "partial_success", "pending" ] }, "file_name": { "type": "string" }, "download_url": { "type": "string", "description": "Short-lived signed download URL. It can be a pending:// placeholder before the artifact is ready." }, "download_url_expires_at": { "type": [ "string", "null" ] }, "expires_at": { "type": [ "string", "null" ] }, "error_code": { "type": [ "string", "null" ] }, "error_message": { "type": [ "string", "null" ] }, "max_posts": { "type": [ "number", "null" ] }, "truncated": { "type": "boolean" }, "profile": { "type": "object", "properties": { "id": { "type": [ "string", "null" ] }, "username": { "type": "string" }, "full_name": { "type": [ "string", "null" ] }, "is_private": { "type": "boolean" }, "total_posts": { "type": "number" }, "profile_pic_url": { "type": [ "string", "null" ] }, "authenticated": { "type": "boolean" } }, "required": [ "id", "username", "full_name", "is_private", "total_posts", "profile_pic_url", "authenticated" ], "additionalProperties": false }, "result_summary": { "type": "object", "properties": { "postsDiscovered": { "type": "number" }, "mediaDiscovered": { "type": "number" }, "estimatedBytes": { "type": "number" }, "downloadedFiles": { "type": "number" }, "failedFiles": { "type": "number" }, "skippedFiles": { "type": "number" }, "truncated": { "type": "boolean" }, "postsDownloaded": { "type": "number" } }, "required": [ "postsDiscovered", "mediaDiscovered", "estimatedBytes", "downloadedFiles", "failedFiles", "skippedFiles", "truncated", "postsDownloaded" ], "additionalProperties": false }, "failed_media": { "type": "array", "items": { "type": "object", "properties": { "post_id": { "type": [ "string", "null" ] }, "post_code": { "type": [ "string", "null" ] }, "post_url": { "type": [ "string", "null" ] }, "post_index": { "type": [ "number", "null" ] }, "media_index": { "type": [ "number", "null" ] }, "media_id": { "type": [ "string", "null" ] }, "file_name": { "type": [ "string", "null" ] }, "failure_reason": { "type": "string" } }, "required": [ "post_id", "post_code", "post_url", "post_index", "media_index", "media_id", "file_name", "failure_reason" ], "additionalProperties": false } } }, "required": [ "success", "export_id", "status", "file_name", "download_url", "download_url_expires_at", "expires_at", "error_code", "error_message", "max_posts", "truncated", "profile", "result_summary", "failed_media" ], "additionalProperties": false }, { "type": "object", "properties": { "export_id": { "type": "string" } }, "required": [ "export_id" ], "additionalProperties": false } ] } ``` ### View a polled run response ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "instagram-profile-download", "task_name": "Instagram Profile Download", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "success": true, "export_id": "id-1", "status": "completed", "file_name": "Stylish Shoreditch Loft with Balcony", "download_url": "https://example.com/item-1", "download_url_expires_at": "https://example.com/item-1", "expires_at": "sample", "error_code": "sample", "error_message": "sample", "max_posts": 1.5, "truncated": true, "profile": { "id": "id-1", "username": "Stylish Shoreditch Loft with Balcony", "full_name": "Stylish Shoreditch Loft with Balcony", "is_private": true, "total_posts": 180, "profile_pic_url": "https://example.com/item-1", "authenticated": true }, "result_summary": { "postsDiscovered": 1.5, "mediaDiscovered": 1.5, "estimatedBytes": 1.5, "downloadedFiles": 1.5, "failedFiles": 1.5, "skippedFiles": 1.5, "truncated": true, "postsDownloaded": 1.5 }, "failed_media": [ { "post_id": "id-1", "post_code": "sample", "post_url": "https://example.com/item-1", "post_index": 1.5, "media_index": 1.5, "media_id": "id-1", "file_name": "Stylish Shoreditch Loft with Balcony", "failure_reason": "sample" } ] }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/instagram/profile-download" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"profile":"natgeo"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/instagram/profile-download", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "profile": "natgeo" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/instagram/profile-download", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "profile": "natgeo" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/instagram/profile-download" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"profile":"natgeo","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/instagram/profile-download", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "profile": "natgeo", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/instagram/profile-download", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "profile": "natgeo", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/instagram-profile-download/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/instagram/profile-download" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"profile":"natgeo","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/instagram/profile-download", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "profile": "natgeo", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/instagram/profile-download", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "profile": "natgeo", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "instagram-profile-download", "task_name": "Instagram Profile Download", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "success": true, "export_id": "id-1", "status": "completed", "file_name": "Stylish Shoreditch Loft with Balcony", "download_url": "https://example.com/item-1", "download_url_expires_at": "https://example.com/item-1", "expires_at": "sample", "error_code": "sample", "error_message": "sample", "max_posts": 1.5, "truncated": true, "profile": { "id": "id-1", "username": "Stylish Shoreditch Loft with Balcony", "full_name": "Stylish Shoreditch Loft with Balcony", "is_private": true, "total_posts": 180, "profile_pic_url": "https://example.com/item-1", "authenticated": true }, "result_summary": { "postsDiscovered": 1.5, "mediaDiscovered": 1.5, "estimatedBytes": 1.5, "downloadedFiles": 1.5, "failedFiles": 1.5, "skippedFiles": 1.5, "truncated": true, "postsDownloaded": 1.5 }, "failed_media": [ { "post_id": "id-1", "post_code": "sample", "post_url": "https://example.com/item-1", "post_index": 1.5, "media_index": 1.5, "media_id": "id-1", "file_name": "Stylish Shoreditch Loft with Balcony", "failure_reason": "sample" } ] }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-instagram-profile-download [Instagram APIs](/docs/api.md#instagram) # Instagram Public Profile Fetch a public Instagram profile anonymously, including profile metadata and paginated posts. POST `/v1/instagram/profile` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`username` string Required** Instagram username to scrape anonymously. Minimum length: 1. Maximum length: 2000. - **`limit` integer Optional** Number of posts to fetch (1-50). Preferred name; count remains supported. Default: 12. Minimum: 1. Maximum: 50. - **`after` string Optional** Pagination cursor from a previous response. ### Advanced & compatibility inputs 1 - **`count` integer Optional** Number of posts to fetch (1-50). You can also use limit. Default: 12. Minimum: 1. Maximum: 50. ## 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", "profile", "posts", "pagination" ], "properties": { "posts": { "type": "array", "items": { "type": "object", "required": [ "id", "code", "media_type", "is_video" ], "properties": { "id": { "type": "string" }, "code": { "type": "string" }, "owner": { "type": "object", "properties": { "id": { "type": "string" }, "username": { "type": "string" } }, "additionalProperties": false }, "caption": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "is_video": { "type": "boolean" }, "media_url": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "timestamp": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "dimensions": { "type": "object", "properties": { "width": { "type": "number" }, "height": { "type": "number" } }, "additionalProperties": false }, "like_count": { "anyOf": [ { "type": "number" }, { "type": "null" } ] }, "media_type": { "type": "number" }, "display_url": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "media_items": { "type": "array", "items": { "type": "object" } }, "comment_count": { "anyOf": [ { "type": "number" }, { "type": "null" } ] }, "thumbnail_url": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "accessibility_caption": { "anyOf": [ { "type": "string" }, { "type": "null" } ] } }, "additionalProperties": true } }, "profile": { "type": "object", "required": [ "id", "username", "followers", "following", "total_posts", "is_private", "is_verified" ], "properties": { "id": { "type": "string" }, "username": { "type": "string" }, "biography": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "followers": { "type": "number" }, "following": { "type": "number" }, "full_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "is_private": { "type": "boolean" }, "is_verified": { "type": "boolean" }, "total_posts": { "type": "number" }, "external_url": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "profile_pic_url": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "profile_pic_url_hd": { "anyOf": [ { "type": "string" }, { "type": "null" } ] } }, "additionalProperties": true }, "success": { "type": "boolean" }, "pagination": { "type": "object", "required": [ "has_next_page", "end_cursor", "count" ], "properties": { "count": { "type": "number" }, "end_cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "has_next_page": { "type": "boolean" } }, "additionalProperties": false } }, "additionalProperties": true } ``` ### View a polled run response ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "instagram-profile", "task_name": "Instagram Public Profile", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "posts": [ { "id": "id-1", "code": "sample", "owner": { "id": "id-1", "username": "Stylish Shoreditch Loft with Balcony" }, "caption": "sample", "is_video": true, "media_url": "https://example.com/item-1", "timestamp": "sample", "dimensions": { "width": 1.5, "height": 1.5 }, "like_count": 1, "media_type": 1.5, "display_url": "https://example.com/item-1", "media_items": [ {} ], "comment_count": 1, "thumbnail_url": "https://images.example.com/thumbnail_url-1.jpg", "accessibility_caption": "sample" } ], "profile": { "id": "id-1", "username": "Stylish Shoreditch Loft with Balcony", "biography": "sample", "followers": 1.5, "following": 1.5, "full_name": "Stylish Shoreditch Loft with Balcony", "is_private": true, "is_verified": true, "total_posts": 180, "external_url": "https://example.com/item-1", "profile_pic_url": "https://example.com/item-1", "profile_pic_url_hd": "https://example.com/item-1" }, "success": true, "pagination": { "count": 1, "end_cursor": "cursor-page-1", "has_next_page": true } }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/instagram/profile" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"username":"natgeo"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/instagram/profile", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "username": "natgeo" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/instagram/profile", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "username": "natgeo" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/instagram/profile" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"username":"natgeo","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/instagram/profile", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "username": "natgeo", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/instagram/profile", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "username": "natgeo", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/instagram-profile/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/instagram/profile" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"username":"natgeo","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/instagram/profile", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "username": "natgeo", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/instagram/profile", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "username": "natgeo", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "instagram-profile", "task_name": "Instagram Public Profile", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "posts": [ { "id": "id-1", "code": "sample", "owner": { "id": "id-1", "username": "Stylish Shoreditch Loft with Balcony" }, "caption": "sample", "is_video": true, "media_url": "https://example.com/item-1", "timestamp": "sample", "dimensions": { "width": 1.5, "height": 1.5 }, "like_count": 1, "media_type": 1.5, "display_url": "https://example.com/item-1", "media_items": [ {} ], "comment_count": 1, "thumbnail_url": "https://images.example.com/thumbnail_url-1.jpg", "accessibility_caption": "sample" } ], "profile": { "id": "id-1", "username": "Stylish Shoreditch Loft with Balcony", "biography": "sample", "followers": 1.5, "following": 1.5, "full_name": "Stylish Shoreditch Loft with Balcony", "is_private": true, "is_verified": true, "total_posts": 180, "external_url": "https://example.com/item-1", "profile_pic_url": "https://example.com/item-1", "profile_pic_url_hd": "https://example.com/item-1" }, "success": true, "pagination": { "count": 1, "end_cursor": "cursor-page-1", "has_next_page": true } }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-instagram-profile [Instagram APIs](/docs/api.md#instagram) # Instagram Public Profile (No Auth) Fetch a public Instagram profile anonymously, including profile metadata and paginated posts. POST `/v1/instagram/public-profile` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`username` string Required** Instagram username to scrape anonymously. Minimum length: 1. Maximum length: 2000. - **`limit` integer Optional** Number of posts to fetch (1-50). Preferred name; count remains supported. Default: 12. Minimum: 1. Maximum: 50. - **`after` string Optional** Pagination cursor from a previous response. ### Advanced & compatibility inputs 1 - **`count` integer Optional** Number of posts to fetch (1-50). You can also use limit. Default: 12. Minimum: 1. Maximum: 50. ## 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", "profile", "posts", "pagination" ], "properties": { "posts": { "type": "array", "items": { "type": "object", "required": [ "id", "code", "media_type", "is_video" ], "properties": { "id": { "type": "string" }, "code": { "type": "string" }, "owner": { "type": "object", "properties": { "id": { "type": "string" }, "username": { "type": "string" } }, "additionalProperties": false }, "caption": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "is_video": { "type": "boolean" }, "media_url": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "timestamp": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "dimensions": { "type": "object", "properties": { "width": { "type": "number" }, "height": { "type": "number" } }, "additionalProperties": false }, "like_count": { "anyOf": [ { "type": "number" }, { "type": "null" } ] }, "media_type": { "type": "number" }, "display_url": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "media_items": { "type": "array", "items": { "type": "object" } }, "comment_count": { "anyOf": [ { "type": "number" }, { "type": "null" } ] }, "thumbnail_url": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "accessibility_caption": { "anyOf": [ { "type": "string" }, { "type": "null" } ] } }, "additionalProperties": true } }, "profile": { "type": "object", "required": [ "id", "username", "followers", "following", "total_posts", "is_private", "is_verified" ], "properties": { "id": { "type": "string" }, "username": { "type": "string" }, "biography": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "followers": { "type": "number" }, "following": { "type": "number" }, "full_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "is_private": { "type": "boolean" }, "is_verified": { "type": "boolean" }, "total_posts": { "type": "number" }, "external_url": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "profile_pic_url": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "profile_pic_url_hd": { "anyOf": [ { "type": "string" }, { "type": "null" } ] } }, "additionalProperties": true }, "success": { "type": "boolean" }, "pagination": { "type": "object", "required": [ "has_next_page", "end_cursor", "count" ], "properties": { "count": { "type": "number" }, "end_cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "has_next_page": { "type": "boolean" } }, "additionalProperties": false } }, "additionalProperties": true } ``` ### View a polled run response ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "instagram-public-profile", "task_name": "Instagram Public Profile (No Auth)", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "posts": [ { "id": "id-1", "code": "sample", "owner": { "id": "id-1", "username": "Stylish Shoreditch Loft with Balcony" }, "caption": "sample", "is_video": true, "media_url": "https://example.com/item-1", "timestamp": "sample", "dimensions": { "width": 1.5, "height": 1.5 }, "like_count": 1, "media_type": 1.5, "display_url": "https://example.com/item-1", "media_items": [ {} ], "comment_count": 1, "thumbnail_url": "https://images.example.com/thumbnail_url-1.jpg", "accessibility_caption": "sample" } ], "profile": { "id": "id-1", "username": "Stylish Shoreditch Loft with Balcony", "biography": "sample", "followers": 1.5, "following": 1.5, "full_name": "Stylish Shoreditch Loft with Balcony", "is_private": true, "is_verified": true, "total_posts": 180, "external_url": "https://example.com/item-1", "profile_pic_url": "https://example.com/item-1", "profile_pic_url_hd": "https://example.com/item-1" }, "success": true, "pagination": { "count": 1, "end_cursor": "cursor-page-1", "has_next_page": true } }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/instagram/public-profile" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"username":"natgeo"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/instagram/public-profile", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "username": "natgeo" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/instagram/public-profile", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "username": "natgeo" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/instagram/public-profile" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"username":"natgeo","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/instagram/public-profile", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "username": "natgeo", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/instagram/public-profile", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "username": "natgeo", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/instagram-public-profile/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/instagram/public-profile" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"username":"natgeo","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/instagram/public-profile", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "username": "natgeo", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/instagram/public-profile", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "username": "natgeo", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "instagram-public-profile", "task_name": "Instagram Public Profile (No Auth)", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "posts": [ { "id": "id-1", "code": "sample", "owner": { "id": "id-1", "username": "Stylish Shoreditch Loft with Balcony" }, "caption": "sample", "is_video": true, "media_url": "https://example.com/item-1", "timestamp": "sample", "dimensions": { "width": 1.5, "height": 1.5 }, "like_count": 1, "media_type": 1.5, "display_url": "https://example.com/item-1", "media_items": [ {} ], "comment_count": 1, "thumbnail_url": "https://images.example.com/thumbnail_url-1.jpg", "accessibility_caption": "sample" } ], "profile": { "id": "id-1", "username": "Stylish Shoreditch Loft with Balcony", "biography": "sample", "followers": 1.5, "following": 1.5, "full_name": "Stylish Shoreditch Loft with Balcony", "is_private": true, "is_verified": true, "total_posts": 180, "external_url": "https://example.com/item-1", "profile_pic_url": "https://example.com/item-1", "profile_pic_url_hd": "https://example.com/item-1" }, "success": true, "pagination": { "count": 1, "end_cursor": "cursor-page-1", "has_next_page": true } }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-instagram-public-profile [Instagram APIs](/docs/api.md#instagram) # Instagram Reels API Scrape public Instagram reels from a profile. POST `/v1/instagram/reels` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`username` string Required** Instagram username. Minimum length: 1. Maximum length: 2000. - **`limit` integer Optional** Maximum number of results to return. Default: 25. Minimum: 1. Maximum: 100. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "instagram-reels", "task_name": "Instagram Reels API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/instagram/reels" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"username":"nasa"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/instagram/reels", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "username": "nasa" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/instagram/reels", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "username": "nasa" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/instagram/reels" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"username":"nasa","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/instagram/reels", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "username": "nasa", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/instagram/reels", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "username": "nasa", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/instagram-reels/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/instagram/reels" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"username":"nasa","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/instagram/reels", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "username": "nasa", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/instagram/reels", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "username": "nasa", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "instagram-reels", "task_name": "Instagram Reels API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-instagram-reels [Kayak APIs](/docs/api.md#kayak) # Kayak API Scrape rendered public Kayak flight result pages from a flight query. Partner APIs require credentials. POST `/v1/kayak/search` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`origin` string Required** Departure city or airport code, such as London or LHR. Use an airport code for a specific airport. - **`destination` string Required** Arrival city or airport code, such as New York or JFK. Use an airport code for a specific airport. - **`depart_date` string Required** Departure date in YYYY-MM-DD format. Must not be in the past. Format: date. Pattern: ^\d{4}-\d{2}-\d{2}$. - **`return_date` string Optional** Optional return date in YYYY-MM-DD format, on or after departure. Format: date. Pattern: ^\d{4}-\d{2}-\d{2}$. - **`limit` integer Optional** Maximum number of results to return. Default: 25. Minimum: 1. Maximum: 100. - **`adults` integer Optional** Number of adult guests or travellers. Default: 1. Minimum: 1. Maximum: 9. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "kayak-search", "task_name": "Kayak API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/kayak/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"origin":"NYC","destination":"LON","depart_date":"2027-06-14"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/kayak/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "origin": "NYC", "destination": "LON", "depart_date": "2027-06-14" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/kayak/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "origin": "NYC", "destination": "LON", "depart_date": "2027-06-14" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/kayak/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"origin":"NYC","destination":"LON","depart_date":"2027-06-14","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/kayak/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "origin": "NYC", "destination": "LON", "depart_date": "2027-06-14", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/kayak/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "origin": "NYC", "destination": "LON", "depart_date": "2027-06-14", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/kayak-search/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/kayak/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"origin":"NYC","destination":"LON","depart_date":"2027-06-14","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/kayak/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "origin": "NYC", "destination": "LON", "depart_date": "2027-06-14", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/kayak/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "origin": "NYC", "destination": "LON", "depart_date": "2027-06-14", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "kayak-search", "task_name": "Kayak API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-kayak-search [Kiwi APIs](/docs/api.md#kiwi) # Kiwi API Scrape rendered public Kiwi flight result pages from a flight query. Tequila API access requires credentials. POST `/v1/kiwi/search` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`origin` string Required** Departure city or airport code, such as London or LHR. Use an airport code for a specific airport. - **`destination` string Required** Arrival city or airport code, such as New York or JFK. Use an airport code for a specific airport. - **`depart_date` string Required** Departure date in YYYY-MM-DD format. Must not be in the past. Format: date. Pattern: ^\d{4}-\d{2}-\d{2}$. - **`return_date` string Optional** Optional return date in YYYY-MM-DD format, on or after departure. Format: date. Pattern: ^\d{4}-\d{2}-\d{2}$. - **`limit` integer Optional** Maximum number of results to return. Default: 25. Minimum: 1. Maximum: 100. - **`adults` integer Optional** Number of adult guests or travellers. Default: 1. Minimum: 1. Maximum: 9. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "kiwi-search", "task_name": "Kiwi API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/kiwi/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"origin":"new-york-city-ny-united-states","destination":"lisbon-portugal","depart_date":"2027-06-14"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/kiwi/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "origin": "new-york-city-ny-united-states", "destination": "lisbon-portugal", "depart_date": "2027-06-14" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/kiwi/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "origin": "new-york-city-ny-united-states", "destination": "lisbon-portugal", "depart_date": "2027-06-14" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/kiwi/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"origin":"new-york-city-ny-united-states","destination":"lisbon-portugal","depart_date":"2027-06-14","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/kiwi/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "origin": "new-york-city-ny-united-states", "destination": "lisbon-portugal", "depart_date": "2027-06-14", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/kiwi/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "origin": "new-york-city-ny-united-states", "destination": "lisbon-portugal", "depart_date": "2027-06-14", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/kiwi-search/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/kiwi/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"origin":"new-york-city-ny-united-states","destination":"lisbon-portugal","depart_date":"2027-06-14","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/kiwi/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "origin": "new-york-city-ny-united-states", "destination": "lisbon-portugal", "depart_date": "2027-06-14", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/kiwi/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "origin": "new-york-city-ny-united-states", "destination": "lisbon-portugal", "depart_date": "2027-06-14", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "kiwi-search", "task_name": "Kiwi API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-kiwi-search [Letterboxd APIs](/docs/api.md#letterboxd) # Letterboxd Film API Scrape a public Letterboxd film page. POST `/v1/letterboxd/film` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`url` string Required** URL returned by the matching search endpoint. Minimum length: 1. Maximum length: 2000. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "type": "object", "required": [ "id", "type", "slug", "title", "full_title", "original_title", "year", "release_date", "url", "film_id", "uid", "letterboxd_id", "tmdb_id", "tmdb_type", "imdb_id", "external_urls", "description", "tagline", "runtime_minutes", "duration", "genres", "countries", "languages", "language_codes", "directors", "director_names", "cast", "cast_names", "crew", "image_url", "image_urls", "poster_images", "stats", "ratings", "popular_reviews" ], "properties": { "id": { "type": "string" }, "uid": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "url": { "type": "string" }, "cast": { "type": "array", "items": { "type": "object", "required": [ "name", "url" ], "properties": { "url": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "name": { "type": "string" } }, "additionalProperties": false } }, "crew": { "type": "object", "additionalProperties": { "type": "array", "items": { "type": "object", "required": [ "name", "url" ], "properties": { "url": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "name": { "type": "string" } }, "additionalProperties": false } } }, "slug": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "type": { "const": "film" }, "year": { "anyOf": [ { "type": "integer" }, { "type": "null" } ] }, "stats": { "type": "object", "properties": { "like_count": { "anyOf": [ { "type": "integer" }, { "type": "null" } ] }, "list_count": { "anyOf": [ { "type": "integer" }, { "type": "null" } ] }, "watched_count": { "anyOf": [ { "type": "integer" }, { "type": "null" } ] } }, "additionalProperties": false }, "title": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "genres": { "type": "array", "items": { "type": "string" } }, "film_id": { "anyOf": [ { "type": "integer" }, { "type": "null" } ] }, "imdb_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "ratings": { "type": "object", "required": [ "count", "calculated_average", "distribution" ], "properties": { "count": { "type": "integer" }, "distribution": { "type": "array", "items": { "type": "object", "required": [ "rating", "label", "count", "percentage" ], "properties": { "count": { "type": "integer" }, "label": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "rating": { "anyOf": [ { "type": "number" }, { "type": "null" } ] }, "percentage": { "anyOf": [ { "type": "number" }, { "type": "null" } ] } }, "additionalProperties": false } }, "calculated_average": { "anyOf": [ { "type": "number" }, { "type": "null" } ] } }, "additionalProperties": false }, "tagline": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "tmdb_id": { "anyOf": [ { "type": "integer" }, { "type": "null" } ] }, "duration": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "countries": { "type": "array", "items": { "type": "string" } }, "directors": { "type": "array", "items": { "type": "object", "required": [ "name", "url" ], "properties": { "url": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "name": { "type": "string" } }, "additionalProperties": false } }, "image_url": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "languages": { "type": "array", "items": { "type": "string" } }, "tmdb_type": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "cast_names": { "type": "array", "items": { "type": "string" } }, "full_title": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "image_urls": { "type": "array", "items": { "type": "string" } }, "description": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "release_date": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "external_urls": { "type": "object", "required": [ "imdb", "tmdb" ], "properties": { "imdb": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "tmdb": { "anyOf": [ { "type": "string" }, { "type": "null" } ] } }, "additionalProperties": false }, "letterboxd_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "poster_images": { "type": "object", "required": [ "small", "medium", "large" ], "properties": { "large": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "small": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "medium": { "anyOf": [ { "type": "string" }, { "type": "null" } ] } }, "additionalProperties": false }, "director_names": { "type": "array", "items": { "type": "string" } }, "language_codes": { "type": "array", "items": { "type": "string" } }, "original_title": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "popular_reviews": { "type": "array", "items": { "type": "object", "required": [ "id", "reviewer_name", "reviewer_username", "url", "rating", "rating_label", "text", "like_count" ], "properties": { "id": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "url": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "text": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "rating": { "anyOf": [ { "type": "number" }, { "type": "null" } ] }, "like_count": { "anyOf": [ { "type": "number" }, { "type": "null" } ] }, "rating_label": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "reviewer_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "reviewer_username": { "anyOf": [ { "type": "string" }, { "type": "null" } ] } }, "additionalProperties": false } }, "runtime_minutes": { "anyOf": [ { "type": "number" }, { "type": "null" } ] } }, "additionalProperties": false }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "const": "letterboxd-film" }, "results": { "type": "array", "items": { "type": "object", "required": [ "id", "type", "slug", "title", "full_title", "year", "url", "film_id", "image_url" ], "properties": { "id": { "type": "string" }, "url": { "type": "string" }, "slug": { "type": "string" }, "type": { "const": "film" }, "year": { "anyOf": [ { "type": "integer" }, { "type": "null" } ] }, "title": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "film_id": { "anyOf": [ { "type": "integer" }, { "type": "null" } ] }, "image_url": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "full_title": { "anyOf": [ { "type": "string" }, { "type": "null" } ] } }, "additionalProperties": false } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "letterboxd-film", "task_name": "Letterboxd Film API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": { "id": "id-1", "uid": "id-1", "url": "https://example.com/item-1", "cast": [ { "url": "https://example.com/item-1", "name": "Stylish Shoreditch Loft with Balcony" } ], "crew": {}, "slug": "sample", "type": "film", "year": 1, "stats": { "like_count": 1, "list_count": 1, "watched_count": 1 }, "title": "Stylish Shoreditch Loft with Balcony", "genres": [ "sample" ], "film_id": 1, "imdb_id": "id-1", "ratings": { "count": 1, "distribution": [ { "count": 1, "label": "Stylish Shoreditch Loft with Balcony", "rating": 4.91, "percentage": 1.5 } ], "calculated_average": 51.5074 }, "tagline": "Featured", "tmdb_id": 1, "duration": "sample", "countries": [ "sample" ], "directors": [ { "url": "https://example.com/item-1", "name": "Stylish Shoreditch Loft with Balcony" } ], "image_url": "https://example.com/item-1", "languages": [ "sample" ], "tmdb_type": "sample", "cast_names": [ "Stylish Shoreditch Loft with Balcony" ], "full_title": "Stylish Shoreditch Loft with Balcony", "image_urls": [ "https://images.example.com/image_urls-1.jpg" ], "description": "Sample description 1", "release_date": "sample", "external_urls": { "imdb": "sample", "tmdb": "sample" }, "letterboxd_id": "id-1", "poster_images": { "large": "sample", "small": "sample", "medium": "sample" }, "director_names": [ "Stylish Shoreditch Loft with Balcony" ], "language_codes": [ "sample" ], "original_title": "Stylish Shoreditch Loft with Balcony", "popular_reviews": [ { "id": "id-1", "url": "https://example.com/item-1", "text": "Sample text 1", "rating": 4.91, "like_count": 1, "rating_label": "Stylish Shoreditch Loft with Balcony", "reviewer_name": "Stylish Shoreditch Loft with Balcony", "reviewer_username": "Stylish Shoreditch Loft with Balcony" } ], "runtime_minutes": 1.5 }, "count": 1, "query": "London", "source": "letterboxd-film", "results": [ { "id": "id-1", "url": "https://example.com/item-1", "slug": "sample", "type": "film", "year": 1, "title": "Stylish Shoreditch Loft with Balcony", "film_id": 1, "image_url": "https://example.com/item-1", "full_title": "Stylish Shoreditch Loft with Balcony" } ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/letterboxd/film" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://letterboxd.com/film/parasite-2019/"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/letterboxd/film", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://letterboxd.com/film/parasite-2019/" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/letterboxd/film", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://letterboxd.com/film/parasite-2019/" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/letterboxd/film" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://letterboxd.com/film/parasite-2019/","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/letterboxd/film", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://letterboxd.com/film/parasite-2019/", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/letterboxd/film", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://letterboxd.com/film/parasite-2019/", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/letterboxd-film/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/letterboxd/film" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://letterboxd.com/film/parasite-2019/","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/letterboxd/film", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://letterboxd.com/film/parasite-2019/", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/letterboxd/film", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://letterboxd.com/film/parasite-2019/", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "letterboxd-film", "task_name": "Letterboxd Film API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": { "id": "id-1", "uid": "id-1", "url": "https://example.com/item-1", "cast": [ { "url": "https://example.com/item-1", "name": "Stylish Shoreditch Loft with Balcony" } ], "crew": {}, "slug": "sample", "type": "film", "year": 1, "stats": { "like_count": 1, "list_count": 1, "watched_count": 1 }, "title": "Stylish Shoreditch Loft with Balcony", "genres": [ "sample" ], "film_id": 1, "imdb_id": "id-1", "ratings": { "count": 1, "distribution": [ { "count": 1, "label": "Stylish Shoreditch Loft with Balcony", "rating": 4.91, "percentage": 1.5 } ], "calculated_average": 51.5074 }, "tagline": "Featured", "tmdb_id": 1, "duration": "sample", "countries": [ "sample" ], "directors": [ { "url": "https://example.com/item-1", "name": "Stylish Shoreditch Loft with Balcony" } ], "image_url": "https://example.com/item-1", "languages": [ "sample" ], "tmdb_type": "sample", "cast_names": [ "Stylish Shoreditch Loft with Balcony" ], "full_title": "Stylish Shoreditch Loft with Balcony", "image_urls": [ "https://images.example.com/image_urls-1.jpg" ], "description": "Sample description 1", "release_date": "sample", "external_urls": { "imdb": "sample", "tmdb": "sample" }, "letterboxd_id": "id-1", "poster_images": { "large": "sample", "small": "sample", "medium": "sample" }, "director_names": [ "Stylish Shoreditch Loft with Balcony" ], "language_codes": [ "sample" ], "original_title": "Stylish Shoreditch Loft with Balcony", "popular_reviews": [ { "id": "id-1", "url": "https://example.com/item-1", "text": "Sample text 1", "rating": 4.91, "like_count": 1, "rating_label": "Stylish Shoreditch Loft with Balcony", "reviewer_name": "Stylish Shoreditch Loft with Balcony", "reviewer_username": "Stylish Shoreditch Loft with Balcony" } ], "runtime_minutes": 1.5 }, "count": 1, "query": "London", "source": "letterboxd-film", "results": [ { "id": "id-1", "url": "https://example.com/item-1", "slug": "sample", "type": "film", "year": 1, "title": "Stylish Shoreditch Loft with Balcony", "film_id": 1, "image_url": "https://example.com/item-1", "full_title": "Stylish Shoreditch Loft with Balcony" } ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-letterboxd-film [Letterboxd APIs](/docs/api.md#letterboxd) # Letterboxd Search API Scrape public Letterboxd film search results. POST `/v1/letterboxd/search` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`query` string Required** Search query. Minimum length: 1. Maximum length: 2000. - **`limit` integer Optional** Maximum number of results to return. Default: 25. Minimum: 1. Maximum: 100. - **`cursor` string Optional** Cursor returned as next_cursor from the previous response. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "type": "object", "required": [ "result_type", "source_endpoint" ], "properties": { "result_type": { "const": "film" }, "source_endpoint": { "type": "string" } }, "additionalProperties": false }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "const": "letterboxd-search" }, "results": { "type": "array", "items": { "type": "object", "required": [ "id", "type", "slug", "title", "url", "film_id", "uid", "letterboxd_id", "image_url", "image_urls", "details_endpoint", "directors", "director_names", "alternative_titles", "original_title", "summary", "position" ], "properties": { "id": { "type": "string" }, "uid": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "url": { "type": "string" }, "slug": { "type": "string" }, "type": { "const": "film" }, "year": { "anyOf": [ { "type": "integer" }, { "type": "null" } ] }, "title": { "type": "string" }, "film_id": { "anyOf": [ { "type": "integer" }, { "type": "null" } ] }, "summary": { "type": "string" }, "position": { "type": "integer" }, "directors": { "type": "array", "items": { "type": "object", "required": [ "name", "url" ], "properties": { "url": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "name": { "type": "string" } }, "additionalProperties": false } }, "image_url": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "full_title": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "image_urls": { "type": "array", "items": { "type": "string" } }, "letterboxd_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "director_names": { "type": "array", "items": { "type": "string" } }, "original_title": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "details_endpoint": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "alternative_titles": { "type": "array", "items": { "type": "string" } } }, "additionalProperties": false } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "letterboxd-search", "task_name": "Letterboxd Search API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": { "result_type": "film", "source_endpoint": "sample" }, "count": 1, "query": "London", "source": "letterboxd-search", "results": [ { "id": "id-1", "uid": "id-1", "url": "https://example.com/item-1", "slug": "sample", "type": "film", "year": 1, "title": "Stylish Shoreditch Loft with Balcony", "film_id": 1, "summary": "Sample summary 1", "position": 1, "directors": [ { "url": "https://example.com/item-1", "name": "Stylish Shoreditch Loft with Balcony" } ], "image_url": "https://example.com/item-1", "full_title": "Stylish Shoreditch Loft with Balcony", "image_urls": [ "https://images.example.com/image_urls-1.jpg" ], "letterboxd_id": "id-1", "director_names": [ "Stylish Shoreditch Loft with Balcony" ], "original_title": "Stylish Shoreditch Loft with Balcony", "details_endpoint": "2 guests", "alternative_titles": [ "Stylish Shoreditch Loft with Balcony" ] } ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/letterboxd/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"Parasite"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/letterboxd/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "Parasite" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/letterboxd/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "Parasite" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/letterboxd/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"Parasite","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/letterboxd/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "Parasite", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/letterboxd/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "Parasite", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/letterboxd-search/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/letterboxd/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"Parasite","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/letterboxd/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "Parasite", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/letterboxd/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "Parasite", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "letterboxd-search", "task_name": "Letterboxd Search API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": { "result_type": "film", "source_endpoint": "sample" }, "count": 1, "query": "London", "source": "letterboxd-search", "results": [ { "id": "id-1", "uid": "id-1", "url": "https://example.com/item-1", "slug": "sample", "type": "film", "year": 1, "title": "Stylish Shoreditch Loft with Balcony", "film_id": 1, "summary": "Sample summary 1", "position": 1, "directors": [ { "url": "https://example.com/item-1", "name": "Stylish Shoreditch Loft with Balcony" } ], "image_url": "https://example.com/item-1", "full_title": "Stylish Shoreditch Loft with Balcony", "image_urls": [ "https://images.example.com/image_urls-1.jpg" ], "letterboxd_id": "id-1", "director_names": [ "Stylish Shoreditch Loft with Balcony" ], "original_title": "Stylish Shoreditch Loft with Balcony", "details_endpoint": "2 guests", "alternative_titles": [ "Stylish Shoreditch Loft with Balcony" ] } ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-letterboxd-search [LinkedIn APIs](/docs/api.md#linkedin) # LinkedIn Company Employees API Scrape a LinkedIn company people page using a managed signed-in session. POST `/v1/linkedin/company-employees` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) **Connected website account required** Requires a connected linkedin.com account. Browsable automatically uses a saved connection on your team when one is available. If none is available, HTTP `428` includes a `hosted_url`. Complete sign-in there, then retry. [Connect an account →](/docs/api/website-logins.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`company` string Required** LinkedIn company slug. - **`limit` integer Optional** Maximum number of results to return. Default: 25. Minimum: 1. Maximum: 100. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "linkedin-company-employees", "task_name": "LinkedIn Company Employees API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/linkedin/company-employees" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"company":"stripe"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/linkedin/company-employees", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "company": "stripe" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/linkedin/company-employees", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "company": "stripe" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/linkedin/company-employees" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"company":"stripe","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/linkedin/company-employees", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "company": "stripe", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/linkedin/company-employees", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "company": "stripe", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/linkedin-company-employees/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/linkedin/company-employees" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"company":"stripe","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/linkedin/company-employees", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "company": "stripe", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/linkedin/company-employees", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "company": "stripe", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "linkedin-company-employees", "task_name": "LinkedIn Company Employees API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-linkedin-company-employees [LinkedIn APIs](/docs/api.md#linkedin) # LinkedIn Post Comments API Scrape public comments visible on a LinkedIn post page. POST `/v1/linkedin/post-comments` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`url` string Required** URL returned by the matching search endpoint. Minimum length: 1. Maximum length: 2000. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "linkedin-post-comments", "task_name": "LinkedIn Post Comments API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/linkedin/post-comments" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.linkedin.com/posts/example"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/linkedin/post-comments", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.linkedin.com/posts/example" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/linkedin/post-comments", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.linkedin.com/posts/example" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/linkedin/post-comments" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.linkedin.com/posts/example","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/linkedin/post-comments", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.linkedin.com/posts/example", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/linkedin/post-comments", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.linkedin.com/posts/example", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/linkedin-post-comments/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/linkedin/post-comments" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.linkedin.com/posts/example","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/linkedin/post-comments", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.linkedin.com/posts/example", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/linkedin/post-comments", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.linkedin.com/posts/example", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "linkedin-post-comments", "task_name": "LinkedIn Post Comments API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-linkedin-post-comments [Mastodon APIs](/docs/api.md#mastodon) # Mastodon API Search public Mastodon accounts on a chosen instance. POST `/v1/mastodon/search` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`query` string Required** Search query. Minimum length: 1. Maximum length: 2000. - **`limit` integer Optional** Maximum number of results to return. Default: 25. Minimum: 1. Maximum: 100. - **`cursor` string Optional** Cursor returned as next_cursor from the previous response. - **`instance` string Optional** Mastodon instance hostname. Default: "mastodon.social". ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "mastodon-search", "task_name": "Mastodon API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/mastodon/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"climate"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/mastodon/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "climate" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/mastodon/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "climate" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/mastodon/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"climate","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/mastodon/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "climate", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/mastodon/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "climate", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/mastodon-search/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/mastodon/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"climate","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/mastodon/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "climate", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/mastodon/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "climate", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "mastodon-search", "task_name": "Mastodon API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-mastodon-search [Mastodon APIs](/docs/api.md#mastodon) # Mastodon Status API Scrape a public Mastodon status page. POST `/v1/mastodon/status` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`url` string Required** URL returned by the matching search endpoint. Minimum length: 1. Maximum length: 2000. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "mastodon-status", "task_name": "Mastodon Status API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/mastodon/status" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://mastodon.social/@user/1234567890"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/mastodon/status", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://mastodon.social/@user/1234567890" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/mastodon/status", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://mastodon.social/@user/1234567890" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/mastodon/status" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://mastodon.social/@user/1234567890","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/mastodon/status", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://mastodon.social/@user/1234567890", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/mastodon/status", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://mastodon.social/@user/1234567890", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/mastodon-status/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/mastodon/status" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://mastodon.social/@user/1234567890","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/mastodon/status", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://mastodon.social/@user/1234567890", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/mastodon/status", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://mastodon.social/@user/1234567890", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "mastodon-status", "task_name": "Mastodon Status API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-mastodon-status [Medium APIs](/docs/api.md#medium) # Medium Post API Scrape a public Medium post page. POST `/v1/medium/post` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`url` string Required** URL returned by the matching search endpoint. Minimum length: 1. Maximum length: 2000. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "medium-post", "task_name": "Medium Post API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/medium/post" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://medium.com/@author/example-post"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/medium/post", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://medium.com/@author/example-post" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/medium/post", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://medium.com/@author/example-post" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/medium/post" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://medium.com/@author/example-post","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/medium/post", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://medium.com/@author/example-post", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/medium/post", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://medium.com/@author/example-post", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/medium-post/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/medium/post" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://medium.com/@author/example-post","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/medium/post", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://medium.com/@author/example-post", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/medium/post", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://medium.com/@author/example-post", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "medium-post", "task_name": "Medium Post API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-medium-post [Medium APIs](/docs/api.md#medium) # Medium API Scrape public Medium story search results. POST `/v1/medium/search` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`query` string Required** Search query. Minimum length: 1. Maximum length: 2000. - **`limit` integer Optional** Maximum number of results to return. Default: 25. Minimum: 1. Maximum: 100. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "medium-search", "task_name": "Medium API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/medium/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"distributed systems"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/medium/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "distributed systems" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/medium/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "distributed systems" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/medium/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"distributed systems","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/medium/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "distributed systems", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/medium/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "distributed systems", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/medium-search/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/medium/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"distributed systems","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/medium/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "distributed systems", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/medium/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "distributed systems", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "medium-search", "task_name": "Medium API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-medium-search [Mercari APIs](/docs/api.md#mercari) # Mercari Listing API Get a Mercari US listing’s title, price, photos, condition and seller name. POST `/v1/mercari/listing` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`url` string Required** Mercari US item URL. Minimum length: 1. Maximum length: 2000. Format: uri. ## 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" }, "data": { "type": "object", "required": [ "id", "url", "title", "description", "image_url", "image_urls", "price", "currency", "availability", "condition", "brand", "seller" ], "properties": { "id": { "type": "string" }, "url": { "type": "string" }, "brand": { "type": [ "string", "null" ] }, "price": { "type": [ "string", "null" ] }, "title": { "type": "string" }, "seller": { "type": [ "string", "null" ] }, "currency": { "type": [ "string", "null" ] }, "condition": { "type": [ "string", "null" ] }, "image_url": { "type": [ "string", "null" ] }, "image_urls": { "type": "array", "items": { "type": "string" } }, "description": { "type": [ "string", "null" ] }, "availability": { "type": [ "string", "null" ] } }, "additionalProperties": false }, "count": { "type": "integer", "minimum": 0 }, "query": { "type": [ "string", "null" ] }, "source": { "const": "mercari-listing" }, "results": { "type": "array", "items": { "type": "object", "required": [ "id", "url", "title", "description", "image_url", "image_urls", "price", "currency", "availability", "condition", "brand", "seller" ], "properties": { "id": { "type": "string" }, "url": { "type": "string" }, "brand": { "type": [ "string", "null" ] }, "price": { "type": [ "string", "null" ] }, "title": { "type": "string" }, "seller": { "type": [ "string", "null" ] }, "currency": { "type": [ "string", "null" ] }, "condition": { "type": [ "string", "null" ] }, "image_url": { "type": [ "string", "null" ] }, "image_urls": { "type": "array", "items": { "type": "string" } }, "description": { "type": [ "string", "null" ] }, "availability": { "type": [ "string", "null" ] } }, "additionalProperties": false } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer", "minimum": 0 }, "cursor": { "type": [ "string", "null" ] }, "strategy": { "type": "string" }, "next_cursor": { "type": [ "string", "null" ] }, "has_next_page": { "type": "boolean" } }, "additionalProperties": false }, "max_results_requested": { "type": "integer", "maximum": 100, "minimum": 1 } }, "additionalProperties": false } ``` ### View a polled run response ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "mercari-listing", "task_name": "Mercari Listing API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": { "id": "id-1", "url": "https://example.com/item-1", "brand": "sample", "price": "180", "title": "Stylish Shoreditch Loft with Balcony", "seller": "sample", "currency": "USD", "condition": "sample", "image_url": "https://example.com/item-1", "image_urls": [ "https://images.example.com/image_urls-1.jpg" ], "description": "Sample description 1", "availability": "sample" }, "count": 1, "query": "London", "source": "mercari-listing", "results": [ { "id": "id-1", "url": "https://example.com/item-1", "brand": "sample", "price": "180", "title": "Stylish Shoreditch Loft with Balcony", "seller": "sample", "currency": "USD", "condition": "sample", "image_url": "https://example.com/item-1", "image_urls": [ "https://images.example.com/image_urls-1.jpg" ], "description": "Sample description 1", "availability": "sample" } ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/mercari/listing" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.mercari.com/us/item/m15770090881/"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/mercari/listing", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.mercari.com/us/item/m15770090881/" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/mercari/listing", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.mercari.com/us/item/m15770090881/" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/mercari/listing" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.mercari.com/us/item/m15770090881/","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/mercari/listing", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.mercari.com/us/item/m15770090881/", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/mercari/listing", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.mercari.com/us/item/m15770090881/", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/mercari-listing/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/mercari/listing" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.mercari.com/us/item/m15770090881/","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/mercari/listing", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.mercari.com/us/item/m15770090881/", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/mercari/listing", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.mercari.com/us/item/m15770090881/", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "mercari-listing", "task_name": "Mercari Listing API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": { "id": "id-1", "url": "https://example.com/item-1", "brand": "sample", "price": "180", "title": "Stylish Shoreditch Loft with Balcony", "seller": "sample", "currency": "USD", "condition": "sample", "image_url": "https://example.com/item-1", "image_urls": [ "https://images.example.com/image_urls-1.jpg" ], "description": "Sample description 1", "availability": "sample" }, "count": 1, "query": "London", "source": "mercari-listing", "results": [ { "id": "id-1", "url": "https://example.com/item-1", "brand": "sample", "price": "180", "title": "Stylish Shoreditch Loft with Balcony", "seller": "sample", "currency": "USD", "condition": "sample", "image_url": "https://example.com/item-1", "image_urls": [ "https://images.example.com/image_urls-1.jpg" ], "description": "Sample description 1", "availability": "sample" } ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-mercari-listing [Mercari APIs](/docs/api.md#mercari) # Mercari Search API Search Mercari US listings with price, brand, category, condition and status filters. Follow next_cursor to get more results. POST `/v1/mercari/search` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. Provide at least one of: query; url. - **`url` string Optional** Copy a filtered Mercari search URL to reuse brand, category, condition and price filters without looking up IDs. Minimum length: 1. Maximum length: 500. Format: uri. - **`query` string Optional** Search keywords. Minimum length: 1. Maximum length: 2000. - **`limit` integer Optional** Maximum results to return. Review pages may return fewer than this limit. Default: 25. Minimum: 1. Maximum: 100. - **`conditions` array Optional** Include listings in these conditions. Items must be unique. - **`cursor` string Optional** Opaque next_cursor from the previous response. Keep the same seller, query, filters, and limit. - **`max_price` number Optional** Maximum item price in US dollars, excluding shipping and fees. Minimum: 0. Maximum: 1000000. - **`min_price` number Optional** Minimum item price in US dollars, excluding shipping and fees. Minimum: 0. Maximum: 1000000. - **`sort` string Optional** Order results by relevance, listing date, price, or sale recency. Default: "best_match". Allowed: "best_match", "newest", "price_low_to_high", "price_high_to_low", "recently_sold". - **`status` string Optional** Listing status. Sold includes completed and in-progress sales; displayed prices are not guaranteed final transaction prices. Allowed: "all", "available", "sold". ### Advanced & compatibility inputs 2 - **`brand_ids` array Optional** Mercari brand IDs. Results include brand_id for subsequent filtering. Maximum items: 50. Items must be unique. - **`category_ids` array Optional** Mercari category IDs. Results include category_id for subsequent filtering. Maximum items: 50. Items must be unique. ## 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" }, "data": { "type": "object", "required": [ "total_count" ], "properties": { "total_count": { "type": "integer", "minimum": 0 } }, "additionalProperties": false }, "count": { "type": "integer", "minimum": 0 }, "query": { "type": [ "string", "null" ] }, "source": { "const": "mercari-search" }, "results": { "type": "array", "items": { "type": "object", "required": [ "id", "seller_id", "brand_id", "category_id", "title", "url", "price", "currency", "original_price", "image_url", "summary", "rating", "status", "brand", "condition", "size" ], "properties": { "id": { "type": "string" }, "url": { "type": "string" }, "size": { "type": [ "string", "null" ] }, "brand": { "type": [ "string", "null" ] }, "price": { "type": "string" }, "title": { "type": "string" }, "rating": { "type": "null" }, "status": { "type": [ "string", "null" ] }, "summary": { "type": [ "string", "null" ] }, "brand_id": { "type": [ "number", "null" ] }, "currency": { "const": "USD" }, "condition": { "type": [ "string", "null" ] }, "image_url": { "type": [ "string", "null" ] }, "seller_id": { "type": [ "string", "null" ] }, "category_id": { "type": [ "number", "null" ] }, "original_price": { "type": [ "string", "null" ] } }, "additionalProperties": false } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer", "minimum": 0 }, "cursor": { "type": [ "string", "null" ] }, "strategy": { "type": "string" }, "next_cursor": { "type": [ "string", "null" ] }, "has_next_page": { "type": "boolean" } }, "additionalProperties": false }, "max_results_requested": { "type": "integer", "maximum": 100, "minimum": 1 } }, "additionalProperties": false } ``` ### View a polled run response ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "mercari-search", "task_name": "Mercari Search API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": { "total_count": 1 }, "count": 1, "query": "London", "source": "mercari-search", "results": [ { "id": "id-1", "url": "https://example.com/item-1", "size": "sample", "brand": "sample", "price": "180", "title": "Stylish Shoreditch Loft with Balcony", "rating": null, "status": "sample", "summary": "Sample summary 1", "brand_id": 1.5, "currency": "USD", "condition": "sample", "image_url": "https://example.com/item-1", "seller_id": "id-1", "category_id": 1.5, "original_price": "180" } ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/mercari/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.mercari.com/search/?keyword=jacket&brandIds=4591"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/mercari/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.mercari.com/search/?keyword=jacket&brandIds=4591" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/mercari/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.mercari.com/search/?keyword=jacket&brandIds=4591" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/mercari/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.mercari.com/search/?keyword=jacket&brandIds=4591","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/mercari/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.mercari.com/search/?keyword=jacket&brandIds=4591", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/mercari/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.mercari.com/search/?keyword=jacket&brandIds=4591", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/mercari-search/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/mercari/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.mercari.com/search/?keyword=jacket&brandIds=4591","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/mercari/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.mercari.com/search/?keyword=jacket&brandIds=4591", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/mercari/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.mercari.com/search/?keyword=jacket&brandIds=4591", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "mercari-search", "task_name": "Mercari Search API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": { "total_count": 1 }, "count": 1, "query": "London", "source": "mercari-search", "results": [ { "id": "id-1", "url": "https://example.com/item-1", "size": "sample", "brand": "sample", "price": "180", "title": "Stylish Shoreditch Loft with Balcony", "rating": null, "status": "sample", "summary": "Sample summary 1", "brand_id": 1.5, "currency": "USD", "condition": "sample", "image_url": "https://example.com/item-1", "seller_id": "id-1", "category_id": 1.5, "original_price": "180" } ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-mercari-search [Mercari APIs](/docs/api.md#mercari) # Mercari Seller Listings API Get a Mercari US seller’s listings with keyword, price, brand, category, condition and status filters. Follow next_cursor to get more results. POST `/v1/mercari/seller/listings` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. Provide at least one of: seller_id; username; url. - **`url` string Optional** Public Mercari US seller profile URL. Minimum length: 1. Maximum length: 2000. Format: uri. - **`username` string Optional** Public Mercari username. Minimum length: 1. Maximum length: 2000. Pattern: ^[A-Za-z0-9_.-]+$. - **`query` string Optional** Optional keywords within this seller’s listings. Minimum length: 1. Maximum length: 2000. - **`limit` integer Optional** Maximum results to return. Review pages may return fewer than this limit. Default: 25. Minimum: 1. Maximum: 100. - **`conditions` array Optional** Include listings in these conditions. Items must be unique. - **`cursor` string Optional** Opaque next_cursor from the previous response. Keep the same seller, query, filters, and limit. - **`filters_url` string Optional** Copy a filtered Mercari search URL to reuse brand, category, condition and price filters without looking up IDs. Minimum length: 1. Maximum length: 500. Format: uri. - **`max_price` number Optional** Maximum item price in US dollars, excluding shipping and fees. Minimum: 0. Maximum: 1000000. - **`min_price` number Optional** Minimum item price in US dollars, excluding shipping and fees. Minimum: 0. Maximum: 1000000. - **`sort` string Optional** Order results by relevance, listing date, price, or sale recency. Default: "newest". Allowed: "best_match", "newest", "price_low_to_high", "price_high_to_low", "recently_sold". - **`status` string Optional** Listing status. Sold includes completed and in-progress sales; displayed prices are not guaranteed final transaction prices. Default: "available". Allowed: "all", "available", "sold". ### Advanced & compatibility inputs 3 - **`brand_ids` array Optional** Mercari brand IDs. Results include brand_id for subsequent filtering. Maximum items: 50. Items must be unique. - **`category_ids` array Optional** Mercari category IDs. Results include category_id for subsequent filtering. Maximum items: 50. Items must be unique. - **`seller_id` string Optional** Mercari seller ID, returned by search or seller listings. Pattern: ^[0-9]+$. ## 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" }, "data": { "type": "object", "required": [ "total_count", "seller_id" ], "properties": { "seller_id": { "type": "string" }, "total_count": { "type": "integer", "minimum": 0 } }, "additionalProperties": false }, "count": { "type": "integer", "minimum": 0 }, "query": { "type": [ "string", "null" ] }, "source": { "const": "mercari-seller-listings" }, "results": { "type": "array", "items": { "type": "object", "required": [ "id", "seller_id", "brand_id", "category_id", "title", "url", "price", "currency", "original_price", "image_url", "summary", "rating", "status", "brand", "condition", "size" ], "properties": { "id": { "type": "string" }, "url": { "type": "string" }, "size": { "type": [ "string", "null" ] }, "brand": { "type": [ "string", "null" ] }, "price": { "type": "string" }, "title": { "type": "string" }, "rating": { "type": "null" }, "status": { "type": [ "string", "null" ] }, "summary": { "type": [ "string", "null" ] }, "brand_id": { "type": [ "number", "null" ] }, "currency": { "const": "USD" }, "condition": { "type": [ "string", "null" ] }, "image_url": { "type": [ "string", "null" ] }, "seller_id": { "type": [ "string", "null" ] }, "category_id": { "type": [ "number", "null" ] }, "original_price": { "type": [ "string", "null" ] } }, "additionalProperties": false } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer", "minimum": 0 }, "cursor": { "type": [ "string", "null" ] }, "strategy": { "type": "string" }, "next_cursor": { "type": [ "string", "null" ] }, "has_next_page": { "type": "boolean" } }, "additionalProperties": false }, "max_results_requested": { "type": "integer", "maximum": 100, "minimum": 1 } }, "additionalProperties": false } ``` ### View a polled run response ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "mercari-seller-listings", "task_name": "Mercari Seller Listings API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": { "seller_id": "id-1", "total_count": 1 }, "count": 1, "query": "London", "source": "mercari-seller-listings", "results": [ { "id": "id-1", "url": "https://example.com/item-1", "size": "sample", "brand": "sample", "price": "180", "title": "Stylish Shoreditch Loft with Balcony", "rating": null, "status": "sample", "summary": "Sample summary 1", "brand_id": 1.5, "currency": "USD", "condition": "sample", "image_url": "https://example.com/item-1", "seller_id": "id-1", "category_id": 1.5, "original_price": "180" } ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/mercari/seller/listings" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.mercari.com/u/jaijuu/"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/mercari/seller/listings", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.mercari.com/u/jaijuu/" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/mercari/seller/listings", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.mercari.com/u/jaijuu/" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/mercari/seller/listings" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.mercari.com/u/jaijuu/","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/mercari/seller/listings", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.mercari.com/u/jaijuu/", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/mercari/seller/listings", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.mercari.com/u/jaijuu/", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/mercari-seller-listings/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/mercari/seller/listings" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.mercari.com/u/jaijuu/","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/mercari/seller/listings", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.mercari.com/u/jaijuu/", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/mercari/seller/listings", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.mercari.com/u/jaijuu/", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "mercari-seller-listings", "task_name": "Mercari Seller Listings API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": { "seller_id": "id-1", "total_count": 1 }, "count": 1, "query": "London", "source": "mercari-seller-listings", "results": [ { "id": "id-1", "url": "https://example.com/item-1", "size": "sample", "brand": "sample", "price": "180", "title": "Stylish Shoreditch Loft with Balcony", "rating": null, "status": "sample", "summary": "Sample summary 1", "brand_id": 1.5, "currency": "USD", "condition": "sample", "image_url": "https://example.com/item-1", "seller_id": "id-1", "category_id": 1.5, "original_price": "180" } ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-mercari-seller-listings [Mercari APIs](/docs/api.md#mercari) # Mercari Seller Reviews API Get public Mercari US account feedback, newest first. Choose reviews from buyers or sellers. Automated Mercari messages are labelled. POST `/v1/mercari/seller/reviews` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. Provide at least one of: seller_id; username; url. - **`url` string Optional** Public Mercari US seller profile URL. Minimum length: 1. Maximum length: 2000. Format: uri. - **`username` string Optional** Public Mercari username. Minimum length: 1. Maximum length: 2000. Pattern: ^[A-Za-z0-9_.-]+$. - **`limit` integer Optional** Maximum results to return. Review pages may return fewer than this limit. Default: 25. Minimum: 1. Maximum: 100. - **`cursor` string Optional** Opaque next_cursor from the previous response. Keep the same seller, query, filters, and limit. - **`review_type` string Optional** Buyers reviews assess this account as a seller; sellers reviews assess it as a buyer. Default: "buyers". Allowed: "buyers", "sellers". ### Advanced & compatibility inputs 1 - **`seller_id` string Optional** Mercari seller ID, returned by search or seller listings. Pattern: ^[0-9]+$. ## 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" }, "data": { "type": "object", "required": [ "seller_id", "review_type" ], "properties": { "seller_id": { "type": "string" }, "review_type": { "enum": [ "buyers", "sellers" ], "type": "string" } }, "additionalProperties": false }, "count": { "type": "integer", "minimum": 0 }, "query": { "type": [ "string", "null" ] }, "source": { "const": "mercari-seller-reviews" }, "results": { "type": "array", "items": { "type": "object", "required": [ "text", "rating_label", "created_at", "reviewer_id", "reviewer_name", "reviewer_image_url", "is_automated", "reviewer_role", "feedback" ], "properties": { "text": { "type": "string" }, "feedback": { "type": "array", "items": { "type": "string" } }, "created_at": { "type": "string" }, "reviewer_id": { "type": [ "string", "null" ] }, "is_automated": { "type": "boolean" }, "rating_label": { "type": [ "string", "null" ] }, "reviewer_name": { "type": [ "string", "null" ] }, "reviewer_role": { "type": [ "string", "null" ] }, "reviewer_image_url": { "type": [ "string", "null" ] } }, "additionalProperties": false } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer", "minimum": 0 }, "cursor": { "type": [ "string", "null" ] }, "strategy": { "type": "string" }, "next_cursor": { "type": [ "string", "null" ] }, "has_next_page": { "type": "boolean" } }, "additionalProperties": false }, "max_results_requested": { "type": "integer", "maximum": 100, "minimum": 1 } }, "additionalProperties": false } ``` ### View a polled run response ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "mercari-seller-reviews", "task_name": "Mercari Seller Reviews API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": { "seller_id": "id-1", "review_type": "buyers" }, "count": 1, "query": "London", "source": "mercari-seller-reviews", "results": [ { "text": "Sample text 1", "feedback": [ "sample" ], "created_at": "2026-06-14T15:30:00Z", "reviewer_id": "id-1", "is_automated": true, "rating_label": "Stylish Shoreditch Loft with Balcony", "reviewer_name": "Stylish Shoreditch Loft with Balcony", "reviewer_role": "sample", "reviewer_image_url": "https://example.com/item-1" } ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/mercari/seller/reviews" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.mercari.com/u/jaijuu/"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/mercari/seller/reviews", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.mercari.com/u/jaijuu/" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/mercari/seller/reviews", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.mercari.com/u/jaijuu/" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/mercari/seller/reviews" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.mercari.com/u/jaijuu/","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/mercari/seller/reviews", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.mercari.com/u/jaijuu/", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/mercari/seller/reviews", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.mercari.com/u/jaijuu/", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/mercari-seller-reviews/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/mercari/seller/reviews" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.mercari.com/u/jaijuu/","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/mercari/seller/reviews", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.mercari.com/u/jaijuu/", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/mercari/seller/reviews", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.mercari.com/u/jaijuu/", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "mercari-seller-reviews", "task_name": "Mercari Seller Reviews API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": { "seller_id": "id-1", "review_type": "buyers" }, "count": 1, "query": "London", "source": "mercari-seller-reviews", "results": [ { "text": "Sample text 1", "feedback": [ "sample" ], "created_at": "2026-06-14T15:30:00Z", "reviewer_id": "id-1", "is_automated": true, "rating_label": "Stylish Shoreditch Loft with Balcony", "reviewer_name": "Stylish Shoreditch Loft with Balcony", "reviewer_role": "sample", "reviewer_image_url": "https://example.com/item-1" } ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-mercari-seller-reviews [Mercari APIs](/docs/api.md#mercari) # Mercari Seller API Get a public Mercari US seller profile, ratings, follower counts and selling statistics. POST `/v1/mercari/seller` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. Provide at least one of: seller_id; username; url. - **`url` string Optional** Public Mercari US seller profile URL. Minimum length: 1. Maximum length: 2000. Format: uri. - **`username` string Optional** Public Mercari username. Minimum length: 1. Maximum length: 2000. Pattern: ^[A-Za-z0-9_.-]+$. ### Advanced & compatibility inputs 1 - **`seller_id` string Optional** Mercari seller ID, returned by search or seller listings. Pattern: ^[0-9]+$. ## 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" }, "data": { "type": "object", "required": [ "id", "username", "name", "url", "image_url", "description", "created_at", "listing_count", "sold_count", "follower_count", "following_count", "rating_count", "rating_average", "is_pro_seller", "is_fast_shipper", "is_fast_responder", "cancellation_rate" ], "properties": { "id": { "type": "string" }, "url": { "type": "string" }, "name": { "type": "string" }, "username": { "type": [ "string", "null" ] }, "image_url": { "type": [ "string", "null" ] }, "created_at": { "type": [ "string", "null" ] }, "sold_count": { "type": [ "number", "null" ] }, "description": { "type": [ "string", "null" ] }, "rating_count": { "type": [ "number", "null" ] }, "is_pro_seller": { "type": [ "boolean", "null" ] }, "listing_count": { "type": [ "number", "null" ] }, "follower_count": { "type": [ "number", "null" ] }, "rating_average": { "type": [ "number", "null" ] }, "following_count": { "type": [ "number", "null" ] }, "is_fast_shipper": { "type": [ "boolean", "null" ] }, "cancellation_rate": { "type": [ "number", "null" ] }, "is_fast_responder": { "type": [ "boolean", "null" ] } }, "additionalProperties": false }, "count": { "type": "integer", "minimum": 0 }, "query": { "type": [ "string", "null" ] }, "source": { "const": "mercari-seller" }, "results": { "type": "array", "items": { "type": "object", "required": [ "id", "username", "name", "url", "image_url", "description", "created_at", "listing_count", "sold_count", "follower_count", "following_count", "rating_count", "rating_average", "is_pro_seller", "is_fast_shipper", "is_fast_responder", "cancellation_rate" ], "properties": { "id": { "type": "string" }, "url": { "type": "string" }, "name": { "type": "string" }, "username": { "type": [ "string", "null" ] }, "image_url": { "type": [ "string", "null" ] }, "created_at": { "type": [ "string", "null" ] }, "sold_count": { "type": [ "number", "null" ] }, "description": { "type": [ "string", "null" ] }, "rating_count": { "type": [ "number", "null" ] }, "is_pro_seller": { "type": [ "boolean", "null" ] }, "listing_count": { "type": [ "number", "null" ] }, "follower_count": { "type": [ "number", "null" ] }, "rating_average": { "type": [ "number", "null" ] }, "following_count": { "type": [ "number", "null" ] }, "is_fast_shipper": { "type": [ "boolean", "null" ] }, "cancellation_rate": { "type": [ "number", "null" ] }, "is_fast_responder": { "type": [ "boolean", "null" ] } }, "additionalProperties": false } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer", "minimum": 0 }, "cursor": { "type": [ "string", "null" ] }, "strategy": { "type": "string" }, "next_cursor": { "type": [ "string", "null" ] }, "has_next_page": { "type": "boolean" } }, "additionalProperties": false }, "max_results_requested": { "type": "integer", "maximum": 100, "minimum": 1 } }, "additionalProperties": false } ``` ### View a polled run response ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "mercari-seller", "task_name": "Mercari Seller API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": { "id": "id-1", "url": "https://example.com/item-1", "name": "Stylish Shoreditch Loft with Balcony", "username": "Stylish Shoreditch Loft with Balcony", "image_url": "https://example.com/item-1", "created_at": "2026-06-14T15:30:00Z", "sold_count": 1, "description": "Sample description 1", "rating_count": 4.91, "is_pro_seller": true, "listing_count": 1, "follower_count": 1, "rating_average": 4.91, "following_count": 1, "is_fast_shipper": true, "cancellation_rate": 51.5074, "is_fast_responder": true }, "count": 1, "query": "London", "source": "mercari-seller", "results": [ { "id": "id-1", "url": "https://example.com/item-1", "name": "Stylish Shoreditch Loft with Balcony", "username": "Stylish Shoreditch Loft with Balcony", "image_url": "https://example.com/item-1", "created_at": "2026-06-14T15:30:00Z", "sold_count": 1, "description": "Sample description 1", "rating_count": 4.91, "is_pro_seller": true, "listing_count": 1, "follower_count": 1, "rating_average": 4.91, "following_count": 1, "is_fast_shipper": true, "cancellation_rate": 51.5074, "is_fast_responder": true } ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/mercari/seller" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.mercari.com/u/jaijuu/"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/mercari/seller", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.mercari.com/u/jaijuu/" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/mercari/seller", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.mercari.com/u/jaijuu/" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/mercari/seller" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.mercari.com/u/jaijuu/","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/mercari/seller", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.mercari.com/u/jaijuu/", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/mercari/seller", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.mercari.com/u/jaijuu/", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/mercari-seller/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/mercari/seller" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.mercari.com/u/jaijuu/","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/mercari/seller", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.mercari.com/u/jaijuu/", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/mercari/seller", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.mercari.com/u/jaijuu/", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "mercari-seller", "task_name": "Mercari Seller API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": { "id": "id-1", "url": "https://example.com/item-1", "name": "Stylish Shoreditch Loft with Balcony", "username": "Stylish Shoreditch Loft with Balcony", "image_url": "https://example.com/item-1", "created_at": "2026-06-14T15:30:00Z", "sold_count": 1, "description": "Sample description 1", "rating_count": 4.91, "is_pro_seller": true, "listing_count": 1, "follower_count": 1, "rating_average": 4.91, "following_count": 1, "is_fast_shipper": true, "cancellation_rate": 51.5074, "is_fast_responder": true }, "count": 1, "query": "London", "source": "mercari-seller", "results": [ { "id": "id-1", "url": "https://example.com/item-1", "name": "Stylish Shoreditch Loft with Balcony", "username": "Stylish Shoreditch Loft with Balcony", "image_url": "https://example.com/item-1", "created_at": "2026-06-14T15:30:00Z", "sold_count": 1, "description": "Sample description 1", "rating_count": 4.91, "is_pro_seller": true, "listing_count": 1, "follower_count": 1, "rating_average": 4.91, "following_count": 1, "is_fast_shipper": true, "cancellation_rate": 51.5074, "is_fast_responder": true } ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-mercari-seller [OfferUp APIs](/docs/api.md#offerup) # OfferUp Item API Read an OfferUp listing's full description, photos, condition code, price and available seller trust summary. No website login required. Removed listings may be unavailable. POST `/v1/offerup/item` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. Provide at least one of: id; url. - **`url` string Optional** Public page URL. Minimum length: 1. Maximum length: 2000. Pattern: ^https://(?:www\.)?offerup\.com/item/detail/[a-fA-F0-9]{8}(?:-[a-fA-F0-9]{4}){3}-[a-fA-F0-9]{12}/?(?:[?#].*)?$. - **`id` string Optional** Item ID from an OfferUp listing URL or search result. You can provide the listing URL instead. Pattern: ^[a-fA-F0-9]{8}(?:-[a-fA-F0-9]{4}){3}-[a-fA-F0-9]{12}$. ## 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": [ "id", "url", "title", "description", "price", "currency", "status", "condition_code", "posted_at", "firm_price", "location", "image_urls", "local_pickup", "shipping_enabled", "shipping_price", "category", "seller" ], "properties": { "id": { "type": "string" }, "url": { "type": "string" }, "price": { "type": [ "string", "null" ] }, "title": { "type": [ "string", "null" ] }, "seller": { "anyOf": [ { "type": "null" }, { "type": "object", "required": [ "id", "url", "name", "location", "joined_at", "rating", "rating_count", "items_sold", "items_purchased", "followers", "response_time", "last_active", "badges", "compliments", "truyou_verified", "is_business", "image_url" ], "properties": { "id": { "type": "string" }, "url": { "type": "string" }, "name": { "type": [ "string", "null" ] }, "badges": { "type": "array", "items": { "type": "string" } }, "rating": { "type": [ "number", "null" ] }, "location": { "type": [ "string", "null" ] }, "followers": { "type": [ "number", "null" ] }, "image_url": { "type": [ "string", "null" ] }, "joined_at": { "type": [ "string", "null" ] }, "items_sold": { "type": [ "number", "null" ] }, "compliments": { "type": "array", "items": { "type": "object", "required": [ "label", "count" ], "properties": { "count": { "type": [ "number", "null" ] }, "label": { "type": [ "string", "null" ] } }, "additionalProperties": false } }, "is_business": { "type": [ "boolean", "null" ] }, "last_active": { "type": [ "string", "null" ] }, "rating_count": { "type": [ "number", "null" ] }, "response_time": { "type": [ "string", "null" ] }, "items_purchased": { "type": [ "number", "null" ] }, "truyou_verified": { "type": [ "boolean", "null" ] } }, "additionalProperties": false } ] }, "status": { "type": [ "string", "null" ] }, "category": { "type": "object", "required": [ "id", "name" ], "properties": { "id": { "type": [ "string", "null" ] }, "name": { "type": [ "string", "null" ] } }, "additionalProperties": false }, "currency": { "const": "USD" }, "location": { "type": [ "string", "null" ] }, "posted_at": { "type": [ "string", "null" ] }, "firm_price": { "type": [ "boolean", "null" ] }, "image_urls": { "type": "array", "items": { "type": "string" } }, "description": { "type": [ "string", "null" ] }, "local_pickup": { "type": [ "boolean", "null" ] }, "condition_code": { "type": [ "number", "null" ] }, "shipping_price": { "type": [ "string", "null" ] }, "shipping_enabled": { "type": [ "boolean", "null" ] } }, "additionalProperties": false }, "count": { "type": "integer", "minimum": 0 }, "query": { "type": [ "string", "null" ] }, "source": { "const": "offerup-item" }, "results": { "type": "array", "items": { "type": "object", "required": [ "id", "url", "title", "description", "price", "currency", "status", "condition_code", "posted_at", "firm_price", "location", "image_urls", "local_pickup", "shipping_enabled", "shipping_price", "category", "seller" ], "properties": { "id": { "type": "string" }, "url": { "type": "string" }, "price": { "type": [ "string", "null" ] }, "title": { "type": [ "string", "null" ] }, "seller": { "anyOf": [ { "type": "null" }, { "type": "object", "required": [ "id", "url", "name", "location", "joined_at", "rating", "rating_count", "items_sold", "items_purchased", "followers", "response_time", "last_active", "badges", "compliments", "truyou_verified", "is_business", "image_url" ], "properties": { "id": { "type": "string" }, "url": { "type": "string" }, "name": { "type": [ "string", "null" ] }, "badges": { "type": "array", "items": { "type": "string" } }, "rating": { "type": [ "number", "null" ] }, "location": { "type": [ "string", "null" ] }, "followers": { "type": [ "number", "null" ] }, "image_url": { "type": [ "string", "null" ] }, "joined_at": { "type": [ "string", "null" ] }, "items_sold": { "type": [ "number", "null" ] }, "compliments": { "type": "array", "items": { "type": "object", "required": [ "label", "count" ], "properties": { "count": { "type": [ "number", "null" ] }, "label": { "type": [ "string", "null" ] } }, "additionalProperties": false } }, "is_business": { "type": [ "boolean", "null" ] }, "last_active": { "type": [ "string", "null" ] }, "rating_count": { "type": [ "number", "null" ] }, "response_time": { "type": [ "string", "null" ] }, "items_purchased": { "type": [ "number", "null" ] }, "truyou_verified": { "type": [ "boolean", "null" ] } }, "additionalProperties": false } ] }, "status": { "type": [ "string", "null" ] }, "category": { "type": "object", "required": [ "id", "name" ], "properties": { "id": { "type": [ "string", "null" ] }, "name": { "type": [ "string", "null" ] } }, "additionalProperties": false }, "currency": { "const": "USD" }, "location": { "type": [ "string", "null" ] }, "posted_at": { "type": [ "string", "null" ] }, "firm_price": { "type": [ "boolean", "null" ] }, "image_urls": { "type": "array", "items": { "type": "string" } }, "description": { "type": [ "string", "null" ] }, "local_pickup": { "type": [ "boolean", "null" ] }, "condition_code": { "type": [ "number", "null" ] }, "shipping_price": { "type": [ "string", "null" ] }, "shipping_enabled": { "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": { "type": [ "string", "null" ] }, "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-item", "task_name": "OfferUp Item API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": { "id": "id-1", "url": "https://example.com/item-1", "price": "180", "title": "Stylish Shoreditch Loft with Balcony", "seller": null, "status": "sample", "category": { "id": "id-1", "name": "Stylish Shoreditch Loft with Balcony" }, "currency": "USD", "location": "London", "posted_at": "sample", "firm_price": true, "image_urls": [ "https://images.example.com/image_urls-1.jpg" ], "description": "Sample description 1", "local_pickup": true, "condition_code": 1.5, "shipping_price": "180", "shipping_enabled": true }, "count": 1, "query": "London", "source": "offerup-item", "results": [ { "id": "id-1", "url": "https://example.com/item-1", "price": "180", "title": "Stylish Shoreditch Loft with Balcony", "seller": null, "status": "sample", "category": { "id": "id-1", "name": "Stylish Shoreditch Loft with Balcony" }, "currency": "USD", "location": "London", "posted_at": "sample", "firm_price": true, "image_urls": [ "https://images.example.com/image_urls-1.jpg" ], "description": "Sample description 1", "local_pickup": true, "condition_code": 1.5, "shipping_price": "180", "shipping_enabled": true } ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/offerup/item" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://offerup.com/item/detail/98e4c905-31bf-39df-a6dc-751c1fa6553d"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/offerup/item", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://offerup.com/item/detail/98e4c905-31bf-39df-a6dc-751c1fa6553d" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/offerup/item", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://offerup.com/item/detail/98e4c905-31bf-39df-a6dc-751c1fa6553d" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/offerup/item" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://offerup.com/item/detail/98e4c905-31bf-39df-a6dc-751c1fa6553d","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/offerup/item", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://offerup.com/item/detail/98e4c905-31bf-39df-a6dc-751c1fa6553d", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/offerup/item", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://offerup.com/item/detail/98e4c905-31bf-39df-a6dc-751c1fa6553d", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/offerup-item/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/offerup/item" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://offerup.com/item/detail/98e4c905-31bf-39df-a6dc-751c1fa6553d","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/offerup/item", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://offerup.com/item/detail/98e4c905-31bf-39df-a6dc-751c1fa6553d", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/offerup/item", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://offerup.com/item/detail/98e4c905-31bf-39df-a6dc-751c1fa6553d", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "offerup-item", "task_name": "OfferUp Item API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": { "id": "id-1", "url": "https://example.com/item-1", "price": "180", "title": "Stylish Shoreditch Loft with Balcony", "seller": null, "status": "sample", "category": { "id": "id-1", "name": "Stylish Shoreditch Loft with Balcony" }, "currency": "USD", "location": "London", "posted_at": "sample", "firm_price": true, "image_urls": [ "https://images.example.com/image_urls-1.jpg" ], "description": "Sample description 1", "local_pickup": true, "condition_code": 1.5, "shipping_price": "180", "shipping_enabled": true }, "count": 1, "query": "London", "source": "offerup-item", "results": [ { "id": "id-1", "url": "https://example.com/item-1", "price": "180", "title": "Stylish Shoreditch Loft with Balcony", "seller": null, "status": "sample", "category": { "id": "id-1", "name": "Stylish Shoreditch Loft with Balcony" }, "currency": "USD", "location": "London", "posted_at": "sample", "firm_price": true, "image_urls": [ "https://images.example.com/image_urls-1.jpg" ], "description": "Sample description 1", "local_pickup": true, "condition_code": 1.5, "shipping_price": "180", "shipping_enabled": true } ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-offerup-item [OfferUp APIs](/docs/api.md#offerup) # 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` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`location` string Required** 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. - **`query` string Required** Search words, such as iPhone 13 or Nintendo Switch. Minimum length: 1. Maximum length: 200. - **`limit` integer Optional** Maximum results in this response. Default: 25. Minimum: 1. Maximum: 50. - **`condition` string Optional** Filter by an allowed product condition. Allowed: "new", "open_box", "refurbished", "used", "for_parts", "other". - **`cursor` string Optional** next_cursor from the previous response. Keep the other search inputs unchanged. Maximum length: 131072. - **`max_price` number Optional** Maximum price in the marketplace currency. Minimum: 0. Maximum: 1000000. - **`min_price` number Optional** Minimum price in the marketplace currency. Minimum: 0. Maximum: 1000000. - **`radius_miles` integer Optional** Search radius in miles around the resolved location. Default: 30. Allowed: 5, 10, 20, 30, 50, 80. - **`sort` string Optional** Sort order. Choose an allowed value below. Allowed: "best_match", "newest", "closest", "price_low", "price_high". ### Advanced & compatibility inputs 1 - **`category_id` string Optional** 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 - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/offerup/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "London", "location": "London" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/offerup/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "London", "location": "London" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash 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}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/offerup/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "London", "location": "London", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/offerup/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "London", "location": "London", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/offerup-search/runs`. Example request Request mode Wait for resultsAsync + polling ```bash 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}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/offerup/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "London", "location": "London", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/offerup/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "London", "location": "London", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```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 } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-offerup-search [OfferUp APIs](/docs/api.md#offerup) # OfferUp Seller Listings API Browse a public OfferUp seller's active listings with cursor pagination. Keep seller_id and limit unchanged when continuing. POST `/v1/offerup/seller-listings` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. Provide at least one of: seller_id; url. - **`url` string Optional** Public page URL. Minimum length: 1. Maximum length: 2000. Pattern: ^https://(?:www\.)?offerup\.com/p/[0-9]{1,15}/?(?:[?#].*)?$. - **`limit` integer Optional** Maximum results in this response. Default: 25. Minimum: 1. Maximum: 50. - **`cursor` string Optional** next_cursor from the previous response. Keep all other inputs unchanged. Expires after 30 minutes. Maximum length: 131072. ### Advanced & compatibility inputs 1 - **`seller_id` string Optional** Upstream seller ID returned by search or a seller profile. Prefer a seller URL when supported. Pattern: ^[0-9]{1,15}$. ## 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": [ "seller_id" ], "properties": { "seller_id": { "type": "string" } }, "additionalProperties": false }, "count": { "type": "integer", "minimum": 0 }, "query": { "type": [ "string", "null" ] }, "source": { "const": "offerup-seller-listings" }, "results": { "type": "array", "items": { "type": "object", "required": [ "id", "url", "title", "price", "currency", "status", "location", "image_url" ], "properties": { "id": { "type": "string" }, "url": { "type": "string" }, "price": { "type": [ "string", "null" ] }, "title": { "type": [ "string", "null" ] }, "status": { "type": [ "string", "null" ] }, "currency": { "const": "USD" }, "location": { "type": [ "string", "null" ] }, "image_url": { "type": [ "string", "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": { "type": [ "string", "null" ] }, "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-seller-listings", "task_name": "OfferUp Seller Listings API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": { "seller_id": "id-1" }, "count": 1, "query": "London", "source": "offerup-seller-listings", "results": [ { "id": "id-1", "url": "https://example.com/item-1", "price": "180", "title": "Stylish Shoreditch Loft with Balcony", "status": "sample", "currency": "USD", "location": "London", "image_url": "https://example.com/item-1" } ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/offerup/seller-listings" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://offerup.com/p/123456"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/offerup/seller-listings", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://offerup.com/p/123456" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/offerup/seller-listings", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://offerup.com/p/123456" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/offerup/seller-listings" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://offerup.com/p/123456","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/offerup/seller-listings", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://offerup.com/p/123456", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/offerup/seller-listings", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://offerup.com/p/123456", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/offerup-seller-listings/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/offerup/seller-listings" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://offerup.com/p/123456","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/offerup/seller-listings", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://offerup.com/p/123456", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/offerup/seller-listings", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://offerup.com/p/123456", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "offerup-seller-listings", "task_name": "OfferUp Seller Listings API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": { "seller_id": "id-1" }, "count": 1, "query": "London", "source": "offerup-seller-listings", "results": [ { "id": "id-1", "url": "https://example.com/item-1", "price": "180", "title": "Stylish Shoreditch Loft with Balcony", "status": "sample", "currency": "USD", "location": "London", "image_url": "https://example.com/item-1" } ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-offerup-seller-listings [OfferUp APIs](/docs/api.md#offerup) # OfferUp Seller API Read a public OfferUp seller profile, including available ratings, account age, activity, response time, badges and compliments. Missing metrics are null; cancellation rates are not available. POST `/v1/offerup/seller` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. Provide at least one of: seller_id; url. - **`url` string Optional** Public page URL. Minimum length: 1. Maximum length: 2000. Pattern: ^https://(?:www\.)?offerup\.com/p/[0-9]{1,15}/?(?:[?#].*)?$. ### Advanced & compatibility inputs 1 - **`seller_id` string Optional** Upstream seller ID returned by search or a seller profile. Prefer a seller URL when supported. Pattern: ^[0-9]{1,15}$. ## 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": [ "id", "url", "name", "location", "joined_at", "rating", "rating_count", "items_sold", "items_purchased", "followers", "response_time", "last_active", "badges", "compliments", "truyou_verified", "is_business", "image_url" ], "properties": { "id": { "type": "string" }, "url": { "type": "string" }, "name": { "type": [ "string", "null" ] }, "badges": { "type": "array", "items": { "type": "string" } }, "rating": { "type": [ "number", "null" ] }, "location": { "type": [ "string", "null" ] }, "followers": { "type": [ "number", "null" ] }, "image_url": { "type": [ "string", "null" ] }, "joined_at": { "type": [ "string", "null" ] }, "items_sold": { "type": [ "number", "null" ] }, "compliments": { "type": "array", "items": { "type": "object", "required": [ "label", "count" ], "properties": { "count": { "type": [ "number", "null" ] }, "label": { "type": [ "string", "null" ] } }, "additionalProperties": false } }, "is_business": { "type": [ "boolean", "null" ] }, "last_active": { "type": [ "string", "null" ] }, "rating_count": { "type": [ "number", "null" ] }, "response_time": { "type": [ "string", "null" ] }, "items_purchased": { "type": [ "number", "null" ] }, "truyou_verified": { "type": [ "boolean", "null" ] } }, "additionalProperties": false }, "count": { "type": "integer", "minimum": 0 }, "query": { "type": [ "string", "null" ] }, "source": { "const": "offerup-seller" }, "results": { "type": "array", "items": { "type": "object", "required": [ "id", "url", "name", "location", "joined_at", "rating", "rating_count", "items_sold", "items_purchased", "followers", "response_time", "last_active", "badges", "compliments", "truyou_verified", "is_business", "image_url" ], "properties": { "id": { "type": "string" }, "url": { "type": "string" }, "name": { "type": [ "string", "null" ] }, "badges": { "type": "array", "items": { "type": "string" } }, "rating": { "type": [ "number", "null" ] }, "location": { "type": [ "string", "null" ] }, "followers": { "type": [ "number", "null" ] }, "image_url": { "type": [ "string", "null" ] }, "joined_at": { "type": [ "string", "null" ] }, "items_sold": { "type": [ "number", "null" ] }, "compliments": { "type": "array", "items": { "type": "object", "required": [ "label", "count" ], "properties": { "count": { "type": [ "number", "null" ] }, "label": { "type": [ "string", "null" ] } }, "additionalProperties": false } }, "is_business": { "type": [ "boolean", "null" ] }, "last_active": { "type": [ "string", "null" ] }, "rating_count": { "type": [ "number", "null" ] }, "response_time": { "type": [ "string", "null" ] }, "items_purchased": { "type": [ "number", "null" ] }, "truyou_verified": { "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": { "type": [ "string", "null" ] }, "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-seller", "task_name": "OfferUp Seller API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": { "id": "id-1", "url": "https://example.com/item-1", "name": "Stylish Shoreditch Loft with Balcony", "badges": [ "Guest favorite" ], "rating": 4.91, "location": "London", "followers": 1.5, "image_url": "https://example.com/item-1", "joined_at": "sample", "items_sold": 1.5, "compliments": [ { "count": 1, "label": "Stylish Shoreditch Loft with Balcony" } ], "is_business": true, "last_active": "sample", "rating_count": 4.91, "response_time": "sample", "items_purchased": 1.5, "truyou_verified": true }, "count": 1, "query": "London", "source": "offerup-seller", "results": [ { "id": "id-1", "url": "https://example.com/item-1", "name": "Stylish Shoreditch Loft with Balcony", "badges": [ "Guest favorite" ], "rating": 4.91, "location": "London", "followers": 1.5, "image_url": "https://example.com/item-1", "joined_at": "sample", "items_sold": 1.5, "compliments": [ { "count": 1, "label": "Stylish Shoreditch Loft with Balcony" } ], "is_business": true, "last_active": "sample", "rating_count": 4.91, "response_time": "sample", "items_purchased": 1.5, "truyou_verified": true } ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/offerup/seller" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://offerup.com/p/123456"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/offerup/seller", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://offerup.com/p/123456" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/offerup/seller", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://offerup.com/p/123456" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/offerup/seller" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://offerup.com/p/123456","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/offerup/seller", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://offerup.com/p/123456", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/offerup/seller", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://offerup.com/p/123456", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/offerup-seller/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/offerup/seller" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://offerup.com/p/123456","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/offerup/seller", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://offerup.com/p/123456", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/offerup/seller", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://offerup.com/p/123456", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "offerup-seller", "task_name": "OfferUp Seller API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": { "id": "id-1", "url": "https://example.com/item-1", "name": "Stylish Shoreditch Loft with Balcony", "badges": [ "Guest favorite" ], "rating": 4.91, "location": "London", "followers": 1.5, "image_url": "https://example.com/item-1", "joined_at": "sample", "items_sold": 1.5, "compliments": [ { "count": 1, "label": "Stylish Shoreditch Loft with Balcony" } ], "is_business": true, "last_active": "sample", "rating_count": 4.91, "response_time": "sample", "items_purchased": 1.5, "truyou_verified": true }, "count": 1, "query": "London", "source": "offerup-seller", "results": [ { "id": "id-1", "url": "https://example.com/item-1", "name": "Stylish Shoreditch Loft with Balcony", "badges": [ "Guest favorite" ], "rating": 4.91, "location": "London", "followers": 1.5, "image_url": "https://example.com/item-1", "joined_at": "sample", "items_sold": 1.5, "compliments": [ { "count": 1, "label": "Stylish Shoreditch Loft with Balcony" } ], "is_business": true, "last_active": "sample", "rating_count": 4.91, "response_time": "sample", "items_purchased": 1.5, "truyou_verified": true } ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-offerup-seller [OLX APIs](/docs/api.md#olx) # OLX Listing API Scrape a public OLX listing page. POST `/v1/olx/listing` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`url` string Required** URL returned by the matching search endpoint. Minimum length: 1. Maximum length: 2000. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "olx-listing", "task_name": "OLX Listing API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/olx/listing" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.olx.com/item/example"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/olx/listing", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.olx.com/item/example" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/olx/listing", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.olx.com/item/example" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/olx/listing" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.olx.com/item/example","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/olx/listing", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.olx.com/item/example", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/olx/listing", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.olx.com/item/example", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/olx-listing/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/olx/listing" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.olx.com/item/example","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/olx/listing", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.olx.com/item/example", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/olx/listing", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.olx.com/item/example", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "olx-listing", "task_name": "OLX Listing API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-olx-listing [OLX APIs](/docs/api.md#olx) # OLX API Scrape public OLX listing search results. POST `/v1/olx/search` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`query` string Required** Search query. Minimum length: 1. Maximum length: 2000. - **`limit` integer Optional** Maximum number of results to return. Default: 25. Minimum: 1. Maximum: 100. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "olx-search", "task_name": "OLX API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/olx/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"bicycle"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/olx/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "bicycle" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/olx/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "bicycle" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/olx/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"bicycle","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/olx/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "bicycle", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/olx/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "bicycle", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/olx-search/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/olx/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"bicycle","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/olx/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "bicycle", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/olx/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "bicycle", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "olx-search", "task_name": "OLX API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-olx-search [OnlyFans APIs](/docs/api.md#onlyfans) # OnlyFans API Fetch public OnlyFans profile details, subscription pricing and visible counts without connecting an OnlyFans account. Hidden counts are null; restricted profiles may be unavailable. POST `/v1/onlyfans/profile` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`username` string Required** OnlyFans username, @handle, or profile URL. Minimum length: 1. Maximum length: 128. ### Advanced & compatibility inputs 1 - **`limit` integer Optional** Accepted for compatibility; a profile lookup returns one profile. It does not paginate posts. Minimum: 1. Maximum: 100. ## 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": [ "id", "username", "name", "title", "url", "description", "avatar_url", "image_url", "header_url", "subscription_price", "posts_count", "photos_count", "videos_count", "audios_count", "media_count", "likes_count", "subscribers_count", "is_verified", "is_performer", "website", "location", "joined_at", "fetched_at" ], "properties": { "id": { "type": "string" }, "url": { "type": "string" }, "name": { "type": [ "string", "null" ] }, "title": { "type": "string" }, "website": { "type": [ "string", "null" ] }, "location": { "type": [ "string", "null" ] }, "username": { "type": "string" }, "image_url": { "type": [ "string", "null" ] }, "joined_at": { "type": [ "string", "null" ] }, "avatar_url": { "type": [ "string", "null" ] }, "fetched_at": { "type": "string" }, "header_url": { "type": [ "string", "null" ] }, "description": { "type": [ "string", "null" ], "description": "Creator biography; may contain HTML." }, "is_verified": { "type": [ "boolean", "null" ] }, "likes_count": { "type": [ "number", "null" ], "minimum": 0 }, "media_count": { "type": [ "number", "null" ], "minimum": 0 }, "posts_count": { "type": [ "number", "null" ], "minimum": 0 }, "audios_count": { "type": [ "number", "null" ], "minimum": 0 }, "is_performer": { "type": [ "boolean", "null" ] }, "photos_count": { "type": [ "number", "null" ], "minimum": 0 }, "videos_count": { "type": [ "number", "null" ], "minimum": 0 }, "subscribers_count": { "type": [ "number", "null" ], "minimum": 0 }, "subscription_price": { "type": [ "number", "null" ], "minimum": 0 } }, "additionalProperties": false }, "count": { "type": "integer", "minimum": 0 }, "query": { "type": [ "string", "null" ] }, "source": { "const": "onlyfans-profile" }, "results": { "type": "array", "items": { "type": "object", "required": [ "id", "username", "name", "title", "url", "description", "avatar_url", "image_url", "header_url", "subscription_price", "posts_count", "photos_count", "videos_count", "audios_count", "media_count", "likes_count", "subscribers_count", "is_verified", "is_performer", "website", "location", "joined_at", "fetched_at" ], "properties": { "id": { "type": "string" }, "url": { "type": "string" }, "name": { "type": [ "string", "null" ] }, "title": { "type": "string" }, "website": { "type": [ "string", "null" ] }, "location": { "type": [ "string", "null" ] }, "username": { "type": "string" }, "image_url": { "type": [ "string", "null" ] }, "joined_at": { "type": [ "string", "null" ] }, "avatar_url": { "type": [ "string", "null" ] }, "fetched_at": { "type": "string" }, "header_url": { "type": [ "string", "null" ] }, "description": { "type": [ "string", "null" ], "description": "Creator biography; may contain HTML." }, "is_verified": { "type": [ "boolean", "null" ] }, "likes_count": { "type": [ "number", "null" ], "minimum": 0 }, "media_count": { "type": [ "number", "null" ], "minimum": 0 }, "posts_count": { "type": [ "number", "null" ], "minimum": 0 }, "audios_count": { "type": [ "number", "null" ], "minimum": 0 }, "is_performer": { "type": [ "boolean", "null" ] }, "photos_count": { "type": [ "number", "null" ], "minimum": 0 }, "videos_count": { "type": [ "number", "null" ], "minimum": 0 }, "subscribers_count": { "type": [ "number", "null" ], "minimum": 0 }, "subscription_price": { "type": [ "number", "null" ], "minimum": 0 } }, "additionalProperties": false } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer", "minimum": 0 }, "cursor": { "type": [ "string", "null" ] }, "strategy": { "type": "string" }, "next_cursor": { "type": [ "string", "null" ] }, "has_next_page": { "type": "boolean" } }, "additionalProperties": false }, "max_results_requested": { "type": "integer", "minimum": 1 } }, "additionalProperties": false } ``` ### View a polled run response ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "onlyfans-profile", "task_name": "OnlyFans API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": { "id": "id-1", "url": "https://example.com/item-1", "name": "Stylish Shoreditch Loft with Balcony", "title": "Stylish Shoreditch Loft with Balcony", "website": "sample", "location": "London", "username": "Stylish Shoreditch Loft with Balcony", "image_url": "https://example.com/item-1", "joined_at": "sample", "avatar_url": "https://images.example.com/avatar_url-1.jpg", "fetched_at": "sample", "header_url": "https://example.com/item-1", "description": "Sample description 1", "is_verified": true, "likes_count": 1, "media_count": 1, "posts_count": 1, "audios_count": 1, "is_performer": true, "photos_count": 1, "videos_count": 1, "subscribers_count": 1, "subscription_price": 180 }, "count": 1, "query": "London", "source": "onlyfans-profile", "results": [ { "id": "id-1", "url": "https://example.com/item-1", "name": "Stylish Shoreditch Loft with Balcony", "title": "Stylish Shoreditch Loft with Balcony", "website": "sample", "location": "London", "username": "Stylish Shoreditch Loft with Balcony", "image_url": "https://example.com/item-1", "joined_at": "sample", "avatar_url": "https://images.example.com/avatar_url-1.jpg", "fetched_at": "sample", "header_url": "https://example.com/item-1", "description": "Sample description 1", "is_verified": true, "likes_count": 1, "media_count": 1, "posts_count": 1, "audios_count": 1, "is_performer": true, "photos_count": 1, "videos_count": 1, "subscribers_count": 1, "subscription_price": 180 } ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/onlyfans/profile" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"username":"onlyfans"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/onlyfans/profile", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "username": "onlyfans" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/onlyfans/profile", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "username": "onlyfans" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/onlyfans/profile" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"username":"onlyfans","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/onlyfans/profile", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "username": "onlyfans", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/onlyfans/profile", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "username": "onlyfans", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/onlyfans-profile/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/onlyfans/profile" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"username":"onlyfans","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/onlyfans/profile", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "username": "onlyfans", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/onlyfans/profile", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "username": "onlyfans", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "onlyfans-profile", "task_name": "OnlyFans API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": { "id": "id-1", "url": "https://example.com/item-1", "name": "Stylish Shoreditch Loft with Balcony", "title": "Stylish Shoreditch Loft with Balcony", "website": "sample", "location": "London", "username": "Stylish Shoreditch Loft with Balcony", "image_url": "https://example.com/item-1", "joined_at": "sample", "avatar_url": "https://images.example.com/avatar_url-1.jpg", "fetched_at": "sample", "header_url": "https://example.com/item-1", "description": "Sample description 1", "is_verified": true, "likes_count": 1, "media_count": 1, "posts_count": 1, "audios_count": 1, "is_performer": true, "photos_count": 1, "videos_count": 1, "subscribers_count": 1, "subscription_price": 180 }, "count": 1, "query": "London", "source": "onlyfans-profile", "results": [ { "id": "id-1", "url": "https://example.com/item-1", "name": "Stylish Shoreditch Loft with Balcony", "title": "Stylish Shoreditch Loft with Balcony", "website": "sample", "location": "London", "username": "Stylish Shoreditch Loft with Balcony", "image_url": "https://example.com/item-1", "joined_at": "sample", "avatar_url": "https://images.example.com/avatar_url-1.jpg", "fetched_at": "sample", "header_url": "https://example.com/item-1", "description": "Sample description 1", "is_verified": true, "likes_count": 1, "media_count": 1, "posts_count": 1, "audios_count": 1, "is_performer": true, "photos_count": 1, "videos_count": 1, "subscribers_count": 1, "subscription_price": 180 } ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-onlyfans-profile [OnlyFans APIs](/docs/api.md#onlyfans) # OnlyFans Profiles API Fetch public details for up to 10 OnlyFans profiles without connecting an account. Duplicate usernames are fetched once. Partial batches include per-profile errors; all-failed batches fail the run. Costs 10 credits per batch. POST `/v1/onlyfans/profiles` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`usernames` array Required** Public usernames to retrieve. Errors or unavailable profiles are reported individually. Minimum items: 1. Maximum items: 10. ## 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": [ "requested", "succeeded", "failed", "errors" ], "properties": { "errors": { "type": "array", "items": { "type": "object", "required": [ "username", "code", "message" ], "properties": { "code": { "type": "string" }, "message": { "type": "string" }, "username": { "type": "string" } }, "additionalProperties": false } }, "failed": { "type": "integer" }, "requested": { "type": "integer" }, "succeeded": { "type": "integer" } }, "additionalProperties": false }, "count": { "type": "integer", "minimum": 0 }, "query": { "type": [ "string", "null" ] }, "source": { "const": "onlyfans-profiles" }, "results": { "type": "array", "items": { "type": "object", "required": [ "id", "username", "name", "title", "url", "description", "avatar_url", "image_url", "header_url", "subscription_price", "posts_count", "photos_count", "videos_count", "audios_count", "media_count", "likes_count", "subscribers_count", "is_verified", "is_performer", "website", "location", "joined_at", "fetched_at" ], "properties": { "id": { "type": "string" }, "url": { "type": "string" }, "name": { "type": [ "string", "null" ] }, "title": { "type": "string" }, "website": { "type": [ "string", "null" ] }, "location": { "type": [ "string", "null" ] }, "username": { "type": "string" }, "image_url": { "type": [ "string", "null" ] }, "joined_at": { "type": [ "string", "null" ] }, "avatar_url": { "type": [ "string", "null" ] }, "fetched_at": { "type": "string" }, "header_url": { "type": [ "string", "null" ] }, "description": { "type": [ "string", "null" ], "description": "Creator biography; may contain HTML." }, "is_verified": { "type": [ "boolean", "null" ] }, "likes_count": { "type": [ "number", "null" ], "minimum": 0 }, "media_count": { "type": [ "number", "null" ], "minimum": 0 }, "posts_count": { "type": [ "number", "null" ], "minimum": 0 }, "audios_count": { "type": [ "number", "null" ], "minimum": 0 }, "is_performer": { "type": [ "boolean", "null" ] }, "photos_count": { "type": [ "number", "null" ], "minimum": 0 }, "videos_count": { "type": [ "number", "null" ], "minimum": 0 }, "subscribers_count": { "type": [ "number", "null" ], "minimum": 0 }, "subscription_price": { "type": [ "number", "null" ], "minimum": 0 } }, "additionalProperties": false } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer", "minimum": 0 }, "cursor": { "type": [ "string", "null" ] }, "strategy": { "type": "string" }, "next_cursor": { "type": [ "string", "null" ] }, "has_next_page": { "type": "boolean" } }, "additionalProperties": false }, "max_results_requested": { "type": "integer", "minimum": 1 } }, "additionalProperties": false } ``` ### View a polled run response ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "onlyfans-profiles", "task_name": "OnlyFans Profiles API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": { "errors": [ { "code": "sample", "message": "sample", "username": "Stylish Shoreditch Loft with Balcony" } ], "failed": 1, "requested": 1, "succeeded": 1 }, "count": 1, "query": "London", "source": "onlyfans-profiles", "results": [ { "id": "id-1", "url": "https://example.com/item-1", "name": "Stylish Shoreditch Loft with Balcony", "title": "Stylish Shoreditch Loft with Balcony", "website": "sample", "location": "London", "username": "Stylish Shoreditch Loft with Balcony", "image_url": "https://example.com/item-1", "joined_at": "sample", "avatar_url": "https://images.example.com/avatar_url-1.jpg", "fetched_at": "sample", "header_url": "https://example.com/item-1", "description": "Sample description 1", "is_verified": true, "likes_count": 1, "media_count": 1, "posts_count": 1, "audios_count": 1, "is_performer": true, "photos_count": 1, "videos_count": 1, "subscribers_count": 1, "subscription_price": 180 } ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/onlyfans/profiles" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"usernames":["onlyfans","oftv"]}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/onlyfans/profiles", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "usernames": [ "onlyfans", "oftv" ] }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/onlyfans/profiles", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "usernames": [ "onlyfans", "oftv" ] }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/onlyfans/profiles" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"usernames":["onlyfans","oftv"],"_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/onlyfans/profiles", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "usernames": [ "onlyfans", "oftv" ], "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/onlyfans/profiles", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "usernames": [ "onlyfans", "oftv" ], "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/onlyfans-profiles/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/onlyfans/profiles" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"usernames":["onlyfans","oftv"],"_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/onlyfans/profiles", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "usernames": [ "onlyfans", "oftv" ], "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/onlyfans/profiles", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "usernames": [ "onlyfans", "oftv" ], "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "onlyfans-profiles", "task_name": "OnlyFans Profiles API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": { "errors": [ { "code": "sample", "message": "sample", "username": "Stylish Shoreditch Loft with Balcony" } ], "failed": 1, "requested": 1, "succeeded": 1 }, "count": 1, "query": "London", "source": "onlyfans-profiles", "results": [ { "id": "id-1", "url": "https://example.com/item-1", "name": "Stylish Shoreditch Loft with Balcony", "title": "Stylish Shoreditch Loft with Balcony", "website": "sample", "location": "London", "username": "Stylish Shoreditch Loft with Balcony", "image_url": "https://example.com/item-1", "joined_at": "sample", "avatar_url": "https://images.example.com/avatar_url-1.jpg", "fetched_at": "sample", "header_url": "https://example.com/item-1", "description": "Sample description 1", "is_verified": true, "likes_count": 1, "media_count": 1, "posts_count": 1, "audios_count": 1, "is_performer": true, "photos_count": 1, "videos_count": 1, "subscribers_count": 1, "subscription_price": 180 } ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-onlyfans-profiles [OnlyFans APIs](/docs/api.md#onlyfans) # OnlyFans Creator Search API Discover OnlyFans creator profile links and snippets from Google's search index. No OnlyFans login needed. Coverage is not exhaustive and snippets may be outdated; use the profile endpoint for current data. A page can contain fewer results or be empty after non-profile links are excluded; continue while next_cursor is present. POST `/v1/onlyfans/search` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`query` string Required** Creator name, username or topic to search for. Minimum length: 1. Maximum length: 200. - **`limit` integer Optional** Maximum creator profiles to return from this search page. Default: 10. Minimum: 1. Maximum: 10. - **`cursor` string Optional** next_cursor from the previous response. Keep the same query. Search rankings can change between requests. Maximum length: 131072. ## 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": [ "discovery_source", "exhaustive", "profiles_fetched", "fetched_at" ], "properties": { "exhaustive": { "const": false }, "fetched_at": { "type": "string" }, "discovery_source": { "const": "google_via_serper" }, "profiles_fetched": { "const": false } }, "additionalProperties": false }, "count": { "type": "integer", "minimum": 0 }, "query": { "type": [ "string", "null" ] }, "source": { "const": "onlyfans-search" }, "results": { "type": "array", "items": { "type": "object", "required": [ "username", "url", "title", "description" ], "properties": { "url": { "type": "string" }, "title": { "type": "string" }, "username": { "type": "string" }, "description": { "type": [ "string", "null" ] } }, "additionalProperties": false } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer", "minimum": 0 }, "cursor": { "type": [ "string", "null" ] }, "strategy": { "type": "string" }, "next_cursor": { "type": [ "string", "null" ] }, "has_next_page": { "type": "boolean" } }, "additionalProperties": false }, "max_results_requested": { "type": "integer", "minimum": 1 } }, "additionalProperties": false } ``` ### View a polled run response ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "onlyfans-search", "task_name": "OnlyFans Creator Search API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": { "exhaustive": false, "fetched_at": "sample", "discovery_source": "google_via_serper", "profiles_fetched": false }, "count": 1, "query": "London", "source": "onlyfans-search", "results": [ { "url": "https://example.com/item-1", "title": "Stylish Shoreditch Loft with Balcony", "username": "Stylish Shoreditch Loft with Balcony", "description": "Sample description 1" } ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/onlyfans/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"boxing"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/onlyfans/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "boxing" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/onlyfans/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "boxing" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/onlyfans/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"boxing","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/onlyfans/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "boxing", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/onlyfans/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "boxing", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/onlyfans-search/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/onlyfans/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"boxing","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/onlyfans/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "boxing", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/onlyfans/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "boxing", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "onlyfans-search", "task_name": "OnlyFans Creator Search API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": { "exhaustive": false, "fetched_at": "sample", "discovery_source": "google_via_serper", "profiles_fetched": false }, "count": 1, "query": "London", "source": "onlyfans-search", "results": [ { "url": "https://example.com/item-1", "title": "Stylish Shoreditch Loft with Balcony", "username": "Stylish Shoreditch Loft with Balcony", "description": "Sample description 1" } ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-onlyfans-search [Patreon APIs](/docs/api.md#patreon) # Patreon Campaign API Fetch public Patreon creator details, visible counts, membership tiers and goals. Hidden earnings remain null. POST `/v1/patreon/campaign` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`username` string Required** Patreon creator username. Minimum length: 1. Maximum length: 2000. - **`limit` integer Optional** Maximum number of results to return. Default: 25. Minimum: 1. Maximum: 100. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "patreon-campaign", "task_name": "Patreon Campaign API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/patreon/campaign" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"username":"waitbutwhy"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/patreon/campaign", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "username": "waitbutwhy" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/patreon/campaign", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "username": "waitbutwhy" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/patreon/campaign" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"username":"waitbutwhy","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/patreon/campaign", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "username": "waitbutwhy", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/patreon/campaign", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "username": "waitbutwhy", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/patreon-campaign/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/patreon/campaign" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"username":"waitbutwhy","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/patreon/campaign", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "username": "waitbutwhy", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/patreon/campaign", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "username": "waitbutwhy", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "patreon-campaign", "task_name": "Patreon Campaign API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-patreon-campaign [Patreon APIs](/docs/api.md#patreon) # Patreon Creator Download Export a Patreon creator's posts and accessible media as a ZIP file. Managed Patreon auth is optional and recommended for paid content your account can view. POST `/v1/patreon/creator-download` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`creator` string Required** Patreon creator username, vanity path, or creator URL to export as a ZIP file. Minimum length: 1. Maximum length: 2000. - **`limit` integer Optional** Optional maximum number of posts to include. Omit this field to attempt the full creator export. Preferred name; maxPosts remains supported. Minimum: 1. Maximum: 100000. ### Advanced & compatibility inputs 1 - **`maxPosts` integer Optional** Optional maximum number of posts to include. Omit this field to attempt the full creator export. You can also use limit. Minimum: 1. Maximum: 100000. ## 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 { "$schema": "https://json-schema.org/draft/2020-12/schema", "description": "The result begins with an export ID. A completed run returns artifact details, download expiry and collection statistics. partial_success means some media could not be downloaded; inspect failed_media.", "anyOf": [ { "type": "object", "properties": { "success": { "type": "boolean", "const": true }, "export_id": { "type": "string", "description": "Export identifier. Poll the run until it succeeds before downloading." }, "status": { "type": "string", "enum": [ "completed", "partial_success", "pending" ] }, "file_name": { "type": "string" }, "download_url": { "type": "string", "description": "Short-lived signed download URL. It can be a pending:// placeholder before the artifact is ready." }, "download_url_expires_at": { "type": [ "string", "null" ] }, "expires_at": { "type": [ "string", "null" ] }, "error_code": { "type": [ "string", "null" ] }, "error_message": { "type": [ "string", "null" ] }, "max_posts": { "type": [ "number", "null" ] }, "truncated": { "type": "boolean" }, "creator": { "type": "object", "properties": { "username": { "type": "string" }, "campaign_id": { "type": [ "string", "null" ] }, "name": { "type": [ "string", "null" ] }, "creation_name": { "type": [ "string", "null" ] }, "url": { "type": [ "string", "null" ] }, "avatar_url": { "type": [ "string", "null" ] }, "patron_count": { "type": [ "number", "null" ] }, "post_count": { "type": [ "number", "null" ] }, "is_nsfw": { "type": [ "boolean", "null" ] }, "authenticated": { "type": "boolean" } }, "required": [ "username", "campaign_id", "name", "creation_name", "url", "avatar_url", "patron_count", "post_count", "is_nsfw", "authenticated" ], "additionalProperties": false }, "result_summary": { "type": "object", "properties": { "postsDiscovered": { "type": "number" }, "mediaDiscovered": { "type": "number" }, "estimatedBytes": { "type": "number" }, "downloadedFiles": { "type": "number" }, "failedFiles": { "type": "number" }, "skippedFiles": { "type": "number" }, "truncated": { "type": "boolean" }, "postsWithMedia": { "type": "number" }, "lockedPosts": { "type": "number" } }, "required": [ "postsDiscovered", "mediaDiscovered", "estimatedBytes", "downloadedFiles", "failedFiles", "skippedFiles", "truncated", "postsWithMedia", "lockedPosts" ], "additionalProperties": false }, "failed_media": { "type": "array", "items": { "type": "object", "properties": { "post_id": { "type": [ "string", "null" ] }, "post_title": { "type": [ "string", "null" ] }, "post_url": { "type": [ "string", "null" ] }, "post_index": { "type": [ "number", "null" ] }, "media_index": { "type": [ "number", "null" ] }, "media_id": { "type": [ "string", "null" ] }, "file_name": { "type": [ "string", "null" ] }, "failure_reason": { "type": "string" } }, "required": [ "post_id", "post_title", "post_url", "post_index", "media_index", "media_id", "file_name", "failure_reason" ], "additionalProperties": false } } }, "required": [ "success", "export_id", "status", "file_name", "download_url", "download_url_expires_at", "expires_at", "error_code", "error_message", "max_posts", "truncated", "creator", "result_summary", "failed_media" ], "additionalProperties": false }, { "type": "object", "properties": { "export_id": { "type": "string" } }, "required": [ "export_id" ], "additionalProperties": false } ] } ``` ### View a polled run response ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "patreon-creator-download", "task_name": "Patreon Creator Download", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "success": true, "export_id": "id-1", "status": "completed", "file_name": "Stylish Shoreditch Loft with Balcony", "download_url": "https://example.com/item-1", "download_url_expires_at": "https://example.com/item-1", "expires_at": "sample", "error_code": "sample", "error_message": "sample", "max_posts": 1.5, "truncated": true, "creator": { "username": "Stylish Shoreditch Loft with Balcony", "campaign_id": "id-1", "name": "Stylish Shoreditch Loft with Balcony", "creation_name": "Stylish Shoreditch Loft with Balcony", "url": "https://example.com/item-1", "avatar_url": "https://images.example.com/avatar_url-1.jpg", "patron_count": 1, "post_count": 1, "is_nsfw": true, "authenticated": true }, "result_summary": { "postsDiscovered": 1.5, "mediaDiscovered": 1.5, "estimatedBytes": 1.5, "downloadedFiles": 1.5, "failedFiles": 1.5, "skippedFiles": 1.5, "truncated": true, "postsWithMedia": 1.5, "lockedPosts": 1.5 }, "failed_media": [ { "post_id": "id-1", "post_title": "Stylish Shoreditch Loft with Balcony", "post_url": "https://example.com/item-1", "post_index": 1.5, "media_index": 1.5, "media_id": "id-1", "file_name": "Stylish Shoreditch Loft with Balcony", "failure_reason": "sample" } ] }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/patreon/creator-download" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"creator":"technologyconnections"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/patreon/creator-download", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "creator": "technologyconnections" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/patreon/creator-download", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "creator": "technologyconnections" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/patreon/creator-download" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"creator":"technologyconnections","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/patreon/creator-download", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "creator": "technologyconnections", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/patreon/creator-download", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "creator": "technologyconnections", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/patreon-creator-download/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/patreon/creator-download" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"creator":"technologyconnections","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/patreon/creator-download", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "creator": "technologyconnections", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/patreon/creator-download", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "creator": "technologyconnections", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "patreon-creator-download", "task_name": "Patreon Creator Download", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "success": true, "export_id": "id-1", "status": "completed", "file_name": "Stylish Shoreditch Loft with Balcony", "download_url": "https://example.com/item-1", "download_url_expires_at": "https://example.com/item-1", "expires_at": "sample", "error_code": "sample", "error_message": "sample", "max_posts": 1.5, "truncated": true, "creator": { "username": "Stylish Shoreditch Loft with Balcony", "campaign_id": "id-1", "name": "Stylish Shoreditch Loft with Balcony", "creation_name": "Stylish Shoreditch Loft with Balcony", "url": "https://example.com/item-1", "avatar_url": "https://images.example.com/avatar_url-1.jpg", "patron_count": 1, "post_count": 1, "is_nsfw": true, "authenticated": true }, "result_summary": { "postsDiscovered": 1.5, "mediaDiscovered": 1.5, "estimatedBytes": 1.5, "downloadedFiles": 1.5, "failedFiles": 1.5, "skippedFiles": 1.5, "truncated": true, "postsWithMedia": 1.5, "lockedPosts": 1.5 }, "failed_media": [ { "post_id": "id-1", "post_title": "Stylish Shoreditch Loft with Balcony", "post_url": "https://example.com/item-1", "post_index": 1.5, "media_index": 1.5, "media_id": "id-1", "file_name": "Stylish Shoreditch Loft with Balcony", "failure_reason": "sample" } ] }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-patreon-creator-download [Patreon APIs](/docs/api.md#patreon) # Patreon Creator Posts API Fetch public Patreon post metadata from a creator by username, URL, or campaign id. POST `/v1/patreon/creator-posts` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. Provide at least one of: creator; url; campaign_id. - **`url` string Optional** Optional Patreon creator URL. Minimum length: 1. Maximum length: 2000. - **`creator` string Optional** Patreon creator username or vanity path. Minimum length: 1. Maximum length: 2000. - **`limit` integer Optional** Maximum number of results to return. Default: 10. Minimum: 1. Maximum: 50. - **`cursor` string Optional** Cursor returned as next_cursor from the previous response. ### Advanced & compatibility inputs 1 - **`campaign_id` string Optional** Optional Patreon campaign id returned by patreon/search. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "patreon-creator-posts", "task_name": "Patreon Creator Posts API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/patreon/creator-posts" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.patreon.com/technologyconnections"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/patreon/creator-posts", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.patreon.com/technologyconnections" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/patreon/creator-posts", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.patreon.com/technologyconnections" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/patreon/creator-posts" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.patreon.com/technologyconnections","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/patreon/creator-posts", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.patreon.com/technologyconnections", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/patreon/creator-posts", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.patreon.com/technologyconnections", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/patreon-creator-posts/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/patreon/creator-posts" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.patreon.com/technologyconnections","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/patreon/creator-posts", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.patreon.com/technologyconnections", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/patreon/creator-posts", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.patreon.com/technologyconnections", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "patreon-creator-posts", "task_name": "Patreon Creator Posts API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-patreon-creator-posts [Patreon APIs](/docs/api.md#patreon) # Patreon Creator API Scrape public Patreon creator metadata. POST `/v1/patreon/creator` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`username` string Required** Patreon creator username. Minimum length: 1. Maximum length: 2000. - **`limit` integer Optional** Maximum number of results to return. Default: 25. Minimum: 1. Maximum: 100. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "patreon-creator", "task_name": "Patreon Creator API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/patreon/creator" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"username":"waitbutwhy"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/patreon/creator", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "username": "waitbutwhy" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/patreon/creator", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "username": "waitbutwhy" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/patreon/creator" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"username":"waitbutwhy","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/patreon/creator", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "username": "waitbutwhy", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/patreon/creator", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "username": "waitbutwhy", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/patreon-creator/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/patreon/creator" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"username":"waitbutwhy","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/patreon/creator", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "username": "waitbutwhy", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/patreon/creator", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "username": "waitbutwhy", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "patreon-creator", "task_name": "Patreon Creator API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-patreon-creator [Patreon APIs](/docs/api.md#patreon) # Patreon Post Media API Extract public media and attachment metadata from a Patreon post by post URL. POST `/v1/patreon/post-media` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`url` string Required** Patreon post URL returned by patreon/creator-posts. Minimum length: 1. Maximum length: 2000. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "patreon-post-media", "task_name": "Patreon Post Media API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/patreon/post-media" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.patreon.com/technologyconnections/posts/ceiling-fans-161200155"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/patreon/post-media", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.patreon.com/technologyconnections/posts/ceiling-fans-161200155" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/patreon/post-media", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.patreon.com/technologyconnections/posts/ceiling-fans-161200155" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/patreon/post-media" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.patreon.com/technologyconnections/posts/ceiling-fans-161200155","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/patreon/post-media", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.patreon.com/technologyconnections/posts/ceiling-fans-161200155", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/patreon/post-media", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.patreon.com/technologyconnections/posts/ceiling-fans-161200155", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/patreon-post-media/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/patreon/post-media" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.patreon.com/technologyconnections/posts/ceiling-fans-161200155","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/patreon/post-media", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.patreon.com/technologyconnections/posts/ceiling-fans-161200155", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/patreon/post-media", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.patreon.com/technologyconnections/posts/ceiling-fans-161200155", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "patreon-post-media", "task_name": "Patreon Post Media API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-patreon-post-media [Patreon APIs](/docs/api.md#patreon) # Patreon Post API Fetch public Patreon post details by post URL. POST `/v1/patreon/post` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`url` string Required** Patreon post URL returned by patreon/creator-posts. Minimum length: 1. Maximum length: 2000. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "patreon-post", "task_name": "Patreon Post API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/patreon/post" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.patreon.com/technologyconnections/posts/ceiling-fans-161200155"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/patreon/post", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.patreon.com/technologyconnections/posts/ceiling-fans-161200155" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/patreon/post", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.patreon.com/technologyconnections/posts/ceiling-fans-161200155" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/patreon/post" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.patreon.com/technologyconnections/posts/ceiling-fans-161200155","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/patreon/post", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.patreon.com/technologyconnections/posts/ceiling-fans-161200155", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/patreon/post", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.patreon.com/technologyconnections/posts/ceiling-fans-161200155", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/patreon-post/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/patreon/post" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.patreon.com/technologyconnections/posts/ceiling-fans-161200155","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/patreon/post", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.patreon.com/technologyconnections/posts/ceiling-fans-161200155", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/patreon/post", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.patreon.com/technologyconnections/posts/ceiling-fans-161200155", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "patreon-post", "task_name": "Patreon Post API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-patreon-post [Patreon APIs](/docs/api.md#patreon) # Patreon Search API Search public Patreon creators by query with page pagination. POST `/v1/patreon/search` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`query` string Required** Search query. Minimum length: 1. Maximum length: 2000. - **`limit` integer Optional** Maximum number of results to return. Default: 25. Minimum: 1. Maximum: 100. - **`cursor` string Optional** Cursor returned as next_cursor from the previous response. - **`page` integer Optional** Page number for sources that support page-based pagination. Default: 1. Minimum: 1. Maximum: 10000. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "patreon-search", "task_name": "Patreon Search API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/patreon/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"technology"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/patreon/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "technology" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/patreon/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "technology" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/patreon/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"technology","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/patreon/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "technology", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/patreon/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "technology", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/patreon-search/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/patreon/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"technology","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/patreon/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "technology", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/patreon/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "technology", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "patreon-search", "task_name": "Patreon Search API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-patreon-search [Pinterest APIs](/docs/api.md#pinterest) # Pinterest Board API Scrape pins from an accessible Pinterest board using your connected Pinterest account. POST `/v1/pinterest/board` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) **Connected website account required** Requires a connected pinterest.com account. Browsable automatically uses a saved connection on your team when one is available. If none is available, HTTP `428` includes a `hosted_url`. Complete sign-in there, then retry. [Connect an account →](/docs/api/website-logins.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`board_url` string Required** URL of the Pinterest board to scrape. The board must be accessible to the connected Pinterest account. - **`limit` integer Optional** Maximum number of pins to return in this page. Default: 100. Minimum: 1. Maximum: 250. - **`cursor` string Optional** Offset cursor returned by the previous page. Omit it to start from the first pin. ## 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", "board", "count", "pins", "limit", "pagination" ], "properties": { "pins": { "type": "array", "items": { "type": "object", "required": [ "id", "url", "title", "description", "alt_text", "image_url", "image_urls", "link_url", "is_video", "pinner_username", "pinner_name" ], "properties": { "id": { "type": "string" }, "url": { "type": "string" }, "title": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "alt_text": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "is_video": { "type": "boolean" }, "link_url": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "image_url": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "image_urls": { "type": "array", "items": { "type": "string" } }, "description": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "pinner_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "pinner_username": { "anyOf": [ { "type": "string" }, { "type": "null" } ] } }, "additionalProperties": false } }, "board": { "type": "object", "required": [ "url", "name", "owner", "privacy" ], "properties": { "url": { "type": "string" }, "name": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "owner": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "privacy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] } }, "additionalProperties": false }, "count": { "type": "integer" }, "limit": { "type": "integer" }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "has_next_page", "next_cursor" ], "properties": { "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "has_next_page": { "type": "boolean" } }, "additionalProperties": false } }, "additionalProperties": false } ``` ### View a polled run response ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "pinterest-board", "task_name": "Pinterest Board API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "pins": [ { "id": "id-1", "url": "https://example.com/item-1", "title": "Stylish Shoreditch Loft with Balcony", "alt_text": "Sample alt_text 1", "is_video": true, "link_url": "https://example.com/item-1", "image_url": "https://example.com/item-1", "image_urls": [ "https://images.example.com/image_urls-1.jpg" ], "description": "Sample description 1", "pinner_name": "Stylish Shoreditch Loft with Balcony", "pinner_username": "Stylish Shoreditch Loft with Balcony" } ], "board": { "url": "https://example.com/item-1", "name": "Stylish Shoreditch Loft with Balcony", "owner": "sample", "privacy": "sample" }, "count": 1, "limit": 1, "success": true, "pagination": { "next_cursor": "cursor-page-1", "has_next_page": true } }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/pinterest/board" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"board_url":"https://example.com/item-1"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/pinterest/board", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "board_url": "https://example.com/item-1" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/pinterest/board", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "board_url": "https://example.com/item-1" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/pinterest/board" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"board_url":"https://example.com/item-1","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/pinterest/board", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "board_url": "https://example.com/item-1", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/pinterest/board", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "board_url": "https://example.com/item-1", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/pinterest-board/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/pinterest/board" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"board_url":"https://example.com/item-1","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/pinterest/board", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "board_url": "https://example.com/item-1", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/pinterest/board", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "board_url": "https://example.com/item-1", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "pinterest-board", "task_name": "Pinterest Board API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "pins": [ { "id": "id-1", "url": "https://example.com/item-1", "title": "Stylish Shoreditch Loft with Balcony", "alt_text": "Sample alt_text 1", "is_video": true, "link_url": "https://example.com/item-1", "image_url": "https://example.com/item-1", "image_urls": [ "https://images.example.com/image_urls-1.jpg" ], "description": "Sample description 1", "pinner_name": "Stylish Shoreditch Loft with Balcony", "pinner_username": "Stylish Shoreditch Loft with Balcony" } ], "board": { "url": "https://example.com/item-1", "name": "Stylish Shoreditch Loft with Balcony", "owner": "sample", "privacy": "sample" }, "count": 1, "limit": 1, "success": true, "pagination": { "next_cursor": "cursor-page-1", "has_next_page": true } }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-pinterest-board [Pinterest APIs](/docs/api.md#pinterest) # Pinterest Pin API Scrape a public Pinterest pin detail page from a search result URL. POST `/v1/pinterest/pin` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`url` string Required** Pinterest pin URL returned by pinterest/search. Minimum length: 1. Maximum length: 2000. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "pinterest-pin", "task_name": "Pinterest Pin API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/pinterest/pin" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.pinterest.com/pin/123456789012345678/"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/pinterest/pin", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.pinterest.com/pin/123456789012345678/" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/pinterest/pin", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.pinterest.com/pin/123456789012345678/" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/pinterest/pin" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.pinterest.com/pin/123456789012345678/","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/pinterest/pin", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.pinterest.com/pin/123456789012345678/", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/pinterest/pin", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.pinterest.com/pin/123456789012345678/", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/pinterest-pin/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/pinterest/pin" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.pinterest.com/pin/123456789012345678/","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/pinterest/pin", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.pinterest.com/pin/123456789012345678/", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/pinterest/pin", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.pinterest.com/pin/123456789012345678/", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "pinterest-pin", "task_name": "Pinterest Pin API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-pinterest-pin [Product Hunt APIs](/docs/api.md#product-hunt) # Product Hunt Product API Scrape a public Product Hunt product or launch page. POST `/v1/producthunt/product` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`url` string Required** URL returned by the matching search endpoint. Minimum length: 1. Maximum length: 2000. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "producthunt-product", "task_name": "Product Hunt Product API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/producthunt/product" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.producthunt.com/products/notion"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/producthunt/product", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.producthunt.com/products/notion" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/producthunt/product", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.producthunt.com/products/notion" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/producthunt/product" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.producthunt.com/products/notion","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/producthunt/product", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.producthunt.com/products/notion", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/producthunt/product", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.producthunt.com/products/notion", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/producthunt-product/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/producthunt/product" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.producthunt.com/products/notion","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/producthunt/product", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.producthunt.com/products/notion", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/producthunt/product", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.producthunt.com/products/notion", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "producthunt-product", "task_name": "Product Hunt Product API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-producthunt-product [Product Hunt APIs](/docs/api.md#product-hunt) # Product Hunt API Scrape public Product Hunt product and launch search results. POST `/v1/producthunt/search` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`query` string Required** Search query. Minimum length: 1. Maximum length: 2000. - **`limit` integer Optional** Maximum number of results to return. Default: 25. Minimum: 1. Maximum: 100. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "producthunt-search", "task_name": "Product Hunt API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/producthunt/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"design tools"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/producthunt/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "design tools" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/producthunt/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "design tools" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/producthunt/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"design tools","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/producthunt/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "design tools", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/producthunt/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "design tools", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/producthunt-search/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/producthunt/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"design tools","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/producthunt/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "design tools", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/producthunt/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "design tools", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "producthunt-search", "task_name": "Product Hunt API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-producthunt-search [Quora APIs](/docs/api.md#quora) # Quora Question API Scrape a public Quora question page. POST `/v1/quora/question` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`url` string Required** Public Quora question URL. Minimum length: 1. Maximum length: 2000. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "quora-question", "task_name": "Quora Question API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/quora/question" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.quora.com/What-is-example"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/quora/question", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.quora.com/What-is-example" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/quora/question", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.quora.com/What-is-example" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/quora/question" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.quora.com/What-is-example","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/quora/question", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.quora.com/What-is-example", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/quora/question", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.quora.com/What-is-example", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/quora-question/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/quora/question" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.quora.com/What-is-example","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/quora/question", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.quora.com/What-is-example", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/quora/question", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.quora.com/What-is-example", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "quora-question", "task_name": "Quora Question API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-quora-question [Realtor APIs](/docs/api.md#realtor) # Realtor.com Property API Scrape a public Realtor.com property page. POST `/v1/realtor/property` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`url` string Required** URL returned by the matching search endpoint. Minimum length: 1. Maximum length: 2000. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "realtor-property", "task_name": "Realtor.com Property API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/realtor/property" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.realtor.com/realestateandhomes-detail/example"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/realtor/property", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.realtor.com/realestateandhomes-detail/example" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/realtor/property", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.realtor.com/realestateandhomes-detail/example" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/realtor/property" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.realtor.com/realestateandhomes-detail/example","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/realtor/property", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.realtor.com/realestateandhomes-detail/example", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/realtor/property", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.realtor.com/realestateandhomes-detail/example", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/realtor-property/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/realtor/property" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.realtor.com/realestateandhomes-detail/example","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/realtor/property", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.realtor.com/realestateandhomes-detail/example", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/realtor/property", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.realtor.com/realestateandhomes-detail/example", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "realtor-property", "task_name": "Realtor.com Property API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-realtor-property [Realtor APIs](/docs/api.md#realtor) # Realtor.com API Scrape public Realtor.com property search results. POST `/v1/realtor/search` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`query` string Required** Search query. Minimum length: 1. Maximum length: 2000. - **`limit` integer Optional** Maximum number of results to return. Default: 25. Minimum: 1. Maximum: 100. - **`cursor` string Optional** Cursor returned as next_cursor from the previous response. - **`page` integer Optional** Page number for sources that support page-based pagination. Default: 1. Minimum: 1. Maximum: 10000. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "realtor-search", "task_name": "Realtor.com API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/realtor/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"Austin TX"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/realtor/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "Austin TX" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/realtor/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "Austin TX" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/realtor/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"Austin TX","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/realtor/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "Austin TX", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/realtor/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "Austin TX", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/realtor-search/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/realtor/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"Austin TX","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/realtor/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "Austin TX", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/realtor/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "Austin TX", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "realtor-search", "task_name": "Realtor.com API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-realtor-search [Reddit APIs](/docs/api.md#reddit) # Reddit Multireddit Fetch posts from a user's multireddit. POST `/v1/reddit/multireddit` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`username` string Required** Reddit username. Minimum length: 1. Maximum length: 2000. - **`multiName` string Required** Multireddit name. - **`limit` integer Optional** Maximum number of items to return. Default: 25. Minimum: 1. Maximum: 100. - **`after` string Optional** Cursor returned by the previous response. - **`before` string Optional** Cursor returned by the previous response. ## 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": [ "results", "count" ], "properties": { "after": { "type": "string" }, "count": { "type": "integer" }, "before": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "required": [ "id", "title", "author", "subreddit", "score", "upvoteRatio", "numComments", "created", "url", "isVideo" ], "properties": { "id": { "type": "string" }, "url": { "type": "string" }, "score": { "type": "number" }, "title": { "type": "string" }, "author": { "type": "string" }, "created": { "type": "number" }, "isVideo": { "type": "boolean" }, "selftext": { "type": "string" }, "subreddit": { "type": "string" }, "thumbnail": { "type": "string" }, "numComments": { "type": "number" }, "upvoteRatio": { "type": "number" } }, "additionalProperties": false } } }, "additionalProperties": false } ``` ### View a polled run response ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "reddit-multireddit", "task_name": "Reddit Multireddit", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "after": "sample", "count": 1, "before": "sample", "results": [ { "id": "id-1", "url": "https://example.com/item-1", "score": 1.5, "title": "Stylish Shoreditch Loft with Balcony", "author": "user_1", "created": 1.5, "isVideo": true, "selftext": "Sample selftext 1", "subreddit": "programming", "thumbnail": "https://images.example.com/thumbnail-1.jpg", "numComments": 1.5, "upvoteRatio": 0.95 } ] }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/reddit/multireddit" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"username":"goretsky","multiName":"security"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/reddit/multireddit", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "username": "goretsky", "multiName": "security" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/reddit/multireddit", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "username": "goretsky", "multiName": "security" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/reddit/multireddit" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"username":"goretsky","multiName":"security","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/reddit/multireddit", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "username": "goretsky", "multiName": "security", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/reddit/multireddit", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "username": "goretsky", "multiName": "security", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/reddit-multireddit/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/reddit/multireddit" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"username":"goretsky","multiName":"security","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/reddit/multireddit", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "username": "goretsky", "multiName": "security", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/reddit/multireddit", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "username": "goretsky", "multiName": "security", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "reddit-multireddit", "task_name": "Reddit Multireddit", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "after": "sample", "count": 1, "before": "sample", "results": [ { "id": "id-1", "url": "https://example.com/item-1", "score": 1.5, "title": "Stylish Shoreditch Loft with Balcony", "author": "user_1", "created": 1.5, "isVideo": true, "selftext": "Sample selftext 1", "subreddit": "programming", "thumbnail": "https://images.example.com/thumbnail-1.jpg", "numComments": 1.5, "upvoteRatio": 0.95 } ] }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-reddit-multireddit [Reddit APIs](/docs/api.md#reddit) # Reddit Post Comments Fetch a Reddit post and its comments by URL. POST `/v1/reddit/post/comments` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`url` string Required** Reddit post URL. Minimum length: 1. Maximum length: 2000. - **`includeComments` boolean Optional** Whether to include comments. Default: true. ## 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", "additionalProperties": true } ``` ### View a polled run response ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "reddit-post-comments", "task_name": "Reddit Post Comments", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": {}, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/reddit/post/comments" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.reddit.com/r/programming/comments/abc123/post/"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/reddit/post/comments", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.reddit.com/r/programming/comments/abc123/post/" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/reddit/post/comments", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.reddit.com/r/programming/comments/abc123/post/" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/reddit/post/comments" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.reddit.com/r/programming/comments/abc123/post/","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/reddit/post/comments", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.reddit.com/r/programming/comments/abc123/post/", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/reddit/post/comments", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.reddit.com/r/programming/comments/abc123/post/", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/reddit-post-comments/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/reddit/post/comments" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.reddit.com/r/programming/comments/abc123/post/","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/reddit/post/comments", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.reddit.com/r/programming/comments/abc123/post/", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/reddit/post/comments", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.reddit.com/r/programming/comments/abc123/post/", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "reddit-post-comments", "task_name": "Reddit Post Comments", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": {}, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-reddit-post-comments [Reddit APIs](/docs/api.md#reddit) # Reddit Posts Fetch frontpage or subreddit posts with sort, timeframe, and cursor controls. POST `/v1/reddit/posts` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`limit` integer Optional** Maximum number of items to return. Default: 25. Minimum: 1. Maximum: 100. - **`after` string Optional** Cursor returned by the previous response. - **`before` string Optional** Cursor returned by the previous response. - **`sort` string Optional** Listing sort. Default: "hot". Allowed: "hot", "new", "top", "rising", "controversial". - **`subreddit` string Optional** Subreddit name, r/name, or subreddit URL. - **`timeframe` string Optional** Timeframe for results where supported. Allowed: "hour", "day", "week", "month", "year", "all". ## 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": [ "results", "count" ], "properties": { "after": { "type": "string" }, "count": { "type": "integer" }, "before": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "required": [ "id", "title", "author", "subreddit", "score", "upvoteRatio", "numComments", "created", "url", "isVideo" ], "properties": { "id": { "type": "string" }, "url": { "type": "string" }, "score": { "type": "number" }, "title": { "type": "string" }, "author": { "type": "string" }, "created": { "type": "number" }, "isVideo": { "type": "boolean" }, "selftext": { "type": "string" }, "subreddit": { "type": "string" }, "thumbnail": { "type": "string" }, "numComments": { "type": "number" }, "upvoteRatio": { "type": "number" } }, "additionalProperties": false } } }, "additionalProperties": false } ``` ### View a polled run response ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "reddit-posts", "task_name": "Reddit Posts", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "after": "sample", "count": 1, "before": "sample", "results": [ { "id": "id-1", "url": "https://example.com/item-1", "score": 1.5, "title": "Stylish Shoreditch Loft with Balcony", "author": "user_1", "created": 1.5, "isVideo": true, "selftext": "Sample selftext 1", "subreddit": "programming", "thumbnail": "https://images.example.com/thumbnail-1.jpg", "numComments": 1.5, "upvoteRatio": 0.95 } ] }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/reddit/posts" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/reddit/posts", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({}), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/reddit/posts", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={}, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/reddit/posts" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/reddit/posts", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/reddit/posts", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/reddit-posts/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/reddit/posts" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/reddit/posts", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/reddit/posts", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "reddit-posts", "task_name": "Reddit Posts", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "after": "sample", "count": 1, "before": "sample", "results": [ { "id": "id-1", "url": "https://example.com/item-1", "score": 1.5, "title": "Stylish Shoreditch Loft with Balcony", "author": "user_1", "created": 1.5, "isVideo": true, "selftext": "Sample selftext 1", "subreddit": "programming", "thumbnail": "https://images.example.com/thumbnail-1.jpg", "numComments": 1.5, "upvoteRatio": 0.95 } ] }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-reddit-posts [Reddit APIs](/docs/api.md#reddit) # Reddit Search Search Reddit posts globally or within a subreddit. POST `/v1/reddit/search` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`query` string Required** Search query. Minimum length: 1. Maximum length: 2000. - **`limit` integer Optional** Maximum number of items to return. Default: 25. Minimum: 1. Maximum: 100. - **`after` string Optional** Cursor returned by the previous response. - **`before` string Optional** Cursor returned by the previous response. - **`sort` string Optional** Sort order. Global search supports relevance, new, top, and comment_count; subreddit search also supports hot and comments. Allowed: "relevance", "new", "top", "comment_count", "hot", "comments". - **`subreddit` string Optional** Subreddit name, r/name, or subreddit URL. - **`timeframe` string Optional** Timeframe for results where supported. Allowed: "hour", "day", "week", "month", "year", "all". ## 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": [ "results", "count" ], "properties": { "after": { "type": "string" }, "count": { "type": "integer" }, "before": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "required": [ "id", "title", "author", "subreddit", "score", "upvoteRatio", "numComments", "created", "url", "isVideo" ], "properties": { "id": { "type": "string" }, "url": { "type": "string" }, "score": { "type": "number" }, "title": { "type": "string" }, "author": { "type": "string" }, "created": { "type": "number" }, "isVideo": { "type": "boolean" }, "selftext": { "type": "string" }, "subreddit": { "type": "string" }, "thumbnail": { "type": "string" }, "numComments": { "type": "number" }, "upvoteRatio": { "type": "number" } }, "additionalProperties": false } } }, "additionalProperties": false } ``` ### View a polled run response ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "reddit-search", "task_name": "Reddit Search", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "count": 2, "results": [ { "id": "1k9x2ab", "title": "What are the best resources for learning machine learning in 2026?", "author": "ml_beginner_42", "subreddit": "MachineLearning", "score": 187, "upvoteRatio": 0.96, "numComments": 54, "created": 1773328800, "url": "https://www.reddit.com/r/MachineLearning/comments/1k9x2ab/what_are_the_best_resources_for_learning_machine/", "isVideo": false, "selftext": "I have a solid Python background and want to move into practical ML projects. Looking for courses, books, and hands-on resources.", "thumbnail": "https://styles.redditmedia.com/t5_2r3gv/styles/communityIcon_example.png" }, { "id": "1k93yz7", "title": "Show HN: I built a small model to classify research paper abstracts by topic", "author": "latent_vector", "subreddit": "programming", "score": 92, "upvoteRatio": 0.91, "numComments": 18, "created": 1773242400, "url": "https://www.reddit.com/r/programming/comments/1k93yz7/show_hn_i_built_a_small_model_to_classify/", "isVideo": false, "selftext": "It uses a lightweight embedding model and a simple classifier. I wrote up the approach and linked the repo in the comments.", "thumbnail": "https://b.thumbs.redditmedia.com/example-thumbnail.png" } ] }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/reddit/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"machine learning"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/reddit/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "machine learning" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/reddit/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "machine learning" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/reddit/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"machine learning","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/reddit/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "machine learning", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/reddit/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "machine learning", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/reddit-search/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/reddit/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"machine learning","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/reddit/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "machine learning", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/reddit/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "machine learning", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "reddit-search", "task_name": "Reddit Search", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "count": 2, "results": [ { "id": "1k9x2ab", "title": "What are the best resources for learning machine learning in 2026?", "author": "ml_beginner_42", "subreddit": "MachineLearning", "score": 187, "upvoteRatio": 0.96, "numComments": 54, "created": 1773328800, "url": "https://www.reddit.com/r/MachineLearning/comments/1k9x2ab/what_are_the_best_resources_for_learning_machine/", "isVideo": false, "selftext": "I have a solid Python background and want to move into practical ML projects. Looking for courses, books, and hands-on resources.", "thumbnail": "https://styles.redditmedia.com/t5_2r3gv/styles/communityIcon_example.png" }, { "id": "1k93yz7", "title": "Show HN: I built a small model to classify research paper abstracts by topic", "author": "latent_vector", "subreddit": "programming", "score": 92, "upvoteRatio": 0.91, "numComments": 18, "created": 1773242400, "url": "https://www.reddit.com/r/programming/comments/1k93yz7/show_hn_i_built_a_small_model_to_classify/", "isVideo": false, "selftext": "It uses a lightweight embedding model and a simple classifier. I wrote up the approach and linked the repo in the comments.", "thumbnail": "https://b.thumbs.redditmedia.com/example-thumbnail.png" } ] }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-reddit-search [Reddit APIs](/docs/api.md#reddit) # Reddit Subreddit Details Fetch subreddit about data, rules, and optionally moderators. POST `/v1/reddit/subreddit/details` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. Provide at least one of: subreddit; url. - **`url` string Optional** Subreddit URL. Minimum length: 1. Maximum length: 2000. - **`include` array Optional** Sections to include. Defaults to about and rules. Default: ["about","rules"]. - **`includeModerators` boolean Optional** Convenience flag to include moderators. Default: false. - **`subreddit` string Optional** Subreddit name, r/name, or subreddit URL. ## 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": [ "data" ], "properties": { "data": { "type": "object", "additionalProperties": true }, "count": { "type": "number" } }, "additionalProperties": false } ``` ### View a polled run response ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "reddit-subreddit-details", "task_name": "Reddit Subreddit Details", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "data": {}, "count": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/reddit/subreddit/details" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.reddit.com/r/programming/"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/reddit/subreddit/details", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.reddit.com/r/programming/" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/reddit/subreddit/details", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.reddit.com/r/programming/" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/reddit/subreddit/details" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.reddit.com/r/programming/","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/reddit/subreddit/details", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.reddit.com/r/programming/", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/reddit/subreddit/details", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.reddit.com/r/programming/", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/reddit-subreddit-details/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/reddit/subreddit/details" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.reddit.com/r/programming/","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/reddit/subreddit/details", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.reddit.com/r/programming/", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/reddit/subreddit/details", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.reddit.com/r/programming/", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "reddit-subreddit-details", "task_name": "Reddit Subreddit Details", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "data": {}, "count": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-reddit-subreddit-details [Reddit APIs](/docs/api.md#reddit) # Reddit Subreddits Discover popular, new, or trending subreddits. POST `/v1/reddit/subreddits` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`type` string Optional** Discovery feed type. Default: "popular". Allowed: "popular", "new", "trending". ## 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": [ "data", "count" ], "properties": { "data": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "count": { "type": "integer" } }, "additionalProperties": false } ``` ### View a polled run response ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "reddit-subreddits", "task_name": "Reddit Subreddits", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "data": [ {} ], "count": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/reddit/subreddits" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/reddit/subreddits", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({}), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/reddit/subreddits", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={}, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/reddit/subreddits" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/reddit/subreddits", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/reddit/subreddits", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/reddit-subreddits/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/reddit/subreddits" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/reddit/subreddits", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/reddit/subreddits", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "reddit-subreddits", "task_name": "Reddit Subreddits", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "data": [ {} ], "count": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-reddit-subreddits [Reddit APIs](/docs/api.md#reddit) # Reddit User Content Fetch a Reddit user's overview, submitted posts, or comments. POST `/v1/reddit/user/content` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`username` string Required** Reddit username. Minimum length: 1. Maximum length: 2000. - **`limit` integer Optional** Maximum number of items to return. Default: 25. Minimum: 1. Maximum: 100. - **`after` string Optional** Cursor returned by the previous response. - **`before` string Optional** Cursor returned by the previous response. - **`type` string Optional** User feed type. Default: "overview". Allowed: "overview", "submitted", "comments". ## 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": [ "items", "count" ], "properties": { "count": { "type": "integer" }, "items": { "type": "array", "items": { "type": "object", "additionalProperties": true } } }, "additionalProperties": false } ``` ### View a polled run response ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "reddit-user-content", "task_name": "Reddit User Content", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "count": 1, "items": [ {} ] }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/reddit/user/content" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"username":"spez"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/reddit/user/content", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "username": "spez" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/reddit/user/content", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "username": "spez" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/reddit/user/content" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"username":"spez","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/reddit/user/content", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "username": "spez", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/reddit/user/content", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "username": "spez", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/reddit-user-content/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/reddit/user/content" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"username":"spez","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/reddit/user/content", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "username": "spez", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/reddit/user/content", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "username": "spez", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "reddit-user-content", "task_name": "Reddit User Content", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "count": 1, "items": [ {} ] }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-reddit-user-content [Reddit APIs](/docs/api.md#reddit) # Reddit Wiki List subreddit wiki pages or fetch one wiki page. POST `/v1/reddit/wiki` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`subreddit` string Required** Subreddit name, r/name, or subreddit URL. - **`pageName` string Optional** Optional wiki page name. Omit to list pages. ## 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": [ "data" ], "properties": { "data": { "type": "object", "additionalProperties": true }, "count": { "type": "number" } }, "additionalProperties": false } ``` ### View a polled run response ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "reddit-wiki", "task_name": "Reddit Wiki", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "data": {}, "count": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/reddit/wiki" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"subreddit":"learnprogramming"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/reddit/wiki", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "subreddit": "learnprogramming" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/reddit/wiki", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "subreddit": "learnprogramming" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/reddit/wiki" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"subreddit":"learnprogramming","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/reddit/wiki", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "subreddit": "learnprogramming", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/reddit/wiki", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "subreddit": "learnprogramming", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/reddit-wiki/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/reddit/wiki" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"subreddit":"learnprogramming","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/reddit/wiki", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "subreddit": "learnprogramming", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/reddit/wiki", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "subreddit": "learnprogramming", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "reddit-wiki", "task_name": "Reddit Wiki", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "data": {}, "count": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-reddit-wiki [Redfin APIs](/docs/api.md#redfin) # Redfin Property API Scrape a public Redfin property detail page from a search result URL. POST `/v1/redfin/property` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`url` string Required** Redfin property URL returned by redfin/search. Minimum length: 1. Maximum length: 2000. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "redfin-property", "task_name": "Redfin Property API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/redfin/property" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.redfin.com/WA/Seattle/123-Main-St-98101/home/12345"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/redfin/property", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.redfin.com/WA/Seattle/123-Main-St-98101/home/12345" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/redfin/property", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.redfin.com/WA/Seattle/123-Main-St-98101/home/12345" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/redfin/property" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.redfin.com/WA/Seattle/123-Main-St-98101/home/12345","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/redfin/property", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.redfin.com/WA/Seattle/123-Main-St-98101/home/12345", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/redfin/property", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.redfin.com/WA/Seattle/123-Main-St-98101/home/12345", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/redfin-property/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/redfin/property" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.redfin.com/WA/Seattle/123-Main-St-98101/home/12345","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/redfin/property", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.redfin.com/WA/Seattle/123-Main-St-98101/home/12345", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/redfin/property", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.redfin.com/WA/Seattle/123-Main-St-98101/home/12345", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "redfin-property", "task_name": "Redfin Property API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-redfin-property [Redfin APIs](/docs/api.md#redfin) # Redfin API Search public Redfin property listings by location. POST `/v1/redfin/search` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`query` string Required** City, neighborhood, county, state, or ZIP code. Minimum length: 1. Maximum length: 2000. - **`limit` integer Optional** Maximum number of results to return. Default: 25. Minimum: 1. Maximum: 100. - **`cursor` string Optional** Cursor returned as next_cursor from the previous response. - **`page` integer Optional** Page number for sources that support page-based pagination. Default: 1. Minimum: 1. Maximum: 10000. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "redfin-search", "task_name": "Redfin API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/redfin/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"Denver, CO"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/redfin/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "Denver, CO" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/redfin/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "Denver, CO" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/redfin/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"Denver, CO","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/redfin/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "Denver, CO", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/redfin/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "Denver, CO", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/redfin-search/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/redfin/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"Denver, CO","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/redfin/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "Denver, CO", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/redfin/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "Denver, CO", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "redfin-search", "task_name": "Redfin API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-redfin-search [Rightmove APIs](/docs/api.md#rightmove) # Rightmove Property API Scrape a public Rightmove property detail page from a search result URL. POST `/v1/rightmove/property` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`url` string Required** Rightmove property URL returned by rightmove/search. Minimum length: 1. Maximum length: 2000. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "rightmove-property", "task_name": "Rightmove Property API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/rightmove/property" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.rightmove.co.uk/properties/123456789"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/rightmove/property", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.rightmove.co.uk/properties/123456789" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/rightmove/property", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.rightmove.co.uk/properties/123456789" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/rightmove/property" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.rightmove.co.uk/properties/123456789","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/rightmove/property", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.rightmove.co.uk/properties/123456789", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/rightmove/property", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.rightmove.co.uk/properties/123456789", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/rightmove-property/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/rightmove/property" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.rightmove.co.uk/properties/123456789","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/rightmove/property", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.rightmove.co.uk/properties/123456789", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/rightmove/property", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.rightmove.co.uk/properties/123456789", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "rightmove-property", "task_name": "Rightmove Property API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-rightmove-property [Rightmove APIs](/docs/api.md#rightmove) # Rightmove API Search public Rightmove property listings by location. POST `/v1/rightmove/search` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`query` string Required** UK town, city, postcode, or area. Minimum length: 1. Maximum length: 2000. - **`limit` integer Optional** Maximum number of results to return. Default: 25. Minimum: 1. Maximum: 100. - **`cursor` string Optional** Cursor returned as next_cursor from the previous response. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "rightmove-search", "task_name": "Rightmove API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/rightmove/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"Manchester"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/rightmove/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "Manchester" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/rightmove/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "Manchester" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/rightmove/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"Manchester","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/rightmove/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "Manchester", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/rightmove/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "Manchester", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/rightmove-search/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/rightmove/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"Manchester","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/rightmove/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "Manchester", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/rightmove/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "Manchester", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "rightmove-search", "task_name": "Rightmove API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-rightmove-search [Skyscanner APIs](/docs/api.md#skyscanner) # Skyscanner API Search live flight itineraries from a Skyscanner-style route query. If Skyscanner blocks the browser, results transparently identify the live fallback provider. POST `/v1/skyscanner/search` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`origin` string Required** Departure city or airport code, such as London or LHR. Use an airport code for a specific airport. - **`destination` string Required** Arrival city or airport code, such as New York or JFK. Use an airport code for a specific airport. - **`depart_date` string Required** Departure date in YYYY-MM-DD format. Must not be in the past. Format: date. Pattern: ^\d{4}-\d{2}-\d{2}$. - **`return_date` string Optional** Optional return date in YYYY-MM-DD format, on or after departure. Format: date. Pattern: ^\d{4}-\d{2}-\d{2}$. - **`limit` integer Optional** Maximum number of results to return. Default: 25. Minimum: 1. Maximum: 100. - **`adults` integer Optional** Number of adult guests or travellers. Default: 1. Minimum: 1. Maximum: 9. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "skyscanner-search", "task_name": "Skyscanner API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/skyscanner/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"origin":"US","destination":"UK","depart_date":"2027-06-14"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/skyscanner/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "origin": "US", "destination": "UK", "depart_date": "2027-06-14" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/skyscanner/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "origin": "US", "destination": "UK", "depart_date": "2027-06-14" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/skyscanner/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"origin":"US","destination":"UK","depart_date":"2027-06-14","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/skyscanner/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "origin": "US", "destination": "UK", "depart_date": "2027-06-14", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/skyscanner/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "origin": "US", "destination": "UK", "depart_date": "2027-06-14", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/skyscanner-search/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/skyscanner/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"origin":"US","destination":"UK","depart_date":"2027-06-14","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/skyscanner/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "origin": "US", "destination": "UK", "depart_date": "2027-06-14", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/skyscanner/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "origin": "US", "destination": "UK", "depart_date": "2027-06-14", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "skyscanner-search", "task_name": "Skyscanner API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-skyscanner-search [SoundCloud APIs](/docs/api.md#soundcloud) # SoundCloud Page API Scrape a public SoundCloud track, playlist, or profile page. POST `/v1/soundcloud/page` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`url` string Required** URL returned by the matching search endpoint. Minimum length: 1. Maximum length: 2000. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "soundcloud-page", "task_name": "SoundCloud Page API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/soundcloud/page" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://soundcloud.com/artist/track"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/soundcloud/page", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://soundcloud.com/artist/track" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/soundcloud/page", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://soundcloud.com/artist/track" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/soundcloud/page" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://soundcloud.com/artist/track","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/soundcloud/page", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://soundcloud.com/artist/track", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/soundcloud/page", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://soundcloud.com/artist/track", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/soundcloud-page/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/soundcloud/page" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://soundcloud.com/artist/track","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/soundcloud/page", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://soundcloud.com/artist/track", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/soundcloud/page", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://soundcloud.com/artist/track", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "soundcloud-page", "task_name": "SoundCloud Page API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-soundcloud-page [SoundCloud APIs](/docs/api.md#soundcloud) # SoundCloud API Scrape public SoundCloud search results. POST `/v1/soundcloud/search` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`query` string Required** Search query. Minimum length: 1. Maximum length: 2000. - **`limit` integer Optional** Maximum number of results to return. Default: 25. Minimum: 1. Maximum: 100. - **`cursor` string Optional** Cursor returned as next_cursor from the previous response. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "soundcloud-search", "task_name": "SoundCloud API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/soundcloud/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"lo-fi beats"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/soundcloud/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "lo-fi beats" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/soundcloud/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "lo-fi beats" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/soundcloud/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"lo-fi beats","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/soundcloud/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "lo-fi beats", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/soundcloud/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "lo-fi beats", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/soundcloud-search/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/soundcloud/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"lo-fi beats","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/soundcloud/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "lo-fi beats", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/soundcloud/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "lo-fi beats", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "soundcloud-search", "task_name": "SoundCloud API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-soundcloud-search [Spotify APIs](/docs/api.md#spotify) # Spotify API Fetch public Spotify oEmbed metadata for Spotify URLs. Search and catalog APIs require OAuth. POST `/v1/spotify/metadata` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`url` string Required** Spotify track, album, playlist, artist, episode, or show URL. Minimum length: 1. Maximum length: 2000. - **`limit` integer Optional** Maximum number of results to return. Default: 25. Minimum: 1. Maximum: 100. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "spotify-metadata", "task_name": "Spotify API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/spotify/metadata" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://open.spotify.com/track/11dFghVXANMlKmJXsNCbNl"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/spotify/metadata", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://open.spotify.com/track/11dFghVXANMlKmJXsNCbNl" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/spotify/metadata", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://open.spotify.com/track/11dFghVXANMlKmJXsNCbNl" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/spotify/metadata" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://open.spotify.com/track/11dFghVXANMlKmJXsNCbNl","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/spotify/metadata", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://open.spotify.com/track/11dFghVXANMlKmJXsNCbNl", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/spotify/metadata", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://open.spotify.com/track/11dFghVXANMlKmJXsNCbNl", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/spotify-metadata/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/spotify/metadata" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://open.spotify.com/track/11dFghVXANMlKmJXsNCbNl","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/spotify/metadata", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://open.spotify.com/track/11dFghVXANMlKmJXsNCbNl", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/spotify/metadata", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://open.spotify.com/track/11dFghVXANMlKmJXsNCbNl", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "spotify-metadata", "task_name": "Spotify API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-spotify-metadata [Stack Overflow APIs](/docs/api.md#stack-overflow) # Stack Overflow Question API Scrape a public Stack Overflow question detail page from a search result URL. POST `/v1/stackoverflow/question` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`url` string Required** Stack Overflow question URL returned by stackoverflow/search. Minimum length: 1. Maximum length: 2000. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "stackoverflow-question", "task_name": "Stack Overflow Question API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/stackoverflow/question" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://stackoverflow.com/questions/12345678/example-question"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/stackoverflow/question", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://stackoverflow.com/questions/12345678/example-question" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/stackoverflow/question", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://stackoverflow.com/questions/12345678/example-question" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/stackoverflow/question" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://stackoverflow.com/questions/12345678/example-question","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/stackoverflow/question", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://stackoverflow.com/questions/12345678/example-question", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/stackoverflow/question", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://stackoverflow.com/questions/12345678/example-question", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/stackoverflow-question/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/stackoverflow/question" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://stackoverflow.com/questions/12345678/example-question","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/stackoverflow/question", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://stackoverflow.com/questions/12345678/example-question", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/stackoverflow/question", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://stackoverflow.com/questions/12345678/example-question", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "stackoverflow-question", "task_name": "Stack Overflow Question API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-stackoverflow-question [Stack Overflow APIs](/docs/api.md#stack-overflow) # Stack Overflow API Search Stack Overflow through the public Stack Exchange API with page pagination. POST `/v1/stackoverflow/search` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`query` string Required** Programming question keywords. Minimum length: 1. Maximum length: 2000. - **`limit` integer Optional** Maximum number of results to return. Default: 25. Minimum: 1. Maximum: 100. - **`cursor` string Optional** Cursor returned as next_cursor from the previous response. - **`page` integer Optional** Page number for sources that support page-based pagination. Default: 1. Minimum: 1. Maximum: 10000. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "stackoverflow-search", "task_name": "Stack Overflow API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/stackoverflow/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"playwright timeout"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/stackoverflow/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "playwright timeout" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/stackoverflow/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "playwright timeout" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/stackoverflow/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"playwright timeout","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/stackoverflow/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "playwright timeout", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/stackoverflow/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "playwright timeout", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/stackoverflow-search/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/stackoverflow/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"playwright timeout","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/stackoverflow/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "playwright timeout", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/stackoverflow/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "playwright timeout", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "stackoverflow-search", "task_name": "Stack Overflow API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-stackoverflow-search [Steam APIs](/docs/api.md#steam) # Steam App API Scrape a public Steam Store app page. POST `/v1/steam/app` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`url` string Required** URL returned by the matching search endpoint. Minimum length: 1. Maximum length: 2000. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "steam-app", "task_name": "Steam App API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/steam/app" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://store.steampowered.com/app/730/CounterStrike_2/"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/steam/app", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://store.steampowered.com/app/730/CounterStrike_2/" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/steam/app", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://store.steampowered.com/app/730/CounterStrike_2/" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/steam/app" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://store.steampowered.com/app/730/CounterStrike_2/","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/steam/app", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://store.steampowered.com/app/730/CounterStrike_2/", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/steam/app", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://store.steampowered.com/app/730/CounterStrike_2/", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/steam-app/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/steam/app" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://store.steampowered.com/app/730/CounterStrike_2/","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/steam/app", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://store.steampowered.com/app/730/CounterStrike_2/", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/steam/app", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://store.steampowered.com/app/730/CounterStrike_2/", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "steam-app", "task_name": "Steam App API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-steam-app [Steam APIs](/docs/api.md#steam) # Steam API Scrape public Steam Store search results with page pagination. POST `/v1/steam/search` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`query` string Required** Search query. Minimum length: 1. Maximum length: 2000. - **`limit` integer Optional** Maximum number of results to return. Default: 25. Minimum: 1. Maximum: 100. - **`cursor` string Optional** Cursor returned as next_cursor from the previous response. - **`page` integer Optional** Page number for sources that support page-based pagination. Default: 1. Minimum: 1. Maximum: 10000. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "steam-search", "task_name": "Steam API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/steam/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"roguelike"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/steam/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "roguelike" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/steam/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "roguelike" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/steam/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"roguelike","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/steam/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "roguelike", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/steam/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "roguelike", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/steam-search/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/steam/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"roguelike","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/steam/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "roguelike", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/steam/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "roguelike", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "steam-search", "task_name": "Steam API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-steam-search [Substack APIs](/docs/api.md#substack) # Substack Post API Scrape a public Substack post page. POST `/v1/substack/post` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`url` string Required** URL returned by the matching search endpoint. Minimum length: 1. Maximum length: 2000. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "substack-post", "task_name": "Substack Post API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/substack/post" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://example.substack.com/p/post-title"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/substack/post", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://example.substack.com/p/post-title" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/substack/post", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://example.substack.com/p/post-title" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/substack/post" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://example.substack.com/p/post-title","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/substack/post", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://example.substack.com/p/post-title", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/substack/post", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://example.substack.com/p/post-title", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/substack-post/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/substack/post" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://example.substack.com/p/post-title","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/substack/post", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://example.substack.com/p/post-title", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/substack/post", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://example.substack.com/p/post-title", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "substack-post", "task_name": "Substack Post API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-substack-post [Substack APIs](/docs/api.md#substack) # Substack API Scrape public Substack search results. POST `/v1/substack/search` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`query` string Required** Search query. Minimum length: 1. Maximum length: 2000. - **`limit` integer Optional** Maximum number of results to return. Default: 25. Minimum: 1. Maximum: 100. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "substack-search", "task_name": "Substack API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/substack/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"fintech"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/substack/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "fintech" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/substack/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "fintech" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/substack/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"fintech","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/substack/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "fintech", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/substack/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "fintech", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/substack-search/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/substack/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"fintech","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/substack/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "fintech", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/substack/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "fintech", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "substack-search", "task_name": "Substack API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-substack-search [Threads APIs](/docs/api.md#threads) # Threads Profile API Scrape a public Threads profile or post page. POST `/v1/threads/profile` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`url` string Required** URL returned by the matching search endpoint. Minimum length: 1. Maximum length: 2000. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "threads-profile", "task_name": "Threads Profile API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/threads/profile" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.threads.net/@instagram"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/threads/profile", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.threads.net/@instagram" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/threads/profile", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.threads.net/@instagram" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/threads/profile" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.threads.net/@instagram","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/threads/profile", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.threads.net/@instagram", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/threads/profile", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.threads.net/@instagram", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/threads-profile/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/threads/profile" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.threads.net/@instagram","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/threads/profile", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.threads.net/@instagram", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/threads/profile", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.threads.net/@instagram", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "threads-profile", "task_name": "Threads Profile API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-threads-profile [Threads APIs](/docs/api.md#threads) # Threads API Scrape public Threads search results. POST `/v1/threads/search` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`query` string Required** Search query. Minimum length: 1. Maximum length: 2000. - **`limit` integer Optional** Maximum number of results to return. Default: 25. Minimum: 1. Maximum: 100. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "threads-search", "task_name": "Threads API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/threads/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"open source"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/threads/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "open source" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/threads/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "open source" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/threads/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"open source","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/threads/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "open source", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/threads/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "open source", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/threads-search/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/threads/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"open source","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/threads/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "open source", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/threads/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "open source", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "threads-search", "task_name": "Threads API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-threads-search [TikTok APIs](/docs/api.md#tiktok) # TikTok comments Get comments for a TikTok video using a connected TikTok account. The current website requires sign-in to open comments; video and profile metadata remain available through the public endpoints. POST `/v1/tiktok/comments` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) **Connected website account required** Requires a connected tiktok.com account. Browsable automatically uses a saved connection on your team when one is available. If none is available, HTTP `428` includes a `hosted_url`. Complete sign-in there, then retry. [Connect an account →](/docs/api/website-logins.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. Provide at least one of: url; username + video_id. - **`url` string Optional** Full public TikTok video URL. Minimum length: 1. Maximum length: 2000. - **`username` string Optional** TikTok username, with or without the leading @. Minimum length: 1. Maximum length: 2000. - **`limit` integer Optional** Maximum number of public comments to collect from the rendered page. Preferred name; max_comments remains supported. Default: 50. Minimum: 0. Maximum: 200. - **`cursor` string Optional** Zero-based pagination cursor returned as next_cursor from the previous response. - **`video_id` string Optional** TikTok numeric video id. Use with username when url is not provided. ### Advanced & compatibility inputs 1 - **`max_comments` integer Optional** Maximum number of public comments to collect from the rendered page. You can also use limit. Default: 50. Minimum: 0. Maximum: 200. ## 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", "video", "comments", "count", "max_comments_requested", "pagination" ], "properties": { "count": { "type": "integer" }, "video": { "type": "object", "required": [ "id", "url", "username" ], "properties": { "id": { "type": "string" }, "url": { "type": "string" }, "username": { "anyOf": [ { "type": "string" }, { "type": "null" } ] } }, "additionalProperties": false }, "success": { "type": "boolean" }, "comments": { "type": "array", "items": { "type": "object", "required": [ "id", "author_username", "author_display_name", "text", "created_at_text", "likes_text", "like_count", "reply_count", "url" ], "properties": { "id": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "url": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "text": { "type": "string" }, "like_count": { "anyOf": [ { "type": "number" }, { "type": "null" } ] }, "likes_text": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "reply_count": { "anyOf": [ { "type": "number" }, { "type": "null" } ] }, "author_username": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "created_at_text": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "author_display_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ] } }, "additionalProperties": false } }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "has_next_page": { "type": "boolean" } }, "additionalProperties": false }, "max_comments_requested": { "type": "integer" } }, "additionalProperties": false } ``` ### View a polled run response ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "tiktok-comments", "task_name": "TikTok comments", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "count": 1, "video": { "id": "id-1", "url": "https://example.com/item-1", "username": "Stylish Shoreditch Loft with Balcony" }, "success": true, "comments": [ { "id": "id-1", "url": "https://example.com/item-1", "text": "Sample text 1", "like_count": 1, "likes_text": "Sample likes_text 1", "reply_count": 1, "author_username": "Stylish Shoreditch Loft with Balcony", "created_at_text": "2026-06-14T15:30:00Z", "author_display_name": "Stylish Shoreditch Loft with Balcony" } ], "pagination": { "count": 1, "cursor": "cursor-page-1", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_comments_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/tiktok/comments" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.tiktok.com/@tiktok/video/7641647587056962846"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/tiktok/comments", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.tiktok.com/@tiktok/video/7641647587056962846" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/tiktok/comments", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.tiktok.com/@tiktok/video/7641647587056962846" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/tiktok/comments" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.tiktok.com/@tiktok/video/7641647587056962846","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/tiktok/comments", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.tiktok.com/@tiktok/video/7641647587056962846", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/tiktok/comments", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.tiktok.com/@tiktok/video/7641647587056962846", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/tiktok-comments/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/tiktok/comments" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.tiktok.com/@tiktok/video/7641647587056962846","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/tiktok/comments", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.tiktok.com/@tiktok/video/7641647587056962846", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/tiktok/comments", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.tiktok.com/@tiktok/video/7641647587056962846", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "tiktok-comments", "task_name": "TikTok comments", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "count": 1, "video": { "id": "id-1", "url": "https://example.com/item-1", "username": "Stylish Shoreditch Loft with Balcony" }, "success": true, "comments": [ { "id": "id-1", "url": "https://example.com/item-1", "text": "Sample text 1", "like_count": 1, "likes_text": "Sample likes_text 1", "reply_count": 1, "author_username": "Stylish Shoreditch Loft with Balcony", "created_at_text": "2026-06-14T15:30:00Z", "author_display_name": "Stylish Shoreditch Loft with Balcony" } ], "pagination": { "count": 1, "cursor": "cursor-page-1", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_comments_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-tiktok-comments [TikTok APIs](/docs/api.md#tiktok) # TikTok Follower Count Get public follower counts and profile statistics for a TikTok username. Individual follower identities are not returned. POST `/v1/tiktok/follower-count` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`username` string Required** TikTok username. Minimum length: 1. Maximum length: 2000. ### Advanced & compatibility inputs 1 - **`limit` integer Optional** Compatibility result cap; this endpoint returns profile statistics rather than a list of followers. Default: 25. Minimum: 1. Maximum: 100. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "tiktok-follower-count", "task_name": "TikTok Follower Count", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/tiktok/follower-count" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"username":"natgeo"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/tiktok/follower-count", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "username": "natgeo" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/tiktok/follower-count", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "username": "natgeo" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/tiktok/follower-count" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"username":"natgeo","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/tiktok/follower-count", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "username": "natgeo", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/tiktok/follower-count", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "username": "natgeo", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/tiktok-follower-count/runs`. Compatibility route: `/v1/tiktok/followers`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/tiktok/follower-count" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"username":"natgeo","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/tiktok/follower-count", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "username": "natgeo", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/tiktok/follower-count", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "username": "natgeo", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "tiktok-follower-count", "task_name": "TikTok Follower Count", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-tiktok-follower-count [TikTok APIs](/docs/api.md#tiktok) # TikTok hashtag Fetch public hashtag metadata and a paginated slice of rendered public videos for a TikTok hashtag. POST `/v1/tiktok/hashtag` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`hashtag` string Required** TikTok hashtag, with or without the leading #. Minimum length: 1. Maximum length: 2000. - **`limit` integer Optional** Maximum number of public videos to collect from the rendered page. Preferred name; max_videos remains supported. Default: 30. Minimum: 0. Maximum: 100. - **`cursor` string Optional** Zero-based pagination cursor returned as next_cursor from the previous response. ### Advanced & compatibility inputs 1 - **`max_videos` integer Optional** Maximum number of public videos to collect from the rendered page. You can also use limit. Default: 30. Minimum: 0. Maximum: 100. ## 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", "hashtag", "videos", "count", "max_videos_requested", "pagination" ], "properties": { "count": { "type": "integer" }, "videos": { "type": "array", "items": { "type": "object", "required": [ "id", "url", "caption", "thumbnail_url", "views_text", "view_count", "author_username", "author_display_name", "hashtags" ], "properties": { "id": { "type": "string" }, "url": { "type": "string" }, "caption": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "hashtags": { "type": "array", "items": { "type": "string" } }, "view_count": { "anyOf": [ { "type": "number" }, { "type": "null" } ] }, "views_text": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "thumbnail_url": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "author_username": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "author_display_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ] } }, "additionalProperties": false } }, "hashtag": { "type": "object", "required": [ "name", "title", "post_count_text", "post_count", "url" ], "properties": { "url": { "type": "string" }, "name": { "type": "string" }, "title": { "type": "string" }, "post_count": { "anyOf": [ { "type": "number" }, { "type": "null" } ] }, "post_count_text": { "anyOf": [ { "type": "string" }, { "type": "null" } ] } }, "additionalProperties": false }, "success": { "type": "boolean" }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "has_next_page": { "type": "boolean" } }, "additionalProperties": false }, "max_videos_requested": { "type": "integer" } }, "additionalProperties": false } ``` ### View a polled run response ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "tiktok-hashtag", "task_name": "TikTok hashtag", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "count": 1, "videos": [ { "id": "id-1", "url": "https://example.com/item-1", "caption": "sample", "hashtags": [ "Featured" ], "view_count": 1, "views_text": "Sample views_text 1", "thumbnail_url": "https://images.example.com/thumbnail_url-1.jpg", "author_username": "Stylish Shoreditch Loft with Balcony", "author_display_name": "Stylish Shoreditch Loft with Balcony" } ], "hashtag": { "url": "https://example.com/item-1", "name": "Stylish Shoreditch Loft with Balcony", "title": "Stylish Shoreditch Loft with Balcony", "post_count": 1, "post_count_text": "Sample post_count_text 1" }, "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_videos_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/tiktok/hashtag" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"hashtag":"tiktok"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/tiktok/hashtag", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "hashtag": "tiktok" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/tiktok/hashtag", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "hashtag": "tiktok" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/tiktok/hashtag" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"hashtag":"tiktok","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/tiktok/hashtag", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "hashtag": "tiktok", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/tiktok/hashtag", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "hashtag": "tiktok", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/tiktok-hashtag/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/tiktok/hashtag" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"hashtag":"tiktok","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/tiktok/hashtag", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "hashtag": "tiktok", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/tiktok/hashtag", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "hashtag": "tiktok", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "tiktok-hashtag", "task_name": "TikTok hashtag", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "count": 1, "videos": [ { "id": "id-1", "url": "https://example.com/item-1", "caption": "sample", "hashtags": [ "Featured" ], "view_count": 1, "views_text": "Sample views_text 1", "thumbnail_url": "https://images.example.com/thumbnail_url-1.jpg", "author_username": "Stylish Shoreditch Loft with Balcony", "author_display_name": "Stylish Shoreditch Loft with Balcony" } ], "hashtag": { "url": "https://example.com/item-1", "name": "Stylish Shoreditch Loft with Balcony", "title": "Stylish Shoreditch Loft with Balcony", "post_count": 1, "post_count_text": "Sample post_count_text 1" }, "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_videos_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-tiktok-hashtag [TikTok APIs](/docs/api.md#tiktok) # TikTok profile Fetch public TikTok profile metadata and a paginated slice of recent public videos from a creator profile. POST `/v1/tiktok/profile` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`username` string Required** TikTok username, with or without the leading @. Minimum length: 1. Maximum length: 2000. - **`limit` integer Optional** Maximum number of public videos to collect from the rendered page. Preferred name; max_videos remains supported. Default: 30. Minimum: 0. Maximum: 100. - **`cursor` string Optional** Zero-based pagination cursor returned as next_cursor from the previous response. ### Advanced & compatibility inputs 1 - **`max_videos` integer Optional** Maximum number of public videos to collect from the rendered page. You can also use limit. Default: 30. Minimum: 0. Maximum: 100. ## 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", "profile", "videos", "count", "max_videos_requested", "pagination" ], "properties": { "count": { "type": "integer" }, "videos": { "type": "array", "items": { "type": "object", "required": [ "id", "url", "caption", "thumbnail_url", "views_text", "view_count", "author_username", "author_display_name", "hashtags" ], "properties": { "id": { "type": "string" }, "url": { "type": "string" }, "caption": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "hashtags": { "type": "array", "items": { "type": "string" } }, "view_count": { "anyOf": [ { "type": "number" }, { "type": "null" } ] }, "views_text": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "thumbnail_url": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "author_username": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "author_display_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ] } }, "additionalProperties": false } }, "profile": { "type": "object", "required": [ "id", "username", "display_name", "bio", "bio_link", "avatar_url", "avatar_url_hd", "verified", "private", "followers", "following", "likes", "video_count", "profile_url" ], "properties": { "id": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "bio": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "likes": { "anyOf": [ { "type": "number" }, { "type": "null" } ] }, "private": { "type": "boolean" }, "bio_link": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "username": { "type": "string" }, "verified": { "type": "boolean" }, "followers": { "anyOf": [ { "type": "number" }, { "type": "null" } ] }, "following": { "anyOf": [ { "type": "number" }, { "type": "null" } ] }, "avatar_url": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "profile_url": { "type": "string" }, "video_count": { "anyOf": [ { "type": "number" }, { "type": "null" } ] }, "display_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "avatar_url_hd": { "anyOf": [ { "type": "string" }, { "type": "null" } ] } }, "additionalProperties": false }, "success": { "type": "boolean" }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "has_next_page": { "type": "boolean" } }, "additionalProperties": false }, "max_videos_requested": { "type": "integer" } }, "additionalProperties": false } ``` ### View a polled run response ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "tiktok-profile", "task_name": "TikTok profile", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "count": 1, "videos": [ { "id": "id-1", "url": "https://example.com/item-1", "caption": "sample", "hashtags": [ "Featured" ], "view_count": 1, "views_text": "Sample views_text 1", "thumbnail_url": "https://images.example.com/thumbnail_url-1.jpg", "author_username": "Stylish Shoreditch Loft with Balcony", "author_display_name": "Stylish Shoreditch Loft with Balcony" } ], "profile": { "id": "id-1", "bio": "sample", "likes": 1.5, "private": true, "bio_link": "https://example.com/item-1", "username": "Stylish Shoreditch Loft with Balcony", "verified": true, "followers": 1.5, "following": 1.5, "avatar_url": "https://images.example.com/avatar_url-1.jpg", "profile_url": "https://example.com/item-1", "video_count": 1, "display_name": "Stylish Shoreditch Loft with Balcony", "avatar_url_hd": "https://images.example.com/avatar_url_hd-1.jpg" }, "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_videos_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/tiktok/profile" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"username":"tiktok"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/tiktok/profile", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "username": "tiktok" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/tiktok/profile", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "username": "tiktok" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/tiktok/profile" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"username":"tiktok","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/tiktok/profile", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "username": "tiktok", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/tiktok/profile", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "username": "tiktok", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/tiktok-profile/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/tiktok/profile" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"username":"tiktok","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/tiktok/profile", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "username": "tiktok", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/tiktok/profile", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "username": "tiktok", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "tiktok-profile", "task_name": "TikTok profile", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "count": 1, "videos": [ { "id": "id-1", "url": "https://example.com/item-1", "caption": "sample", "hashtags": [ "Featured" ], "view_count": 1, "views_text": "Sample views_text 1", "thumbnail_url": "https://images.example.com/thumbnail_url-1.jpg", "author_username": "Stylish Shoreditch Loft with Balcony", "author_display_name": "Stylish Shoreditch Loft with Balcony" } ], "profile": { "id": "id-1", "bio": "sample", "likes": 1.5, "private": true, "bio_link": "https://example.com/item-1", "username": "Stylish Shoreditch Loft with Balcony", "verified": true, "followers": 1.5, "following": 1.5, "avatar_url": "https://images.example.com/avatar_url-1.jpg", "profile_url": "https://example.com/item-1", "video_count": 1, "display_name": "Stylish Shoreditch Loft with Balcony", "avatar_url_hd": "https://images.example.com/avatar_url_hd-1.jpg" }, "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_videos_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-tiktok-profile [TikTok APIs](/docs/api.md#tiktok) # TikTok search Fetch a paginated slice of public rendered TikTok video search results for a query. POST `/v1/tiktok/search` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`query` string Required** Search query. Minimum length: 1. Maximum length: 2000. - **`limit` integer Optional** Maximum number of public search results to collect. Preferred name; max_results remains supported. Default: 30. Minimum: 0. Maximum: 100. - **`cursor` string Optional** Zero-based pagination cursor returned as next_cursor from the previous response. - **`search_type` string Optional** Search result type. Public unauthenticated TikTok search is most reliable for users; videos may require managed auth. Default: "users". Allowed: "users", "videos". ### Advanced & compatibility inputs 1 - **`max_results` integer Optional** Maximum number of public search results to collect. You can also use limit. Default: 30. Minimum: 0. Maximum: 100. ## 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", "query", "search_type", "search_url", "results", "count", "max_results_requested", "pagination" ], "properties": { "count": { "type": "integer" }, "query": { "type": "string" }, "results": { "type": "array", "items": { "oneOf": [ { "type": "object", "required": [ "type", "id", "sec_uid", "username", "display_name", "bio", "avatar_url", "verified", "followers", "likes", "profile_url" ], "properties": { "id": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "bio": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "type": { "const": "user" }, "likes": { "anyOf": [ { "type": "number" }, { "type": "null" } ] }, "sec_uid": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "username": { "type": "string" }, "verified": { "type": "boolean" }, "followers": { "anyOf": [ { "type": "number" }, { "type": "null" } ] }, "avatar_url": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "profile_url": { "type": "string" }, "display_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ] } }, "additionalProperties": false }, { "type": "object", "required": [ "type", "id", "url", "caption", "thumbnail_url", "views_text", "view_count", "author_username", "author_display_name", "hashtags" ], "properties": { "id": { "type": "string" }, "url": { "type": "string" }, "type": { "const": "video" }, "caption": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "hashtags": { "type": "array", "items": { "type": "string" } }, "view_count": { "anyOf": [ { "type": "number" }, { "type": "null" } ] }, "views_text": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "thumbnail_url": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "author_username": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "author_display_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ] } }, "additionalProperties": false } ] } }, "success": { "type": "boolean" }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "has_next_page": { "type": "boolean" } }, "additionalProperties": false }, "search_url": { "type": "string" }, "search_type": { "enum": [ "users", "videos" ], "type": "string" }, "max_results_requested": { "type": "integer" } }, "additionalProperties": false } ``` ### View a polled run response ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "tiktok-search", "task_name": "TikTok search", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "count": 1, "query": "London", "results": [ { "id": "id-1", "bio": "sample", "type": "user", "likes": 1.5, "sec_uid": "id-1", "username": "Stylish Shoreditch Loft with Balcony", "verified": true, "followers": 1.5, "avatar_url": "https://images.example.com/avatar_url-1.jpg", "profile_url": "https://example.com/item-1", "display_name": "Stylish Shoreditch Loft with Balcony" } ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "next_cursor": "cursor-page-1", "has_next_page": true }, "search_url": "https://example.com/item-1", "search_type": "users", "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/tiktok/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"dance"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/tiktok/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "dance" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/tiktok/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "dance" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/tiktok/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"dance","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/tiktok/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "dance", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/tiktok/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "dance", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/tiktok-search/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/tiktok/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"dance","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/tiktok/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "dance", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/tiktok/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "dance", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "tiktok-search", "task_name": "TikTok search", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "count": 1, "query": "London", "results": [ { "id": "id-1", "bio": "sample", "type": "user", "likes": 1.5, "sec_uid": "id-1", "username": "Stylish Shoreditch Loft with Balcony", "verified": true, "followers": 1.5, "avatar_url": "https://images.example.com/avatar_url-1.jpg", "profile_url": "https://example.com/item-1", "display_name": "Stylish Shoreditch Loft with Balcony" } ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "next_cursor": "cursor-page-1", "has_next_page": true }, "search_url": "https://example.com/item-1", "search_type": "users", "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-tiktok-search [TikTok APIs](/docs/api.md#tiktok) # TikTok video Fetch public metadata, stats, media, music, hashtags, and author data for a TikTok video. POST `/v1/tiktok/video` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. Provide at least one of: url; username + video_id. - **`url` string Optional** Full public TikTok video URL. Minimum length: 1. Maximum length: 2000. - **`username` string Optional** TikTok username, with or without the leading @. Minimum length: 1. Maximum length: 2000. - **`video_id` string Optional** TikTok numeric video id. Use with username when url is not provided. ## 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", "video" ], "properties": { "video": { "type": "object", "required": [ "id", "url", "description", "created_at", "create_time", "duration", "region", "author", "stats", "music", "hashtags", "mentions", "media", "subtitles" ], "properties": { "id": { "type": "string" }, "url": { "type": "string" }, "media": { "type": "object", "required": [ "cover_url", "dynamic_cover_url", "origin_cover_url", "play_url", "download_url", "width", "height", "duration", "format", "ratio", "definition" ], "properties": { "ratio": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "width": { "anyOf": [ { "type": "number" }, { "type": "null" } ] }, "format": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "height": { "anyOf": [ { "type": "number" }, { "type": "null" } ] }, "duration": { "anyOf": [ { "type": "number" }, { "type": "null" } ] }, "play_url": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "cover_url": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "definition": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "download_url": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "origin_cover_url": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "dynamic_cover_url": { "anyOf": [ { "type": "string" }, { "type": "null" } ] } }, "additionalProperties": false }, "music": { "type": "object", "required": [ "id", "title", "author_name", "duration", "original", "play_url", "cover_url" ], "properties": { "id": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "title": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "duration": { "anyOf": [ { "type": "number" }, { "type": "null" } ] }, "original": { "type": "boolean" }, "play_url": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "cover_url": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "author_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ] } }, "additionalProperties": false }, "stats": { "type": "object", "required": [ "play_count", "like_count", "comment_count", "share_count", "collect_count", "repost_count" ], "properties": { "like_count": { "anyOf": [ { "type": "number" }, { "type": "null" } ] }, "play_count": { "anyOf": [ { "type": "number" }, { "type": "null" } ] }, "share_count": { "anyOf": [ { "type": "number" }, { "type": "null" } ] }, "repost_count": { "anyOf": [ { "type": "number" }, { "type": "null" } ] }, "collect_count": { "anyOf": [ { "type": "number" }, { "type": "null" } ] }, "comment_count": { "anyOf": [ { "type": "number" }, { "type": "null" } ] } }, "additionalProperties": false }, "author": { "type": "object", "required": [ "id", "username", "display_name", "verified", "avatar_url", "profile_url", "followers", "following", "likes", "video_count" ], "properties": { "id": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "likes": { "anyOf": [ { "type": "number" }, { "type": "null" } ] }, "username": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "verified": { "type": "boolean" }, "followers": { "anyOf": [ { "type": "number" }, { "type": "null" } ] }, "following": { "anyOf": [ { "type": "number" }, { "type": "null" } ] }, "avatar_url": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "profile_url": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "video_count": { "anyOf": [ { "type": "number" }, { "type": "null" } ] }, "display_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ] } }, "additionalProperties": false }, "region": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "duration": { "anyOf": [ { "type": "number" }, { "type": "null" } ] }, "hashtags": { "type": "array", "items": { "type": "object", "required": [ "id", "title" ], "properties": { "id": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "title": { "anyOf": [ { "type": "string" }, { "type": "null" } ] } }, "additionalProperties": false } }, "mentions": { "type": "array", "items": { "type": "object", "required": [ "username", "user_id", "sec_uid" ], "properties": { "sec_uid": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "user_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "username": { "anyOf": [ { "type": "string" }, { "type": "null" } ] } }, "additionalProperties": false } }, "subtitles": { "type": "array", "items": { "type": "object", "required": [ "language", "language_code", "url", "format", "source" ], "properties": { "url": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "format": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "language": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "language_code": { "anyOf": [ { "type": "string" }, { "type": "null" } ] } }, "additionalProperties": false } }, "created_at": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "create_time": { "anyOf": [ { "type": "number" }, { "type": "null" } ] }, "description": { "anyOf": [ { "type": "string" }, { "type": "null" } ] } }, "additionalProperties": false }, "success": { "type": "boolean" } }, "additionalProperties": false } ``` ### View a polled run response ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "tiktok-video", "task_name": "TikTok video", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "video": { "id": "id-1", "url": "https://example.com/item-1", "media": { "ratio": "sample", "width": 1.5, "format": "sample", "height": 1.5, "duration": 1.5, "play_url": "https://example.com/item-1", "cover_url": "https://example.com/item-1", "definition": "sample", "download_url": "https://example.com/item-1", "origin_cover_url": "https://example.com/item-1", "dynamic_cover_url": "https://example.com/item-1" }, "music": { "id": "id-1", "title": "Stylish Shoreditch Loft with Balcony", "duration": 1.5, "original": true, "play_url": "https://example.com/item-1", "cover_url": "https://example.com/item-1", "author_name": "Stylish Shoreditch Loft with Balcony" }, "stats": { "like_count": 1, "play_count": 1, "share_count": 1, "repost_count": 1, "collect_count": 1, "comment_count": 1 }, "author": { "id": "id-1", "likes": 1.5, "username": "Stylish Shoreditch Loft with Balcony", "verified": true, "followers": 1.5, "following": 1.5, "avatar_url": "https://images.example.com/avatar_url-1.jpg", "profile_url": "https://example.com/item-1", "video_count": 1, "display_name": "Stylish Shoreditch Loft with Balcony" }, "region": "London", "duration": 1.5, "hashtags": [ { "id": "id-1", "title": "Stylish Shoreditch Loft with Balcony" } ], "mentions": [ { "sec_uid": "id-1", "user_id": "user_1", "username": "Stylish Shoreditch Loft with Balcony" } ], "subtitles": [ { "url": "https://example.com/item-1", "format": "sample", "source": "sample", "language": "sample", "language_code": "sample" } ], "created_at": "2026-06-14T15:30:00Z", "create_time": 1.5, "description": "Sample description 1" }, "success": true }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/tiktok/video" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.tiktok.com/@tiktok/video/7641647587056962846"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/tiktok/video", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.tiktok.com/@tiktok/video/7641647587056962846" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/tiktok/video", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.tiktok.com/@tiktok/video/7641647587056962846" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/tiktok/video" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.tiktok.com/@tiktok/video/7641647587056962846","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/tiktok/video", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.tiktok.com/@tiktok/video/7641647587056962846", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/tiktok/video", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.tiktok.com/@tiktok/video/7641647587056962846", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/tiktok-video/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/tiktok/video" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.tiktok.com/@tiktok/video/7641647587056962846","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/tiktok/video", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.tiktok.com/@tiktok/video/7641647587056962846", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/tiktok/video", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.tiktok.com/@tiktok/video/7641647587056962846", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "tiktok-video", "task_name": "TikTok video", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "video": { "id": "id-1", "url": "https://example.com/item-1", "media": { "ratio": "sample", "width": 1.5, "format": "sample", "height": 1.5, "duration": 1.5, "play_url": "https://example.com/item-1", "cover_url": "https://example.com/item-1", "definition": "sample", "download_url": "https://example.com/item-1", "origin_cover_url": "https://example.com/item-1", "dynamic_cover_url": "https://example.com/item-1" }, "music": { "id": "id-1", "title": "Stylish Shoreditch Loft with Balcony", "duration": 1.5, "original": true, "play_url": "https://example.com/item-1", "cover_url": "https://example.com/item-1", "author_name": "Stylish Shoreditch Loft with Balcony" }, "stats": { "like_count": 1, "play_count": 1, "share_count": 1, "repost_count": 1, "collect_count": 1, "comment_count": 1 }, "author": { "id": "id-1", "likes": 1.5, "username": "Stylish Shoreditch Loft with Balcony", "verified": true, "followers": 1.5, "following": 1.5, "avatar_url": "https://images.example.com/avatar_url-1.jpg", "profile_url": "https://example.com/item-1", "video_count": 1, "display_name": "Stylish Shoreditch Loft with Balcony" }, "region": "London", "duration": 1.5, "hashtags": [ { "id": "id-1", "title": "Stylish Shoreditch Loft with Balcony" } ], "mentions": [ { "sec_uid": "id-1", "user_id": "user_1", "username": "Stylish Shoreditch Loft with Balcony" } ], "subtitles": [ { "url": "https://example.com/item-1", "format": "sample", "source": "sample", "language": "sample", "language_code": "sample" } ], "created_at": "2026-06-14T15:30:00Z", "create_time": 1.5, "description": "Sample description 1" }, "success": true }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-tiktok-video [TikTok APIs](/docs/api.md#tiktok) # TikTok videos Fetch a paginated slice of public videos from a TikTok creator profile. POST `/v1/tiktok/videos` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`username` string Required** TikTok username, with or without the leading @. Minimum length: 1. Maximum length: 2000. - **`limit` integer Optional** Maximum number of public videos to collect from the rendered page. Preferred name; max_videos remains supported. Default: 30. Minimum: 0. Maximum: 100. - **`cursor` string Optional** Zero-based pagination cursor returned as next_cursor from the previous response. ### Advanced & compatibility inputs 1 - **`max_videos` integer Optional** Maximum number of public videos to collect from the rendered page. You can also use limit. Default: 30. Minimum: 0. Maximum: 100. ## 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", "username", "profile", "videos", "count", "max_videos_requested", "pagination" ], "properties": { "count": { "type": "integer" }, "videos": { "type": "array", "items": { "type": "object", "required": [ "id", "url", "caption", "thumbnail_url", "views_text", "view_count", "author_username", "author_display_name", "hashtags" ], "properties": { "id": { "type": "string" }, "url": { "type": "string" }, "caption": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "hashtags": { "type": "array", "items": { "type": "string" } }, "view_count": { "anyOf": [ { "type": "number" }, { "type": "null" } ] }, "views_text": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "thumbnail_url": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "author_username": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "author_display_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ] } }, "additionalProperties": false } }, "profile": { "type": "object", "required": [ "id", "username", "display_name", "bio", "bio_link", "avatar_url", "avatar_url_hd", "verified", "private", "followers", "following", "likes", "video_count", "profile_url" ], "properties": { "id": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "bio": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "likes": { "anyOf": [ { "type": "number" }, { "type": "null" } ] }, "private": { "type": "boolean" }, "bio_link": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "username": { "type": "string" }, "verified": { "type": "boolean" }, "followers": { "anyOf": [ { "type": "number" }, { "type": "null" } ] }, "following": { "anyOf": [ { "type": "number" }, { "type": "null" } ] }, "avatar_url": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "profile_url": { "type": "string" }, "video_count": { "anyOf": [ { "type": "number" }, { "type": "null" } ] }, "display_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "avatar_url_hd": { "anyOf": [ { "type": "string" }, { "type": "null" } ] } }, "additionalProperties": false }, "success": { "type": "boolean" }, "username": { "type": "string" }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "has_next_page": { "type": "boolean" } }, "additionalProperties": false }, "max_videos_requested": { "type": "integer" } }, "additionalProperties": false } ``` ### View a polled run response ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "tiktok-videos", "task_name": "TikTok videos", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "count": 1, "videos": [ { "id": "id-1", "url": "https://example.com/item-1", "caption": "sample", "hashtags": [ "Featured" ], "view_count": 1, "views_text": "Sample views_text 1", "thumbnail_url": "https://images.example.com/thumbnail_url-1.jpg", "author_username": "Stylish Shoreditch Loft with Balcony", "author_display_name": "Stylish Shoreditch Loft with Balcony" } ], "profile": { "id": "id-1", "bio": "sample", "likes": 1.5, "private": true, "bio_link": "https://example.com/item-1", "username": "Stylish Shoreditch Loft with Balcony", "verified": true, "followers": 1.5, "following": 1.5, "avatar_url": "https://images.example.com/avatar_url-1.jpg", "profile_url": "https://example.com/item-1", "video_count": 1, "display_name": "Stylish Shoreditch Loft with Balcony", "avatar_url_hd": "https://images.example.com/avatar_url_hd-1.jpg" }, "success": true, "username": "Stylish Shoreditch Loft with Balcony", "pagination": { "count": 1, "cursor": "cursor-page-1", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_videos_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/tiktok/videos" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"username":"tiktok"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/tiktok/videos", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "username": "tiktok" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/tiktok/videos", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "username": "tiktok" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/tiktok/videos" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"username":"tiktok","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/tiktok/videos", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "username": "tiktok", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/tiktok/videos", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "username": "tiktok", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/tiktok-videos/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/tiktok/videos" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"username":"tiktok","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/tiktok/videos", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "username": "tiktok", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/tiktok/videos", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "username": "tiktok", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "tiktok-videos", "task_name": "TikTok videos", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "count": 1, "videos": [ { "id": "id-1", "url": "https://example.com/item-1", "caption": "sample", "hashtags": [ "Featured" ], "view_count": 1, "views_text": "Sample views_text 1", "thumbnail_url": "https://images.example.com/thumbnail_url-1.jpg", "author_username": "Stylish Shoreditch Loft with Balcony", "author_display_name": "Stylish Shoreditch Loft with Balcony" } ], "profile": { "id": "id-1", "bio": "sample", "likes": 1.5, "private": true, "bio_link": "https://example.com/item-1", "username": "Stylish Shoreditch Loft with Balcony", "verified": true, "followers": 1.5, "following": 1.5, "avatar_url": "https://images.example.com/avatar_url-1.jpg", "profile_url": "https://example.com/item-1", "video_count": 1, "display_name": "Stylish Shoreditch Loft with Balcony", "avatar_url_hd": "https://images.example.com/avatar_url_hd-1.jpg" }, "success": true, "username": "Stylish Shoreditch Loft with Balcony", "pagination": { "count": 1, "cursor": "cursor-page-1", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_videos_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-tiktok-videos [Tripadvisor APIs](/docs/api.md#tripadvisor) # Tripadvisor Detail API Scrape a public Tripadvisor hotel, restaurant, or attraction page. POST `/v1/tripadvisor/detail` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`url` string Required** URL returned by the matching search endpoint. Minimum length: 1. Maximum length: 2000. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "tripadvisor-detail", "task_name": "Tripadvisor Detail API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/tripadvisor/detail" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.tripadvisor.com/Restaurant_Review-example.html"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/tripadvisor/detail", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.tripadvisor.com/Restaurant_Review-example.html" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/tripadvisor/detail", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.tripadvisor.com/Restaurant_Review-example.html" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/tripadvisor/detail" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.tripadvisor.com/Restaurant_Review-example.html","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/tripadvisor/detail", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.tripadvisor.com/Restaurant_Review-example.html", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/tripadvisor/detail", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.tripadvisor.com/Restaurant_Review-example.html", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/tripadvisor-detail/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/tripadvisor/detail" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.tripadvisor.com/Restaurant_Review-example.html","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/tripadvisor/detail", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.tripadvisor.com/Restaurant_Review-example.html", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/tripadvisor/detail", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.tripadvisor.com/Restaurant_Review-example.html", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "tripadvisor-detail", "task_name": "Tripadvisor Detail API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-tripadvisor-detail [Tripadvisor APIs](/docs/api.md#tripadvisor) # Tripadvisor API Scrape public Tripadvisor search results for hotels, restaurants, and attractions. POST `/v1/tripadvisor/search` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`query` string Required** Search query. Minimum length: 1. Maximum length: 2000. - **`limit` integer Optional** Maximum number of results to return. Default: 25. Minimum: 1. Maximum: 100. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "tripadvisor-search", "task_name": "Tripadvisor API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/tripadvisor/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"Rome restaurants"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/tripadvisor/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "Rome restaurants" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/tripadvisor/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "Rome restaurants" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/tripadvisor/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"Rome restaurants","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/tripadvisor/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "Rome restaurants", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/tripadvisor/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "Rome restaurants", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/tripadvisor-search/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/tripadvisor/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"Rome restaurants","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/tripadvisor/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "Rome restaurants", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/tripadvisor/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "Rome restaurants", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "tripadvisor-search", "task_name": "Tripadvisor API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-tripadvisor-search [Trustpilot APIs](/docs/api.md#trustpilot) # Trustpilot Company API Scrape a public Trustpilot company review page. POST `/v1/trustpilot/company` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`url` string Required** URL returned by the matching search endpoint. Minimum length: 1. Maximum length: 2000. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "trustpilot-company", "task_name": "Trustpilot Company API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/trustpilot/company" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.trustpilot.com/review/www.example.com"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/trustpilot/company", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.trustpilot.com/review/www.example.com" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/trustpilot/company", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.trustpilot.com/review/www.example.com" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/trustpilot/company" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.trustpilot.com/review/www.example.com","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/trustpilot/company", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.trustpilot.com/review/www.example.com", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/trustpilot/company", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.trustpilot.com/review/www.example.com", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/trustpilot-company/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/trustpilot/company" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.trustpilot.com/review/www.example.com","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/trustpilot/company", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.trustpilot.com/review/www.example.com", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/trustpilot/company", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.trustpilot.com/review/www.example.com", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "trustpilot-company", "task_name": "Trustpilot Company API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-trustpilot-company [Trustpilot APIs](/docs/api.md#trustpilot) # Trustpilot API Scrape public Trustpilot company search results. POST `/v1/trustpilot/search` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`query` string Required** Search query. Minimum length: 1. Maximum length: 2000. - **`limit` integer Optional** Maximum number of results to return. Default: 25. Minimum: 1. Maximum: 100. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "trustpilot-search", "task_name": "Trustpilot API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/trustpilot/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"monzo"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/trustpilot/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "monzo" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/trustpilot/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "monzo" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/trustpilot/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"monzo","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/trustpilot/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "monzo", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/trustpilot/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "monzo", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/trustpilot-search/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/trustpilot/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"monzo","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/trustpilot/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "monzo", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/trustpilot/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "monzo", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "trustpilot-search", "task_name": "Trustpilot API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-trustpilot-search [Twitch APIs](/docs/api.md#twitch) # Twitch Channel API Scrape a public Twitch channel page. POST `/v1/twitch/channel` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`url` string Required** URL returned by the matching search endpoint. Minimum length: 1. Maximum length: 2000. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "twitch-channel", "task_name": "Twitch Channel API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/twitch/channel" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.twitch.tv/chess"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/twitch/channel", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.twitch.tv/chess" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/twitch/channel", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.twitch.tv/chess" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/twitch/channel" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.twitch.tv/chess","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/twitch/channel", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.twitch.tv/chess", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/twitch/channel", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.twitch.tv/chess", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/twitch-channel/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/twitch/channel" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.twitch.tv/chess","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/twitch/channel", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.twitch.tv/chess", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/twitch/channel", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.twitch.tv/chess", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "twitch-channel", "task_name": "Twitch Channel API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-twitch-channel [Twitch APIs](/docs/api.md#twitch) # Twitch API Scrape public Twitch search results. POST `/v1/twitch/search` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`query` string Required** Search query. Minimum length: 1. Maximum length: 2000. - **`limit` integer Optional** Maximum number of results to return. Default: 25. Minimum: 1. Maximum: 100. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "twitch-search", "task_name": "Twitch API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/twitch/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"chess"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/twitch/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "chess" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/twitch/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "chess" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/twitch/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"chess","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/twitch/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "chess", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/twitch/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "chess", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/twitch-search/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/twitch/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"chess","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/twitch/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "chess", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/twitch/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "chess", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "twitch-search", "task_name": "Twitch API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-twitch-search [Vimeo APIs](/docs/api.md#vimeo) # Vimeo API Scrape public Vimeo video search results. POST `/v1/vimeo/search` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`query` string Required** Search query. Minimum length: 1. Maximum length: 2000. - **`limit` integer Optional** Maximum number of results to return. Default: 25. Minimum: 1. Maximum: 100. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "vimeo-search", "task_name": "Vimeo API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/vimeo/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"short film"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/vimeo/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "short film" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/vimeo/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "short film" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/vimeo/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"short film","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/vimeo/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "short film", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/vimeo/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "short film", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/vimeo-search/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/vimeo/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"short film","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/vimeo/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "short film", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/vimeo/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "short film", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "vimeo-search", "task_name": "Vimeo API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-vimeo-search [Vimeo APIs](/docs/api.md#vimeo) # Vimeo Video API Scrape a public Vimeo video page. POST `/v1/vimeo/video` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`url` string Required** URL returned by the matching search endpoint. Minimum length: 1. Maximum length: 2000. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "vimeo-video", "task_name": "Vimeo Video API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/vimeo/video" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://vimeo.com/123456789"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/vimeo/video", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://vimeo.com/123456789" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/vimeo/video", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://vimeo.com/123456789" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/vimeo/video" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://vimeo.com/123456789","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/vimeo/video", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://vimeo.com/123456789", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/vimeo/video", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://vimeo.com/123456789", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/vimeo-video/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/vimeo/video" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://vimeo.com/123456789","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/vimeo/video", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://vimeo.com/123456789", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/vimeo/video", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://vimeo.com/123456789", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "vimeo-video", "task_name": "Vimeo Video API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-vimeo-video [Vinted APIs](/docs/api.md#vinted) # Vinted Brand Feed API Scrape public Vinted catalog results for a brand. POST `/v1/vinted/brand` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`brand` string Required** Brand name. - **`limit` integer Optional** Maximum number of results to return. Default: 25. Minimum: 1. Maximum: 100. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "vinted-brand", "task_name": "Vinted Brand Feed API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/vinted/brand" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"brand":"Patagonia"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/vinted/brand", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "brand": "Patagonia" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/vinted/brand", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "brand": "Patagonia" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/vinted/brand" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"brand":"Patagonia","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/vinted/brand", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "brand": "Patagonia", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/vinted/brand", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "brand": "Patagonia", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/vinted-brand/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/vinted/brand" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"brand":"Patagonia","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/vinted/brand", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "brand": "Patagonia", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/vinted/brand", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "brand": "Patagonia", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "vinted-brand", "task_name": "Vinted Brand Feed API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-vinted-brand [Vinted APIs](/docs/api.md#vinted) # Vinted item Fetch a Vinted item page and return normalized item details plus similar items from the same page. POST `/v1/vinted/item` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`url` string Optional** Vinted item URL (e.g. https://www.vinted.co.uk/items/8289132552-foo). Preferred name; item_url remains supported. - **`domain` string Optional** Optional Vinted domain/origin (e.g. vinted.de, www.vinted.fr, or https://www.vinted.co.uk). Used when item_id is provided or to override the default UK domain. Default: "vinted.co.uk". - **`item_id` string Optional** Numeric Vinted item ID. When used without item_url, the scraper defaults to vinted.co.uk unless domain is provided. ### Advanced & compatibility inputs 1 - **`item_url` string Optional** Vinted item URL (e.g. https://www.vinted.co.uk/items/8289132552-foo). You can also use url. ## 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", "item_id", "item_url", "price", "price_including_buyer_protection", "service_fee", "shipping_price", "image_urls", "attributes", "similar_items" ], "properties": { "size": { "type": "string" }, "brand": { "type": "string" }, "color": { "type": "string" }, "likes": { "type": "number" }, "price": { "anyOf": [ { "type": "object", "required": [ "amount", "amount_numeric", "currency" ], "properties": { "amount": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "currency": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "amount_numeric": { "anyOf": [ { "type": "number" }, { "type": "null" } ] } }, "additionalProperties": false }, { "type": "null" } ] }, "title": { "type": "string" }, "views": { "type": "number" }, "seller": { "anyOf": [ { "type": "object", "properties": { "id": { "type": "string" }, "username": { "type": "string" }, "avatar_url": { "type": "string" }, "is_business": { "type": "boolean" }, "profile_url": { "type": "string" }, "feedback_count": { "type": "number" }, "feedback_reputation": { "type": "number" } }, "additionalProperties": false }, { "type": "null" } ] }, "is_sold": { "type": "boolean" }, "item_id": { "type": "string" }, "success": { "type": "boolean" }, "item_url": { "type": "string" }, "location": { "type": "string" }, "material": { "type": "string" }, "promoted": { "type": "boolean" }, "condition": { "type": "string" }, "is_hidden": { "type": "boolean" }, "attributes": { "type": "array", "items": { "type": "object", "properties": { "code": { "type": "string" }, "label": { "type": "string" }, "value": { "type": "string" } }, "additionalProperties": false } }, "catalog_id": { "type": "string" }, "created_at": { "type": "string" }, "image_urls": { "type": "array", "items": { "type": "string" } }, "updated_at": { "type": "string" }, "description": { "type": "string" }, "is_reserved": { "type": "boolean" }, "service_fee": { "anyOf": [ { "type": "object", "required": [ "amount", "amount_numeric", "currency" ], "properties": { "amount": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "currency": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "amount_numeric": { "anyOf": [ { "type": "number" }, { "type": "null" } ] } }, "additionalProperties": false }, { "type": "null" } ] }, "is_favourite": { "type": "boolean" }, "similar_items": { "type": "array", "items": { "type": "object", "required": [ "id", "page", "link", "image_urls", "price", "price_including_buyer_protection", "service_fee" ], "properties": { "id": { "type": "string" }, "link": { "type": "string" }, "name": { "type": "string" }, "page": { "type": "number" }, "size": { "type": "string" }, "brand": { "type": "string" }, "color": { "type": "string" }, "likes": { "type": "number" }, "price": { "anyOf": [ { "type": "object", "required": [ "amount", "amount_numeric", "currency" ], "properties": { "amount": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "currency": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "amount_numeric": { "anyOf": [ { "type": "number" }, { "type": "null" } ] } }, "additionalProperties": false }, { "type": "null" } ] }, "views": { "type": "number" }, "seller": { "anyOf": [ { "type": "object", "properties": { "id": { "type": "string" }, "username": { "type": "string" }, "avatar_url": { "type": "string" }, "is_business": { "type": "boolean" }, "profile_url": { "type": "string" }, "feedback_count": { "type": "number" }, "feedback_reputation": { "type": "number" } }, "additionalProperties": false }, { "type": "null" } ] }, "location": { "type": "string" }, "material": { "type": "string" }, "promoted": { "type": "boolean" }, "condition": { "type": "string" }, "catalog_id": { "type": "string" }, "created_at": { "type": "string" }, "image_urls": { "type": "array", "items": { "type": "string" } }, "description": { "type": "string" }, "service_fee": { "anyOf": [ { "type": "object", "required": [ "amount", "amount_numeric", "currency" ], "properties": { "amount": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "currency": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "amount_numeric": { "anyOf": [ { "type": "number" }, { "type": "null" } ] } }, "additionalProperties": false }, { "type": "null" } ] }, "is_favourite": { "type": "boolean" }, "thumbnail_url": { "type": "string" }, "price_including_buyer_protection": { "anyOf": [ { "type": "object", "required": [ "amount", "amount_numeric", "currency" ], "properties": { "amount": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "currency": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "amount_numeric": { "anyOf": [ { "type": "number" }, { "type": "null" } ] } }, "additionalProperties": false }, { "type": "null" } ] } }, "additionalProperties": false } }, "thumbnail_url": { "type": "string" }, "shipping_price": { "anyOf": [ { "type": "object", "required": [ "amount", "amount_numeric", "currency" ], "properties": { "amount": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "currency": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "amount_numeric": { "anyOf": [ { "type": "number" }, { "type": "null" } ] } }, "additionalProperties": false }, { "type": "null" } ] }, "price_including_buyer_protection": { "anyOf": [ { "type": "object", "required": [ "amount", "amount_numeric", "currency" ], "properties": { "amount": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "currency": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "amount_numeric": { "anyOf": [ { "type": "number" }, { "type": "null" } ] } }, "additionalProperties": false }, { "type": "null" } ] } }, "additionalProperties": true } ``` ### View a polled run response ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "vinted-item", "task_name": "Vinted item", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "size": "sample", "brand": "sample", "color": "sample", "likes": 1.5, "price": { "amount": "180", "currency": "USD", "amount_numeric": 180 }, "title": "Stylish Shoreditch Loft with Balcony", "views": 1.5, "seller": { "id": "id-1", "username": "Stylish Shoreditch Loft with Balcony", "avatar_url": "https://images.example.com/avatar_url-1.jpg", "is_business": true, "profile_url": "https://example.com/item-1", "feedback_count": 1, "feedback_reputation": 1.5 }, "is_sold": true, "item_id": "id-1", "success": true, "item_url": "https://example.com/item-1", "location": "London", "material": "sample", "promoted": true, "condition": "sample", "is_hidden": true, "attributes": [ { "code": "sample", "label": "Stylish Shoreditch Loft with Balcony", "value": "180" } ], "catalog_id": "id-1", "created_at": "2026-06-14T15:30:00Z", "image_urls": [ "https://images.example.com/image_urls-1.jpg" ], "updated_at": "2026-06-14T15:30:00Z", "description": "Sample description 1", "is_reserved": true, "service_fee": { "amount": "180", "currency": "USD", "amount_numeric": 180 }, "is_favourite": true, "similar_items": [ { "id": "id-1", "link": "https://example.com/item-1", "name": "Stylish Shoreditch Loft with Balcony", "page": 1, "size": "sample", "brand": "sample", "color": "sample", "likes": 1.5, "price": { "amount": "180", "currency": "USD", "amount_numeric": 180 }, "views": 1.5, "seller": { "id": "id-1", "username": "Stylish Shoreditch Loft with Balcony", "avatar_url": "https://images.example.com/avatar_url-1.jpg", "is_business": true, "profile_url": "https://example.com/item-1", "feedback_count": 1, "feedback_reputation": 1.5 }, "location": "London", "material": "sample", "promoted": true, "condition": "sample", "catalog_id": "id-1", "created_at": "2026-06-14T15:30:00Z", "image_urls": [ "https://images.example.com/image_urls-1.jpg" ], "description": "Sample description 1", "service_fee": { "amount": "180", "currency": "USD", "amount_numeric": 180 }, "is_favourite": true, "thumbnail_url": "https://images.example.com/thumbnail_url-1.jpg", "price_including_buyer_protection": { "amount": "180", "currency": "USD", "amount_numeric": 180 } } ], "thumbnail_url": "https://images.example.com/thumbnail_url-1.jpg", "shipping_price": { "amount": "180", "currency": "USD", "amount_numeric": 180 }, "price_including_buyer_protection": { "amount": "180", "currency": "USD", "amount_numeric": 180 } }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/vinted/item" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/vinted/item", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({}), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/vinted/item", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={}, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/vinted/item" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/vinted/item", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/vinted/item", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/vinted-item/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/vinted/item" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/vinted/item", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/vinted/item", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "vinted-item", "task_name": "Vinted item", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "size": "sample", "brand": "sample", "color": "sample", "likes": 1.5, "price": { "amount": "180", "currency": "USD", "amount_numeric": 180 }, "title": "Stylish Shoreditch Loft with Balcony", "views": 1.5, "seller": { "id": "id-1", "username": "Stylish Shoreditch Loft with Balcony", "avatar_url": "https://images.example.com/avatar_url-1.jpg", "is_business": true, "profile_url": "https://example.com/item-1", "feedback_count": 1, "feedback_reputation": 1.5 }, "is_sold": true, "item_id": "id-1", "success": true, "item_url": "https://example.com/item-1", "location": "London", "material": "sample", "promoted": true, "condition": "sample", "is_hidden": true, "attributes": [ { "code": "sample", "label": "Stylish Shoreditch Loft with Balcony", "value": "180" } ], "catalog_id": "id-1", "created_at": "2026-06-14T15:30:00Z", "image_urls": [ "https://images.example.com/image_urls-1.jpg" ], "updated_at": "2026-06-14T15:30:00Z", "description": "Sample description 1", "is_reserved": true, "service_fee": { "amount": "180", "currency": "USD", "amount_numeric": 180 }, "is_favourite": true, "similar_items": [ { "id": "id-1", "link": "https://example.com/item-1", "name": "Stylish Shoreditch Loft with Balcony", "page": 1, "size": "sample", "brand": "sample", "color": "sample", "likes": 1.5, "price": { "amount": "180", "currency": "USD", "amount_numeric": 180 }, "views": 1.5, "seller": { "id": "id-1", "username": "Stylish Shoreditch Loft with Balcony", "avatar_url": "https://images.example.com/avatar_url-1.jpg", "is_business": true, "profile_url": "https://example.com/item-1", "feedback_count": 1, "feedback_reputation": 1.5 }, "location": "London", "material": "sample", "promoted": true, "condition": "sample", "catalog_id": "id-1", "created_at": "2026-06-14T15:30:00Z", "image_urls": [ "https://images.example.com/image_urls-1.jpg" ], "description": "Sample description 1", "service_fee": { "amount": "180", "currency": "USD", "amount_numeric": 180 }, "is_favourite": true, "thumbnail_url": "https://images.example.com/thumbnail_url-1.jpg", "price_including_buyer_protection": { "amount": "180", "currency": "USD", "amount_numeric": 180 } } ], "thumbnail_url": "https://images.example.com/thumbnail_url-1.jpg", "shipping_price": { "amount": "180", "currency": "USD", "amount_numeric": 180 }, "price_including_buyer_protection": { "amount": "180", "currency": "USD", "amount_numeric": 180 } }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-vinted-item [Vinted APIs](/docs/api.md#vinted) # Vinted member items Fetch a Vinted member wardrobe feed with pagination and normalized item data. POST `/v1/vinted/member/items` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. Provide at least one of: url; member_url. - **`url` string Optional** Vinted member profile URL (e.g. https://www.vinted.co.uk/member/189338805 or https://www.vinted.fr/member/40333919). Preferred name; member_url remains supported. - **`limit` integer Optional** Items per page (default 20, max 96). Preferred name; per_page remains supported. Default: 20. Minimum: 1. Maximum: 96. - **`order` string Optional** Wardrobe sort order. Default: "relevance". - **`pages` integer Optional** Number of infinite-scroll pages to fetch (1-50). Default: 1. Minimum: 1. Maximum: 50. ### Advanced & compatibility inputs 2 - **`member_url` string Optional** Vinted member profile URL (e.g. https://www.vinted.co.uk/member/189338805 or https://www.vinted.fr/member/40333919). You can also use url. - **`per_page` integer Optional** Items per page (default 20, max 96). You can also use limit. Default: 20. Minimum: 1. Maximum: 96. ## 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", "member_id", "member_url", "pages_requested", "pages_fetched", "count", "results", "pagination" ], "properties": { "count": { "type": "number" }, "results": { "type": "array", "items": { "type": "object", "required": [ "id", "page", "link", "image_urls", "price", "price_including_buyer_protection", "service_fee" ], "properties": { "id": { "type": "string" }, "link": { "type": "string" }, "name": { "type": "string" }, "page": { "type": "number" }, "size": { "type": "string" }, "brand": { "type": "string" }, "color": { "type": "string" }, "likes": { "type": "number" }, "price": { "anyOf": [ { "type": "object", "required": [ "amount", "amount_numeric", "currency" ], "properties": { "amount": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "currency": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "amount_numeric": { "anyOf": [ { "type": "number" }, { "type": "null" } ] } }, "additionalProperties": false }, { "type": "null" } ] }, "views": { "type": "number" }, "seller": { "anyOf": [ { "type": "object", "properties": { "id": { "type": "string" }, "username": { "type": "string" }, "avatar_url": { "type": "string" }, "is_business": { "type": "boolean" }, "profile_url": { "type": "string" }, "feedback_count": { "type": "number" }, "feedback_reputation": { "type": "number" } }, "additionalProperties": false }, { "type": "null" } ] }, "location": { "type": "string" }, "material": { "type": "string" }, "promoted": { "type": "boolean" }, "condition": { "type": "string" }, "catalog_id": { "type": "string" }, "created_at": { "type": "string" }, "image_urls": { "type": "array", "items": { "type": "string" } }, "description": { "type": "string" }, "service_fee": { "anyOf": [ { "type": "object", "required": [ "amount", "amount_numeric", "currency" ], "properties": { "amount": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "currency": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "amount_numeric": { "anyOf": [ { "type": "number" }, { "type": "null" } ] } }, "additionalProperties": false }, { "type": "null" } ] }, "is_favourite": { "type": "boolean" }, "thumbnail_url": { "type": "string" }, "price_including_buyer_protection": { "anyOf": [ { "type": "object", "required": [ "amount", "amount_numeric", "currency" ], "properties": { "amount": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "currency": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "amount_numeric": { "anyOf": [ { "type": "number" }, { "type": "null" } ] } }, "additionalProperties": false }, { "type": "null" } ] } }, "additionalProperties": false } }, "success": { "type": "boolean" }, "member_id": { "type": "string" }, "member_url": { "type": "string" }, "pagination": { "type": "object", "required": [ "has_next_page", "next_page" ], "properties": { "per_page": { "type": "number" }, "next_page": { "anyOf": [ { "type": "number" }, { "type": "null" } ] }, "total_pages": { "anyOf": [ { "type": "number" }, { "type": "null" } ] }, "current_page": { "anyOf": [ { "type": "number" }, { "type": "null" } ] }, "has_next_page": { "type": "boolean" }, "total_entries": { "anyOf": [ { "type": "number" }, { "type": "null" } ] } }, "additionalProperties": false }, "pages_fetched": { "type": "number" }, "pages_requested": { "type": "number" } }, "additionalProperties": true } ``` ### View a polled run response ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "vinted-member-items", "task_name": "Vinted member items", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "count": 1, "results": [ { "id": "id-1", "link": "https://example.com/item-1", "name": "Stylish Shoreditch Loft with Balcony", "page": 1, "size": "sample", "brand": "sample", "color": "sample", "likes": 1.5, "price": { "amount": "180", "currency": "USD", "amount_numeric": 180 }, "views": 1.5, "seller": { "id": "id-1", "username": "Stylish Shoreditch Loft with Balcony", "avatar_url": "https://images.example.com/avatar_url-1.jpg", "is_business": true, "profile_url": "https://example.com/item-1", "feedback_count": 1, "feedback_reputation": 1.5 }, "location": "London", "material": "sample", "promoted": true, "condition": "sample", "catalog_id": "id-1", "created_at": "2026-06-14T15:30:00Z", "image_urls": [ "https://images.example.com/image_urls-1.jpg" ], "description": "Sample description 1", "service_fee": { "amount": "180", "currency": "USD", "amount_numeric": 180 }, "is_favourite": true, "thumbnail_url": "https://images.example.com/thumbnail_url-1.jpg", "price_including_buyer_protection": { "amount": "180", "currency": "USD", "amount_numeric": 180 } } ], "success": true, "member_id": "id-1", "member_url": "https://example.com/item-1", "pagination": { "per_page": 1, "next_page": 1, "total_pages": 1, "current_page": 1, "has_next_page": true, "total_entries": 180 }, "pages_fetched": 1, "pages_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/vinted/member/items" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://example.com/item-1"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/vinted/member/items", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://example.com/item-1" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/vinted/member/items", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://example.com/item-1" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/vinted/member/items" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://example.com/item-1","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/vinted/member/items", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://example.com/item-1", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/vinted/member/items", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://example.com/item-1", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/vinted-member-items/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/vinted/member/items" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://example.com/item-1","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/vinted/member/items", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://example.com/item-1", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/vinted/member/items", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://example.com/item-1", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "vinted-member-items", "task_name": "Vinted member items", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "count": 1, "results": [ { "id": "id-1", "link": "https://example.com/item-1", "name": "Stylish Shoreditch Loft with Balcony", "page": 1, "size": "sample", "brand": "sample", "color": "sample", "likes": 1.5, "price": { "amount": "180", "currency": "USD", "amount_numeric": 180 }, "views": 1.5, "seller": { "id": "id-1", "username": "Stylish Shoreditch Loft with Balcony", "avatar_url": "https://images.example.com/avatar_url-1.jpg", "is_business": true, "profile_url": "https://example.com/item-1", "feedback_count": 1, "feedback_reputation": 1.5 }, "location": "London", "material": "sample", "promoted": true, "condition": "sample", "catalog_id": "id-1", "created_at": "2026-06-14T15:30:00Z", "image_urls": [ "https://images.example.com/image_urls-1.jpg" ], "description": "Sample description 1", "service_fee": { "amount": "180", "currency": "USD", "amount_numeric": 180 }, "is_favourite": true, "thumbnail_url": "https://images.example.com/thumbnail_url-1.jpg", "price_including_buyer_protection": { "amount": "180", "currency": "USD", "amount_numeric": 180 } } ], "success": true, "member_id": "id-1", "member_url": "https://example.com/item-1", "pagination": { "per_page": 1, "next_page": 1, "total_pages": 1, "current_page": 1, "has_next_page": true, "total_entries": 180 }, "pages_fetched": 1, "pages_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-vinted-member-items [Vinted APIs](/docs/api.md#vinted) # Vinted member search Search Vinted member profiles by username and return normalized member matches across multiple pages. POST `/v1/vinted/member/search` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`query` string Required** Vinted member search term. Minimum length: 1. Maximum length: 2000. - **`domain` string Optional** Optional Vinted domain/origin (e.g. vinted.de, www.vinted.fr, or https://www.vinted.co.uk). Defaults to UK. Default: "vinted.co.uk". - **`pages` integer Optional** Number of result pages to fetch (1-20). Default: 1. Minimum: 1. Maximum: 20. ## 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", "query", "pages_requested", "pages_fetched", "count", "results", "pagination" ], "properties": { "count": { "type": "number" }, "query": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "required": [ "member_id", "page", "profile_url" ], "properties": { "page": { "type": "number" }, "username": { "type": "string" }, "member_id": { "type": "string" }, "avatar_url": { "type": "string" }, "profile_url": { "type": "string" }, "review_count": { "type": "number" }, "rating_average": { "type": "number" }, "review_summary": { "type": "string" } }, "additionalProperties": false } }, "success": { "type": "boolean" }, "pagination": { "type": "object", "required": [ "has_next_page", "next_page" ], "properties": { "per_page": { "type": "number" }, "next_page": { "anyOf": [ { "type": "number" }, { "type": "null" } ] }, "total_pages": { "anyOf": [ { "type": "number" }, { "type": "null" } ] }, "current_page": { "anyOf": [ { "type": "number" }, { "type": "null" } ] }, "has_next_page": { "type": "boolean" }, "total_entries": { "anyOf": [ { "type": "number" }, { "type": "null" } ] } }, "additionalProperties": false }, "pages_fetched": { "type": "number" }, "pages_requested": { "type": "number" } }, "additionalProperties": true } ``` ### View a polled run response ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "vinted-member-search", "task_name": "Vinted member search", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "count": 1, "query": "London", "results": [ { "page": 1, "username": "Stylish Shoreditch Loft with Balcony", "member_id": "id-1", "avatar_url": "https://images.example.com/avatar_url-1.jpg", "profile_url": "https://example.com/item-1", "review_count": 1, "rating_average": 4.91, "review_summary": "Sample review_summary 1" } ], "success": true, "pagination": { "per_page": 1, "next_page": 1, "total_pages": 1, "current_page": 1, "has_next_page": true, "total_entries": 180 }, "pages_fetched": 1, "pages_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/vinted/member/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/vinted/member/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "London" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/vinted/member/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "London" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/vinted/member/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"London","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/vinted/member/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "London", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/vinted/member/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "London", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/vinted-member-search/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/vinted/member/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"London","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/vinted/member/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "London", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/vinted/member/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "London", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "vinted-member-search", "task_name": "Vinted member search", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "count": 1, "query": "London", "results": [ { "page": 1, "username": "Stylish Shoreditch Loft with Balcony", "member_id": "id-1", "avatar_url": "https://images.example.com/avatar_url-1.jpg", "profile_url": "https://example.com/item-1", "review_count": 1, "rating_average": 4.91, "review_summary": "Sample review_summary 1" } ], "success": true, "pagination": { "per_page": 1, "next_page": 1, "total_pages": 1, "current_page": 1, "has_next_page": true, "total_entries": 180 }, "pages_fetched": 1, "pages_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-vinted-member-search [Vinted APIs](/docs/api.md#vinted) # Vinted filtered search Search Vinted listings with catalog, size, brand, condition, color, pattern, material, price, and sort filters. POST `/v1/vinted/search/filtered` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. Provide at least one of: query; url. - **`url` string Optional** Copy a filtered Vinted catalogue search URL. Search text, category, size, brand, colour, condition and material filters are extracted automatically. Minimum length: 1. Maximum length: 500. Format: uri. - **`query` string Optional** Vinted search term. Minimum length: 1. Maximum length: 2000. - **`domain` string Optional** Optional Vinted domain/origin (e.g. vinted.de, www.vinted.fr, or https://www.vinted.co.uk). Defaults to UK. Default: "vinted.co.uk". - **`max_price` number Optional** Maximum price in the selected Vinted marketplace currency. Minimum: 0. - **`min_price` number Optional** Minimum price in the selected Vinted marketplace currency. Minimum: 0. - **`order` string Optional** Sort order (e.g. relevance, newest_first, price_high_to_low). Default: "relevance". - **`pages` integer Optional** Number of result pages to fetch (1-20). Default: 1. Minimum: 1. Maximum: 20. ### Advanced & compatibility inputs 10 - **`brand_ids` string | array Optional** Brand filter IDs. Accepts a comma-separated string or an array. - **`catalog` string | array Optional** Catalog/category IDs. Accepts a comma-separated string or an array. - **`catalog_ids` string | array Optional** Catalog/category IDs. Accepts a comma-separated string or an array. - **`color_ids` string | array Optional** Color filter IDs. Accepts a comma-separated string or an array. - **`material_ids` string | array Optional** Material filter IDs. Accepts a comma-separated string or an array. - **`patterns_ids` string | array Optional** Pattern filter IDs. Accepts a comma-separated string or an array. - **`price_from` string | number Optional** Minimum item price. Prefer min_price/max_price. - **`price_to` string | number Optional** Maximum item price. Prefer min_price/max_price. - **`size_ids` string | array Optional** Size filter IDs. Accepts a comma-separated string or an array. - **`status_ids` string | array Optional** Condition/status filter IDs. Accepts a comma-separated string or an array. ## 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", "query", "pages_requested", "pages_fetched", "count", "results", "pagination" ], "properties": { "count": { "type": "number" }, "query": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "required": [ "id", "page", "link", "image_urls", "price", "price_including_buyer_protection", "service_fee" ], "properties": { "id": { "type": "string" }, "link": { "type": "string" }, "name": { "type": "string" }, "page": { "type": "number" }, "size": { "type": "string" }, "brand": { "type": "string" }, "color": { "type": "string" }, "likes": { "type": "number" }, "price": { "anyOf": [ { "type": "object", "required": [ "amount", "amount_numeric", "currency" ], "properties": { "amount": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "currency": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "amount_numeric": { "anyOf": [ { "type": "number" }, { "type": "null" } ] } }, "additionalProperties": false }, { "type": "null" } ] }, "views": { "type": "number" }, "seller": { "anyOf": [ { "type": "object", "properties": { "id": { "type": "string" }, "username": { "type": "string" }, "avatar_url": { "type": "string" }, "is_business": { "type": "boolean" }, "profile_url": { "type": "string" }, "feedback_count": { "type": "number" }, "feedback_reputation": { "type": "number" } }, "additionalProperties": false }, { "type": "null" } ] }, "location": { "type": "string" }, "material": { "type": "string" }, "promoted": { "type": "boolean" }, "condition": { "type": "string" }, "catalog_id": { "type": "string" }, "created_at": { "type": "string" }, "image_urls": { "type": "array", "items": { "type": "string" } }, "description": { "type": "string" }, "service_fee": { "anyOf": [ { "type": "object", "required": [ "amount", "amount_numeric", "currency" ], "properties": { "amount": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "currency": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "amount_numeric": { "anyOf": [ { "type": "number" }, { "type": "null" } ] } }, "additionalProperties": false }, { "type": "null" } ] }, "is_favourite": { "type": "boolean" }, "thumbnail_url": { "type": "string" }, "price_including_buyer_protection": { "anyOf": [ { "type": "object", "required": [ "amount", "amount_numeric", "currency" ], "properties": { "amount": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "currency": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "amount_numeric": { "anyOf": [ { "type": "number" }, { "type": "null" } ] } }, "additionalProperties": false }, { "type": "null" } ] } }, "additionalProperties": false } }, "success": { "type": "boolean" }, "pagination": { "type": "object", "required": [ "has_next_page", "next_page" ], "properties": { "per_page": { "type": "number" }, "next_page": { "anyOf": [ { "type": "number" }, { "type": "null" } ] }, "total_pages": { "anyOf": [ { "type": "number" }, { "type": "null" } ] }, "current_page": { "anyOf": [ { "type": "number" }, { "type": "null" } ] }, "has_next_page": { "type": "boolean" }, "total_entries": { "anyOf": [ { "type": "number" }, { "type": "null" } ] } }, "additionalProperties": false }, "pages_fetched": { "type": "number" }, "pages_requested": { "type": "number" }, "search_session_id": { "type": "string" } }, "additionalProperties": true } ``` ### View a polled run response ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "vinted-search-filtered", "task_name": "Vinted filtered search", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "count": 1, "query": "London", "results": [ { "id": "id-1", "link": "https://example.com/item-1", "name": "Stylish Shoreditch Loft with Balcony", "page": 1, "size": "sample", "brand": "sample", "color": "sample", "likes": 1.5, "price": { "amount": "180", "currency": "USD", "amount_numeric": 180 }, "views": 1.5, "seller": { "id": "id-1", "username": "Stylish Shoreditch Loft with Balcony", "avatar_url": "https://images.example.com/avatar_url-1.jpg", "is_business": true, "profile_url": "https://example.com/item-1", "feedback_count": 1, "feedback_reputation": 1.5 }, "location": "London", "material": "sample", "promoted": true, "condition": "sample", "catalog_id": "id-1", "created_at": "2026-06-14T15:30:00Z", "image_urls": [ "https://images.example.com/image_urls-1.jpg" ], "description": "Sample description 1", "service_fee": { "amount": "180", "currency": "USD", "amount_numeric": 180 }, "is_favourite": true, "thumbnail_url": "https://images.example.com/thumbnail_url-1.jpg", "price_including_buyer_protection": { "amount": "180", "currency": "USD", "amount_numeric": 180 } } ], "success": true, "pagination": { "per_page": 1, "next_page": 1, "total_pages": 1, "current_page": 1, "has_next_page": true, "total_entries": 180 }, "pages_fetched": 1, "pages_requested": 1, "search_session_id": "search-session-1" }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/vinted/search/filtered" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.vinted.co.uk/catalog?search_text=nike&brand_ids[]=53"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/vinted/search/filtered", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.vinted.co.uk/catalog?search_text=nike&brand_ids[]=53" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/vinted/search/filtered", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.vinted.co.uk/catalog?search_text=nike&brand_ids[]=53" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/vinted/search/filtered" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.vinted.co.uk/catalog?search_text=nike&brand_ids[]=53","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/vinted/search/filtered", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.vinted.co.uk/catalog?search_text=nike&brand_ids[]=53", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/vinted/search/filtered", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.vinted.co.uk/catalog?search_text=nike&brand_ids[]=53", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/vinted-search-filtered/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/vinted/search/filtered" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.vinted.co.uk/catalog?search_text=nike&brand_ids[]=53","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/vinted/search/filtered", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.vinted.co.uk/catalog?search_text=nike&brand_ids[]=53", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/vinted/search/filtered", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.vinted.co.uk/catalog?search_text=nike&brand_ids[]=53", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "vinted-search-filtered", "task_name": "Vinted filtered search", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "count": 1, "query": "London", "results": [ { "id": "id-1", "link": "https://example.com/item-1", "name": "Stylish Shoreditch Loft with Balcony", "page": 1, "size": "sample", "brand": "sample", "color": "sample", "likes": 1.5, "price": { "amount": "180", "currency": "USD", "amount_numeric": 180 }, "views": 1.5, "seller": { "id": "id-1", "username": "Stylish Shoreditch Loft with Balcony", "avatar_url": "https://images.example.com/avatar_url-1.jpg", "is_business": true, "profile_url": "https://example.com/item-1", "feedback_count": 1, "feedback_reputation": 1.5 }, "location": "London", "material": "sample", "promoted": true, "condition": "sample", "catalog_id": "id-1", "created_at": "2026-06-14T15:30:00Z", "image_urls": [ "https://images.example.com/image_urls-1.jpg" ], "description": "Sample description 1", "service_fee": { "amount": "180", "currency": "USD", "amount_numeric": 180 }, "is_favourite": true, "thumbnail_url": "https://images.example.com/thumbnail_url-1.jpg", "price_including_buyer_protection": { "amount": "180", "currency": "USD", "amount_numeric": 180 } } ], "success": true, "pagination": { "per_page": 1, "next_page": 1, "total_pages": 1, "current_page": 1, "has_next_page": true, "total_entries": 180 }, "pages_fetched": 1, "pages_requested": 1, "search_session_id": "search-session-1" }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-vinted-search-filtered [Vinted APIs](/docs/api.md#vinted) # Vinted search Search Vinted listings by keyword and return normalized item data across multiple pages. POST `/v1/vinted/search` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`query` string Required** Vinted search term. Minimum length: 1. Maximum length: 2000. - **`domain` string Optional** Optional Vinted domain/origin (e.g. vinted.de, www.vinted.fr, or https://www.vinted.co.uk). Defaults to UK. Default: "vinted.co.uk". - **`pages` integer Optional** Number of result pages to fetch (1-20). Default: 1. Minimum: 1. Maximum: 20. ## 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", "query", "pages_requested", "pages_fetched", "count", "results", "pagination" ], "properties": { "count": { "type": "number" }, "query": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "required": [ "id", "page", "link", "image_urls", "price", "price_including_buyer_protection", "service_fee" ], "properties": { "id": { "type": "string" }, "link": { "type": "string" }, "name": { "type": "string" }, "page": { "type": "number" }, "size": { "type": "string" }, "brand": { "type": "string" }, "color": { "type": "string" }, "likes": { "type": "number" }, "price": { "anyOf": [ { "type": "object", "required": [ "amount", "amount_numeric", "currency" ], "properties": { "amount": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "currency": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "amount_numeric": { "anyOf": [ { "type": "number" }, { "type": "null" } ] } }, "additionalProperties": false }, { "type": "null" } ] }, "views": { "type": "number" }, "seller": { "anyOf": [ { "type": "object", "properties": { "id": { "type": "string" }, "username": { "type": "string" }, "avatar_url": { "type": "string" }, "is_business": { "type": "boolean" }, "profile_url": { "type": "string" }, "feedback_count": { "type": "number" }, "feedback_reputation": { "type": "number" } }, "additionalProperties": false }, { "type": "null" } ] }, "location": { "type": "string" }, "material": { "type": "string" }, "promoted": { "type": "boolean" }, "condition": { "type": "string" }, "catalog_id": { "type": "string" }, "created_at": { "type": "string" }, "image_urls": { "type": "array", "items": { "type": "string" } }, "description": { "type": "string" }, "service_fee": { "anyOf": [ { "type": "object", "required": [ "amount", "amount_numeric", "currency" ], "properties": { "amount": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "currency": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "amount_numeric": { "anyOf": [ { "type": "number" }, { "type": "null" } ] } }, "additionalProperties": false }, { "type": "null" } ] }, "is_favourite": { "type": "boolean" }, "thumbnail_url": { "type": "string" }, "price_including_buyer_protection": { "anyOf": [ { "type": "object", "required": [ "amount", "amount_numeric", "currency" ], "properties": { "amount": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "currency": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "amount_numeric": { "anyOf": [ { "type": "number" }, { "type": "null" } ] } }, "additionalProperties": false }, { "type": "null" } ] } }, "additionalProperties": false } }, "success": { "type": "boolean" }, "pagination": { "type": "object", "required": [ "has_next_page", "next_page" ], "properties": { "per_page": { "type": "number" }, "next_page": { "anyOf": [ { "type": "number" }, { "type": "null" } ] }, "total_pages": { "anyOf": [ { "type": "number" }, { "type": "null" } ] }, "current_page": { "anyOf": [ { "type": "number" }, { "type": "null" } ] }, "has_next_page": { "type": "boolean" }, "total_entries": { "anyOf": [ { "type": "number" }, { "type": "null" } ] } }, "additionalProperties": false }, "pages_fetched": { "type": "number" }, "pages_requested": { "type": "number" }, "search_session_id": { "type": "string" } }, "additionalProperties": true } ``` ### View a polled run response ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "vinted-search", "task_name": "Vinted search", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "count": 1, "query": "London", "results": [ { "id": "id-1", "link": "https://example.com/item-1", "name": "Stylish Shoreditch Loft with Balcony", "page": 1, "size": "sample", "brand": "sample", "color": "sample", "likes": 1.5, "price": { "amount": "180", "currency": "USD", "amount_numeric": 180 }, "views": 1.5, "seller": { "id": "id-1", "username": "Stylish Shoreditch Loft with Balcony", "avatar_url": "https://images.example.com/avatar_url-1.jpg", "is_business": true, "profile_url": "https://example.com/item-1", "feedback_count": 1, "feedback_reputation": 1.5 }, "location": "London", "material": "sample", "promoted": true, "condition": "sample", "catalog_id": "id-1", "created_at": "2026-06-14T15:30:00Z", "image_urls": [ "https://images.example.com/image_urls-1.jpg" ], "description": "Sample description 1", "service_fee": { "amount": "180", "currency": "USD", "amount_numeric": 180 }, "is_favourite": true, "thumbnail_url": "https://images.example.com/thumbnail_url-1.jpg", "price_including_buyer_protection": { "amount": "180", "currency": "USD", "amount_numeric": 180 } } ], "success": true, "pagination": { "per_page": 1, "next_page": 1, "total_pages": 1, "current_page": 1, "has_next_page": true, "total_entries": 180 }, "pages_fetched": 1, "pages_requested": 1, "search_session_id": "search-session-1" }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/vinted/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/vinted/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "London" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/vinted/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "London" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/vinted/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"London","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/vinted/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "London", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/vinted/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "London", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/vinted-search/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/vinted/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"London","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/vinted/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "London", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/vinted/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "London", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "vinted-search", "task_name": "Vinted search", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "count": 1, "query": "London", "results": [ { "id": "id-1", "link": "https://example.com/item-1", "name": "Stylish Shoreditch Loft with Balcony", "page": 1, "size": "sample", "brand": "sample", "color": "sample", "likes": 1.5, "price": { "amount": "180", "currency": "USD", "amount_numeric": 180 }, "views": 1.5, "seller": { "id": "id-1", "username": "Stylish Shoreditch Loft with Balcony", "avatar_url": "https://images.example.com/avatar_url-1.jpg", "is_business": true, "profile_url": "https://example.com/item-1", "feedback_count": 1, "feedback_reputation": 1.5 }, "location": "London", "material": "sample", "promoted": true, "condition": "sample", "catalog_id": "id-1", "created_at": "2026-06-14T15:30:00Z", "image_urls": [ "https://images.example.com/image_urls-1.jpg" ], "description": "Sample description 1", "service_fee": { "amount": "180", "currency": "USD", "amount_numeric": 180 }, "is_favourite": true, "thumbnail_url": "https://images.example.com/thumbnail_url-1.jpg", "price_including_buyer_protection": { "amount": "180", "currency": "USD", "amount_numeric": 180 } } ], "success": true, "pagination": { "per_page": 1, "next_page": 1, "total_pages": 1, "current_page": 1, "has_next_page": true, "total_entries": 180 }, "pages_fetched": 1, "pages_requested": 1, "search_session_id": "search-session-1" }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-vinted-search [Walmart APIs](/docs/api.md#walmart) # Walmart Product API Scrape a public Walmart product detail page from a search result URL. POST `/v1/walmart/product` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`url` string Required** Walmart product URL returned by walmart/search. Minimum length: 1. Maximum length: 2000. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "walmart-product", "task_name": "Walmart Product API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/walmart/product" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.walmart.com/ip/123456789"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/walmart/product", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.walmart.com/ip/123456789" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/walmart/product", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.walmart.com/ip/123456789" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/walmart/product" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.walmart.com/ip/123456789","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/walmart/product", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.walmart.com/ip/123456789", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/walmart/product", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.walmart.com/ip/123456789", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/walmart-product/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/walmart/product" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.walmart.com/ip/123456789","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/walmart/product", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.walmart.com/ip/123456789", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/walmart/product", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.walmart.com/ip/123456789", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "walmart-product", "task_name": "Walmart Product API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-walmart-product [Walmart APIs](/docs/api.md#walmart) # Walmart API Scrape public Walmart search result pages by query with page pagination. POST `/v1/walmart/search` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`query` string Required** Search query. Minimum length: 1. Maximum length: 2000. - **`limit` integer Optional** Maximum number of results to return. Default: 25. Minimum: 1. Maximum: 100. - **`cursor` string Optional** Cursor returned as next_cursor from the previous response. - **`page` integer Optional** Page number for sources that support page-based pagination. Default: 1. Minimum: 1. Maximum: 10000. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "walmart-search", "task_name": "Walmart API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/walmart/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"air fryer"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/walmart/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "air fryer" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/walmart/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "air fryer" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/walmart/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"air fryer","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/walmart/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "air fryer", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/walmart/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "air fryer", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/walmart-search/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/walmart/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"air fryer","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/walmart/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "air fryer", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/walmart/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "air fryer", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "walmart-search", "task_name": "Walmart API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-walmart-search [Wellfound APIs](/docs/api.md#wellfound) # Wellfound Profile API Scrape a public Wellfound company or job page. POST `/v1/wellfound/profile` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`url` string Required** URL returned by the matching search endpoint. Minimum length: 1. Maximum length: 2000. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "wellfound-profile", "task_name": "Wellfound Profile API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/wellfound/profile" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://wellfound.com/company/example"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/wellfound/profile", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://wellfound.com/company/example" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/wellfound/profile", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://wellfound.com/company/example" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/wellfound/profile" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://wellfound.com/company/example","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/wellfound/profile", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://wellfound.com/company/example", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/wellfound/profile", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://wellfound.com/company/example", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/wellfound-profile/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/wellfound/profile" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://wellfound.com/company/example","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/wellfound/profile", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://wellfound.com/company/example", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/wellfound/profile", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://wellfound.com/company/example", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "wellfound-profile", "task_name": "Wellfound Profile API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-wellfound-profile [Wellfound APIs](/docs/api.md#wellfound) # Wellfound API Find public Wellfound jobs by role or company name. POST `/v1/wellfound/search` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`query` string Required** Search query. Minimum length: 1. Maximum length: 2000. - **`limit` integer Optional** Maximum number of results to return. Default: 25. Minimum: 1. Maximum: 100. - **`cursor` string Optional** Cursor returned as next_cursor from the previous response. - **`page` integer Optional** Page number for sources that support page-based pagination. Default: 1. Minimum: 1. Maximum: 10000. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "wellfound-search", "task_name": "Wellfound API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/wellfound/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"frontend engineer"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/wellfound/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "frontend engineer" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/wellfound/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "frontend engineer" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/wellfound/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"frontend engineer","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/wellfound/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "frontend engineer", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/wellfound/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "frontend engineer", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/wellfound-search/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/wellfound/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"frontend engineer","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/wellfound/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "frontend engineer", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/wellfound/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "frontend engineer", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "wellfound-search", "task_name": "Wellfound API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-wellfound-search [Wikipedia APIs](/docs/api.md#wikipedia) # Wikipedia Page API Scrape a public Wikipedia article page from a search result URL. POST `/v1/wikipedia/page` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`url` string Required** Wikipedia page URL returned by wikipedia/search. Minimum length: 1. Maximum length: 2000. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "wikipedia-page", "task_name": "Wikipedia Page API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/wikipedia/page" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://en.wikipedia.org/wiki/Ada_Lovelace"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/wikipedia/page", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://en.wikipedia.org/wiki/Ada_Lovelace" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/wikipedia/page", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://en.wikipedia.org/wiki/Ada_Lovelace" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/wikipedia/page" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://en.wikipedia.org/wiki/Ada_Lovelace","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/wikipedia/page", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://en.wikipedia.org/wiki/Ada_Lovelace", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/wikipedia/page", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://en.wikipedia.org/wiki/Ada_Lovelace", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/wikipedia-page/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/wikipedia/page" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://en.wikipedia.org/wiki/Ada_Lovelace","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/wikipedia/page", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://en.wikipedia.org/wiki/Ada_Lovelace", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/wikipedia/page", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://en.wikipedia.org/wiki/Ada_Lovelace", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "wikipedia-page", "task_name": "Wikipedia Page API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-wikipedia-page [Wikipedia APIs](/docs/api.md#wikipedia) # Wikipedia API Search Wikipedia through the public MediaWiki API with offset pagination. POST `/v1/wikipedia/search` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`query` string Required** Wikipedia article search query. Minimum length: 1. Maximum length: 2000. - **`limit` integer Optional** Maximum number of results to return. Default: 25. Minimum: 1. Maximum: 100. - **`cursor` string Optional** Cursor returned as next_cursor from the previous response. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "wikipedia-search", "task_name": "Wikipedia API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/wikipedia/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"Ada Lovelace"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/wikipedia/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "Ada Lovelace" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/wikipedia/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "Ada Lovelace" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/wikipedia/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"Ada Lovelace","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/wikipedia/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "Ada Lovelace", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/wikipedia/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "Ada Lovelace", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/wikipedia-search/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/wikipedia/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"Ada Lovelace","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/wikipedia/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "Ada Lovelace", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/wikipedia/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "Ada Lovelace", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "wikipedia-search", "task_name": "Wikipedia API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-wikipedia-search [X APIs](/docs/api.md#x) # X Lists API Scrape a public X or Twitter list page. POST `/v1/x/lists` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) **Connected website account required** Requires a connected x.com account. Browsable automatically uses a saved connection on your team when one is available. If none is available, HTTP `428` includes a `hosted_url`. Complete sign-in there, then retry. [Connect an account →](/docs/api/website-logins.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`url` string Required** URL returned by the matching search endpoint. Minimum length: 1. Maximum length: 2000. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "x-lists", "task_name": "X Lists API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/x/lists" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://x.com/i/lists/123456789"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/x/lists", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://x.com/i/lists/123456789" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/x/lists", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://x.com/i/lists/123456789" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/x/lists" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://x.com/i/lists/123456789","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/x/lists", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://x.com/i/lists/123456789", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/x/lists", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://x.com/i/lists/123456789", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/x-lists/runs`. Compatibility route: `/v1/twitter/lists`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/x/lists" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://x.com/i/lists/123456789","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/x/lists", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://x.com/i/lists/123456789", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/x/lists", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://x.com/i/lists/123456789", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "x-lists", "task_name": "X Lists API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-x-lists [X APIs](/docs/api.md#x) # X profile Fetch tweets from an X profile inside a managed signed-in session. POST `/v1/x/profile` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) **Connected website account required** Requires a connected x.com account. Browsable automatically uses a saved connection on your team when one is available. If none is available, HTTP `428` includes a `hosted_url`. Complete sign-in there, then retry. [Connect an account →](/docs/api/website-logins.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. Provide at least one of: profile_url; username. - **`url` string Optional** X profile URL, for example https://x.com/jack. Preferred name; profile_url remains supported. - **`username` string Optional** X username without the leading @. Minimum length: 1. Maximum length: 2000. - **`limit` integer Optional** Maximum number of tweets to collect from the profile timeline. Preferred name; max_tweets remains supported. Default: 100. Minimum: 1. Maximum: 500. ### Advanced & compatibility inputs 2 - **`max_tweets` integer Optional** Maximum number of tweets to collect from the profile timeline. You can also use limit. Default: 100. Minimum: 1. Maximum: 500. - **`profile_url` string Optional** X profile URL, for example https://x.com/jack. You can also use url. ## 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", "profile", "max_tweets_requested", "count", "tweets", "pagination" ], "properties": { "count": { "type": "integer" }, "tweets": { "type": "array", "items": { "type": "object", "required": [ "textContent", "displayName", "username", "profilePhotoUrl", "timestamp", "tweetLink", "isAd", "numberOfReplies", "numberOfRetweets", "numberOfLikes", "numberOfViews" ], "properties": { "isAd": { "type": "boolean" }, "username": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "timestamp": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "tweetLink": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "displayName": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "textContent": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "numberOfLikes": { "type": "integer" }, "numberOfViews": { "type": "integer" }, "numberOfReplies": { "type": "integer" }, "profilePhotoUrl": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "numberOfRetweets": { "type": "integer" } }, "additionalProperties": false } }, "profile": { "type": "object", "required": [ "url", "username" ], "properties": { "url": { "type": "string" }, "username": { "anyOf": [ { "type": "string" }, { "type": "null" } ] } }, "additionalProperties": false }, "success": { "type": "boolean" }, "pagination": { "type": "object", "required": [ "has_next_page", "next_cursor" ], "properties": { "next_cursor": { "type": "null" }, "has_next_page": { "type": "boolean" } }, "additionalProperties": false }, "max_tweets_requested": { "type": "integer" } }, "additionalProperties": false } ``` ### View a polled run response ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "x-profile", "task_name": "X profile", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "count": 1, "tweets": [ { "isAd": true, "username": "Stylish Shoreditch Loft with Balcony", "timestamp": "sample", "tweetLink": "https://example.com/item-1", "displayName": "Stylish Shoreditch Loft with Balcony", "textContent": "Sample textcontent 1", "numberOfLikes": 1, "numberOfViews": 1, "numberOfReplies": 1, "profilePhotoUrl": "https://images.example.com/profilephotourl-1.jpg", "numberOfRetweets": 1 } ], "profile": { "url": "https://example.com/item-1", "username": "Stylish Shoreditch Loft with Balcony" }, "success": true, "pagination": { "next_cursor": null, "has_next_page": true }, "max_tweets_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/x/profile" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"profile_url":"https://example.com/item-1"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/x/profile", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "profile_url": "https://example.com/item-1" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/x/profile", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "profile_url": "https://example.com/item-1" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/x/profile" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"profile_url":"https://example.com/item-1","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/x/profile", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "profile_url": "https://example.com/item-1", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/x/profile", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "profile_url": "https://example.com/item-1", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/x-profile/runs`. Compatibility route: `/v1/twitter/profile`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/x/profile" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"profile_url":"https://example.com/item-1","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/x/profile", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "profile_url": "https://example.com/item-1", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/x/profile", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "profile_url": "https://example.com/item-1", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "x-profile", "task_name": "X profile", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "count": 1, "tweets": [ { "isAd": true, "username": "Stylish Shoreditch Loft with Balcony", "timestamp": "sample", "tweetLink": "https://example.com/item-1", "displayName": "Stylish Shoreditch Loft with Balcony", "textContent": "Sample textcontent 1", "numberOfLikes": 1, "numberOfViews": 1, "numberOfReplies": 1, "profilePhotoUrl": "https://images.example.com/profilephotourl-1.jpg", "numberOfRetweets": 1 } ], "profile": { "url": "https://example.com/item-1", "username": "Stylish Shoreditch Loft with Balcony" }, "success": true, "pagination": { "next_cursor": null, "has_next_page": true }, "max_tweets_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-x-profile [X APIs](/docs/api.md#x) # X search Search X posts inside a managed signed-in session. POST `/v1/x/search` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) **Connected website account required** Requires a connected x.com account. Browsable automatically uses a saved connection on your team when one is available. If none is available, HTTP `428` includes a `hosted_url`. Complete sign-in there, then retry. [Connect an account →](/docs/api/website-logins.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`query` string Required** Keyword or phrase to search on X. Minimum length: 1. Maximum length: 2000. - **`limit` integer Optional** Maximum number of tweets to collect from the current search surface. Preferred name; max_tweets remains supported. Default: 100. Minimum: 1. Maximum: 500. - **`tab` string Optional** Search tab to scrape. Default: "top". Allowed: "top", "latest", "people", "media", "lists". ### Advanced & compatibility inputs 1 - **`max_tweets` integer Optional** Maximum number of tweets to collect from the current search surface. You can also use limit. Default: 100. Minimum: 1. Maximum: 500. ## 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", "query", "tab", "max_tweets_requested", "count", "tweets", "pagination" ], "properties": { "tab": { "enum": [ "top", "latest", "people", "media", "lists" ], "type": "string" }, "count": { "type": "integer" }, "query": { "type": "string" }, "tweets": { "type": "array", "items": { "type": "object", "required": [ "textContent", "displayName", "username", "profilePhotoUrl", "timestamp", "tweetLink", "isAd", "numberOfReplies", "numberOfRetweets", "numberOfLikes", "numberOfViews" ], "properties": { "isAd": { "type": "boolean" }, "username": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "timestamp": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "tweetLink": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "displayName": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "textContent": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "numberOfLikes": { "type": "integer" }, "numberOfViews": { "type": "integer" }, "numberOfReplies": { "type": "integer" }, "profilePhotoUrl": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "numberOfRetweets": { "type": "integer" } }, "additionalProperties": false } }, "success": { "type": "boolean" }, "pagination": { "type": "object", "required": [ "has_next_page", "next_cursor" ], "properties": { "next_cursor": { "type": "null" }, "has_next_page": { "type": "boolean" } }, "additionalProperties": false }, "max_tweets_requested": { "type": "integer" } }, "additionalProperties": false } ``` ### View a polled run response ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "x-search", "task_name": "X search", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "tab": "top", "count": 1, "query": "London", "tweets": [ { "isAd": true, "username": "Stylish Shoreditch Loft with Balcony", "timestamp": "sample", "tweetLink": "https://example.com/item-1", "displayName": "Stylish Shoreditch Loft with Balcony", "textContent": "Sample textcontent 1", "numberOfLikes": 1, "numberOfViews": 1, "numberOfReplies": 1, "profilePhotoUrl": "https://images.example.com/profilephotourl-1.jpg", "numberOfRetweets": 1 } ], "success": true, "pagination": { "next_cursor": null, "has_next_page": true }, "max_tweets_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/x/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/x/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "London" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/x/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "London" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/x/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"London","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/x/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "London", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/x/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "London", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/x-search/runs`. Compatibility route: `/v1/twitter/search`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/x/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"London","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/x/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "London", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/x/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "London", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "x-search", "task_name": "X search", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "tab": "top", "count": 1, "query": "London", "tweets": [ { "isAd": true, "username": "Stylish Shoreditch Loft with Balcony", "timestamp": "sample", "tweetLink": "https://example.com/item-1", "displayName": "Stylish Shoreditch Loft with Balcony", "textContent": "Sample textcontent 1", "numberOfLikes": 1, "numberOfViews": 1, "numberOfReplies": 1, "profilePhotoUrl": "https://images.example.com/profilephotourl-1.jpg", "numberOfRetweets": 1 } ], "success": true, "pagination": { "next_cursor": null, "has_next_page": true }, "max_tweets_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-x-search [X APIs](/docs/api.md#x) # X timeline Fetch tweets from the signed-in X home timeline using managed auth. POST `/v1/x/timeline` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) **Connected website account required** Requires a connected x.com account. Browsable automatically uses a saved connection on your team when one is available. If none is available, HTTP `428` includes a `hosted_url`. Complete sign-in there, then retry. [Connect an account →](/docs/api/website-logins.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`limit` integer Optional** Maximum number of tweets to collect from the requested home timeline. Preferred name; max_tweets remains supported. Default: 100. Minimum: 1. Maximum: 500. - **`timeline_type` string Optional** Which signed-in home timeline to scrape. Default: "following". Allowed: "following", "for_you". ### Advanced & compatibility inputs 1 - **`max_tweets` integer Optional** Maximum number of tweets to collect from the requested home timeline. You can also use limit. Default: 100. Minimum: 1. Maximum: 500. ## 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", "timeline_type", "max_tweets_requested", "count", "tweets", "pagination" ], "properties": { "count": { "type": "integer" }, "tweets": { "type": "array", "items": { "type": "object", "required": [ "textContent", "displayName", "username", "profilePhotoUrl", "timestamp", "tweetLink", "isAd", "numberOfReplies", "numberOfRetweets", "numberOfLikes", "numberOfViews" ], "properties": { "isAd": { "type": "boolean" }, "username": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "timestamp": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "tweetLink": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "displayName": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "textContent": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "numberOfLikes": { "type": "integer" }, "numberOfViews": { "type": "integer" }, "numberOfReplies": { "type": "integer" }, "profilePhotoUrl": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "numberOfRetweets": { "type": "integer" } }, "additionalProperties": false } }, "success": { "type": "boolean" }, "pagination": { "type": "object", "required": [ "has_next_page", "next_cursor" ], "properties": { "next_cursor": { "type": "null" }, "has_next_page": { "type": "boolean" } }, "additionalProperties": false }, "timeline_type": { "enum": [ "following", "for_you" ], "type": "string" }, "max_tweets_requested": { "type": "integer" } }, "additionalProperties": false } ``` ### View a polled run response ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "x-timeline", "task_name": "X timeline", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "count": 1, "tweets": [ { "isAd": true, "username": "Stylish Shoreditch Loft with Balcony", "timestamp": "sample", "tweetLink": "https://example.com/item-1", "displayName": "Stylish Shoreditch Loft with Balcony", "textContent": "Sample textcontent 1", "numberOfLikes": 1, "numberOfViews": 1, "numberOfReplies": 1, "profilePhotoUrl": "https://images.example.com/profilephotourl-1.jpg", "numberOfRetweets": 1 } ], "success": true, "pagination": { "next_cursor": null, "has_next_page": true }, "timeline_type": "following", "max_tweets_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/x/timeline" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/x/timeline", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({}), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/x/timeline", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={}, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/x/timeline" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/x/timeline", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/x/timeline", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/x-timeline/runs`. Compatibility route: `/v1/twitter/timeline`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/x/timeline" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/x/timeline", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/x/timeline", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "x-timeline", "task_name": "X timeline", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "count": 1, "tweets": [ { "isAd": true, "username": "Stylish Shoreditch Loft with Balcony", "timestamp": "sample", "tweetLink": "https://example.com/item-1", "displayName": "Stylish Shoreditch Loft with Balcony", "textContent": "Sample textcontent 1", "numberOfLikes": 1, "numberOfViews": 1, "numberOfReplies": 1, "profilePhotoUrl": "https://images.example.com/profilephotourl-1.jpg", "numberOfRetweets": 1 } ], "success": true, "pagination": { "next_cursor": null, "has_next_page": true }, "timeline_type": "following", "max_tweets_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-x-timeline [X APIs](/docs/api.md#x) # X Trends API Scrape public X explore trends. POST `/v1/x/trends` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) **Connected website account required** Requires a connected x.com account. Browsable automatically uses a saved connection on your team when one is available. If none is available, HTTP `428` includes a `hosted_url`. Complete sign-in there, then retry. [Connect an account →](/docs/api/website-logins.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`query` string Optional** Search query. Minimum length: 1. Maximum length: 2000. - **`limit` integer Optional** Maximum number of results to return. Default: 25. Minimum: 1. Maximum: 100. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "x-trends", "task_name": "X Trends API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/x/trends" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/x/trends", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({}), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/x/trends", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={}, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/x/trends" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/x/trends", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/x/trends", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/x-trends/runs`. Compatibility route: `/v1/twitter/trends`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/x/trends" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/x/trends", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/x/trends", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "x-trends", "task_name": "X Trends API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-x-trends [Yelp APIs](/docs/api.md#yelp) # Yelp Business API Scrape a public Yelp business detail page from a search result URL. POST `/v1/yelp/business` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`url` string Required** Yelp business URL returned by yelp/search. Minimum length: 1. Maximum length: 2000. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "yelp-business", "task_name": "Yelp Business API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/yelp/business" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.yelp.com/biz/ramen-tatsu-ya-austin-2"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/yelp/business", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.yelp.com/biz/ramen-tatsu-ya-austin-2" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/yelp/business", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.yelp.com/biz/ramen-tatsu-ya-austin-2" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/yelp/business" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.yelp.com/biz/ramen-tatsu-ya-austin-2","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/yelp/business", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.yelp.com/biz/ramen-tatsu-ya-austin-2", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/yelp/business", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.yelp.com/biz/ramen-tatsu-ya-austin-2", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/yelp-business/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/yelp/business" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.yelp.com/biz/ramen-tatsu-ya-austin-2","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/yelp/business", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.yelp.com/biz/ramen-tatsu-ya-austin-2", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/yelp/business", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.yelp.com/biz/ramen-tatsu-ya-austin-2", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "yelp-business", "task_name": "Yelp Business API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-yelp-business [Yelp APIs](/docs/api.md#yelp) # Yelp Reviews API Scrape public reviews visible on a Yelp business page. POST `/v1/yelp/reviews` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`url` string Required** URL returned by the matching search endpoint. Minimum length: 1. Maximum length: 2000. - **`cursor` string Optional** Cursor returned as next_cursor from the previous response. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "yelp-reviews", "task_name": "Yelp Reviews API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/yelp/reviews" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.yelp.com/biz/ramen-tatsu-ya-austin-2"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/yelp/reviews", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.yelp.com/biz/ramen-tatsu-ya-austin-2" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/yelp/reviews", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.yelp.com/biz/ramen-tatsu-ya-austin-2" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/yelp/reviews" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.yelp.com/biz/ramen-tatsu-ya-austin-2","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/yelp/reviews", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.yelp.com/biz/ramen-tatsu-ya-austin-2", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/yelp/reviews", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.yelp.com/biz/ramen-tatsu-ya-austin-2", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/yelp-reviews/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/yelp/reviews" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.yelp.com/biz/ramen-tatsu-ya-austin-2","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/yelp/reviews", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.yelp.com/biz/ramen-tatsu-ya-austin-2", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/yelp/reviews", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.yelp.com/biz/ramen-tatsu-ya-austin-2", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "yelp-reviews", "task_name": "Yelp Reviews API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-yelp-reviews [Yelp APIs](/docs/api.md#yelp) # Yelp API Scrape public Yelp search results by query and optional location. The official Yelp Fusion API requires credentials. POST `/v1/yelp/search` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`query` string Required** Search query. Minimum length: 1. Maximum length: 2000. - **`location` string Optional** Location filter. Minimum length: 1. Maximum length: 2000. - **`limit` integer Optional** Maximum number of results to return. Default: 25. Minimum: 1. Maximum: 100. - **`cursor` string Optional** Cursor returned as next_cursor from the previous response. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "yelp-search", "task_name": "Yelp API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/yelp/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"ramen"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/yelp/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "ramen" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/yelp/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "ramen" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/yelp/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"ramen","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/yelp/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "ramen", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/yelp/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "ramen", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/yelp-search/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/yelp/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"ramen","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/yelp/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "ramen", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/yelp/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "ramen", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "yelp-search", "task_name": "Yelp API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-yelp-search [YouTube APIs](/docs/api.md#youtube) # YouTube channel email Reveal the protected public business email from a YouTube channel's about panel using a managed signed-in browser. POST `/v1/youtube/channel/email` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) **Connected website account required** Requires a connected youtube.com account. Browsable automatically uses a saved connection on your team when one is available. If none is available, HTTP `428` includes a `hosted_url`. Complete sign-in there, then retry. [Connect an account →](/docs/api/website-logins.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. Provide at least one of: channel_url; handle; channel_id. - **`url` string Optional** YouTube channel URL or tab URL. Handles like https://www.youtube.com/@MrBeast and channel IDs are normalized to the requested tab. Preferred name; channel_url remains supported. - **`channel_id` string Optional** YouTube channel ID (for example UCX6OQ3DkcsbYNE6H8uQQuVA). - **`handle` string Optional** YouTube channel handle, with or without the leading @. ### Advanced & compatibility inputs 2 - **`captcha_timeout_ms` number Optional** Milliseconds to wait for YouTube's captcha and email reveal flow (0-300000). Defaults to 180000. Default: 180000. Minimum: 0. Maximum: 300000. - **`channel_url` string Optional** YouTube channel URL or tab URL. Handles like https://www.youtube.com/@MrBeast and channel IDs are normalized to the requested tab. You can also use url. ## 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", "channel", "source_url", "status", "email", "requires_sign_in", "captcha_required", "captcha_solved", "access_limited", "view_email_clicked", "sign_in_recovery_attempted" ], "properties": { "email": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "status": { "enum": [ "found", "requires_sign_in", "captcha_required", "access_limited", "not_available" ], "type": "string", "description": "The protected email reveal result. access_limited means YouTube has throttled the managed account and callers should stop retrying it." }, "channel": { "type": "object", "required": [ "url" ], "properties": { "url": { "type": "string" }, "title": { "type": "string" }, "handle": { "type": "string" }, "rss_url": { "type": "string" }, "avatar_url": { "type": "string" }, "channel_id": { "type": "string" }, "shorts_url": { "type": "string" }, "videos_url": { "type": "string" }, "description": { "type": "string" } }, "additionalProperties": true }, "message": { "type": "string" }, "success": { "type": "boolean" }, "email_href": { "type": "string" }, "source_url": { "type": "string" }, "access_limited": { "type": "boolean" }, "captcha_solved": { "type": "boolean" }, "captcha_required": { "type": "boolean" }, "requires_sign_in": { "type": "boolean" }, "view_email_clicked": { "type": "boolean" }, "sign_in_recovery_attempted": { "type": "boolean" } }, "additionalProperties": true } ``` ### View a polled run response ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "youtube-channel-email", "task_name": "YouTube channel email", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "email": "user1@example.com", "status": "found", "channel": { "url": "https://example.com/item-1", "title": "Stylish Shoreditch Loft with Balcony", "handle": "sample", "rss_url": "https://example.com/item-1", "avatar_url": "https://images.example.com/avatar_url-1.jpg", "channel_id": "id-1", "shorts_url": "https://example.com/item-1", "videos_url": "https://example.com/item-1", "description": "Sample description 1" }, "message": "sample", "success": true, "email_href": "https://example.com/item-1", "source_url": "https://example.com/item-1", "access_limited": true, "captcha_solved": true, "captcha_required": true, "requires_sign_in": true, "view_email_clicked": true, "sign_in_recovery_attempted": true }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/youtube/channel/email" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"channel_url":"https://example.com/item-1"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/youtube/channel/email", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "channel_url": "https://example.com/item-1" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/youtube/channel/email", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "channel_url": "https://example.com/item-1" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/youtube/channel/email" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"channel_url":"https://example.com/item-1","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/youtube/channel/email", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "channel_url": "https://example.com/item-1", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/youtube/channel/email", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "channel_url": "https://example.com/item-1", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/youtube-channel-email/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/youtube/channel/email" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"channel_url":"https://example.com/item-1","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/youtube/channel/email", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "channel_url": "https://example.com/item-1", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/youtube/channel/email", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "channel_url": "https://example.com/item-1", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "youtube-channel-email", "task_name": "YouTube channel email", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "email": "user1@example.com", "status": "found", "channel": { "url": "https://example.com/item-1", "title": "Stylish Shoreditch Loft with Balcony", "handle": "sample", "rss_url": "https://example.com/item-1", "avatar_url": "https://images.example.com/avatar_url-1.jpg", "channel_id": "id-1", "shorts_url": "https://example.com/item-1", "videos_url": "https://example.com/item-1", "description": "Sample description 1" }, "message": "sample", "success": true, "email_href": "https://example.com/item-1", "source_url": "https://example.com/item-1", "access_limited": true, "captcha_solved": true, "captcha_required": true, "requires_sign_in": true, "view_email_clicked": true, "sign_in_recovery_attempted": true }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-youtube-channel-email [YouTube APIs](/docs/api.md#youtube) # YouTube channel shorts Fetch shorts from a YouTube channel shorts tab using the public web client sort chips and continuations. POST `/v1/youtube/channel/shorts` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. Provide at least one of: channel_url; handle; channel_id. - **`url` string Optional** YouTube channel URL or tab URL. Handles like https://www.youtube.com/@MrBeast and channel IDs are normalized to the requested tab. Preferred name; channel_url remains supported. - **`channel_id` string Optional** YouTube channel ID (for example UCX6OQ3DkcsbYNE6H8uQQuVA). - **`handle` string Optional** YouTube channel handle, with or without the leading @. - **`pages` integer Optional** Number of pages to fetch (1-20). Default: 1. Minimum: 1. Maximum: 20. - **`sort` string Optional** Shorts ordering: latest, popular, or oldest. Default: "latest". Allowed: "latest", "popular", "oldest". ### Advanced & compatibility inputs 1 - **`channel_url` string Optional** YouTube channel URL or tab URL. Handles like https://www.youtube.com/@MrBeast and channel IDs are normalized to the requested tab. You can also use url. ## 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", "channel", "sort", "pages_requested", "pages_fetched", "count", "shorts", "pagination" ], "properties": { "sort": { "enum": [ "latest", "popular", "oldest" ], "type": "string" }, "count": { "type": "number" }, "shorts": { "type": "array", "items": { "type": "object", "required": [ "id", "page", "link", "thumbnail_urls" ], "properties": { "id": { "type": "string" }, "link": { "type": "string" }, "page": { "type": "number" }, "title": { "type": "string" }, "is_live": { "type": "boolean" }, "duration": { "type": "string" }, "view_count": { "type": "number" }, "description": { "type": "string" }, "thumbnail_url": { "type": "string" }, "published_time": { "type": "string" }, "thumbnail_urls": { "type": "array", "items": { "type": "string" } }, "view_count_text": { "type": "string" } }, "additionalProperties": true } }, "channel": { "type": "object", "required": [ "url", "shorts_url" ], "properties": { "url": { "type": "string" }, "title": { "type": "string" }, "handle": { "type": "string" }, "rss_url": { "type": "string" }, "avatar_url": { "type": "string" }, "channel_id": { "type": "string" }, "shorts_url": { "type": "string" }, "videos_url": { "type": "string" }, "description": { "type": "string" } }, "additionalProperties": true }, "success": { "type": "boolean" }, "pagination": { "type": "object", "required": [ "has_next_page", "next_continuation" ], "properties": { "has_next_page": { "type": "boolean" }, "next_continuation": { "anyOf": [ { "type": "string" }, { "type": "null" } ] } }, "additionalProperties": false }, "pages_fetched": { "type": "number" }, "pages_requested": { "type": "number" } }, "additionalProperties": true } ``` ### View a polled run response ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "youtube-channel-shorts", "task_name": "YouTube channel shorts", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "sort": "latest", "count": 1, "shorts": [ { "id": "id-1", "link": "https://example.com/item-1", "page": 1, "title": "Stylish Shoreditch Loft with Balcony", "is_live": true, "duration": "sample", "view_count": 1, "description": "Sample description 1", "thumbnail_url": "https://images.example.com/thumbnail_url-1.jpg", "published_time": "sample", "thumbnail_urls": [ "https://images.example.com/thumbnail_urls-1.jpg" ], "view_count_text": "Sample view_count_text 1" } ], "channel": { "url": "https://example.com/item-1", "title": "Stylish Shoreditch Loft with Balcony", "handle": "sample", "rss_url": "https://example.com/item-1", "avatar_url": "https://images.example.com/avatar_url-1.jpg", "channel_id": "id-1", "shorts_url": "https://example.com/item-1", "videos_url": "https://example.com/item-1", "description": "Sample description 1" }, "success": true, "pagination": { "has_next_page": true, "next_continuation": "sample" }, "pages_fetched": 1, "pages_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/youtube/channel/shorts" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"channel_url":"https://example.com/item-1"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/youtube/channel/shorts", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "channel_url": "https://example.com/item-1" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/youtube/channel/shorts", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "channel_url": "https://example.com/item-1" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/youtube/channel/shorts" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"channel_url":"https://example.com/item-1","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/youtube/channel/shorts", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "channel_url": "https://example.com/item-1", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/youtube/channel/shorts", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "channel_url": "https://example.com/item-1", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/youtube-channel-shorts/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/youtube/channel/shorts" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"channel_url":"https://example.com/item-1","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/youtube/channel/shorts", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "channel_url": "https://example.com/item-1", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/youtube/channel/shorts", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "channel_url": "https://example.com/item-1", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "youtube-channel-shorts", "task_name": "YouTube channel shorts", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "sort": "latest", "count": 1, "shorts": [ { "id": "id-1", "link": "https://example.com/item-1", "page": 1, "title": "Stylish Shoreditch Loft with Balcony", "is_live": true, "duration": "sample", "view_count": 1, "description": "Sample description 1", "thumbnail_url": "https://images.example.com/thumbnail_url-1.jpg", "published_time": "sample", "thumbnail_urls": [ "https://images.example.com/thumbnail_urls-1.jpg" ], "view_count_text": "Sample view_count_text 1" } ], "channel": { "url": "https://example.com/item-1", "title": "Stylish Shoreditch Loft with Balcony", "handle": "sample", "rss_url": "https://example.com/item-1", "avatar_url": "https://images.example.com/avatar_url-1.jpg", "channel_id": "id-1", "shorts_url": "https://example.com/item-1", "videos_url": "https://example.com/item-1", "description": "Sample description 1" }, "success": true, "pagination": { "has_next_page": true, "next_continuation": "sample" }, "pages_fetched": 1, "pages_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-youtube-channel-shorts [YouTube APIs](/docs/api.md#youtube) # YouTube channel videos Fetch videos from a YouTube channel videos tab using public web continuations. POST `/v1/youtube/channel/videos` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. Provide at least one of: channel_url; handle; channel_id. - **`url` string Optional** YouTube channel URL or tab URL. Handles like https://www.youtube.com/@MrBeast and channel IDs are normalized to the requested tab. Preferred name; channel_url remains supported. - **`channel_id` string Optional** YouTube channel ID (for example UCX6OQ3DkcsbYNE6H8uQQuVA). - **`handle` string Optional** YouTube channel handle, with or without the leading @. - **`pages` integer Optional** Number of pages to fetch. Stops earlier when the channel ends. Default: 1. Minimum: 1. ### Advanced & compatibility inputs 1 - **`channel_url` string Optional** YouTube channel URL or tab URL. Handles like https://www.youtube.com/@MrBeast and channel IDs are normalized to the requested tab. You can also use url. ## 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", "channel", "pages_requested", "pages_fetched", "count", "videos", "pagination" ], "properties": { "count": { "type": "number" }, "videos": { "type": "array", "items": { "type": "object", "required": [ "id", "page", "link", "thumbnail_urls" ], "properties": { "id": { "type": "string" }, "link": { "type": "string" }, "page": { "type": "number" }, "title": { "type": "string" }, "is_live": { "type": "boolean" }, "duration": { "type": "string" }, "view_count": { "type": "number" }, "description": { "type": "string" }, "thumbnail_url": { "type": "string" }, "published_time": { "type": "string" }, "thumbnail_urls": { "type": "array", "items": { "type": "string" } }, "view_count_text": { "type": "string" } }, "additionalProperties": true } }, "channel": { "type": "object", "required": [ "url", "videos_url" ], "properties": { "url": { "type": "string" }, "title": { "type": "string" }, "handle": { "type": "string" }, "rss_url": { "type": "string" }, "avatar_url": { "type": "string" }, "channel_id": { "type": "string" }, "shorts_url": { "type": "string" }, "videos_url": { "type": "string" }, "description": { "type": "string" } }, "additionalProperties": true }, "success": { "type": "boolean" }, "pagination": { "type": "object", "required": [ "has_next_page", "next_continuation" ], "properties": { "has_next_page": { "type": "boolean" }, "next_continuation": { "anyOf": [ { "type": "string" }, { "type": "null" } ] } }, "additionalProperties": false }, "pages_fetched": { "type": "number" }, "pages_requested": { "type": "number" } }, "additionalProperties": true } ``` ### View a polled run response ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "youtube-channel-videos", "task_name": "YouTube channel videos", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "count": 1, "videos": [ { "id": "id-1", "link": "https://example.com/item-1", "page": 1, "title": "Stylish Shoreditch Loft with Balcony", "is_live": true, "duration": "sample", "view_count": 1, "description": "Sample description 1", "thumbnail_url": "https://images.example.com/thumbnail_url-1.jpg", "published_time": "sample", "thumbnail_urls": [ "https://images.example.com/thumbnail_urls-1.jpg" ], "view_count_text": "Sample view_count_text 1" } ], "channel": { "url": "https://example.com/item-1", "title": "Stylish Shoreditch Loft with Balcony", "handle": "sample", "rss_url": "https://example.com/item-1", "avatar_url": "https://images.example.com/avatar_url-1.jpg", "channel_id": "id-1", "shorts_url": "https://example.com/item-1", "videos_url": "https://example.com/item-1", "description": "Sample description 1" }, "success": true, "pagination": { "has_next_page": true, "next_continuation": "sample" }, "pages_fetched": 1, "pages_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/youtube/channel/videos" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"channel_url":"https://example.com/item-1"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/youtube/channel/videos", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "channel_url": "https://example.com/item-1" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/youtube/channel/videos", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "channel_url": "https://example.com/item-1" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/youtube/channel/videos" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"channel_url":"https://example.com/item-1","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/youtube/channel/videos", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "channel_url": "https://example.com/item-1", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/youtube/channel/videos", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "channel_url": "https://example.com/item-1", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/youtube-channel-videos/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/youtube/channel/videos" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"channel_url":"https://example.com/item-1","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/youtube/channel/videos", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "channel_url": "https://example.com/item-1", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/youtube/channel/videos", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "channel_url": "https://example.com/item-1", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "youtube-channel-videos", "task_name": "YouTube channel videos", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "count": 1, "videos": [ { "id": "id-1", "link": "https://example.com/item-1", "page": 1, "title": "Stylish Shoreditch Loft with Balcony", "is_live": true, "duration": "sample", "view_count": 1, "description": "Sample description 1", "thumbnail_url": "https://images.example.com/thumbnail_url-1.jpg", "published_time": "sample", "thumbnail_urls": [ "https://images.example.com/thumbnail_urls-1.jpg" ], "view_count_text": "Sample view_count_text 1" } ], "channel": { "url": "https://example.com/item-1", "title": "Stylish Shoreditch Loft with Balcony", "handle": "sample", "rss_url": "https://example.com/item-1", "avatar_url": "https://images.example.com/avatar_url-1.jpg", "channel_id": "id-1", "shorts_url": "https://example.com/item-1", "videos_url": "https://example.com/item-1", "description": "Sample description 1" }, "success": true, "pagination": { "has_next_page": true, "next_continuation": "sample" }, "pages_fetched": 1, "pages_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-youtube-channel-videos [YouTube APIs](/docs/api.md#youtube) # YouTube Livestreams API Scrape public YouTube live video search results. POST `/v1/youtube/livestreams` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`query` string Required** Search query. Minimum length: 1. Maximum length: 2000. - **`limit` integer Optional** Maximum number of results to return. Default: 25. Minimum: 1. Maximum: 100. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "youtube-livestreams", "task_name": "YouTube Livestreams API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/youtube/livestreams" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"space launch live"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/youtube/livestreams", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "space launch live" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/youtube/livestreams", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "space launch live" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/youtube/livestreams" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"space launch live","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/youtube/livestreams", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "space launch live", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/youtube/livestreams", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "space launch live", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/youtube-livestreams/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/youtube/livestreams" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"space launch live","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/youtube/livestreams", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "space launch live", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/youtube/livestreams", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "space launch live", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "youtube-livestreams", "task_name": "YouTube Livestreams API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-youtube-livestreams [YouTube APIs](/docs/api.md#youtube) # YouTube search Search YouTube and return normalized mixed results from the default results page. POST `/v1/youtube/search` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`query` string Required** Search query string. Minimum length: 1. Maximum length: 2000. - **`pages` integer Optional** Number of search result pages to fetch (1-20). Default: 1. Minimum: 1. Maximum: 20. ## 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", "query", "pages_requested", "pages_fetched", "count", "results", "pagination" ], "properties": { "count": { "type": "number" }, "query": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "required": [ "type", "id", "link" ], "properties": { "id": { "type": "string" }, "link": { "type": "string" }, "type": { "enum": [ "video", "channel", "playlist" ], "type": "string" }, "title": { "type": "string" } }, "additionalProperties": true } }, "success": { "type": "boolean" }, "pagination": { "type": "object", "required": [ "has_next_page", "next_continuation" ], "properties": { "has_next_page": { "type": "boolean" }, "next_continuation": { "anyOf": [ { "type": "string" }, { "type": "null" } ] } }, "additionalProperties": false }, "pages_fetched": { "type": "number" }, "pages_requested": { "type": "number" } }, "additionalProperties": true } ``` ### View a polled run response ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "youtube-search", "task_name": "YouTube search", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "count": 1, "query": "London", "results": [ { "id": "id-1", "link": "https://example.com/item-1", "type": "video", "title": "Stylish Shoreditch Loft with Balcony" } ], "success": true, "pagination": { "has_next_page": true, "next_continuation": "sample" }, "pages_fetched": 1, "pages_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/youtube/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/youtube/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "London" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/youtube/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "London" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/youtube/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"London","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/youtube/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "London", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/youtube/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "London", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/youtube-search/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/youtube/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"London","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/youtube/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "London", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/youtube/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "London", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "youtube-search", "task_name": "YouTube search", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "count": 1, "query": "London", "results": [ { "id": "id-1", "link": "https://example.com/item-1", "type": "video", "title": "Stylish Shoreditch Loft with Balcony" } ], "success": true, "pagination": { "has_next_page": true, "next_continuation": "sample" }, "pages_fetched": 1, "pages_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-youtube-search [YouTube APIs](/docs/api.md#youtube) # YouTube to MP3 Convert a public YouTube video to a downloadable MP3 file. POST `/v1/youtube/to-mp3` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. Provide at least one of: url; video_url. - **`url` string Optional** Regular YouTube video URL, youtu.be URL, shorts URL, or video ID for the video to convert. Preferred name; video_url remains supported. - **`bitrate` string Optional** Target MP3 audio bitrate. Default: "192k". Allowed: "128k", "192k", "256k", "320k". - **`include_metadata` boolean Optional** Whether to preserve basic video metadata in the conversion workflow. Default: true. ### Advanced & compatibility inputs 1 - **`video_url` string Optional** Regular YouTube video URL, youtu.be URL, shorts URL, or video ID for the video to convert. You can also use url. ## 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 { "$schema": "https://json-schema.org/draft/2020-12/schema", "description": "Poll the run until it succeeds for a signed MP3 download URL, expiry and conversion statistics.", "anyOf": [ { "type": "object", "properties": { "success": { "type": "boolean", "const": true }, "export_id": { "type": "string", "description": "Export identifier. Poll the run until it succeeds before downloading." }, "status": { "type": "string", "enum": [ "completed", "pending" ] }, "file_name": { "type": "string" }, "download_url": { "type": "string", "description": "Short-lived signed download URL. It can be a pending:// placeholder before the artifact is ready." }, "download_url_expires_at": { "type": [ "string", "null" ] }, "expires_at": { "type": [ "string", "null" ] }, "video": { "type": "object", "properties": { "id": { "type": "string" }, "url": { "type": "string" }, "title": { "type": [ "string", "null" ] }, "thumbnail_url": { "type": [ "string", "null" ] }, "duration_seconds": { "type": [ "number", "null" ] } }, "required": [ "id", "url", "title", "duration_seconds" ], "additionalProperties": false }, "result_summary": { "type": "object", "properties": { "format": { "const": "mp3", "type": "string" }, "bitrate": { "type": "string", "enum": [ "128k", "192k", "256k", "320k" ] }, "sizeBytes": { "type": "number" }, "sourceBytes": { "type": "number" }, "durationSeconds": { "type": [ "number", "null" ] }, "title": { "type": [ "string", "null" ] }, "ytDlpVersion": { "type": [ "string", "null" ] } }, "required": [ "format", "bitrate", "sizeBytes", "sourceBytes", "durationSeconds", "title", "ytDlpVersion" ], "additionalProperties": false } }, "required": [ "success", "export_id", "status", "file_name", "download_url", "download_url_expires_at", "expires_at", "video", "result_summary" ], "additionalProperties": false }, { "type": "object", "properties": { "export_id": { "type": "string" } }, "required": [ "export_id" ], "additionalProperties": false } ] } ``` ### View a polled run response ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "youtube-to-mp3", "task_name": "YouTube to MP3", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "success": true, "export_id": "id-1", "status": "completed", "file_name": "Stylish Shoreditch Loft with Balcony", "download_url": "https://example.com/item-1", "download_url_expires_at": "https://example.com/item-1", "expires_at": "sample", "video": { "id": "id-1", "url": "https://example.com/item-1", "title": "Stylish Shoreditch Loft with Balcony", "thumbnail_url": "https://images.example.com/thumbnail_url-1.jpg", "duration_seconds": 1.5 }, "result_summary": { "format": "mp3", "bitrate": "128k", "sizeBytes": 1.5, "sourceBytes": 1.5, "durationSeconds": 1.5, "title": "Stylish Shoreditch Loft with Balcony", "ytDlpVersion": "sample" } }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/youtube/to-mp3" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.youtube.com/watch?v=dQw4w9WgXcQ"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/youtube/to-mp3", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/youtube/to-mp3", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/youtube/to-mp3" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.youtube.com/watch?v=dQw4w9WgXcQ","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/youtube/to-mp3", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/youtube/to-mp3", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/youtube-to-mp3/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/youtube/to-mp3" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.youtube.com/watch?v=dQw4w9WgXcQ","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/youtube/to-mp3", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/youtube/to-mp3", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "youtube-to-mp3", "task_name": "YouTube to MP3", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "success": true, "export_id": "id-1", "status": "completed", "file_name": "Stylish Shoreditch Loft with Balcony", "download_url": "https://example.com/item-1", "download_url_expires_at": "https://example.com/item-1", "expires_at": "sample", "video": { "id": "id-1", "url": "https://example.com/item-1", "title": "Stylish Shoreditch Loft with Balcony", "thumbnail_url": "https://images.example.com/thumbnail_url-1.jpg", "duration_seconds": 1.5 }, "result_summary": { "format": "mp3", "bitrate": "128k", "sizeBytes": 1.5, "sourceBytes": 1.5, "durationSeconds": 1.5, "title": "Stylish Shoreditch Loft with Balcony", "ytDlpVersion": "sample" } }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-youtube-to-mp3 [YouTube APIs](/docs/api.md#youtube) # YouTube Transcript API Fetch public YouTube caption transcript segments for a video. POST `/v1/youtube/transcript` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. Provide at least one of: url; video_id. - **`url` string Optional** YouTube video URL. Minimum length: 1. Maximum length: 2000. - **`video_id` string Optional** YouTube video id. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "youtube-transcript", "task_name": "YouTube Transcript API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/youtube/transcript" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.youtube.com/watch?v=dQw4w9WgXcQ"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/youtube/transcript", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/youtube/transcript", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/youtube/transcript" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.youtube.com/watch?v=dQw4w9WgXcQ","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/youtube/transcript", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/youtube/transcript", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/youtube-transcript/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/youtube/transcript" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.youtube.com/watch?v=dQw4w9WgXcQ","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/youtube/transcript", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/youtube/transcript", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "youtube-transcript", "task_name": "YouTube Transcript API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-youtube-transcript [YouTube APIs](/docs/api.md#youtube) # YouTube video comments Fetch top-level comments for a YouTube video using the public watch page and comments continuations. POST `/v1/youtube/video/comments` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. Provide at least one of: video_url; video_id. - **`url` string Optional** YouTube video URL, short URL, or shorts URL. Preferred name; video_url remains supported. - **`pages` integer Optional** Number of comment pages to fetch (1-20). Default: 1. Minimum: 1. Maximum: 20. - **`video_id` string Optional** YouTube video ID. ### Advanced & compatibility inputs 1 - **`video_url` string Optional** YouTube video URL, short URL, or shorts URL. You can also use url. ## 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", "pages_requested", "pages_fetched", "count", "comments", "pagination" ], "properties": { "count": { "type": "number" }, "success": { "type": "boolean" }, "comments": { "type": "array", "items": { "type": "object", "required": [ "id", "page" ], "properties": { "id": { "type": "string" }, "page": { "type": "number" }, "text": { "type": "string" }, "is_pinned": { "type": "boolean" }, "author_url": { "type": "string" }, "is_hearted": { "type": "boolean" }, "like_count": { "type": "number" }, "author_name": { "type": "string" }, "reply_count": { "type": "number" }, "published_time": { "type": "string" }, "like_count_text": { "type": "string" }, "author_thumbnail_url": { "type": "string" } }, "additionalProperties": true } }, "pagination": { "type": "object", "required": [ "has_next_page", "next_continuation" ], "properties": { "has_next_page": { "type": "boolean" }, "next_continuation": { "anyOf": [ { "type": "string" }, { "type": "null" } ] } }, "additionalProperties": false }, "pages_fetched": { "type": "number" }, "pages_requested": { "type": "number" } }, "additionalProperties": true } ``` ### View a polled run response ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "youtube-video-comments", "task_name": "YouTube video comments", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "count": 1, "success": true, "comments": [ { "id": "id-1", "page": 1, "text": "Sample text 1", "is_pinned": true, "author_url": "https://example.com/item-1", "is_hearted": true, "like_count": 1, "author_name": "Stylish Shoreditch Loft with Balcony", "reply_count": 1, "published_time": "sample", "like_count_text": "Sample like_count_text 1", "author_thumbnail_url": "https://images.example.com/author_thumbnail_url-1.jpg" } ], "pagination": { "has_next_page": true, "next_continuation": "sample" }, "pages_fetched": 1, "pages_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/youtube/video/comments" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"video_url":"https://example.com/item-1"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/youtube/video/comments", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "video_url": "https://example.com/item-1" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/youtube/video/comments", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "video_url": "https://example.com/item-1" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/youtube/video/comments" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"video_url":"https://example.com/item-1","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/youtube/video/comments", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "video_url": "https://example.com/item-1", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/youtube/video/comments", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "video_url": "https://example.com/item-1", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/youtube-video-comments/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/youtube/video/comments" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"video_url":"https://example.com/item-1","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/youtube/video/comments", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "video_url": "https://example.com/item-1", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/youtube/video/comments", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "video_url": "https://example.com/item-1", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "youtube-video-comments", "task_name": "YouTube video comments", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "count": 1, "success": true, "comments": [ { "id": "id-1", "page": 1, "text": "Sample text 1", "is_pinned": true, "author_url": "https://example.com/item-1", "is_hearted": true, "like_count": 1, "author_name": "Stylish Shoreditch Loft with Balcony", "reply_count": 1, "published_time": "sample", "like_count_text": "Sample like_count_text 1", "author_thumbnail_url": "https://images.example.com/author_thumbnail_url-1.jpg" } ], "pagination": { "has_next_page": true, "next_continuation": "sample" }, "pages_fetched": 1, "pages_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-youtube-video-comments [YouTube APIs](/docs/api.md#youtube) # YouTube video Fetch a YouTube video page with normalized metadata and top-level comments. POST `/v1/youtube/video` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. Provide at least one of: video_url; video_id. - **`url` string Optional** YouTube video URL, short URL, or shorts URL. Preferred name; video_url remains supported. - **`pages` integer Optional** Number of comment pages to fetch (1-20). Default: 1. Minimum: 1. Maximum: 20. - **`video_id` string Optional** YouTube video ID. ### Advanced & compatibility inputs 1 - **`video_url` string Optional** YouTube video URL, short URL, or shorts URL. You can also use url. ## 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", "video", "pages_requested", "pages_fetched", "count", "comments", "pagination" ], "properties": { "count": { "type": "number" }, "video": { "type": "object", "required": [ "id", "url", "thumbnail_urls" ], "properties": { "id": { "type": "string" }, "url": { "type": "string" }, "title": { "type": "string" }, "channel": { "type": "object", "additionalProperties": true }, "duration": { "type": "string" }, "view_count": { "type": "number" }, "description": { "type": "string" }, "thumbnail_url": { "type": "string" }, "published_time": { "type": "string" }, "thumbnail_urls": { "type": "array", "items": { "type": "string" } }, "view_count_text": { "type": "string" } }, "additionalProperties": true }, "success": { "type": "boolean" }, "comments": { "type": "array", "items": { "type": "object", "required": [ "id", "page" ], "properties": { "id": { "type": "string" }, "page": { "type": "number" }, "text": { "type": "string" }, "is_pinned": { "type": "boolean" }, "author_url": { "type": "string" }, "is_hearted": { "type": "boolean" }, "like_count": { "type": "number" }, "author_name": { "type": "string" }, "reply_count": { "type": "number" }, "published_time": { "type": "string" }, "like_count_text": { "type": "string" }, "author_thumbnail_url": { "type": "string" } }, "additionalProperties": true } }, "pagination": { "type": "object", "required": [ "has_next_page", "next_continuation" ], "properties": { "has_next_page": { "type": "boolean" }, "next_continuation": { "anyOf": [ { "type": "string" }, { "type": "null" } ] } }, "additionalProperties": false }, "pages_fetched": { "type": "number" }, "pages_requested": { "type": "number" } }, "additionalProperties": true } ``` ### View a polled run response ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "youtube-video", "task_name": "YouTube video", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "count": 1, "video": { "id": "id-1", "url": "https://example.com/item-1", "title": "Stylish Shoreditch Loft with Balcony", "channel": {}, "duration": "sample", "view_count": 1, "description": "Sample description 1", "thumbnail_url": "https://images.example.com/thumbnail_url-1.jpg", "published_time": "sample", "thumbnail_urls": [ "https://images.example.com/thumbnail_urls-1.jpg" ], "view_count_text": "Sample view_count_text 1" }, "success": true, "comments": [ { "id": "id-1", "page": 1, "text": "Sample text 1", "is_pinned": true, "author_url": "https://example.com/item-1", "is_hearted": true, "like_count": 1, "author_name": "Stylish Shoreditch Loft with Balcony", "reply_count": 1, "published_time": "sample", "like_count_text": "Sample like_count_text 1", "author_thumbnail_url": "https://images.example.com/author_thumbnail_url-1.jpg" } ], "pagination": { "has_next_page": true, "next_continuation": "sample" }, "pages_fetched": 1, "pages_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/youtube/video" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"video_url":"https://example.com/item-1"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/youtube/video", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "video_url": "https://example.com/item-1" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/youtube/video", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "video_url": "https://example.com/item-1" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/youtube/video" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"video_url":"https://example.com/item-1","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/youtube/video", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "video_url": "https://example.com/item-1", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/youtube/video", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "video_url": "https://example.com/item-1", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/youtube-video/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/youtube/video" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"video_url":"https://example.com/item-1","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/youtube/video", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "video_url": "https://example.com/item-1", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/youtube/video", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "video_url": "https://example.com/item-1", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "youtube-video", "task_name": "YouTube video", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "count": 1, "video": { "id": "id-1", "url": "https://example.com/item-1", "title": "Stylish Shoreditch Loft with Balcony", "channel": {}, "duration": "sample", "view_count": 1, "description": "Sample description 1", "thumbnail_url": "https://images.example.com/thumbnail_url-1.jpg", "published_time": "sample", "thumbnail_urls": [ "https://images.example.com/thumbnail_urls-1.jpg" ], "view_count_text": "Sample view_count_text 1" }, "success": true, "comments": [ { "id": "id-1", "page": 1, "text": "Sample text 1", "is_pinned": true, "author_url": "https://example.com/item-1", "is_hearted": true, "like_count": 1, "author_name": "Stylish Shoreditch Loft with Balcony", "reply_count": 1, "published_time": "sample", "like_count_text": "Sample like_count_text 1", "author_thumbnail_url": "https://images.example.com/author_thumbnail_url-1.jpg" } ], "pagination": { "has_next_page": true, "next_continuation": "sample" }, "pages_fetched": 1, "pages_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-youtube-video [Zillow APIs](/docs/api.md#zillow) # Zillow Property API Scrape a public Zillow property detail page from a search result URL. POST `/v1/zillow/property` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`url` string Required** Zillow property URL returned by zillow/search. Minimum length: 1. Maximum length: 2000. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "zillow-property", "task_name": "Zillow Property API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/zillow/property" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.zillow.com/homedetails/123-Main-St-Seattle-WA-98101/12345_zpid/"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/zillow/property", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.zillow.com/homedetails/123-Main-St-Seattle-WA-98101/12345_zpid/" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/zillow/property", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.zillow.com/homedetails/123-Main-St-Seattle-WA-98101/12345_zpid/" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/zillow/property" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.zillow.com/homedetails/123-Main-St-Seattle-WA-98101/12345_zpid/","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/zillow/property", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.zillow.com/homedetails/123-Main-St-Seattle-WA-98101/12345_zpid/", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/zillow/property", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.zillow.com/homedetails/123-Main-St-Seattle-WA-98101/12345_zpid/", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/zillow-property/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/zillow/property" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.zillow.com/homedetails/123-Main-St-Seattle-WA-98101/12345_zpid/","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/zillow/property", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.zillow.com/homedetails/123-Main-St-Seattle-WA-98101/12345_zpid/", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/zillow/property", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.zillow.com/homedetails/123-Main-St-Seattle-WA-98101/12345_zpid/", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "zillow-property", "task_name": "Zillow Property API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-zillow-property [Zillow APIs](/docs/api.md#zillow) # Zillow API Scrape public Zillow search pages by location query. POST `/v1/zillow/search` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`query` string Required** City, neighborhood, ZIP code, or address. Minimum length: 1. Maximum length: 2000. - **`limit` integer Optional** Maximum number of results to return. Default: 25. Minimum: 1. Maximum: 100. - **`cursor` string Optional** Cursor returned as next_cursor from the previous response. - **`page` integer Optional** Page number for sources that support page-based pagination. Default: 1. Minimum: 1. Maximum: 10000. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "zillow-search", "task_name": "Zillow API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/zillow/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"Seattle, WA"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/zillow/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "Seattle, WA" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/zillow/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "Seattle, WA" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/zillow/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"Seattle, WA","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/zillow/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "Seattle, WA", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/zillow/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "Seattle, WA", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/zillow-search/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/zillow/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"Seattle, WA","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/zillow/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "Seattle, WA", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/zillow/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "Seattle, WA", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "zillow-search", "task_name": "Zillow API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-zillow-search [Zoopla APIs](/docs/api.md#zoopla) # Zoopla Property API Scrape a public Zoopla property page. POST `/v1/zoopla/property` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`url` string Required** URL returned by the matching search endpoint. Minimum length: 1. Maximum length: 2000. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "zoopla-property", "task_name": "Zoopla Property API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/zoopla/property" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.zoopla.co.uk/for-sale/details/12345678/"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/zoopla/property", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.zoopla.co.uk/for-sale/details/12345678/" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/zoopla/property", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.zoopla.co.uk/for-sale/details/12345678/" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/zoopla/property" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.zoopla.co.uk/for-sale/details/12345678/","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/zoopla/property", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.zoopla.co.uk/for-sale/details/12345678/", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/zoopla/property", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.zoopla.co.uk/for-sale/details/12345678/", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/zoopla-property/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/zoopla/property" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://www.zoopla.co.uk/for-sale/details/12345678/","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/zoopla/property", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://www.zoopla.co.uk/for-sale/details/12345678/", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/zoopla/property", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://www.zoopla.co.uk/for-sale/details/12345678/", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "zoopla-property", "task_name": "Zoopla Property API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-zoopla-property [Zoopla APIs](/docs/api.md#zoopla) # Zoopla API Scrape public Zoopla property search results. POST `/v1/zoopla/search` [Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) **Authenticate every request** Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) ## Parameters Send these fields in a flat JSON body. Add `_run` to choose execution options. - **`query` string Required** Search query. Minimum length: 1. Maximum length: 2000. - **`limit` integer Optional** Maximum number of results to return. Default: 25. Minimum: 1. Maximum: 100. - **`cursor` string Optional** Cursor returned as next_cursor from the previous response. - **`page` integer Optional** Page number for sources that support page-based pagination. Default: 1. Minimum: 1. Maximum: 10000. ## 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": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "data": { "anyOf": [ { "type": "object", "additionalProperties": true }, { "type": "null" } ] }, "count": { "type": "integer" }, "query": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "source": { "type": "string" }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "success": { "const": true }, "pagination": { "type": "object", "required": [ "cursor", "next_cursor", "has_next_page", "count", "strategy" ], "properties": { "count": { "type": "integer" }, "cursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "strategy": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "next_cursor": { "anyOf": [ { "type": "string" }, { "type": "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": "zoopla-search", "task_name": "Zoopla API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` ## Errors & retries - `400` Fix the fields listed in `errors` before retrying. - `428` Connect the requested website account using the returned sign-in link. - `429` Wait for the duration in `Retry-After`. - `5xx` Retry 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 →](/docs/api/request-guide.md) ## More examples ### Async request with polling ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/zoopla/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"Bristol"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/zoopla/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "Bristol" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/zoopla/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "Bristol" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ### Wait-for-results request ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/zoopla/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"Bristol","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/zoopla/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "Bristol", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/zoopla/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "Bristol", "_run": { "async": False } }, ) result = response.json() print(result) ``` ### Canonical & compatibility routes You can also send the same JSON body to `/v1/tasks/zoopla-search/runs`. Example request Request mode Wait for resultsAsync + polling ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/zoopla/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"Bristol","_run":{"async":false}}' ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/zoopla/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "Bristol", "_run": { "async": false } }), }); const result = await response.json(); console.log(result); ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/zoopla/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "Bristol", "_run": { "async": False } }, ) result = response.json() print(result) ``` Requests can return before a run finishes. Check run_status and poll status_url when needed. ### View example response Example response Illustrative ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "zoopla-search", "task_name": "Zoopla API", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "url": "https://example.com/item-1", "data": {}, "count": 1, "query": "London", "source": "sample", "results": [ {} ], "success": true, "pagination": { "count": 1, "cursor": "cursor-page-1", "strategy": "sample", "next_cursor": "cursor-page-1", "has_next_page": true }, "max_results_requested": 1 }, "error": null } ``` [Understand the response →](#response) --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-zoopla-search API reference # Find the data you need. Choose a website or search for a job. Every API has its inputs, copyable code, and response format in one place. Filter APIsWebsiteAll websitesAirbnbAlibabaAliExpressAmazonBandcampBBC NewsBlueskyBooking.comCapterraCostcoCraigslistCrunchbaseDepopDiscogseBayEtsyFacebookFantasy Premier LeagueG2GlassdoorGoodreadsGoogle MapsGumtreeHacker NewsHome DepotHotels.comIMDbIndeedInstagramKayakKiwiLetterboxdLinkedInMastodonMediumMercariOfferUpOLXOnlyFansPatreonPinterestProduct HuntQuoraRealtorRedditRedfinRightmoveSkyscannerSoundCloudSpotifyStack OverflowSteamSubstackThreadsTikTokTripadvisorTrustpilotTwitchVimeoVintedWalmartWellfoundWikipediaXYelpYouTubeZillowZoopla 192 APIs across 68 websites No APIs match your search. Try a website name, a shorter query, or reset the website filter. ## Airbnb 6 APIs [POST **Airbnb calendar** Read public calendar availability and exposed stay restrictions. Unavailable does not mean booked; prices are displayed calendar prices, not stay quotes. `/v1/airbnb/calendar`](/docs/api/endpoints/post-airbnb-calendar.md) [POST **Airbnb host** Read a public Airbnb host profile. Only publicly exposed attributes are returned; unknown fields remain null. `/v1/airbnb/host`](/docs/api/endpoints/post-airbnb-host.md) [POST **Airbnb host listings** Read publicly exposed stays on an Airbnb host profile, with explicit pagination and completeness. Does not infer hidden listings. `/v1/airbnb/host/listings`](/docs/api/endpoints/post-airbnb-host-listings.md) [POST **Airbnb reviews** Read paginated public listing reviews, rating summary and host responses. Missing upstream review data fails explicitly. `/v1/airbnb/reviews`](/docs/api/endpoints/post-airbnb-reviews.md) [POST **Airbnb room** Fetch an Airbnb room/listing page and return normalized details, photos, host info, amenities, reviews, policies, and availability. `/v1/airbnb/room`](/docs/api/endpoints/post-airbnb-room.md) [POST **Airbnb search** Search Airbnb stay results for a destination/date combination and return normalized listings with cursor pagination. `/v1/airbnb/search`](/docs/api/endpoints/post-airbnb-search.md) ## Alibaba 2 APIs [POST **Alibaba Product API** Scrape a public Alibaba product detail page from a search result URL. `/v1/alibaba/product`](/docs/api/endpoints/post-alibaba-product.md) [POST **Alibaba API** Scrape public Alibaba showroom product pages by query. `/v1/alibaba/search`](/docs/api/endpoints/post-alibaba-search.md) ## AliExpress 2 APIs [POST **AliExpress Item API** Scrape a public AliExpress item detail page from a search result URL or item id. `/v1/aliexpress/item`](/docs/api/endpoints/post-aliexpress-item.md) [POST **AliExpress API** Scrape public AliExpress search result pages by query with page pagination. `/v1/aliexpress/search`](/docs/api/endpoints/post-aliexpress-search.md) ## Amazon 12 APIs [POST **Amazon ASIN Lookup API** Fetch product details, specifications, images, price and availability by ASIN or URL. No Amazon sign-in required. Prices and availability reflect the marketplace and delivery location; unavailable fields are null. `/v1/amazon/asin`](/docs/api/endpoints/post-amazon-asin.md) [POST **Amazon Best Sellers API** Fetch Amazon Best Sellers by category with continuation cursors. Empty lists are returned when Amazon explicitly reports no entries. No Amazon sign-in required. Prices and availability reflect the marketplace and delivery location; unavailable fields are null. `/v1/amazon/best-sellers`](/docs/api/endpoints/post-amazon-best-sellers.md) [POST **Amazon Deals API** Fetch public deals, or search for products with active deal badges. Query pages can be empty after filtering; continue while next_cursor is present. No Amazon sign-in required. Prices and availability reflect the marketplace and delivery location; unavailable fields are null. `/v1/amazon/deals`](/docs/api/endpoints/post-amazon-deals.md) [POST **Amazon Movers and Shakers API** Fetch Amazon Movers and Shakers by category with continuation cursors. Empty lists are returned when Amazon explicitly reports no entries. No Amazon sign-in required. Prices and availability reflect the marketplace and delivery location; unavailable fields are null. `/v1/amazon/movers-and-shakers`](/docs/api/endpoints/post-amazon-movers-and-shakers.md) [POST **Amazon New Releases API** Fetch Amazon New Releases by category with continuation cursors. Empty lists are returned when Amazon explicitly reports no entries. No Amazon sign-in required. Prices and availability reflect the marketplace and delivery location; unavailable fields are null. `/v1/amazon/new-releases`](/docs/api/endpoints/post-amazon-new-releases.md) [POST **Amazon Product Price API** Fetch the current product price and availability by ASIN or URL. No Amazon sign-in required. Prices and availability reflect the marketplace and delivery location; unavailable fields are null. `/v1/amazon/price`](/docs/api/endpoints/post-amazon-price.md) [POST **Amazon Product Offers API** Compare public seller offers, item condition, shipping and Featured Offer status for a product. Total prices are null when shipping cannot be determined. No Amazon sign-in required. Prices and availability reflect the marketplace and delivery location; unavailable fields are null. `/v1/amazon/product/offers`](/docs/api/endpoints/post-amazon-product-offers.md) [POST Website login **Amazon Reviews** `/v1/amazon/product/reviews`](/docs/api/endpoints/post-amazon-product-reviews.md) [POST **Amazon Product Variations API** List related child ASINs and their size, colour and style attributes. Set include_details to fetch each variant's current price and availability (maximum 10 per request). Without it, only the selected variant has product details. Costs 10 credits. No Amazon sign-in required. Prices and availability reflect the marketplace and delivery location; unavailable fields are null. `/v1/amazon/product/variations`](/docs/api/endpoints/post-amazon-product-variations.md) [POST **Amazon Products Batch API** Fetch up to 10 products by ASIN. Duplicate ASINs are fetched once. Partial batches include per-product errors; all-failed batches fail. Costs 10 credits. No Amazon sign-in required. Prices and availability reflect the marketplace and delivery location; unavailable fields are null. `/v1/amazon/products/batch`](/docs/api/endpoints/post-amazon-products-batch.md) [POST **Amazon Search API** Search Amazon products with price, rating, brand and category filters, sorting, and continuation cursors. No Amazon sign-in required. Prices and availability reflect the marketplace and delivery location; unavailable fields are null. `/v1/amazon/search`](/docs/api/endpoints/post-amazon-search.md) [POST **Amazon Seller Products API** Browse a public seller's product catalogue by merchant ID, with optional search, filters, sorting and continuation cursors. No Amazon sign-in required. Prices and availability reflect the marketplace and delivery location; unavailable fields are null. `/v1/amazon/seller/products`](/docs/api/endpoints/post-amazon-seller-products.md) ## Bandcamp 2 APIs [POST **Bandcamp Page API** Scrape a public Bandcamp artist, album, or track page. `/v1/bandcamp/page`](/docs/api/endpoints/post-bandcamp-page.md) [POST **Bandcamp API** Scrape public Bandcamp search results. `/v1/bandcamp/search`](/docs/api/endpoints/post-bandcamp-search.md) ## BBC News 2 APIs [POST **BBC News Article API** Scrape a public BBC article page. `/v1/bbc-news/article`](/docs/api/endpoints/post-bbc-news-article.md) [POST **BBC News API** Scrape public BBC search results. `/v1/bbc-news/search`](/docs/api/endpoints/post-bbc-news-search.md) ## Bluesky 2 APIs [POST **Bluesky Profile API** Fetch a public Bluesky profile by handle, DID, or profile URL. `/v1/bluesky/profile`](/docs/api/endpoints/post-bluesky-profile.md) [POST **Bluesky API** Search public Bluesky profiles through the public AppView API. `/v1/bluesky/search`](/docs/api/endpoints/post-bluesky-search.md) ## Booking.com 2 APIs [POST **Booking.com Hotel API** Scrape hotel details and dated room offers with occupancy, cancellation, meals, payment and tax text. Supply checkin, checkout, group_adults, group_children, no_rooms and selected_currency in the URL. Displayed prices may exclude taxes. Returns public discovery metadata; undated prices are not stay-specific quotes. This endpoint does not accept stay dates or occupancy; check a dated search on the source website for stay-specific prices. `/v1/booking/hotel`](/docs/api/endpoints/post-booking-hotel.md) [POST **Booking.com API** Scrape public Booking.com accommodation search results by destination. Returns public discovery metadata; undated prices are not stay-specific quotes. This endpoint does not accept stay dates or occupancy; check a dated search on the source website for stay-specific prices. `/v1/booking/search`](/docs/api/endpoints/post-booking-search.md) ## Capterra 2 APIs [POST **Capterra Product API** Scrape a public Capterra product page. `/v1/capterra/product`](/docs/api/endpoints/post-capterra-product.md) [POST **Capterra API** Scrape public Capterra software search results. `/v1/capterra/search`](/docs/api/endpoints/post-capterra-search.md) ## Costco 2 APIs [POST **Costco Product API** Scrape a public Costco product detail page from a search result URL. `/v1/costco/product`](/docs/api/endpoints/post-costco-product.md) [POST **Costco API** Scrape public Costco search result pages by query. `/v1/costco/search`](/docs/api/endpoints/post-costco-search.md) ## Craigslist 2 APIs [POST **Craigslist Post API** Scrape a public Craigslist result detail page from a search result URL or post id. `/v1/craigslist/post`](/docs/api/endpoints/post-craigslist-post.md) [POST **Craigslist API** Scrape public Craigslist search results by query and site with offset pagination. `/v1/craigslist/search`](/docs/api/endpoints/post-craigslist-search.md) ## Crunchbase 2 APIs [POST **Crunchbase Organization API** Scrape a public Crunchbase organization profile. `/v1/crunchbase/organization`](/docs/api/endpoints/post-crunchbase-organization.md) [POST **Crunchbase API** Scrape public Crunchbase organization search results. `/v1/crunchbase/search`](/docs/api/endpoints/post-crunchbase-search.md) ## Depop 2 APIs [POST **Depop Listing API** Scrape a public Depop product page. `/v1/depop/listing`](/docs/api/endpoints/post-depop-listing.md) [POST **Depop API** Scrape public Depop listing search results. `/v1/depop/search`](/docs/api/endpoints/post-depop-search.md) ## Discogs 2 APIs [POST **Discogs Release API** Scrape a public Discogs release, master, or artist page. `/v1/discogs/release`](/docs/api/endpoints/post-discogs-release.md) [POST **Discogs API** Scrape public Discogs marketplace and catalog search results. `/v1/discogs/search`](/docs/api/endpoints/post-discogs-search.md) ## eBay 5 APIs [POST **eBay Item API** Read the exact public ebay.com listing by item URL or id, including displayed price, condition, images and seller feedback. Listing sold counters are not a transaction history. eBay may restrict anonymous access. `/v1/ebay/item`](/docs/api/endpoints/post-ebay-item.md) [POST **eBay Search API** Search public active ebay.com listings, including displayed prices and seller feedback when available. Does not search sold/completed listings. eBay may restrict anonymous access. `/v1/ebay/search`](/docs/api/endpoints/post-ebay-search.md) [POST **eBay Seller API** Read an ebay.com seller's public feedback score, positive percentage, registration date, rating counts and detailed seller ratings. No website login required; eBay may restrict anonymous access. `/v1/ebay/seller`](/docs/api/endpoints/post-ebay-seller.md) [POST **eBay Seller Feedback API** Read paginated feedback received as an ebay.com seller, including comments, rating, displayed date, item reference and available seller replies. Supports positive, neutral or negative feedback filters; filtered pages may contain fewer results, so follow next_cursor even when count is zero. Feedback prices are displayed references, not a sold-listings price history. `/v1/ebay/seller-feedback`](/docs/api/endpoints/post-ebay-seller-feedback.md) [POST **eBay Seller Listings API** Search an ebay.com seller's active listings, optionally filtered by keywords, condition, price and category, with cursor pagination. Does not return sold/completed history. `/v1/ebay/seller-listings`](/docs/api/endpoints/post-ebay-seller-listings.md) ## Etsy 2 APIs [POST **Etsy Listing API** Scrape a public Etsy listing detail page from a search result URL. `/v1/etsy/listing`](/docs/api/endpoints/post-etsy-listing.md) [POST **Etsy API** Scrape public Etsy search result pages by query with page pagination. `/v1/etsy/search`](/docs/api/endpoints/post-etsy-search.md) ## Facebook 1 APIs [POST **Facebook group** Scrape public metadata and public initial-page posts from a Facebook group URL or group id. `/v1/facebook/group`](/docs/api/endpoints/post-facebook-group.md) ## Fantasy Premier League 1 APIs [POST **Fantasy Premier League Dataset** Get public FPL players and summaries of teams and gameweek events. `/v1/fantasy-premier-league/bootstrap`](/docs/api/endpoints/post-fantasy-premier-league-bootstrap.md) ## G2 2 APIs [POST **G2 Product API** Scrape a public G2 product page. `/v1/g2/product`](/docs/api/endpoints/post-g2-product.md) [POST **G2 API** Scrape public G2 software search results. `/v1/g2/search`](/docs/api/endpoints/post-g2-search.md) ## Glassdoor 2 APIs [POST **Glassdoor Interviews API** Scrape public Glassdoor interview question pages. `/v1/glassdoor/interviews`](/docs/api/endpoints/post-glassdoor-interviews.md) [POST **Glassdoor Salaries API** Scrape public Glassdoor salary search pages. `/v1/glassdoor/salaries`](/docs/api/endpoints/post-glassdoor-salaries.md) ## Goodreads 2 APIs [POST **Goodreads Book API** Scrape a public Goodreads book page. `/v1/goodreads/book`](/docs/api/endpoints/post-goodreads-book.md) [POST **Goodreads API** Scrape public Goodreads book search results. `/v1/goodreads/search`](/docs/api/endpoints/post-goodreads-search.md) ## Google Maps 5 APIs [POST **Google Maps area search** Search Google Maps for businesses near a specific latitude/longitude. Useful for exhaustive geographic coverage where IP-based location guessing would be unreliable. `/v1/googlemaps/area`](/docs/api/endpoints/post-googlemaps-area.md) [POST **Google Maps Autocomplete API** Fetch public Google Maps autocomplete suggestions. `/v1/googlemaps/autocomplete`](/docs/api/endpoints/post-googlemaps-autocomplete.md) [POST **Google Maps place** Fetch full details for a single Google Maps place — name, rating, category, description, address, phone, website, plus code, opening hours, and coordinates. `/v1/googlemaps/place`](/docs/api/endpoints/post-googlemaps-place.md) [POST **Google Maps reviews** Fetch reviews for a Google Maps place — author, rating, date, text, owner response, plus an overall rating breakdown. `/v1/googlemaps/reviews`](/docs/api/endpoints/post-googlemaps-reviews.md) [POST **Google Maps search** Search Google Maps for businesses or places matching a query and return each result's name, rating, category, address, hours, place ID, and coordinates. `/v1/googlemaps/search`](/docs/api/endpoints/post-googlemaps-search.md) ## Gumtree 2 APIs [POST **Gumtree Listing API** Scrape a public Gumtree listing detail page from a search result URL. `/v1/gumtree/listing`](/docs/api/endpoints/post-gumtree-listing.md) [POST **Gumtree API** Scrape public Gumtree search result pages by query with page pagination. `/v1/gumtree/search`](/docs/api/endpoints/post-gumtree-search.md) ## Hacker News 2 APIs [POST **Hacker News Item API** Fetch a public Hacker News item by URL or item id. `/v1/hacker-news/item`](/docs/api/endpoints/post-hacker-news-item.md) [POST **Hacker News API** Search Hacker News stories through public Algolia data with page pagination. `/v1/hacker-news/search`](/docs/api/endpoints/post-hacker-news-search.md) ## Home Depot 2 APIs [POST **Home Depot Product API** Scrape a public Home Depot product detail page from a search result URL. `/v1/homedepot/product`](/docs/api/endpoints/post-homedepot-product.md) [POST **Home Depot API** Scrape public Home Depot search result pages by query with offset pagination. `/v1/homedepot/search`](/docs/api/endpoints/post-homedepot-search.md) ## Hotels.com 2 APIs [POST **Hotels.com Property API** Get public Hotels.com property details. If stay dates are unavailable, returns an undated property summary without prices or availability. Returns public discovery metadata; undated prices are not stay-specific quotes. This endpoint does not accept stay dates or occupancy; check a dated search on the source website for stay-specific prices. `/v1/hotels/property`](/docs/api/endpoints/post-hotels-property.md) [POST **Hotels.com API** Scrape public Hotels.com accommodation search results by destination. Returns public discovery metadata; undated prices are not stay-specific quotes. This endpoint does not accept stay dates or occupancy; check a dated search on the source website for stay-specific prices. `/v1/hotels/search`](/docs/api/endpoints/post-hotels-search.md) ## IMDb 2 APIs [POST **IMDb Detail API** Scrape a public IMDb title, name, or series detail page from a search result URL. `/v1/imdb/detail`](/docs/api/endpoints/post-imdb-detail.md) [POST **IMDb API** Search IMDb public suggestion data by query. `/v1/imdb/search`](/docs/api/endpoints/post-imdb-search.md) ## Indeed 4 APIs [POST **Indeed Company Reviews API** Scrape public Indeed company review pages. `/v1/indeed/company-reviews`](/docs/api/endpoints/post-indeed-company-reviews.md) [POST **Indeed job details** Fetch full details for a single Indeed job posting — title, company, location, salary, employment type, full description, benefits, posted date, and apply URL. Pass either a job URL or a job key. `/v1/indeed/job`](/docs/api/endpoints/post-indeed-job.md) [POST **Indeed Salaries API** Scrape public Indeed company salary pages. `/v1/indeed/salaries`](/docs/api/endpoints/post-indeed-salaries.md) [POST **Indeed job search** Search Indeed for job postings matching a query (and optional location), returning normalized listings with title, company, location, salary, snippet, posted-date, and the canonical Indeed job URL. `/v1/indeed/search`](/docs/api/endpoints/post-indeed-search.md) ## Instagram 6 APIs [POST Website login **Instagram Authenticated Feed** Fetch your Instagram home feed using a managed website login for instagram.com. `/v1/instagram/feed`](/docs/api/endpoints/post-instagram-feed.md) [POST **Instagram Hashtag Posts** Retrieve public Instagram posts for a hashtag. This endpoint does not retrieve posts tagging a user. `/v1/instagram/hashtag-posts`](/docs/api/endpoints/post-instagram-hashtag-posts.md) [POST **Instagram Public Profile** Fetch a public Instagram profile anonymously, including profile metadata and paginated posts. `/v1/instagram/profile`](/docs/api/endpoints/post-instagram-profile.md) [POST **Instagram Profile Download** Export a full public Instagram profile as a ZIP file with media, captions, post metadata, manifest.json, and posts.csv. Authenticated runs are recommended in async mode. Pricing depends on account eligibility and profile size. See the Instagram profile downloader in your dashboard for your starting price. `/v1/instagram/profile-download`](/docs/api/endpoints/post-instagram-profile-download.md) [POST **Instagram Public Profile (No Auth)** Fetch a public Instagram profile anonymously, including profile metadata and paginated posts. `/v1/instagram/public-profile`](/docs/api/endpoints/post-instagram-public-profile.md) [POST **Instagram Reels API** Scrape public Instagram reels from a profile. `/v1/instagram/reels`](/docs/api/endpoints/post-instagram-reels.md) ## Kayak 1 APIs [POST **Kayak API** Scrape rendered public Kayak flight result pages from a flight query. Partner APIs require credentials. `/v1/kayak/search`](/docs/api/endpoints/post-kayak-search.md) ## Kiwi 1 APIs [POST **Kiwi API** Scrape rendered public Kiwi flight result pages from a flight query. Tequila API access requires credentials. `/v1/kiwi/search`](/docs/api/endpoints/post-kiwi-search.md) ## Letterboxd 2 APIs [POST **Letterboxd Film API** Scrape a public Letterboxd film page. `/v1/letterboxd/film`](/docs/api/endpoints/post-letterboxd-film.md) [POST **Letterboxd Search API** Scrape public Letterboxd film search results. `/v1/letterboxd/search`](/docs/api/endpoints/post-letterboxd-search.md) ## LinkedIn 2 APIs [POST Website login **LinkedIn Company Employees API** Scrape a LinkedIn company people page using a managed signed-in session. `/v1/linkedin/company-employees`](/docs/api/endpoints/post-linkedin-company-employees.md) [POST **LinkedIn Post Comments API** Scrape public comments visible on a LinkedIn post page. `/v1/linkedin/post-comments`](/docs/api/endpoints/post-linkedin-post-comments.md) ## Mastodon 2 APIs [POST **Mastodon API** Search public Mastodon accounts on a chosen instance. `/v1/mastodon/search`](/docs/api/endpoints/post-mastodon-search.md) [POST **Mastodon Status API** Scrape a public Mastodon status page. `/v1/mastodon/status`](/docs/api/endpoints/post-mastodon-status.md) ## Medium 2 APIs [POST **Medium Post API** Scrape a public Medium post page. `/v1/medium/post`](/docs/api/endpoints/post-medium-post.md) [POST **Medium API** Scrape public Medium story search results. `/v1/medium/search`](/docs/api/endpoints/post-medium-search.md) ## Mercari 5 APIs [POST **Mercari Listing API** Get a Mercari US listing’s title, price, photos, condition and seller name. `/v1/mercari/listing`](/docs/api/endpoints/post-mercari-listing.md) [POST **Mercari Search API** Search Mercari US listings with price, brand, category, condition and status filters. Follow next_cursor to get more results. `/v1/mercari/search`](/docs/api/endpoints/post-mercari-search.md) [POST **Mercari Seller API** Get a public Mercari US seller profile, ratings, follower counts and selling statistics. `/v1/mercari/seller`](/docs/api/endpoints/post-mercari-seller.md) [POST **Mercari Seller Listings API** Get a Mercari US seller’s listings with keyword, price, brand, category, condition and status filters. Follow next_cursor to get more results. `/v1/mercari/seller/listings`](/docs/api/endpoints/post-mercari-seller-listings.md) [POST **Mercari Seller Reviews API** Get public Mercari US account feedback, newest first. Choose reviews from buyers or sellers. Automated Mercari messages are labelled. `/v1/mercari/seller/reviews`](/docs/api/endpoints/post-mercari-seller-reviews.md) ## OfferUp 4 APIs [POST **OfferUp Item API** Read an OfferUp listing's full description, photos, condition code, price and available seller trust summary. No website login required. Removed listings may be unavailable. `/v1/offerup/item`](/docs/api/endpoints/post-offerup-item.md) [POST **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/search`](/docs/api/endpoints/post-offerup-search.md) [POST **OfferUp Seller API** Read a public OfferUp seller profile, including available ratings, account age, activity, response time, badges and compliments. Missing metrics are null; cancellation rates are not available. `/v1/offerup/seller`](/docs/api/endpoints/post-offerup-seller.md) [POST **OfferUp Seller Listings API** Browse a public OfferUp seller's active listings with cursor pagination. Keep seller_id and limit unchanged when continuing. `/v1/offerup/seller-listings`](/docs/api/endpoints/post-offerup-seller-listings.md) ## OLX 2 APIs [POST **OLX Listing API** Scrape a public OLX listing page. `/v1/olx/listing`](/docs/api/endpoints/post-olx-listing.md) [POST **OLX API** Scrape public OLX listing search results. `/v1/olx/search`](/docs/api/endpoints/post-olx-search.md) ## OnlyFans 3 APIs [POST **OnlyFans API** Fetch public OnlyFans profile details, subscription pricing and visible counts without connecting an OnlyFans account. Hidden counts are null; restricted profiles may be unavailable. `/v1/onlyfans/profile`](/docs/api/endpoints/post-onlyfans-profile.md) [POST **OnlyFans Profiles API** Fetch public details for up to 10 OnlyFans profiles without connecting an account. Duplicate usernames are fetched once. Partial batches include per-profile errors; all-failed batches fail the run. Costs 10 credits per batch. `/v1/onlyfans/profiles`](/docs/api/endpoints/post-onlyfans-profiles.md) [POST **OnlyFans Creator Search API** Discover OnlyFans creator profile links and snippets from Google's search index. No OnlyFans login needed. Coverage is not exhaustive and snippets may be outdated; use the profile endpoint for current data. A page can contain fewer results or be empty after non-profile links are excluded; continue while next_cursor is present. `/v1/onlyfans/search`](/docs/api/endpoints/post-onlyfans-search.md) ## Patreon 7 APIs [POST **Patreon Campaign API** Fetch public Patreon creator details, visible counts, membership tiers and goals. Hidden earnings remain null. `/v1/patreon/campaign`](/docs/api/endpoints/post-patreon-campaign.md) [POST **Patreon Creator API** Scrape public Patreon creator metadata. `/v1/patreon/creator`](/docs/api/endpoints/post-patreon-creator.md) [POST **Patreon Creator Download** Export a Patreon creator's posts and accessible media as a ZIP file. Managed Patreon auth is optional and recommended for paid content your account can view. `/v1/patreon/creator-download`](/docs/api/endpoints/post-patreon-creator-download.md) [POST **Patreon Creator Posts API** Fetch public Patreon post metadata from a creator by username, URL, or campaign id. `/v1/patreon/creator-posts`](/docs/api/endpoints/post-patreon-creator-posts.md) [POST **Patreon Post API** Fetch public Patreon post details by post URL. `/v1/patreon/post`](/docs/api/endpoints/post-patreon-post.md) [POST **Patreon Post Media API** Extract public media and attachment metadata from a Patreon post by post URL. `/v1/patreon/post-media`](/docs/api/endpoints/post-patreon-post-media.md) [POST **Patreon Search API** Search public Patreon creators by query with page pagination. `/v1/patreon/search`](/docs/api/endpoints/post-patreon-search.md) ## Pinterest 2 APIs [POST Website login **Pinterest Board API** Scrape pins from an accessible Pinterest board using your connected Pinterest account. `/v1/pinterest/board`](/docs/api/endpoints/post-pinterest-board.md) [POST **Pinterest Pin API** Scrape a public Pinterest pin detail page from a search result URL. `/v1/pinterest/pin`](/docs/api/endpoints/post-pinterest-pin.md) ## Product Hunt 2 APIs [POST **Product Hunt Product API** Scrape a public Product Hunt product or launch page. `/v1/producthunt/product`](/docs/api/endpoints/post-producthunt-product.md) [POST **Product Hunt API** Scrape public Product Hunt product and launch search results. `/v1/producthunt/search`](/docs/api/endpoints/post-producthunt-search.md) ## Quora 1 APIs [POST **Quora Question API** Scrape a public Quora question page. `/v1/quora/question`](/docs/api/endpoints/post-quora-question.md) ## Realtor 2 APIs [POST **Realtor.com Property API** Scrape a public Realtor.com property page. `/v1/realtor/property`](/docs/api/endpoints/post-realtor-property.md) [POST **Realtor.com API** Scrape public Realtor.com property search results. `/v1/realtor/search`](/docs/api/endpoints/post-realtor-search.md) ## Reddit 8 APIs [POST **Reddit Multireddit** Fetch posts from a user's multireddit. `/v1/reddit/multireddit`](/docs/api/endpoints/post-reddit-multireddit.md) [POST **Reddit Post Comments** Fetch a Reddit post and its comments by URL. `/v1/reddit/post/comments`](/docs/api/endpoints/post-reddit-post-comments.md) [POST **Reddit Posts** Fetch frontpage or subreddit posts with sort, timeframe, and cursor controls. `/v1/reddit/posts`](/docs/api/endpoints/post-reddit-posts.md) [POST **Reddit Search** Search Reddit posts globally or within a subreddit. `/v1/reddit/search`](/docs/api/endpoints/post-reddit-search.md) [POST **Reddit Subreddit Details** Fetch subreddit about data, rules, and optionally moderators. `/v1/reddit/subreddit/details`](/docs/api/endpoints/post-reddit-subreddit-details.md) [POST **Reddit Subreddits** Discover popular, new, or trending subreddits. `/v1/reddit/subreddits`](/docs/api/endpoints/post-reddit-subreddits.md) [POST **Reddit User Content** Fetch a Reddit user's overview, submitted posts, or comments. `/v1/reddit/user/content`](/docs/api/endpoints/post-reddit-user-content.md) [POST **Reddit Wiki** List subreddit wiki pages or fetch one wiki page. `/v1/reddit/wiki`](/docs/api/endpoints/post-reddit-wiki.md) ## Redfin 2 APIs [POST **Redfin Property API** Scrape a public Redfin property detail page from a search result URL. `/v1/redfin/property`](/docs/api/endpoints/post-redfin-property.md) [POST **Redfin API** Search public Redfin property listings by location. `/v1/redfin/search`](/docs/api/endpoints/post-redfin-search.md) ## Rightmove 2 APIs [POST **Rightmove Property API** Scrape a public Rightmove property detail page from a search result URL. `/v1/rightmove/property`](/docs/api/endpoints/post-rightmove-property.md) [POST **Rightmove API** Search public Rightmove property listings by location. `/v1/rightmove/search`](/docs/api/endpoints/post-rightmove-search.md) ## Skyscanner 1 APIs [POST **Skyscanner API** Search live flight itineraries from a Skyscanner-style route query. If Skyscanner blocks the browser, results transparently identify the live fallback provider. `/v1/skyscanner/search`](/docs/api/endpoints/post-skyscanner-search.md) ## SoundCloud 2 APIs [POST **SoundCloud Page API** Scrape a public SoundCloud track, playlist, or profile page. `/v1/soundcloud/page`](/docs/api/endpoints/post-soundcloud-page.md) [POST **SoundCloud API** Scrape public SoundCloud search results. `/v1/soundcloud/search`](/docs/api/endpoints/post-soundcloud-search.md) ## Spotify 1 APIs [POST **Spotify API** Fetch public Spotify oEmbed metadata for Spotify URLs. Search and catalog APIs require OAuth. `/v1/spotify/metadata`](/docs/api/endpoints/post-spotify-metadata.md) ## Stack Overflow 2 APIs [POST **Stack Overflow Question API** Scrape a public Stack Overflow question detail page from a search result URL. `/v1/stackoverflow/question`](/docs/api/endpoints/post-stackoverflow-question.md) [POST **Stack Overflow API** Search Stack Overflow through the public Stack Exchange API with page pagination. `/v1/stackoverflow/search`](/docs/api/endpoints/post-stackoverflow-search.md) ## Steam 2 APIs [POST **Steam App API** Scrape a public Steam Store app page. `/v1/steam/app`](/docs/api/endpoints/post-steam-app.md) [POST **Steam API** Scrape public Steam Store search results with page pagination. `/v1/steam/search`](/docs/api/endpoints/post-steam-search.md) ## Substack 2 APIs [POST **Substack Post API** Scrape a public Substack post page. `/v1/substack/post`](/docs/api/endpoints/post-substack-post.md) [POST **Substack API** Scrape public Substack search results. `/v1/substack/search`](/docs/api/endpoints/post-substack-search.md) ## Threads 2 APIs [POST **Threads Profile API** Scrape a public Threads profile or post page. `/v1/threads/profile`](/docs/api/endpoints/post-threads-profile.md) [POST **Threads API** Scrape public Threads search results. `/v1/threads/search`](/docs/api/endpoints/post-threads-search.md) ## TikTok 7 APIs [POST Website login **TikTok comments** Get comments for a TikTok video using a connected TikTok account. The current website requires sign-in to open comments; video and profile metadata remain available through the public endpoints. `/v1/tiktok/comments`](/docs/api/endpoints/post-tiktok-comments.md) [POST **TikTok Follower Count** Get public follower counts and profile statistics for a TikTok username. Individual follower identities are not returned. `/v1/tiktok/follower-count`](/docs/api/endpoints/post-tiktok-follower-count.md) [POST **TikTok hashtag** Fetch public hashtag metadata and a paginated slice of rendered public videos for a TikTok hashtag. `/v1/tiktok/hashtag`](/docs/api/endpoints/post-tiktok-hashtag.md) [POST **TikTok profile** Fetch public TikTok profile metadata and a paginated slice of recent public videos from a creator profile. `/v1/tiktok/profile`](/docs/api/endpoints/post-tiktok-profile.md) [POST **TikTok search** Fetch a paginated slice of public rendered TikTok video search results for a query. `/v1/tiktok/search`](/docs/api/endpoints/post-tiktok-search.md) [POST **TikTok video** Fetch public metadata, stats, media, music, hashtags, and author data for a TikTok video. `/v1/tiktok/video`](/docs/api/endpoints/post-tiktok-video.md) [POST **TikTok videos** Fetch a paginated slice of public videos from a TikTok creator profile. `/v1/tiktok/videos`](/docs/api/endpoints/post-tiktok-videos.md) ## Tripadvisor 2 APIs [POST **Tripadvisor Detail API** Scrape a public Tripadvisor hotel, restaurant, or attraction page. `/v1/tripadvisor/detail`](/docs/api/endpoints/post-tripadvisor-detail.md) [POST **Tripadvisor API** Scrape public Tripadvisor search results for hotels, restaurants, and attractions. `/v1/tripadvisor/search`](/docs/api/endpoints/post-tripadvisor-search.md) ## Trustpilot 2 APIs [POST **Trustpilot Company API** Scrape a public Trustpilot company review page. `/v1/trustpilot/company`](/docs/api/endpoints/post-trustpilot-company.md) [POST **Trustpilot API** Scrape public Trustpilot company search results. `/v1/trustpilot/search`](/docs/api/endpoints/post-trustpilot-search.md) ## Twitch 2 APIs [POST **Twitch Channel API** Scrape a public Twitch channel page. `/v1/twitch/channel`](/docs/api/endpoints/post-twitch-channel.md) [POST **Twitch API** Scrape public Twitch search results. `/v1/twitch/search`](/docs/api/endpoints/post-twitch-search.md) ## Vimeo 2 APIs [POST **Vimeo API** Scrape public Vimeo video search results. `/v1/vimeo/search`](/docs/api/endpoints/post-vimeo-search.md) [POST **Vimeo Video API** Scrape a public Vimeo video page. `/v1/vimeo/video`](/docs/api/endpoints/post-vimeo-video.md) ## Vinted 6 APIs [POST **Vinted Brand Feed API** Scrape public Vinted catalog results for a brand. `/v1/vinted/brand`](/docs/api/endpoints/post-vinted-brand.md) [POST **Vinted item** Fetch a Vinted item page and return normalized item details plus similar items from the same page. `/v1/vinted/item`](/docs/api/endpoints/post-vinted-item.md) [POST **Vinted member items** Fetch a Vinted member wardrobe feed with pagination and normalized item data. `/v1/vinted/member/items`](/docs/api/endpoints/post-vinted-member-items.md) [POST **Vinted member search** Search Vinted member profiles by username and return normalized member matches across multiple pages. `/v1/vinted/member/search`](/docs/api/endpoints/post-vinted-member-search.md) [POST **Vinted search** Search Vinted listings by keyword and return normalized item data across multiple pages. `/v1/vinted/search`](/docs/api/endpoints/post-vinted-search.md) [POST **Vinted filtered search** Search Vinted listings with catalog, size, brand, condition, color, pattern, material, price, and sort filters. `/v1/vinted/search/filtered`](/docs/api/endpoints/post-vinted-search-filtered.md) ## Walmart 2 APIs [POST **Walmart Product API** Scrape a public Walmart product detail page from a search result URL. `/v1/walmart/product`](/docs/api/endpoints/post-walmart-product.md) [POST **Walmart API** Scrape public Walmart search result pages by query with page pagination. `/v1/walmart/search`](/docs/api/endpoints/post-walmart-search.md) ## Wellfound 2 APIs [POST **Wellfound Profile API** Scrape a public Wellfound company or job page. `/v1/wellfound/profile`](/docs/api/endpoints/post-wellfound-profile.md) [POST **Wellfound API** Find public Wellfound jobs by role or company name. `/v1/wellfound/search`](/docs/api/endpoints/post-wellfound-search.md) ## Wikipedia 2 APIs [POST **Wikipedia Page API** Scrape a public Wikipedia article page from a search result URL. `/v1/wikipedia/page`](/docs/api/endpoints/post-wikipedia-page.md) [POST **Wikipedia API** Search Wikipedia through the public MediaWiki API with offset pagination. `/v1/wikipedia/search`](/docs/api/endpoints/post-wikipedia-search.md) ## X 5 APIs [POST Website login **X Lists API** Scrape a public X or Twitter list page. `/v1/x/lists`](/docs/api/endpoints/post-x-lists.md) [POST Website login **X profile** Fetch tweets from an X profile inside a managed signed-in session. `/v1/x/profile`](/docs/api/endpoints/post-x-profile.md) [POST Website login **X search** Search X posts inside a managed signed-in session. `/v1/x/search`](/docs/api/endpoints/post-x-search.md) [POST Website login **X timeline** Fetch tweets from the signed-in X home timeline using managed auth. `/v1/x/timeline`](/docs/api/endpoints/post-x-timeline.md) [POST Website login **X Trends API** Scrape public X explore trends. `/v1/x/trends`](/docs/api/endpoints/post-x-trends.md) ## Yelp 3 APIs [POST **Yelp Business API** Scrape a public Yelp business detail page from a search result URL. `/v1/yelp/business`](/docs/api/endpoints/post-yelp-business.md) [POST **Yelp Reviews API** Scrape public reviews visible on a Yelp business page. `/v1/yelp/reviews`](/docs/api/endpoints/post-yelp-reviews.md) [POST **Yelp API** Scrape public Yelp search results by query and optional location. The official Yelp Fusion API requires credentials. `/v1/yelp/search`](/docs/api/endpoints/post-yelp-search.md) ## YouTube 9 APIs [POST Website login **YouTube channel email** Reveal the protected public business email from a YouTube channel's about panel using a managed signed-in browser. `/v1/youtube/channel/email`](/docs/api/endpoints/post-youtube-channel-email.md) [POST **YouTube channel shorts** Fetch shorts from a YouTube channel shorts tab using the public web client sort chips and continuations. `/v1/youtube/channel/shorts`](/docs/api/endpoints/post-youtube-channel-shorts.md) [POST **YouTube channel videos** Fetch videos from a YouTube channel videos tab using public web continuations. `/v1/youtube/channel/videos`](/docs/api/endpoints/post-youtube-channel-videos.md) [POST **YouTube Livestreams API** Scrape public YouTube live video search results. `/v1/youtube/livestreams`](/docs/api/endpoints/post-youtube-livestreams.md) [POST **YouTube search** Search YouTube and return normalized mixed results from the default results page. `/v1/youtube/search`](/docs/api/endpoints/post-youtube-search.md) [POST **YouTube to MP3** Convert a public YouTube video to a downloadable MP3 file. `/v1/youtube/to-mp3`](/docs/api/endpoints/post-youtube-to-mp3.md) [POST **YouTube Transcript API** Fetch public YouTube caption transcript segments for a video. `/v1/youtube/transcript`](/docs/api/endpoints/post-youtube-transcript.md) [POST **YouTube video** Fetch a YouTube video page with normalized metadata and top-level comments. `/v1/youtube/video`](/docs/api/endpoints/post-youtube-video.md) [POST **YouTube video comments** Fetch top-level comments for a YouTube video using the public watch page and comments continuations. `/v1/youtube/video/comments`](/docs/api/endpoints/post-youtube-video-comments.md) ## Zillow 2 APIs [POST **Zillow Property API** Scrape a public Zillow property detail page from a search result URL. `/v1/zillow/property`](/docs/api/endpoints/post-zillow-property.md) [POST **Zillow API** Scrape public Zillow search pages by location query. `/v1/zillow/search`](/docs/api/endpoints/post-zillow-search.md) ## Zoopla 2 APIs [POST **Zoopla Property API** Scrape a public Zoopla property page. `/v1/zoopla/property`](/docs/api/endpoints/post-zoopla-property.md) [POST **Zoopla API** Scrape public Zoopla property search results. `/v1/zoopla/search`](/docs/api/endpoints/post-zoopla-search.md) ## Core API Discover APIs, run a request, track its progress, and manage website connections. [GET **/v1/auth/invocations/:id** Inspect a website authentication flow.](/docs/api/compatibility.md) [POST **/v1/instagram/scrape** Legacy Instagram compatibility route; prefer the catalogue APIs.](/docs/api/compatibility.md) [POST **/v1/integration-assets** Upload a private integration image asset.](/docs/api/compatibility.md) [GET **/v1/integration-assets/:id** Read a private integration image asset.](/docs/api/compatibility.md) [POST **/v1/runs/:id/cancel** Cancel a supported integration run.](/docs/api/compatibility.md) [POST **/v1/tasks/:task_key/edits** Retired: create a replacement API from the dashboard (HTTP 410).](/docs/api/tasks/create.md) [POST **/v1/task-generations/:id/continue-auth** Retired: legacy generation cannot be resumed (HTTP 410).](/docs/api/tasks/create.md) [GET **/v1/task-generations/:id/endpoints** List published endpoints for an existing generation.](/docs/api/tasks/create.md) [GET **/v1/task-generations/:id/evidence** Read available evidence for an existing generation.](/docs/api/tasks/create.md) [GET **/v1/tasks/:task_key/options** Find published filter values and labels.](/docs/api/request-guide.md) [POST **/v1/task-generations** Retired: create replacement APIs from the dashboard (HTTP 410).](/docs/api/tasks/create.md) [GET **/v1/tasks** List tasks accessible to your API key.](/docs/api/tasks/list.md) [GET **/v1/tasks/:task_key** Fetch canonical task metadata by task key.](/docs/api/tasks/list.md) [POST **/v1/tasks/:task_key/runs** Execute a task by canonical task key.](/docs/api/tasks/execute.md) [GET **/v1/task-generations/:id** Read an existing generation record.](/docs/api/tasks/create.md) [GET **/v1/runs/list** List runs for your team and filters.](/docs/api/runs/list.md) [GET **/v1/runs/:id** Fetch a single run payload and status.](/docs/api/runs/details.md) [GET **/v1/runs/:id/logs** Fetch run logs, including auth workflow events.](/docs/api/runs/logs.md) [GET **/v1/website-logins** List external website logins available to tasks.](/docs/api/website-logins.md) [POST **/v1/website-logins** Start a hosted external website login flow.](/docs/api/website-logins.md) [DELETE **/v1/website-logins/:id** Delete an external website login account.](/docs/api/website-logins.md) [GET **/v1/website-logins/invocations/:id** Poll a hosted external website login flow.](/docs/api/website-logins.md) [DELETE **/v1/website-logins/invocations/:id** Cancel a hosted external website login flow.](/docs/api/website-logins.md) [GET **/v1/website-logins/location** Fetch the team location used for website login setup.](/docs/api/website-logins.md) [PATCH **/v1/website-logins/location** Set or reset the team location used for website login setup.](/docs/api/website-logins.md) **Integrating with an agent or generating a client?** Start with [the agent index](/docs/llms.txt) , read any page as Markdown, or download [the prebuilt API OpenAPI specification](/docs/openapi.json) . Core routes are described in the guides above. --- Source: https://browsable-api-ux-staging.pages.dev/docs/api # Instagram Profile Download API Export a public Instagram profile as a ZIP file with photos, reels, videos, captions, post metadata, `manifest.json`, and `posts.csv`. Authenticated runs are recommended in async mode and pricing depends on your account. Standard pricing is 80 credits for up to 1,000 posts, plus 10 credits for each additional started 1,000 posts. Grandfathered accounts retain 40 credits plus 5 per additional 1,000 posts. Before the new pricing launches, all accounts retain the original rates. POST `/v1/instagram/profile-download` Canonical execution route: `/v1/tasks/instagram-profile-download/runs`. For the live task contract, inspect `GET /v1/tasks/instagram-profile-download`. Execution notes - Use authenticated API access for full-profile exports. - Async execution is recommended for large profiles. - The task catalogue shows your account’s starting price. The final charge depends on the posts included in the ZIP. - Set `maxPosts` to cap the export; omit it to attempt the full public profile. - Marketing-site free exports are capped separately to the first 20 posts and do not use this API route. ## Parameters | Parameter | Type | Required | Description | | --- | --- | --- | --- | | profile | string | Yes | Instagram username, @handle, or full profile URL. | | maxPosts | number | No | Maximum number of posts to include. Omit to attempt the full public profile. | | _run.async | boolean | No | Set to `true` to return immediately with a run envelope and poll later. | ## Response ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "instagram-profile-download", "task_name": "Instagram Profile Download", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "success": true, "export_id": "054b71a5-9971-49ee-9470-2fe863901a44", "status": "completed", "file_name": "natgeo.zip", "download_url": "https://...", "download_url_expires_at": "2026-04-05T11:55:00.000Z", "expires_at": "2026-04-05T11:55:00.000Z", "truncated": false, "profile": { "id": "787132", "username": "natgeo", "full_name": "National Geographic", "is_private": false, "total_posts": 1000, "profile_pic_url": "https://..." }, "result_summary": { "postsDiscovered": 84, "mediaDiscovered": 120, "estimatedBytes": 456789123, "downloadedFiles": 120, "failedFiles": 0, "skippedFiles": 0, "truncated": false } }, "error": null } ``` ### Result Fields `download_url` - Temporary signed ZIP URL. `download_url_expires_at` - Expiry for the signed download URL. `expires_at` - Export artifact retention expiry. `truncated` - Whether the final ZIP is partial. `result_summary` - Counts for posts, media, downloads, skips, and estimated bytes. ## Code Examples ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/instagram/profile-download" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"profile":"natgeo","maxPosts":1000,"_run":{"async":true}}' ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/instagram/profile-download", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "profile": "natgeo", "maxPosts": 1000, "_run": {"async": True}, }, ) payload = response.json() print(payload["run_status"]) print(payload["status_url"]) ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/instagram/profile-download", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ profile: "natgeo", maxPosts: 1000, _run: { async: true }, }), }); const payload = await response.json(); console.log(payload.run_status); console.log(payload.status_url); ``` ## Try it Out ### API Playground API Key Stored locally only profile * Instagram username or full profile URL maxPosts Maximum posts to include; omit for full profile ## Error Codes 400 Bad Request The JSON body does not match the task input schema. 401 Unauthorized Missing or invalid API key. 403 Forbidden Your account cannot execute the task, usually because of access or credits. 429 / upstream throttling Instagram may temporarily limit full-profile exports. Poll the run and inspect the final error or partial ZIP result. --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/instagram/profile-download # Reddit Post & Comments API Fetch a Reddit post and its comment tree by URL. This endpoint follows the same run envelope as the rest of the Browsable API. POST `/v1/reddit/post/comments` Canonical execution route: `/v1/tasks/reddit-post-comments/runs`. For the live task contract, inspect `GET /v1/tasks/reddit-post-comments`. For all current parameters, limits and response fields, see the [complete endpoint reference](/docs/api/endpoints/post-reddit-post-comments.md) . This guide shows a basic request. ## Parameters | Parameter | Type | Required | Description | | --- | --- | --- | --- | | url | string | Yes | Full Reddit post URL. | ## Response ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "reddit-post-comments", "task_name": "Reddit Post & Comments", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "post": { "id": "1abc234", "title": "What's the best way to learn programming?", "author": "user123", "subreddit": "learnprogramming", "score": 142, "upvoteRatio": 0.95, "numComments": 45, "created": 1704067200, "url": "https://reddit.com/r/learnprogramming/comments/...", "selftext": "I'm new to programming and wondering...", "isVideo": false, "locked": false }, "comments": [ { "id": "c1", "author": "helpfuluser", "body": "Start with Python! It's beginner-friendly...", "score": 87, "created": 1704067800, "depth": 0, "isSubmitter": false, "replies": [] } ] }, "error": null } ``` ### Result Fields Post Object `title` - Post title. `author` - Post author. `subreddit` - Subreddit name. `numComments` - Total comment count. Comment Object `body` - Comment text. `score` - Comment score. `depth` - Nesting depth. `replies` - Nested replies. ## Code Examples ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/reddit/post/comments" \n -H "Authorization: Bearer YOUR_API_KEY" \n -H "Content-Type: application/json" \n -d '{"url":"https://reddit.com/r/programming/comments/abc123/...","_run":{"async":false}}' ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/reddit/post/comments", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "url": "https://reddit.com/r/programming/comments/abc123/...", "_run": {"async": False}, }, ) payload = response.json() print(payload["result"]["post"]["title"]) print(len(payload["result"]["comments"])) ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/reddit/post/comments", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json" }, body: JSON.stringify({ url: "https://reddit.com/r/programming/comments/abc123/...", _run: { async: false } }) }); const payload = await response.json(); console.log(payload.result.post.title); console.log(payload.result.comments.length); ``` ## Try it Out ### API Playground API Key Stored locally only url * Reddit post URL ## Error Codes 400 Bad Request The JSON body does not match the task input schema. 401 Unauthorized Missing or invalid API key. 403 Forbidden Your account cannot execute the task, usually because of access or credits. 500 Internal Server Error Fetching the Reddit post failed upstream. --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/reddit/post # Reddit Search API Search Reddit posts by query. Like all Browsable execution endpoints, this route returns the standard run envelope with task metadata, run status, and a `result` payload when the run completes. POST `/v1/reddit/search` Canonical execution route: `/v1/tasks/reddit-search/runs`. For the live task contract, inspect `GET /v1/tasks/reddit-search`. For all current parameters, limits and response fields, see the [complete endpoint reference](/docs/api/endpoints/post-reddit-search.md) . This guide shows a basic request. ## Parameters | Parameter | Type | Required | Description | | --- | --- | --- | --- | | query | string | Yes | Search query string. | | subreddit | string | No | Optional subreddit scope. Accepts `AskReddit` or `r/AskReddit`. | | timeframe | string | No | Optional timeframe: hour, day, week, month, year, or all. | | sort | string | No | Optional sort. Global search supports relevance, new, top, and comment_count. Subreddit search also supports hot and comments. | | limit | number | No | Maximum number of posts to return. | | after | string | No | Cursor returned by the previous response. | | before | string | No | Cursor returned by the previous response. | ## Response ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "reddit-search", "task_name": "Reddit Search", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "count": 1, "results": [ { "id": "1abc234", "title": "What's the best way to learn programming?", "author": "user123", "subreddit": "learnprogramming", "score": 142, "upvoteRatio": 0.95, "numComments": 45, "created": 1704067200, "url": "https://reddit.com/r/learnprogramming/comments/...", "selftext": "I'm new to programming and wondering...", "thumbnail": "https://...", "isVideo": false } ] }, "error": null } ``` ### Result Fields `id` - Reddit post ID. `title` - Post title. `author` - Username of the post author. `subreddit` - Subreddit name. `score` - Post score. `upvoteRatio` - Upvote ratio from 0 to 1. `numComments` - Comment count. `created` - Unix timestamp. `url` - Full Reddit URL. `selftext` - Post body for text posts. `thumbnail` - Thumbnail URL when present. `isVideo` - Whether the post is a video. ## Code Examples ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/reddit/search" \n -H "Authorization: Bearer YOUR_API_KEY" \n -H "Content-Type: application/json" \n -d '{"query":"artificial intelligence","_run":{"async":false}}' ``` ```python import requests response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/reddit/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "artificial intelligence", "_run": {"async": False}, }, ) payload = response.json() print(payload["run_status"]) print(payload["result"]["count"]) for post in payload["result"]["results"]: print(post["title"]) ``` ```javascript const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/reddit/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json" }, body: JSON.stringify({ query: "artificial intelligence", _run: { async: false } }) }); const payload = await response.json(); console.log(payload.run_status); console.log(payload.result.count); payload.result.results.forEach((post) => { console.log(post.title); }); ``` ## Try it Out ### API Playground API Key Stored locally only query * Search query subreddit Optional subreddit scope ## Error Codes 400 Bad Request The JSON body does not match the task input schema. 401 Unauthorized Missing or invalid API key. 403 Forbidden Your account cannot execute the task, usually because of access or credits. 500 Internal Server Error Reddit search failed upstream. --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/reddit/search # Requests, pagination and errors Send your API key in `Authorization: Bearer YOUR_API_KEY`. Each endpoint reference lists its JSON inputs, defaults, limits and accepted values. Start with its minimal example, then add filters. When a page says “provide at least one of”, a URL or another listed identifier is required even though each individual field is optional. ## Use familiar inputs Use `location` for Google Maps area searches and Craigslist searches. Google Maps resolves the place itself; Craigslist resolves a city or region from its published regional directory and asks for clarification when a name is ambiguous. For Amazon seller products, pass a public `seller_url` containing `seller=` or `me=`. For Vinted filtered search, copy a filtered catalogue URL into `url`. The API extracts search text, category, size, brand, colour, condition and material IDs. You can also supply `min_price` and `max_price`. For Mercari search, `url` accepts a filtered search URL; seller listings accept `filters_url` for brand, category, query and price filters. Conflicting URL and explicit filter values fail validation. Use `limit` and `url` where listed as preferred inputs. Older names remain available under advanced and compatibility inputs. Supply one version of each input; conflicting aliases are rejected. Pagination styles retain their existing meanings. Flight searches accept city names or airport codes and resolve them through the source site’s autocomplete service. Include a country or region when you need a particular city with a shared name. The resolved selections appear in `result.data.resolved_locations`. Flight searches require `depart_date` in `YYYY-MM-DD` format. Return dates cannot precede departure. Hotel discovery endpoints do not accept stay dates or occupancy, and their undated prices are not stay-specific quotes. `instagram/hashtag-posts` retrieves hashtag posts. `tiktok/follower-count` retrieves follower statistics. Existing tagged-posts and followers routes remain compatible. Twitter routes resolve to X; X is the single catalogue identity. Diagnostic health echo is excluded from the public scraper catalogue. ## Find accepted filter values Inspect `GET /v1/tasks/{task_key}` for the current input schema and credit cost. Use `GET /v1/tasks/{task_key}/options?parameter=amenities` to discover published option values and labels. Omit `parameter` to list parameters with known complete options. This route uses the same API-key authentication. Options are not available for every filter. An empty `values` array with `source: "none"` does not mean that no filter values are supported. Inspect `reason` and the endpoint schema. For example, `options_not_confidently_complete` means no complete option list is published; `parameter_not_found` means the parameter name is unknown. ## Continue results Pagination differs by endpoint. Use the fields listed in that endpoint’s reference: some accept `cursor`, others `after`, `offset`, or `pages`. `pages` is the number of pages fetched by one request, while `page` selects a starting page. Increasing these values can increase request time and the amount of data returned. For endpoints returning `result.pagination.next_cursor`, pass that value unchanged as `cursor` on the next request. Keep the original search and filters unchanged and follow any endpoint-specific cursor expiry or limit restrictions. An empty filtered page can still have a next cursor. Do not invent a cursor for the first request. For Reddit, pass `result.after` as `after` to move forward, or `result.before` as `before` to move backward. For Instagram profiles, pass `result.pagination.end_cursor` as `after` while `has_next_page` is true. For Airbnb reviews and host listings, pass `result.pagination.next_offset` as `offset`. Airbnb search accepts its returned `next_page_cursor` as `cursor`. Endpoints exposing only `pages` fetch a bounded batch starting at their default first page. A continuation value in their output does not imply a reusable input unless the endpoint reference lists one. Keep page-count limits in mind when planning a larger collection. ## Download completed exports Downloader results may initially contain only `export_id`. Poll the run until it succeeds to get the signed `download_url`, `download_url_expires_at` and `result_summary`. A `pending://` URL is a placeholder. For ZIP exports, inspect `status`, `truncated`, `failed_media` and file counts to distinguish a requested post cap from media failures. Download URLs expire separately from the stored artifact; request the run again while the artifact is retained to obtain a refreshed link. ## Handle invalid inputs A schema validation failure returns HTTP 400 before starting a scraper run. The response identifies fields to correct: ```json { "title": "Invalid request", "status": 400, "detail": "Request body failed validation against the task input schema.", "error_code": "validation_error", "retryable": false, "action": "check_input", "request_id": "req_example", "errors": [ { "path": "limit", "message": "must be at most 100" } ] } ``` Some input checks happen after a run starts. Those failures appear in the run’s `error` object and may provide less field detail. Inspect `error.code`, `error.message`, `error.retryable` and `error.action`. ## Wait for a run and retry safely HTTP success means the request was accepted; it does not guarantee successful extraction. Check `run_status`. Poll `status_url` while the run is queued or running, using exponential backoff. Read `result` after `succeeded`. For `failed`, inspect `error`. Keep the run ID and request ID when contacting support. For a pending run, poll its existing status URL instead of submitting another scrape. Honor `Retry-After` on HTTP 429. A failed run with `error.retryable: true` may be retried as a new request; this creates another run. A false value means the input, account connection or another stated condition needs attention first. ## Retry without creating duplicate runs For each new task execution, generate a unique `Idempotency-Key` header and keep it with the request body. If the connection times out before you receive a run ID, retry the same request with the same key and unchanged body. This lets the API return the saved run rather than start another scrape. Once you have a run ID, poll that run. Reusing a key with different input returns `409 idempotency_conflict`. Use a new key for a genuinely new execution, including an intentional retry after a terminal failed run. Do not generate a fresh key just because a response was lost. If HTTP 428 includes a `hosted_url`, open it to connect the required website account. Follow the returned status URL and authentication instructions. See [website logins](/docs/api/website-logins.md) . --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/request-guide # Get Run Details API Retrieve the current status of a run, plus its final `result` or `error` and lifecycle timestamps. GET `/v1/runs/{run_id}` ## Example ```bash curl -X GET "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/00000000-0000-4000-8000-000000000001" \ -H "Authorization: Bearer YOUR_API_KEY" ``` ## Response ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "reddit-search", "task_name": "Reddit Search", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": {"results": [...], "count": 25}, "error": null, "created_at": "2024-01-20T10:30:00Z", "started_at": "2024-01-20T10:30:01Z", "updated_at": "2024-01-20T10:30:15Z", "completed_at": "2024-01-20T10:30:15Z" } ``` --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/runs/details # List Runs API Retrieve runs for your team. You can optionally filter by `task_key` and page through results with a cursor. GET `/v1/runs/list?task_key={task_key}` ## Query Parameters - `task_key` filters runs to a single task. - `limit` controls page size. - `cursor` continues from the previous page. ## Example ```bash curl -X GET "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/list?task_key=reddit-search&limit=20" \ -H "Authorization: Bearer YOUR_API_KEY" ``` ## Response ```json { "runs": [ { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "reddit-search", "task_name": "Reddit Search", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": {"count": 25, "results": []}, "error": null, "created_at": "2024-01-20T10:30:00Z" } ], "pagination": { "has_more": false, "next_cursor": null, "previous_cursor": null } } ``` --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/runs/list # Get Run Logs API Retrieve execution logs for a specific run. GET `/v1/runs/{run_id}/logs` ## Parameters Add `?include=all` to include all logs (including debug). ## Example ```bash curl -X GET "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/00000000-0000-4000-8000-000000000001/logs?include=all" \ -H "Authorization: Bearer YOUR_API_KEY" ``` ## Response ```json { "logs": [ { "id": "log_1", "level": "info", "message": "Searching Reddit", "source": "builtin", "created_at": "2024-01-20T10:30:05Z" } ] } ``` --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/runs/logs # Legacy task generation `POST /v1/task-generations`, `POST /v1/tasks/{task_key}/edits` and `POST /v1/task-generations/{id}/continue-auth` are retired. They return HTTP 410 with `error_code: "legacy_generation_retired"`, `retryable: false`, and no credit charge. Create a replacement API from the [dashboard](https://dashboard.browsable.app) . Existing APIs can still be discovered with `GET /v1/tasks` and executed with `POST /v1/tasks/{task_key}/runs`. The MCP `create_scraper` and `create_scraper_and_run` tools call the retired generation route. Use task discovery and execution for existing APIs. ## Read existing generation records `GET /v1/task-generations/{id}` retrieves an existing generation record. `GET /v1/task-generations/{id}/endpoints` lists its published endpoints and supports `limit` and `cursor` pagination. `GET /v1/task-generations/{id}/evidence` retrieves available generation evidence. These read operations require an API key authorized for the team and do not start or resume generation. See [task discovery](/docs/api/tasks/list.md) , [task execution](/docs/api/tasks/execute.md) and [request and error handling](/docs/api/request-guide.md) . --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/tasks/create # Execute Task API Execute any task by its canonical task key. Prebuilt tasks may also expose a friendly alias route such as `/v1/reddit/search`. POST `/v1/tasks/{task_key}/runs` ## Async vs Sync Set `_run.async` to `false` for synchronous execution (waits up to 25 seconds). ## Example ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/tasks/reddit-search/runs" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query": "openai", "_run": { "async": false }}' ``` ## Response ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "reddit-search", "task_name": "Reddit Search", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "count": 10, "results": [] }, "error": null } ``` --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/tasks/execute # List Tasks API Discover the tasks available to your team, including prebuilt tasks and your own generated tasks. GET `/v1/tasks` This is the main discovery endpoint for humans, generated clients, and LLM-based tooling. It includes the user-facing metadata you need to discover and choose tasks: friendly alias routes, canonical endpoints, parameter summaries, auth requirements, docs URLs, and pricing metadata. For the full machine-readable contract, fetch a single task with `GET /v1/tasks/{task_key}`. ## Query Parameters - `limit` controls page size. - `cursor` continues from a previous page. - `type` filters tasks to `custom` or `prebuilt`. By default, your own custom tasks are returned first, followed by prebuilt tasks. ## Example ```bash curl -X GET "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/tasks?limit=50" \ -H "Authorization: Bearer YOUR_API_KEY" ``` ## Response ```json { "tasks": [ { "task_key": "reddit-search", "task_type": "prebuilt", "name": "Reddit Search", "description": "Search Reddit posts by query and return structured post data.", "method": "POST", "alias_endpoint": "/v1/reddit/search", "canonical_endpoint": "/v1/tasks/reddit-search/runs", "docs_url": "/docs/api/endpoints/post-reddit-search", "credit_cost": 5, "request_parameters": [ { "key": "query", "type": "string", "required": true, "description": "Search query", "location": "body", "sample": "artificial intelligence" } ], "auth_requirements": null } ], "pagination": { "has_more": false, "next_cursor": null, "previous_cursor": null } } ``` Use `GET /v1/tasks/{task_key}` when you need the full metadata for a single task. Custom tasks may return `null` for `alias_endpoint` and `docs_url` when they do not have a public-friendly alias or docs page. --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/tasks/list # Website Logins API Website logins are external site sessions that auth-required Browsable tasks can reuse. ## Endpoints `GET /v1/website-logins` lists sanitized website login accounts. `POST /v1/website-logins` starts a hosted login flow and returns an invocation to poll. `DELETE /v1/website-logins/:id` deletes a website login account. `GET /v1/website-logins/invocations/:id` polls a login invocation. `DELETE /v1/website-logins/invocations/:id` cancels a login invocation. `GET /v1/website-logins/location` reads the team auth location and sanitized proxy state. `PATCH /v1/website-logins/location` sets or resets the team auth location. ## List Website Logins ```bash curl "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/website-logins?domain=x.com" \ -H "x-api-key: $BROWSABLE_API_KEY" ``` ## Start Login Flow ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/website-logins" \ -H "x-api-key: $BROWSABLE_API_KEY" \ -H "Content-Type: application/json" \ -d '{"domain":"x.com","display_name":"Team X login"}' ``` Open the returned `hosted_url`, then poll `/v1/website-logins/invocations/:id` until the invocation reaches `SUCCESS` or `FAILED`. ## Delete Website Login ```bash curl -X DELETE "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/website-logins/acct_123" \ -H "x-api-key: $BROWSABLE_API_KEY" ``` ## Set Location ```bash curl -X PATCH "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/website-logins/location" \ -H "x-api-key: $BROWSABLE_API_KEY" \ -H "Content-Type: application/json" \ -d '{"location":{"country_code":"US","region_code":"CA","city":"San Francisco"}}' ``` --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/website-logins # YouTube to MP3 API Convert a public YouTube video into an MP3 file. Send a regular YouTube link, then poll the run until the MP3 download URL is ready. POST `/v1/youtube/to-mp3` Canonical execution route: `/v1/tasks/youtube-to-mp3/runs`. For the live task contract, inspect `GET /v1/tasks/youtube-to-mp3`. Downloading your MP3 - No YouTube Studio login is required. - MP3 exports are kept for 24 hours. Signed download URLs are temporary. ## Pricing and Limits | Item | Value | | --- | --- | | Credits | 10 credits per started 10 minutes of video. Minimum cost is 10 credits. | | Maximum duration | Up to 12 hours. | | Maximum source size | 1.5 GB. | | Execution mode | Use async mode and poll `status_url`. | ## Parameters | Parameter | Type | Required | Description | | --- | --- | --- | --- | | video_url | string | Yes | A YouTube watch URL, youtu.be URL, shorts URL, or video ID. | | bitrate | string | No | MP3 bitrate. Defaults to `192k`. Allowed: `128k`, `192k`, `256k`, `320k`. | | include_metadata | boolean | No | Defaults to `true`. Preserves basic video metadata when available. | | _run.async | boolean | Recommended | Set to `true` and poll `status_url` for completion. | ## Response ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "youtube-to-mp3", "task_name": "YouTube to MP3", "run_status": "queued", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "metadata": { "video": { "id": "dQw4w9WgXcQ", "url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ", "title": "Video title", "channel_title": "Channel name", "thumbnail_url": "https://...", "duration_seconds": 245 } }, "result": null, "error": null } ``` ### Result fields `download_url` - Temporary signed MP3 URL. `download_url_expires_at` - Expiry for the signed download URL. `expires_at` - Export artifact retention expiry. `metadata.video` - Video title, thumbnail, channel, and duration when available during polling. `result_summary` - MP3 format, bitrate, file size, source size, duration, and title. ## Code Examples ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/youtube/to-mp3" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "video_url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ", "_run": { "async": true } }') STATUS_URL=$(echo "$RUN" | jq -r '.status_url') curl -s "https://api-ingress-worker-staging.browsable-staging.workers.dev$STATUS_URL" \ -H "Authorization: Bearer YOUR_API_KEY" ``` ```python import time import requests headers = { "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", } start = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/youtube/to-mp3", headers=headers, json={ "video_url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ", "_run": {"async": True}, }, ) start.raise_for_status() run = start.json() while run["run_status"] not in {"succeeded", "failed", "canceled"}: time.sleep(3) run = requests.get(f"https://api-ingress-worker-staging.browsable-staging.workers.dev{run['status_url']}", headers=headers).json() if run["run_status"] == "succeeded": print(run["result"]["download_url"]) else: print(run["error"]) ``` ```javascript const headers = { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }; let run = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/youtube/to-mp3", { method: "POST", headers, body: JSON.stringify({ video_url: "https://www.youtube.com/watch?v=dQw4w9WgXcQ", _run: { async: true }, }), }).then((response) => response.json()); while (!["succeeded", "failed", "canceled"].includes(run.run_status)) { await new Promise((resolve) => setTimeout(resolve, 3000)); run = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev" + run.status_url, { headers }).then((response) => response.json()); } if (run.run_status === "succeeded") { console.log(run.result.download_url); } else { console.error(run.error); } ``` ## Try it Out The playground sends the required fields. For production use, prefer the async examples above and poll the returned `status_url`. ### API Playground API Key Stored locally only video_url * YouTube watch, youtu.be, shorts URL, or video ID ## Error Codes 400 Invalid YouTube URL The URL is not a supported YouTube watch, youtu.be, shorts URL, or video ID. 401 Unauthorized Missing or invalid API key. 403 Forbidden Your account cannot execute the task, usually because of access or credits. Conversion failed The source was too large, too long, unavailable, or could not be converted. --- Source: https://browsable-api-ux-staging.pages.dev/docs/api/youtube-to-mp3 # Use Browsable from your agent Connect Browsable once, then ask your agent for the data you need. You only need to step in when a website asks you to sign in or when you want to add more credits. Start here - Add `https://mcp.browsable.app` to your agent. - When prompted, sign in to Browsable in your browser. - Ask for the data you want. Browsable handles the rest. ## How it works for a person There is no API key copy-paste step for MCP. There is no separate agent-only account to manage. You connect Browsable once, then use it from your agent like any other tool. - Add Browsable to your agent with the server URL. - The first time you use it, your agent opens a browser tab so you can log in or create an account. - After that, ask for what you want: find and run an existing API. Create replacement APIs from the dashboard. - If a website needs your login, the agent should stop and give you a link. - If you need more credits, the agent should show your balance and send you to billing, then continue after you upgrade. What you should expect - Sign in once. - Ask for data in plain language. - Only step in again for a website login or billing. ## Recommended flow for agents If you are wiring Browsable into an agent or writing system instructions, use this flow. - Always start with `list_tasks` for a data request, even when the request contains a URL. Pass concise intent keywords in `query`, such as `youtube channel email`. - If `pagination.has_more` is true, continue with `pagination.next_cursor` before concluding that no existing task is available. - Use `get_task` before running anything so you know the inputs, outputs, and credit cost. - Use `run_task` to execute the task. If it runs in the background, check progress with `get_run`. - If Browsable returns a hosted login link, stop and ask the person to open it. Do not keep retrying. - If no existing task matches, direct the person to create an API from the dashboard. The legacy `create_scraper` route is retired (HTTP 410). - If balance or plan status matters, call `get_billing_overview`. - Only create machine API keys when the user explicitly wants automation outside the current MCP session. Good agent behavior - Find the right task before you run it. - Do not create a scraper merely because the request includes a URL. - Ask the person for help only when a website login or payment step is required. - Stay in the same thread and continue after login or billing is done. - Do not ask the user to copy, paste, or manage session credentials. ## Install Browsable Use the same server URL everywhere: `https://mcp.browsable.app` ### Codex CLI ```bash codex mcp add browsable --url https://mcp.browsable.app codex mcp login browsable --scopes tasks.read,tasks.run,runs.read,task_generations.write,billing.read,keys.manage ``` ### Claude Code ```bash claude mcp add --transport http browsable https://mcp.browsable.app ``` ### Cursor ```json { "mcpServers": { "browsable": { "url": "https://mcp.browsable.app" } } } ``` ### VS Code ```json { "servers": { "browsable": { "type": "http", "url": "https://mcp.browsable.app" } } } ``` ### ChatGPT developer mode Add Browsable as a custom remote MCP connector and use the same server URL: `https://mcp.browsable.app`. ## Good first prompts These are good examples of how to ask for work in plain language. - Find the best Browsable task for pulling Reddit post comments, then run it for this URL. - Create a scraper for this page and show me the result. - Check my remaining Browsable credits. - If this site needs a login, stop and give me the link. - Show me the Instagram tasks that fit this job and pick the best one. ## What Browsable handles for you - Sign-in and account creation the first time you connect. - Showing the current account balance. - Finding, running, and tracking tasks. - Pausing for a website login and bringing you back when it is done. - Showing balance and upgrade paths when you need more credits. ## If you are not using MCP You can still use Browsable directly over HTTP. If you are generating code or giving an LLM the raw API, start with the [API reference](/docs/api.md) and [/docs/llms.txt](/docs/llms.txt) . For direct REST use, discover tasks with `GET /v1/tasks` and run them with ` POST /v1/tasks/{task_key}/runs`. --- Source: https://browsable-api-ux-staging.pages.dev/docs/guides/agents # Authentication Authenticate API requests with a Browsable API key and use task metadata to discover live pricing and schema information. ## API Keys All API requests require a Bearer token in the `Authorization` header: ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/reddit/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"test","_run":{"async":false}}' ``` ## Getting an API Key - Sign up for a Browsable account at [browsable.app](https://browsable.app) . - Open the API Keys page in your dashboard. - Create a key and store it securely. ### Security Best Practices - Never commit API keys to version control. - Store keys in environment variables or a secret manager. - Rotate keys regularly. - Revoke compromised keys immediately. ## Optional Idempotency For `POST` endpoints that create work, you can optionally send an `Idempotency-Key` header. When you retry the same request with the same key, Browsable can return the original run or generation instead of creating duplicate work. ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/reddit/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: req_123" \ -d '{"query":"test"}' ``` ## Managing API Keys You can manage your API keys using the Admin API endpoints: ### List API Keys ```bash curl -X GET "https://api-ingress-worker-staging.browsable-staging.workers.dev/admin/list-keys" \ -H "Authorization: Bearer YOUR_API_KEY" ``` ### Create New API Key ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/admin/create-key" \ -H "Authorization: Bearer YOUR_API_KEY" ``` ### Revoke API Key ```bash curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/admin/revoke-key" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"key_id": "key_abc123"}' ``` ## Credits And Rate Limits - Task pricing is exposed live via `/v1/tasks` and `/v1/tasks/{task_key}` in the `credit_cost` field. - Different tasks can cost different amounts. - Rate limits and entitlement checks are enforced at request time. A `429` means you should retry with backoff. A `403` usually means your account cannot execute the task. ## Error Responses API-level failures use a structured problem-details style response. Examples: ### 401 Unauthorized ```json { "type": "https://api-ingress-worker-staging.browsable-staging.workers.dev/problems/http-401", "title": "Unauthorized", "status": 401, "detail": "Missing or invalid API key", "error": "Missing or invalid API key", "request_id": "req_abc123", "error_code": null, "retryable": null, "action": null } ``` ### 403 Forbidden ```json { "type": "https://api-ingress-worker-staging.browsable-staging.workers.dev/problems/http-403", "title": "Forbidden", "status": 403, "detail": "Your account cannot execute this task.", "error": "Your account cannot execute this task.", "request_id": "req_def456", "error_code": null, "retryable": null, "action": null } ``` ### 429 Rate Limit Exceeded ```json { "type": "https://api-ingress-worker-staging.browsable-staging.workers.dev/problems/http-429", "title": "Rate limited", "status": 429, "detail": "Rate limit exceeded. Please try again later.", "error": "Rate limit exceeded. Please try again later.", "request_id": "req_xyz789", "error_code": null, "retryable": null, "action": null } ``` ### Need higher limits? Contact us about higher throughput, custom quotas, or dedicated support. [Contact Sales](https://browsable.app/support) --- Source: https://browsable-api-ux-staging.pages.dev/docs/guides/authentication Get started # Make your first request. You need an API key and a few inputs. This example searches public Reddit posts; the same flow works for the rest of the catalogue. ## 1. Get an API key Open your [Browsable dashboard](https://dashboard.browsable.app) , choose API keys, and copy a key. Keep it in a server-side environment variable, not a public frontend. ## 2. Choose an API Search the [API reference](/docs/api.md) by website or job. Each page lists its required inputs, limits and response format. You can also discover APIs programmatically with `GET /v1/tasks?query=reddit`. ## 3. Run a request Replace `YOUR_API_KEY` with your key, then run this example. It submits a flat JSON body and polls the run until it finishes. The cURL example uses `jq` to read JSON. ```bash RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/reddit/search" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query":"machine learning"}') 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 ``` ```javascript const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/reddit/search", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ "query": "machine learning" }), }); const runPayload = await runResponse.json(); if (!runResponse.ok) throw new Error(JSON.stringify(runPayload)); const runId = runPayload.run_id; if (!runId) throw new Error("Run ID not found in response"); let pollDelayMs = 3000; while (true) { const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, { headers: { Authorization: "Bearer YOUR_API_KEY" }, }); const result = await resultResponse.json().catch(() => ({})); if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) { const retryAfter = resultResponse.headers.get("retry-after"); await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs)); continue; } if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`); const status = result.run_status; if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) { console.log(result); break; } await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2))); pollDelayMs = Math.min(pollDelayMs * 2, 30000); } ``` ```python import random import time import requests run_response = requests.post( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/reddit/search", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, json={ "query": "machine learning" }, ) run_payload = run_response.json() if not run_response.ok: raise RuntimeError(run_payload) run_id = run_payload.get("run_id") if not run_id: raise ValueError("Run ID not found in response") poll_delay = 3.0 while True: result_response = requests.get( "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id, headers={"Authorization": "Bearer YOUR_API_KEY"}, ) if result_response.status_code == 429 or result_response.status_code in (502, 503, 504): retry_after = result_response.headers.get("Retry-After") time.sleep(float(retry_after) if retry_after else poll_delay) continue result_response.raise_for_status() result = result_response.json() status = result.get("run_status") if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"): print(result) break time.sleep(poll_delay * random.uniform(0.9, 1.1)) poll_delay = min(poll_delay * 2, 30.0) ``` ## 4. Read the result Wait for `run_status: succeeded`, then use `result`. A successful HTTP response can also describe a pending or failed run. On failure, inspect `error` before retrying. ```json { "run_id": "00000000-0000-4000-8000-000000000001", "task_key": "reddit-search", "task_name": "Reddit Search", "run_status": "succeeded", "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001", "result": { "count": 2, "results": [ { "id": "1k9x2ab", "title": "What are the best resources for learning machine learning in 2026?", "author": "ml_beginner_42", "subreddit": "MachineLearning", "score": 187, "upvoteRatio": 0.96, "numComments": 54, "created": 1773328800, "url": "https://www.reddit.com/r/MachineLearning/comments/1k9x2ab/what_are_the_best_resources_for_learning_machine/", "isVideo": false, "selftext": "I have a solid Python background and want to move into practical ML projects. Looking for courses, books, and hands-on resources.", "thumbnail": "https://styles.redditmedia.com/t5_2r3gv/styles/communityIcon_example.png" }, { "id": "1k93yz7", "title": "Show HN: I built a small model to classify research paper abstracts by topic", "author": "latent_vector", "subreddit": "programming", "score": 92, "upvoteRatio": 0.91, "numComments": 18, "created": 1773242400, "url": "https://www.reddit.com/r/programming/comments/1k93yz7/show_hn_i_built_a_small_model_to_classify/", "isVideo": false, "selftext": "It uses a lightweight embedding model and a simple classifier. I wrote up the approach and linked the repo in the comments.", "thumbnail": "https://b.thumbs.redditmedia.com/example-thumbnail.png" } ] }, "error": null } ``` Illustrative response generated from the public contract. It is not a captured live search. ## Choose how to wait Requests start asynchronously by default. Send `_run: {"async": false}` to wait for results within the request’s available time. It may still return a pending run, so always check its status. [Execution options →](/docs/api/tasks/execute.md) ## Next steps - [See every Reddit search input](/docs/api/endpoints/post-reddit-search.md) - [Handle pagination and errors](/docs/api/request-guide.md) - [Connect an agent through MCP](/docs/guides/agents.md) --- Source: https://browsable-api-ux-staging.pages.dev/docs/guides/quickstart Build with Browsable # Web data. One straightforward API. Search products, read public profiles, and collect the data your app needs. Start with an API that already does the job. [Make your first request →](/docs/guides/quickstart.md) [Explore the APIs ↗](/docs/api.md) A few minutes to your first result ## Find it. Run it. Use the data. - **1** **Get an API key**Copy a key from your [dashboard](https://dashboard.browsable.app) . - **2** **Choose an API**Search the [catalogue](/docs/api.md) by website or what you want to do. - **3** **Send a request**Copy an example, add your inputs, and check the run for results. Start by discovering an API ```bash curl "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/tasks?query=airbnb" \ -H "Authorization: Bearer YOUR_API_KEY" ``` ```javascript const response = await fetch( 'https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/tasks?query=airbnb', { headers: { Authorization: 'Bearer YOUR_API_KEY' } } ); const { tasks } = await response.json(); console.log(tasks); ``` ```python import requests response = requests.get( 'https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/tasks', params={'query': 'airbnb'}, headers={'Authorization': 'Bearer YOUR_API_KEY'}, ) response.raise_for_status() print(response.json()['tasks']) ``` Listing APIs does not start a scrape. Each endpoint page shows the inputs and a complete request. [**Explore the API reference →** Find APIs for Airbnb, Amazon, Instagram, Reddit and more.](/docs/api.md) [**Understand requests →** Choose inputs, continue through pages, and recover from errors.](/docs/api/request-guide.md) [**Build with an agent →** Connect through MCP, or use Markdown docs and OpenAPI.](/docs/guides/agents.md) **Docs that work for agents, too** Every page has a Markdown version. Use [the documentation index](/docs/llms.txt) to find a specific API, [the complete text](/docs/llms-full.txt) for offline reading, or [OpenAPI](/docs/openapi.json) to generate a client. --- Source: https://browsable-api-ux-staging.pages.dev/docs