Web search

Search the live web from your own code. Structured results, one flat price per search, no scraping and no search-engine contract.

POST/v1/search

This is a plain request/response endpoint, not a chat completion. It returns search results as data — title, URL, snippet, source, publication date, favicon and thumbnail — so you can rank, filter or cite them yourself. Nothing is summarised by a model on the way out, which means nothing is invented on the way out either.

curl https://api.xkiro.com/v1/search \
  -H "Authorization: Bearer $XKIRO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "xkiro/web-search",
    "query": "who won the 2026 Nobel Prize in Physics",
    "max_results": 5
  }'

Request body#

Fields
FieldTypeDescription
modelrequiredstringAlways xkiro/web-search. Required even though there is one value — your account limits and spend controls are resolved from it.
queryrequiredstring | string[]What to search for. Pass an array to run up to five related searches in one request. Each query counts as one billed search.
max_resultsintegerHow many results to return, 1–20. Default 10. Does not change the price.
search_domain_filterstring[]Restrict results to these domains, up to 20. Bare domains work best (reuters.com); a full URL is accepted and trimmed down for you.
search_recency_filterstringday, week, month, year or noLimit (default).
countrystringTwo-letter ISO country code, e.g. VN, to bias results toward a region. Any other value is ignored rather than guessed at.

Field names match Perplexity's search API

search_domain_filter and search_recency_filter are spelled the way you already know them, so moving an existing integration across is a base-URL change rather than a rewrite.

Response#

200 OK
{
  "id": "srch_6db90a15-0bf2-48d2-9bc8-d80830aa8bad",
  "model": "xkiro/web-search",
  "results": [
    {
      "title": "2026 Nobel Prize in Physics",
      "url": "https://www.nobelprize.org/prizes/physics/2026/summary/",
      "snippet": "The Royal Swedish Academy of Sciences has decided to award…",
      "publishedDate": "2026-10-06T11:45:00",
      "source": "nobelprize.org",
      "faviconUrl": "https://…/favicon.png",
      "thumbnailUrl": "https://…/preview.jpg"
    }
  ],
  "usage": { "searches": 1, "remainingToday": 99 }
}
Result fields
FieldTypeDescription
titlestringPage title, with markup stripped.
urlstringCanonical URL, after redirects.
snippetstringThe passage the search engine matched against your query — not the page's meta description, which is usually marketing copy.
publishedDatestring | nullPublication date when the page states one. null means unknown, which is not the same as undated.
sourcestringDomain of the result, e.g. reuters.com. Useful for grouping and for citations.
faviconUrlstring | nullSite icon, ready to render in a result list. null when there isn't one — we do not guess a path that would 404.
thumbnailUrlstring | nullPreview image when the page has one.

Plan allowances#

Web search is included in every paid plan, with a daily allowance counted per account — not per API key, so extra keys do not buy extra quota. The window rolls continuously over 24 hours rather than resetting at midnight.

Searches per day, and burst limits
FieldTypeDescription
Free20Then pay-as-you-go at $0.01 each, from your wallet.
Pro10010 requests/minute · 3 at a time.
Pro Plus20015 requests/minute · 3 at a time.
Max30020 requests/minute · 4 at a time.
Ultra1,50030 requests/minute · 6 at a time.
Power3,00060 requests/minute · 8 at a time.

Search and page reads have separate allowances

A heavy day of searching never eats into your page-read allowance, or the other way round. Each response carries usage.remainingToday so you always know where you stand without having to hit the limit first.

Pricing#

  • On a paid plan, searches inside your allowance cost nothing. When the allowance runs out you get a 429 telling you how long until it frees up — your wallet is never charged behind your back for something the plan said was included.
  • Without a plan: 20 free searches a day, then $0.01 each — $10 per 1,000. One request with one query is one search; a request with three queries is three.
  • The content is included either way. You are not billed tokens for the pages we read on your behalf, so the cost of a search does not depend on how long the results turn out to be.
  • A failed search is not billed. If no search ran, nothing is charged.

Errors#

Status codes
FieldTypeDescription
400invalid_requestMissing or malformed field. The message names the field.
401authentication_errorMissing or invalid API key.
402insufficient_quotaFree allowance used up and wallet balance is zero.
429rate_limitYour plan's daily allowance is used up, or you exceeded the per-minute or concurrent limit. The message says which, and how long to wait.
502no_search_performedNo search ran for this query — rephrase it. You are not billed for this.
503service_unavailableTemporarily unavailable. Retry shortly.

Practical notes

  • Write queries the way you would type them into a search box, not the way you would ask a chatbot. Keywords beat full sentences.
  • Use search_domain_filter when you already know the sources you trust. It is the single biggest lever on result quality.
  • Cache results by query. Yesterday’s answer to a question about last year is still today’s answer, and it costs nothing to reuse.
  • Feeding results to a model? Pass title, url and snippet and ask it to cite the URL. To read a full page, call web fetch.

Was this page helpful?