---
title: "Search the web, paid per request (x402)"
method: POST
path: "/v1/x402/search"
tags: ["Search"]
---

# Search the web, paid per request (x402)

`POST /v1/x402/search`

## Request

- Base URL: `https://api.keenable.ai`
- URL: `https://api.keenable.ai/v1/x402/search`
- Auth: API key in header `PAYMENT-SIGNATURE`

Same search as POST /v1/search, paid per request with x402 instead of an API key. The price is stated in the 402 offer ($0.01 per request by default). Also available as GET with the parameters in the query string.

## Request body

- SearchRequest
  - `query` string, required: Search query
  - `mode` 'pro': Retrieval mode; "pro" is the default
  - `acquired_after` string: Filter: pages acquired after this date (YYYY-MM-DD, ISO 8601, or relative like "7d")
  - `acquired_before` string: Filter: pages acquired before this date
  - `published_after` string: Filter: pages published after this date, a lower bound on publish time. Use this, not query_time, to get recent results.
  - `published_before` string: Filter: pages published before this date
  - `site` string: Restrict results to a specific domain
  - `query_time` string: Leave empty for a normal search. An upper time bound for a point-in-time search: the web as it stood at this moment, with every page newer than it excluded. It sets no lower bound, so this is not a recency filter; for recent results use published_after. Accepts an ISO 8601 datetime (e.g. "2026-09-20T00:00:00Z"), a YYYY-MM-DD date, a Unix epoch, or an offset back from now ("7d" means as of 7 days ago, not the last 7 days). Units: min, h, d, w, mo, y.
  - `snippet_max_length` integer: Maximum length, in characters, of the snippet returned per result. When omitted, a default snippet length is used.
  - `max_results` integer: Maximum number of results to return. When omitted, a default count (10) is used.
  - `enable_wizards` boolean: Experimental: use wizards (structured data outputs). Only valid in "pro" mode. Not available to an organization under a zero data retention policy: the request is refused with 400 zdr_wizards_unsupported.

## Response `200`

Search results

- SearchResponse
  - `query` string, required: Echo of the search query
  - `mode` string, required: Search mode used
  - `results` SearchResult[], required
    - `title` string, required: Page title
    - `url` string, required: Page URL
    - `description` string, required: Always empty. Deprecated — the page description now feeds the snippet fallback.
    - `snippet` string: Search snippet with query-relevant highlights; falls back to the page description
    - `published_at` string: When the page was published (ISO 8601)
    - `acquired_at` string: When the page was indexed (ISO 8601)
  - `warning` string: Present when the request was not answered as a plain search. Either the query was a URL, so the page was fetched directly, or the query carried only a site: operator with no search terms, so the site name was used as the search term. It also says when wizards that the organization's settings turn on were left out because its zero data retention policy does not allow them.
  - `wizards` object[]: Experimental: structured data from wizards. Present only when enable_wizards is true and a wizard matched the query. The fields of each item depend on its wizard type.
    - `wizard` string, required: Wizard type, e.g. finance, sports, product_prices, prediction_markets, places, navigation
  - `usage` Usage: What this request was billed. Present when the request is billed in credits, that is made with an API key or a signed-in session; absent on keyless, x402 and ZeroClick requests. A request that fails (any non-2xx status) is never billed, and its error body carries no usage.
    - `sku` string, required: What was billed: search.<mode> for a search, named after the mode it ran in (search.pro by default, search.time_machine for a Time Machine search), and fetch, fetch.live or fetch.time_machine for a fetch. A search whose query is a URL is billed as the fetch it was answered with.
    - `amount` integer, required: Billed units, 1 for a search or a fetch.
    - `credits` number, required: Credits charged to the organization for this request.
    - `paid` boolean, required: true when the credits came from the purchased balance, false when they came from the plan's free credits.

## Other responses

- `400`: Invalid request parameters, or a request the organization's zero data retention policy does not allow (error zdr_wizards_unsupported, zdr_unsupported_profile or zdr_prompt_unsupported)
- `402`: Payment required: decode the PAYMENT-REQUIRED header (mirrored in the body), sign one of accepts, and retry with PAYMENT-SIGNATURE. Also returned when a payment is rejected, and when a verified payment could not be settled; the result is then withheld.
- `403`: Tell the cases apart by `error`. "Upstream forbidden" happens only when the query is a URL, which is fetched instead of searched: the target server refused the fetch (responded 401, 403, or a vendor block code such as LinkedIn's 999), a bot-wall or access restriction on the target rather than a problem with your credentials. Deterministic: retrying will not help. "Forbidden" means the request itself is not allowed, for example a revoked API key or a search mode your access does not include; see `message`.
- `404`: Only when the query is a URL, which is fetched instead of searched: the target page does not exist — the target server responded 404.
- `422`: Search failed with an unretryable upstream error — see `message`.
- `429`: Rate limit exceeded — slow down or upgrade your plan
- `500`: Internal server error
- `502`: Only when the query is a URL, which is fetched instead of searched: the fetcher could not get the target page: a DNS/TLS/connection failure, an unreachable host, or the target answered with a 5xx error. Unlike 422, no page content came back; unlike 403, the target did not refuse the fetch. Often transient; a retry is reasonable.
- `503`: Pay-per-request access is unavailable right now. Retry shortly or use an API key on /v1/search and /v1/fetch.
- `504`: Only when the query is a URL, which is fetched instead of searched: the upstream fetch to the target page timed out.
- `529`: Search is temporarily overloaded. Retry after the delay in `Retry-After`.

---

[API](https://skmtc.dev/keenable/apis/keenable-api.md) - [All operations](https://skmtc.dev/keenable/apis/keenable-api/llms.txt) - [OpenAPI document](https://skmtc.dev/keenable/apis/keenable-api/revisions/583d5cf92ed5?raw)
