Skip to content

New: deep research, balance and auto-reload tools in the keyless MCP server. Install in one line

API reference

Every ContextFetch endpoint on one page: parameters, example requests and responses, headers and errors. The search, contents and findSimilar endpoints follow Exa's request and response shapes, and /tavily/search follows Tavily's, so the official SDKs work after a base-URL change to https://api.contextfetch.dev.

If you’re an LLM, read llms.txt

Base URL
https://api.contextfetch.dev
Auth
Authorization: Bearer <key>, x-api-key, api_key (body), or none for the free tier

Costs

  • 1 credit per call to POST /v1/search, /v1/findSimilar, /tavily/search and GET /r/{url} (and their aliases).
  • POST /v1/contents: 1 credit per URL that loads (max 10 URLs per call).
  • A paid request that ends in an error is refunded. Keyless requests count even when they fail.
  • Cache hits are charged like live calls.
  • costDollars.total = credits used x 0.001.

Endpoints

Request bodies are JSON. Exa-shaped endpoints accept camelCase and snake_case field names.

POST/v1/contents

Try it

Credits: 1 per URL that loads (max 10)Also at: /contents

Fetch pages as Markdown, with optional query-aware highlights. Failed URLs come back in statuses and are not billed.

Parameters

NameInTypeRequiredDescription
urls / idsbodystring[]yes1 to 10 URLs in total.
textbodyboolnoReturn the page as Markdown. Default true.
highlightsbodybool | {query, numSentences, highlightsPerUrl}no400 to 700 character Markdown chunks, not sentences: numSentences is accepted and ignored.
pruned_contextbodyboolnoReturn prunedContext for the highlight query.

Example request

curl -s https://api.contextfetch.dev/v1/contents \  -H "Authorization: Bearer YOUR_API_KEY" \  -H "Content-Type: application/json" \  -d '{"urls":["https://docs.python.org/3/library/asyncio-task.html"],"text":true,"highlights":{"query":"task groups"}}'

Example response

{
  "requestId": "a1b2c3d4e5f60718293a4b5c6d7e8f90",
  "results": [
    {
      "id": "c7e1a2b3-4d5e-5f60-8a9b-0c1d2e3f4a5b",
      "url": "https://docs.python.org/3/library/asyncio-task.html",
      "title": "Coroutines and Tasks",
      "text": "# Coroutines and Tasks\n\n...",
      "highlights": ["...the chunk most relevant to task groups..."],
      "highlightScores": [0.95],
      "prunedContext": "## Task Groups\n\n..."
    }
  ],
  "costDollars": {"total": 0.001}
}

Response headers

HeaderMeaning
X-Credits-RemainingOn every billable response: free requests left today for keyless calls, credits left for a paid key.

Errors

StatusBodyWhen
400{"error": "url_not_allowed"}The URL is not public http(s): private, loopback, link-local and similar addresses are rejected, also after redirects.
401{"error": "invalid_api_key"}The key is unknown.
402{"error": "insufficient_credits" | "keyless_limit", "message": "...", "checkout_url": "...", "pricing": {...}, "packs": [...], "action": {"type": "payment_link", "url": "https://api.contextfetch.dev/buy/instant", "prompt_to_user": "..."}}Out of credits, or the keyless allowance is used up. Also sends X-Payment-URL.
422-Request validation failed, e.g. a query over 2,000 characters or a threshold outside 100 to 100,000.

POST/v1/findSimilar

Credits: 1Also at: /findSimilar

Scrapes the URL, extracts its topic terms and searches outside its domain. Same response shape as /search.

Parameters

NameInTypeRequiredDescription
urlbodystringyesPublic http(s) URL.
numResults / num_resultsbodyintnoDefault 10, capped at 25.
includeDomains / include_domainsbodystring[]noOnly return results from these domains.
excludeDomains / exclude_domainsbodystring[]noNever return results from these domains.
startPublishedDate / start_published_datebodyISO datenoOnly results published on or after this date.
contentsbodyobject | boolnotext, highlights and pruned_context (or prunedContext), each true/false or an options object as Exa SDKs send it. Omit it and results have no text, highlights or prunedContext.

Example request

curl -s https://api.contextfetch.dev/v1/findSimilar \  -H "Authorization: Bearer YOUR_API_KEY" \  -H "Content-Type: application/json" \  -d '{"url":"https://example.com/blog/vector-database-benchmarks","numResults":5,"contents":{"text":true,"highlights":true}}'

Example response

{
  "requestId": "4f9d2c0e8b5a4b0f9a1e6c2d7b3f8a10",
  "results": [
    {
      "id": "0b6f3c1e-5d2a-5f4b-9c8e-7a1d2e3f4b5c",
      "url": "https://example.com/blog/vector-database-benchmarks",
      "title": "Vector database benchmarks",
      "score": 0.93,
      "publishedDate": "2026-02-11",
      "text": "# Vector database benchmarks\n\nWe measured recall and p99 latency for...",
      "highlights": ["We measured recall and p99 latency for..."],
      "highlightScores": [0.97],
      "prunedContext": "We measured recall and p99 latency for..."
    }
  ],
  "costDollars": {"total": 0.001},
  "searchTimeMs": 412,
  "contextfetch": {"cache": "miss", "timingsMs": {...}, "tokens": {...}, "sources": {...}}
}

Response headers

HeaderMeaning
X-Credits-RemainingOn every billable response: free requests left today for keyless calls, credits left for a paid key.

Errors

StatusBodyWhen
400{"error": "url_not_allowed"}The URL is not public http(s): private, loopback, link-local and similar addresses are rejected, also after redirects.
401{"error": "invalid_api_key"}The key is unknown.
402{"error": "insufficient_credits" | "keyless_limit", "message": "...", "checkout_url": "...", "pricing": {...}, "packs": [...], "action": {"type": "payment_link", "url": "https://api.contextfetch.dev/buy/instant", "prompt_to_user": "..."}}Out of credits, or the keyless allowance is used up. Also sends X-Payment-URL.
422-Request validation failed, e.g. a query over 2,000 characters or a threshold outside 100 to 100,000.
502{"error": "fetch_failed", "message": "..."}The target page could not be fetched.

GET/r/{url}

Try it

Credits: 1

Any public URL as Markdown (text/markdown). Add ?q= to prune the page to the chunks relevant to a question.

Parameters

NameInTypeRequiredDescription
urlpathstringyesFull http(s) URL. GitHub blob URLs are read as raw files, arXiv PDFs as their HTML versions.
qquerystringnoQuestion or topic to prune to.

Example request

curl -si "https://api.contextfetch.dev/r/https://docs.python.org/3/library/asyncio-task.html?q=task+groups" \  -H "Authorization: Bearer YOUR_API_KEY"

Example response

HTTP/2 200
content-type: text/markdown; charset=utf-8
x-token-savings: 91.0
x-raw-tokens: 18240
x-output-tokens: 1650

## Task Groups
...

Response headers

HeaderMeaning
X-Token-SavingsPercent saved: Markdown vs raw HTML, or pruned vs full Markdown when q is given.
X-Raw-TokensTokens before, ceil(chars / 4).
X-Output-TokensTokens returned.
X-Credits-RemainingOn every billable response: free requests left today for keyless calls, credits left for a paid key.

Errors

StatusBodyWhen
400{"error": "url_not_allowed"}The URL is not public http(s): private, loopback, link-local and similar addresses are rejected, also after redirects.
401{"error": "invalid_api_key"}The key is unknown.
402{"error": "insufficient_credits" | "keyless_limit", "message": "...", "checkout_url": "...", "pricing": {...}, "packs": [...], "action": {"type": "payment_link", "url": "https://api.contextfetch.dev/buy/instant", "prompt_to_user": "..."}}Out of credits, or the keyless allowance is used up. Also sends X-Payment-URL.
502{"error": "fetch_failed", "message": "..."}The target page could not be fetched.

GET/v1/balance

Credits: 0

Credits left on a key, its auto-reload settings and the average credits used per day over the last 7 days. The key goes in a header only; ?key= is not accepted, so keys never reach access logs. MCP tool: contextfetch_balance.

Parameters

NameInTypeRequiredDescription
Authorization / x-api-keyheaderstringyesThe key to check.

Example request

curl -s https://api.contextfetch.dev/v1/balance -H "Authorization: Bearer YOUR_API_KEY"

Example response

{
  "credits": 14873,
  "auto_reload": {
    "enabled": true,
    "threshold": 1000,
    "pack": "builder",
    "monthly_max_usd": 500,
    "spent_this_month_usd": 50,
    "last_error": null
  },
  "burn_rate_per_day": 412
}

Errors

StatusBodyWhen
401{"error": "invalid_api_key"}The key is unknown.

POST/v1/billing/auto-reload

Credits: 0

Turn auto-reload on or off, or change it. After a deduction leaves the balance strictly below threshold, the card saved at checkout buys pack once, as long as this UTC month's auto-reload spend plus the pack price stays within monthly_max_usd. Credits arrive when the payment succeeds. A declined payment turns auto-reload off and sets last_error. Through the API a key can turn it off, lower values or change the pack, but monthly_max_usd can never go above $500; a higher cap needs the browser success page. MCP tool: contextfetch_auto_reload.

Parameters

NameInTypeRequiredDescription
Authorization / x-api-keyheaderstringyesThe key to change.
enabledbodyboolyestrue to turn auto-reload on, false to turn it off.
thresholdbodyintnoReload when credits drop below this. 100 to 100,000, default 1,000.
packbody"instant" | "builder" | "scale"noPack to buy on each reload, default builder.
monthly_max_usdbodynumbernoMonthly spending cap in USD, at most 500 through the API. Default 500.

Example request

curl -s https://api.contextfetch.dev/v1/billing/auto-reload \  -H "Authorization: Bearer YOUR_API_KEY" \  -H "Content-Type: application/json" \  -d '{"enabled":true,"threshold":1000,"pack":"builder","monthly_max_usd":500}'

Example response

{
  "credits": 14873,
  "auto_reload": {
    "enabled": true,
    "threshold": 1000,
    "pack": "builder",
    "monthly_max_usd": 500,
    "spent_this_month_usd": 50,
    "last_error": null
  },
  "burn_rate_per_day": 412
}

Errors

StatusBodyWhen
401{"error": "invalid_api_key"}The key is unknown.
409{"error": "no_payment_method", "message": "..."}Auto-reload requested for a key without a saved card. The message carries a buy link; buy with auto-reload on to save one.
422-Request validation failed, e.g. a query over 2,000 characters or a threshold outside 100 to 100,000.

GET/buy/{pack}

Credits: 0

A link for a human, not an API call: answers 303 straight to Stripe Checkout (card, Apple Pay, Google Pay) for instant ($15, 15,000 credits), builder ($50, 60,000 credits), scale ($150, 200,000 credits). After payment the browser lands on https://contextfetch.dev/success, which shows the key and copies it to the clipboard. Optional query parameters opt in to auto-reload and save the card for it.

Parameters

NameInTypeRequiredDescription
packpath"instant" | "builder" | "scale"yesPack to buy.
auto_reloadquery1noTurn auto-reload on and save the card. Off when omitted.
thresholdqueryintnoDefault 1,000.
reload_packquerystringnoDefault builder.
monthly_max_usdquerynumbernoDefault 500.

Example request

# Open in a browser, or show it to your human:https://api.contextfetch.dev/buy/builderhttps://api.contextfetch.dev/buy/builder?auto_reload=1&threshold=1000&reload_pack=builder&monthly_max_usd=500

Example response

HTTP/2 303
location: https://checkout.stripe.com/c/pay/cs_live_...

Errors

StatusBodyWhen
400{"error": "url_not_allowed"}The URL is not public http(s): private, loopback, link-local and similar addresses are rejected, also after redirects.
401{"error": "invalid_api_key"}The key is unknown.
402{"error": "insufficient_credits" | "keyless_limit", "message": "...", "checkout_url": "...", "pricing": {...}, "packs": [...], "action": {"type": "payment_link", "url": "https://api.contextfetch.dev/buy/instant", "prompt_to_user": "..."}}Out of credits, or the keyless allowance is used up. Also sends X-Payment-URL.
409{"error": "no_payment_method", "message": "..."}Auto-reload requested for a key without a saved card. The message carries a buy link; buy with auto-reload on to save one.
422-Request validation failed, e.g. a query over 2,000 characters or a threshold outside 100 to 100,000.
502{"error": "fetch_failed", "message": "..."}The target page could not be fetched.
503{"error": "recall_unavailable", "message": "..."}Web search backends are down; retry shortly.
432{"detail": {"error": "..."}}/tavily/* only: out of credits (Tavily's own status), with the same X-Payment-URL header. Other /tavily/* errors also use this body shape.

Rate limits

LimitValue
Keyless25 requests per IP per UTC day (IPv6: per /64). Failed keyless requests still count.
Paid keysNo per-second or per-minute rate limit; each call is limited only by the key's credits.
query1 to 2,000 characters.
numResults / max_resultsUp to 25.
/v1/contents URLsUp to 10 per call.
Domain filtersUp to 100 entries per list.
Request bodyUp to 1 MB.
Page fetcheshttp/https only, at most 5 redirects, 5 MB body, 15 s timeout.