api

Search.

One endpoint for every mode and engine. Authenticated with a bearer key, metered per call.

POST https://metasearch.sh/api/v1/search
Authorization: Bearer ms_live_…
Content-Type: application/json
Idempotency-Key: 0b7e…            (optional)

Create a key in the dashboard; the key search login stores for search-cli is the same kind of key. An unknown or revoked key returns 401 invalid_api_key.

Request body#

The body is a JSON object. A field not listed here is rejected with 400 invalid_request, never ignored.

fieldtyperule
querystring, requiredTrimmed. In text modes, at most 2,000 characters. In extract, scrape and similar, an absolute http(s) URL of at most 2,048 characters whose host resolves to a public address; private, loopback and link-local hosts are refused with 400 invalid_url.
modestringDefault auto: the server picks one of the modes below and says why in routing.auto (see Auto routing). Otherwise one of the twelve modes below, or scrape, an alias of extract; an explicit mode is always obeyed. The response echoes the mode as you sent it.
providersstring[]1 to 5 distinct engine names. Omitted: the first available engine for the mode, with fallback. One name: pinned, no fallback. Several: queried together and merged by rank fusion. stealth is accepted as the old name of direct.
providerstringLegacy form of providers: [name]. Sending both is a 400 invalid_request.
countinteger1 to 20, default 10. The most results returned; an engine may return fewer. Out of range is a 400 invalid_request.
filtersobjectOptional. Fields listed under Filters. Not allowed in URL modes.
rerankbooleanDefault true. Reorders results by relevance to the query in general, news, academic, scholar, people and deep when there are at least three and the request is not pinned to one engine. Free. Send falseto keep the engines' order.
freshbooleanDefault false. A request repeated within a short time is answered from the stored result, at the same price; send true to always ask the engines.

Filters#

filtertyperule
freshnessstringday, week, month or year.
include_domainsstring[]At most 20 bare hostnames, lowercased, e.g. arxiv.org. In social mode these are X handles without the @, limiting the authors searched.
exclude_domainsstring[]At most 20, same form as include_domains.
countrystringISO 3166-1 alpha-2, e.g. gb.
languagestringISO 639-1, e.g. de.

A filter is never dropped silently. Without providers, the router skips engines that cannot honour every filter you sent. A pinned engine that cannot honour one returns 400 filter_unsupported with the engines that can in supported_by. The manifest lists the filters each engine accepts per mode. An unknown filter name is a 400 invalid_request.

two engines, fused, with filters
{
  "query": "retrieval augmented generation evaluation",
  "mode": "academic",
  "providers": ["exa", "serper"],
  "count": 10,
  "filters": { "freshness": "year", "exclude_domains": ["medium.com"] }
}

Modes#

modequeryuse it for
generaltextAny web lookup not covered by a more specific mode. Not for: Papers (academic), current events (news), a named person (people).
newstextCurrent events and recent coverage.
academictextPapers and studies on a topic, found semantically. Not for: Citation counts and PDF links: use scholar.
scholartextGoogle Scholar records: citation counts, versions, PDF links.
peopletextA named person: their role, employer, LinkedIn profile. Served by Exa alone; if Exa is unavailable, search general for the name and employer. Not for: What people are saying about a topic: use social.
socialtextPosts and videos on X, TikTok, Instagram and YouTube, with views, likes, comments and authors. Name the platform in the query ("on tiktok", "instagram reels", "youtube videos", "on X") to search only there; otherwise X and the one platform likeliest to hold the answer are searched together. Put X handles, without @, in include_domains to limit X authors. Extract a TikTok, Instagram, YouTube, Facebook or Threads post URL for its caption, stats, transcript where there is one, and top comments. Not for: Discussion threads (community), reporting (news).
communitytextWhat real people say about a topic: Reddit posts and Hacker News stories, with scores or points, comment counts and authors. Put r/<subreddit> in the query to search one subreddit (cheapest); without one, all of Reddit is searched. Extract a Reddit thread or news.ycombinator.com/item URL for the whole thread, every comment in order with its author, score and depth. Not for: X, TikTok, Instagram and YouTube posts (social), reporting (news).
imagestextPictures. Returns imageUrl (the image) and url (the page it sits on). Served by Serper, with SerpApi as the fallback on the hosted API.
placestextBusinesses and physical locations, with addresses.
patentstextPatent filings.
deeptextWider coverage on a hard question. Slower and dearer than general. Not for: Routine lookups: general costs a fraction of this.
extracturlOne page as markdown. Tries our own fetch first, then rendering services. A Reddit or Hacker News thread, or a TikTok, Instagram, YouTube, Facebook or Threads post URL, is read by that source: the post, its stats and its comments or transcript. Not for: Finding pages: search first, then extract the URL you want.
scrapeurlAlias of extract. Same behaviour and price.
similarurlPages resembling a given page: competitors, related coverage.

The engines behind each mode are on Providers & modes.

Routing#

With no mode, auto routing picks one first; it never picks deep, and picks social only when the query names a platform: X, Twitter, TikTok, Instagram or YouTube. Send a mode to skip it.

Without providers, engines are tried in the mode's priority order, healthy engines first, until one returns at least one result: at most 3 attempts, 4 in URL modes. If no engine can serve the mode you get 503 no_provider_for_mode.

A named engine is checked strictly: an unknown name is 400 unknown_provider (with valid_providers), one that does not serve the mode is 400 provider_mode_mismatch (with supported_modes), and one that is switched off or failing is 503 provider_not_available.

Idempotency#

Send an Idempotency-Key header (1 to 255 characters of A-Z a-z 0-9 _ . : -) to make a retry safe. Keys are scoped to your organisation and kept for 24 hours.

  • Same key and same body after a 200: the stored response, with replayed: true and the header Idempotent-Replayed: true. A replay is not charged.
  • Same key while the first request is still running: 409 idempotency_in_progress; retry after the Retry-After seconds.
  • Same key with a different body: 422 idempotency_mismatch.
  • A request that ended in an error releases its key.

Response#

Every response, errors included, carries an X-Request-Id header with the same value as request_id.

fielddescription
request_idUUID of this call. Quote it to support.
modeThe mode as you sent it.
providerThe first engine that contributed results, or null. Kept for older clients; prefer routing.
results[]At most count items: title, url, snippet, and when known published and imageUrl (images mode: the image itself; url stays the page). extra holds engine-specific fields; in URL modes it has content_origin: "untrusted_web_content", since the page text comes from the open web. After a rerank, extra.relevance is the judged relevance, 0 to 1.
results[].sourcesFused requests only: each engine that returned this URL and its rank there.
answers[]Present only when an engine returned a written answer: text, provider, citations. Answers never take a result slot.
routing.mergechain (no providers), single (one) or fused (several).
routing.served_byThe engine whose results you got, or null.
routing.providersEvery engine that contributed at least one result.
routing.fell_backTrue when the first engine tried did not serve the request.
routing.autoPresent when the mode was auto: the mode that ran, its source (rule, model or fallback), a one-sentence reason, and when they apply probabilities, filters_applied(a freshness taken from words such as "today", in news and social only) and latency_ms.
routing.rerankedTrue when results were reordered by relevance; each then carries extra.relevance.
routing.cachedTrue when the answer is the stored result of the same request made recently (15 minutes for news and social, hours for web searches, days for papers, patents and profiles); routing.cached_at says when it was fetched. Send fresh: true to skip it.
routing.hints[]Advisory, for an explicit mode that looks wrong: { type: "mode", suggested, p, message }. It never changes what ran.
routing.attempts[]One entry per engine tried: provider, outcome (ok, empty, rejected, failed, timeout or skipped), category and http_status on failure, latency_ms and charged_micros. escalated: truemarks a list that was set aside for the next engine's; it is not charged.
billing.reserved_microsHeld before dispatch. The charge is never higher.
billing.charged_microsWhat this call cost, in micro-USD (1 µ$ = $0.000001).charged_usd is the same in dollars.
billing.balance_microsYour balance after the charge. balance_usd is the same in dollars.
messageSet when there are no results.
replayedPresent, and true, only on an idempotent replay.

No results#

If every engine tried returns nothing, the response is still a 200, with results: [], charged_micros: 0, the message "No provider returned results; nothing was charged." and each attempt's outcome in routing.attempts.

Time limits#

Each mode has one deadline shared by all its attempts. The manifest gives it as deadline_ms. Set your client timeout above it; 90 seconds covers every mode.

deadlinemodes
20 sgeneral, news, people, similar, scholar, patents, images, places, community
25 sacademic
45 sdeep
60 sextract, social
IntroductionGetting started
QuickstartGetting started
Organisations and rolesGetting started
SearchAPI
RoutingAPI
Providers & modesAPI
ErrorsAPI
BillingAPI
Usage APIAPI
search-cliTools
MCP serverTools
ClaudeAssistants
ChatGPTAssistants
CodexAssistants
CursorAssistants
VS Code and CopilotAssistants
Gemini CLIAssistants
Overview
Usage
Logs
Billing
Settings
General
Appearance
Notifications
Security & sessions
Connected apps
Organisation
Members & roles
Plan & billing
Rate limits
Data & privacy
Activity log
Create an API key
Add funds
Redeem a promo code
Export logs