{
  "schemaVersion": 1,
  "origin": "https://searchsdk.dev",
  "description": "Generated public documentation data. This searchSDK schema is not an MCP discovery standard. No credentials, live search results, or benchmark measurements.",
  "mcp": {
    "url": "https://searchsdk.dev/mcp",
    "aliasUrl": "https://searchsdk.dev/api/mcp",
    "protocolVersion": "2026-07-28",
    "guideUrl": "https://searchsdk.dev/docs/guides/mcp",
    "authentication": "none",
    "readOnly": true
  },
  "docs": [
    {
      "slug": "",
      "title": "Search, with the details intact.",
      "description": "Search anywhere, in your language. Twelve SDKs connect servers and apps to explicit provider APIs and traceable sources.",
      "url": "https://searchsdk.dev/docs",
      "markdownPath": "/docs/index.md",
      "markdownUrl": "https://searchsdk.dev/docs/index.md",
      "text": "# Search, with the details intact.\n\nSearch anywhere, in your language. Twelve SDKs connect servers and apps to explicit provider APIs and traceable sources.\n\nCanonical: https://searchsdk.dev/docs\nMarkdown: https://searchsdk.dev/docs/index.md\n\n<a id=\"one-search-contract\"></a>\n\n## Choose your language, keep your sources\n\nUse TypeScript, Python, Go, Java, Rust, C#, C or C++ on your server. Connect Swift, Android, React Native or Expo apps through your application gateway. Normalized web search shares query, result and provenance semantics; provider-native operations remain a separate surface.\n\n- [Choose your SDK](https://searchsdk.dev/docs/sdks): Installation, first search and exact support for all twelve packages.\n- [Connect a mobile or browser app](https://searchsdk.dev/docs/guides/application-gateway): Keep provider credentials and policy behind your server.\n\n<a id=\"choose-your-path\"></a>\n\n## Choose your path\n\n- [Install the SDK](https://searchsdk.dev/docs/installation): Build and install the alpha for your language.\n- [Run without a key](https://searchsdk.dev/docs/quickstart#try-without-credentials): Use deterministic local fixtures.\n- [Explore all providers](https://searchsdk.dev/docs/providers): See normalized support and native boundaries.\n- [Handle failures deliberately](https://searchsdk.dev/docs/reliability/fallback): Set an ordered fallback chain and bounded deadlines.\n\n<a id=\"what-is-verified\"></a>\n\n## Web results and native operations\n\nNormalized search is a deliberately narrow surface. Provider-native clients preserve different operations and response shapes; their documentation is separate. A search snippet, an extracted page, a generated answer, and a corpus passage carry different meaning.\n\n- [Verification and limits](https://searchsdk.dev/docs/reliability/verification)\n"
    },
    {
      "slug": "quickstart",
      "title": "Your first TypeScript search",
      "description": "Run a key-free fixture in Node, then configure a real provider. Other SDKs have their own first-search guides.",
      "url": "https://searchsdk.dev/docs/quickstart",
      "markdownPath": "/docs/quickstart.md",
      "markdownUrl": "https://searchsdk.dev/docs/quickstart.md",
      "text": "# Your first TypeScript search\n\nRun a key-free fixture in Node, then configure a real provider. Other SDKs have their own first-search guides.\n\nCanonical: https://searchsdk.dev/docs/quickstart\nMarkdown: https://searchsdk.dev/docs/quickstart.md\n\n<a id=\"try-without-credentials\"></a>\n\n## Try without credentials\n\n> **TypeScript reference**\n> The API names, code and policy behavior in this article describe the TypeScript SDK. See [your language guide](https://searchsdk.dev/docs/sdks) for its supported surface and limits.\n\n[Build and install the TypeScript artifact](https://searchsdk.dev/docs/sdks/typescript#install), or [choose another language](https://searchsdk.dev/docs/sdks). Save the following example as `first-search.mjs` in your server application, then run `node first-search.mjs` on Node 24. It uses plain ESM JavaScript and needs no compiler. For an immediate browser demo, [open the playground](https://searchsdk.dev/playground) and choose “Demo · no key”.\n\n**first-search.mjs · fixture**\n\n```typescript\nimport { createSearch } from '@belweave/search-sdk';\nimport { createMockProvider } from '@belweave/search-sdk/testing';\n\nconst provider = createMockProvider();\nconst client = createSearch({ provider });\nconst response = await client.web.search({ query: 'SQLite concurrency' });\n\nconsole.log(response.results); // Fixed example-domain fixtures\nconsole.log(provider.calls.length); // 1; no network requests\n```\n\nThe mock returns three fixed example-domain results and performs no outbound requests. This validates your application integration, not a provider's retrieval quality.\n\n<a id=\"connect-context\"></a>\n\n## Connect Context.dev\n\nSave this example as `search.mjs`. Configure `CONTEXT_API_KEY` in a server-only environment or [local .env file](https://searchsdk.dev/docs/installation#server-credentials), then run `node --env-file=.env search.mjs`. With a production-injected environment, use `node search.mjs`. This makes a real provider request and may incur charges.\n\n**search.mjs · server**\n\n```typescript\nimport { createSearch } from '@belweave/search-sdk';\nimport { context } from '@belweave/search-sdk/context';\n\nconst apiKey = process.env.CONTEXT_API_KEY;\nif (!apiKey) throw new Error('CONTEXT_API_KEY is required');\n\nconst client = createSearch({\n  provider: context({ apiKey }),\n  timeoutMs: 10_000,\n});\n\nconst response = await client.web.search({\n  query: 'SQLite write concurrency',\n  limit: 5,\n});\n\nfor (const result of response.results) {\n  console.log(result.title ?? result.url, result.url);\n}\nconsole.log(response.provider, response.attempts);\n```\n\nThe same ESM example can be saved as `search.ts` and run directly with Node 24 in a type: module project. Missing, blank, or invalid keys must be resolved through your provider account. A configured factory is not proof that the key is valid.\n\n<a id=\"read-the-response\"></a>\n\n## Read the response\n\n- `results` contains up to your requested limit in provider order.\n- `provider` identifies the winning provider. Every result also has its own `provenance`.\n- `attempts` records successes and failures. `warnings` uses stable SDK codes.\n- `usage` is provider-reported usage from the winner, or `null` when unknown.\n\n> **Context.dev result count**\n> Context requests at least ten native results to satisfy conflicting provider documents, then caps the SDK output. Trimmed results can still affect reported credits.\n\n<a id=\"next-step\"></a>\n\n## Add one policy at a time\n\n- [Filter by domain](https://searchsdk.dev/docs/guides/domain-filters)\n- [Configure explicit fallback](https://searchsdk.dev/docs/reliability/fallback)\n- [Connect a different provider](https://searchsdk.dev/docs/providers)\n"
    },
    {
      "slug": "concepts",
      "title": "The retrieval model",
      "description": "Understand what is shared, what stays native, and where evidence comes from.",
      "url": "https://searchsdk.dev/docs/concepts",
      "markdownPath": "/docs/concepts.md",
      "markdownUrl": "https://searchsdk.dev/docs/concepts.md",
      "text": "# The retrieval model\n\nUnderstand what is shared, what stays native, and where evidence comes from.\n\nCanonical: https://searchsdk.dev/docs/concepts\nMarkdown: https://searchsdk.dev/docs/concepts.md\n\n<a id=\"normalized-and-native\"></a>\n\n## Normalized and native\n\nNormalized search offers a portable vocabulary for a small shared operation. Provider-native APIs preserve a provider's own arguments, job models, streaming events, and returned data. Choose a surface based on the operation you need, rather than assuming that a similar name implies identical behavior.\n\n<a id=\"four-kinds-of-material\"></a>\n\n## Four kinds of material\n\n| Material | Interpretation |\n| --- | --- |\n| Search result | A ranked source link with provider search text. |\n| Extracted content | Content retrieved for a known page, with its own extraction outcome. |\n| Generated answer | A synthesis that requires separate source and claim handling. |\n| Corpus passage | A span from an ingested document; document and revision identity matter. |\n\nWonderSearch.ai and WonderSearch.com refer to one corpus candidate. Corpus passage IDs are not web source URLs and should never be fabricated into normalized web results.\n\n<a id=\"provider-differences\"></a>\n\n## Provider differences remain visible\n\n- Native scores are preserved when available. They are not a common relevance scale.\n- A result ceiling does not promise an exact count or multiple pages.\n- Provider-native hostname semantics still apply after request validation.\n- An absent usage value is unknown, rather than free.\n"
    },
    {
      "slug": "sdks",
      "title": "Choose your SDK",
      "description": "Search from your server, browser or mobile app. Choose one of twelve SDKs and see exactly which surface it supports.",
      "url": "https://searchsdk.dev/docs/sdks",
      "markdownPath": "/docs/sdks.md",
      "markdownUrl": "https://searchsdk.dev/docs/sdks.md",
      "text": "# Choose your SDK\n\nSearch from your server, browser or mobile app. Choose one of twelve SDKs and see exactly which surface it supports.\n\nCanonical: https://searchsdk.dev/docs/sdks\nMarkdown: https://searchsdk.dev/docs/sdks.md\n\n<a id=\"server-sdks\"></a>\n\n## Server SDKs\n\nUse direct provider adapters for normalized web results, or a separate native client for provider-specific operations. The server SDKs cover 14 normalized adapters and 493 retained native operation bindings across 13 providers. Provider credentials stay in your server process.\n\n- [TypeScript / JavaScript](https://searchsdk.dev/docs/sdks/typescript): Node 24.22.1+ within Node 24, or Node 26.12.1+ within Node 26. Direct provider APIs.\n- [Python](https://searchsdk.dev/docs/sdks/python): Python 3.11+. Direct provider APIs.\n- [Go](https://searchsdk.dev/docs/sdks/go): Go 1.23+. Direct provider APIs.\n- [Java](https://searchsdk.dev/docs/sdks/java): Java 17+. Direct provider APIs.\n- [Rust](https://searchsdk.dev/docs/sdks/rust): Rust / Cargo 1.98+. Direct provider APIs.\n- [C# / .NET](https://searchsdk.dev/docs/sdks/dotnet): .NET 10. Direct provider APIs.\n- [C](https://searchsdk.dev/docs/sdks/c): C11 / POSIX; libcurl 7.85+ for HTTPS. Direct provider APIs.\n- [C++](https://searchsdk.dev/docs/sdks/cpp): C++17 over the C11 / POSIX ABI. Direct provider APIs.\n\n<a id=\"app-sdks\"></a>\n\n## App SDKs\n\nSwift, Android, React Native and Expo send normalized requests to your application's HTTPS gateway. They preserve sources, attempt metadata, deadlines and cancellation while keeping provider keys off the device. Expo also has a browser entry. Provider choice, fallback and native operations remain server-side.\n\n- [Swift](https://searchsdk.dev/docs/sdks/swift): Swift 6 · iOS 16+ · macOS 13+ · tvOS 16+ · watchOS 9+ · visionOS 1+. Application gateway client.\n- [Android / Kotlin](https://searchsdk.dev/docs/sdks/android): Android API 26+. Application gateway client.\n- [React Native](https://searchsdk.dev/docs/sdks/react-native): React Native · iOS 15.1+ · Android API 24+. Application gateway client.\n- [Expo](https://searchsdk.dev/docs/sdks/expo): Expo SDK 55–57 · native development builds and web. Application gateway client.\n\n- [Build your application gateway](https://searchsdk.dev/docs/guides/application-gateway): Connect an app SDK to a server with explicit authorization.\n\n<a id=\"availability\"></a>\n\n## Alpha availability\n\nAll twelve SDKs are alpha source packages. Install from a reviewed checkout or its locally built artifacts. Package names and versions describe those artifacts; they do not establish availability in npm, PyPI, Maven Central, crates.io, NuGet or a release tag. Alpha APIs may change. Record the source revision and retain your application's dependency lock.\n\n**Get the source**\n\n```bash\ngit clone https://github.com/Belweave/searchSDK.git\ncd searchSDK\n# Record this revision with your application's dependency lock.\ngit rev-parse HEAD\n```\n\nFollow the selected SDK's installation guide next. Each language uses its own toolchain; Node is required for the TypeScript/mobile JavaScript packages and repository tooling, not every SDK runtime.\n\n<a id=\"shared-contract\"></a>\n\n## Shared contract, explicit differences\n\n| Surface | What you can rely on |\n| --- | --- |\n| Normalized search | A bounded query/result contract, source provenance, provider order, explicit capabilities and sanitized errors. |\n| Native clients | Provider-specific operation and wire models from retained public source tables and schemas. These bindings are not every upstream endpoint. |\n| App gateway | Application-owned HTTPS, request-scoped application tokens, validated normalized responses and no automatic POST retries. |\n| Language policy | Read the selected SDK's guide for async style, streaming, retry limits, caching and platform coverage. APIs and policies are not identical across languages. |\n\nValyu and SearXNG have normalized adapters; WonderSearch is native corpus retrieval. Use the provider catalog to choose a supported operation. Custom server adapters are the extension point for a provider that is not in the built-in set.\n\n- [Provider capabilities](https://searchsdk.dev/docs/providers)\n- [Extend provider support](https://searchsdk.dev/docs/api/providers#trust)\n\n<a id=\"verification\"></a>\n\n## What has been verified\n\nEach package includes deterministic tests and a consumer that uses its built artifact. The guides distinguish executed runtime checks from source/type or compilation checks. Fixtures and local HTTPS servers do not establish live provider availability, account access, pricing or retrieval quality.\n\n- [Package verification and platform details](https://github.com/Belweave/searchSDK/tree/main/packages#readme)\n- [Verification limits](https://searchsdk.dev/docs/reliability/verification)\n"
    },
    {
      "slug": "installation",
      "title": "Install an SDK",
      "description": "Choose a language, install from source or a local artifact, and keep provider execution on your server.",
      "url": "https://searchsdk.dev/docs/installation",
      "markdownPath": "/docs/installation.md",
      "markdownUrl": "https://searchsdk.dev/docs/installation.md",
      "text": "# Install an SDK\n\nChoose a language, install from source or a local artifact, and keep provider execution on your server.\n\nCanonical: https://searchsdk.dev/docs/installation\nMarkdown: https://searchsdk.dev/docs/installation.md\n\n<a id=\"install\"></a>\n\n## Choose a package\n\nAll twelve SDKs are alpha source packages. Install from a reviewed checkout or its locally built artifacts. Package names and versions describe those artifacts; they do not establish availability in npm, PyPI, Maven Central, crates.io, NuGet or a release tag. Alpha APIs may change. Record the source revision and retain your application's dependency lock.\n\n| Language / platform | Package | Installation guide |\n| --- | --- | --- |\n| TypeScript / JavaScript | `@belweave/search-sdk` | [Install TypeScript / JavaScript](https://searchsdk.dev/docs/sdks/typescript) |\n| Python | `searchsdk` | [Install Python](https://searchsdk.dev/docs/sdks/python) |\n| Go | `github.com/Belweave/searchSDK/packages/go` | [Install Go](https://searchsdk.dev/docs/sdks/go) |\n| Java | `dev.belweave:search-sdk` | [Install Java](https://searchsdk.dev/docs/sdks/java) |\n| Rust | `searchsdk` | [Install Rust](https://searchsdk.dev/docs/sdks/rust) |\n| C# / .NET | `SearchSdk` | [Install C# / .NET](https://searchsdk.dev/docs/sdks/dotnet) |\n| C | `searchsdk::searchsdk / searchsdk::curl` | [Install C](https://searchsdk.dev/docs/sdks/c) |\n| C++ | `searchsdk::cpp / searchsdk::cpp_curl` | [Install C++](https://searchsdk.dev/docs/sdks/cpp) |\n| Swift | `SearchSDK` | [Install Swift](https://searchsdk.dev/docs/sdks/swift) |\n| Android / Kotlin | `dev.searchsdk:searchsdk-android` | [Install Android / Kotlin](https://searchsdk.dev/docs/sdks/android) |\n| React Native | `@belweave/search-sdk-react-native` | [Install React Native](https://searchsdk.dev/docs/sdks/react-native) |\n| Expo | `@belweave/search-sdk-expo` | [Install Expo](https://searchsdk.dev/docs/sdks/expo) |\n\n<a id=\"requirements\"></a>\n\n## Use the matching toolchain\n\nStart with the language guide's minimum runtime and dependency requirements. The TypeScript SDK is ESM and dependency-free at runtime. Other packages have their own dependency contracts: for example, Rust uses Tokio/Reqwest/Serde and Android uses coroutines/OkHttp. A zero-dependency claim for one SDK does not apply to all of them.\n\n<a id=\"server-credentials\"></a>\n\n## Configure credentials at the right boundary\n\nDirect provider credentials belong in server secret configuration. Mobile and browser applications use your own authenticated gateway with application tokens. Never put a provider key in a client bundle, device storage, chat or logs.\n\n- [TypeScript server environment setup](https://searchsdk.dev/docs/sdks/typescript#server-credentials)\n- [Application gateway setup](https://searchsdk.dev/docs/guides/application-gateway)\n\n<a id=\"pack-locally\"></a>\n\n## Build from a reviewed checkout\n\n**Source checkout**\n\n```bash\ngit clone https://github.com/Belweave/searchSDK.git\ncd searchSDK\n# Record this revision with your application's dependency lock.\ngit rev-parse HEAD\n```\n\nUse the selected language's packaging command. Building an archive, installing it locally, pushing a Git commit, deploying the website and publishing a registry package are separate operations.\n"
    },
    {
      "slug": "sdks/typescript",
      "title": "searchSDK for TypeScript and JavaScript",
      "description": "ESM with declarations, zero runtime dependencies, direct provider APIs and an application gateway handler for Node servers.",
      "url": "https://searchsdk.dev/docs/sdks/typescript",
      "markdownPath": "/docs/sdks/typescript.md",
      "markdownUrl": "https://searchsdk.dev/docs/sdks/typescript.md",
      "text": "# searchSDK for TypeScript and JavaScript\n\nESM with declarations, zero runtime dependencies, direct provider APIs and an application gateway handler for Node servers.\n\nCanonical: https://searchsdk.dev/docs/sdks/typescript\nMarkdown: https://searchsdk.dev/docs/sdks/typescript.md\n\n<a id=\"requirements\"></a>\n\n## Requirements\n\n- Use Node 24.22.1 or a newer patched Node 24 release. The SDK is ESM with TypeScript declarations and zero runtime dependencies.\n- Use ESM imports in .mjs or a project with type: module; CommonJS callers can use dynamic import().\n- This alpha is distributed as source and locally built artifacts. Public npm availability is not assumed. Record the reviewed source revision and commit your application lockfile.\n\n<a id=\"install\"></a>\n\n## Install\n\n**Terminal**\n\n```bash\ngit clone https://github.com/Belweave/searchSDK.git\ncd searchSDK\nnvm use\nnpm ci\nnpm run build:sdk\nnpm pack -w @belweave/search-sdk\n\n# In your Node server application:\nnpm install /absolute/path/searchSDK/belweave-search-sdk-0.1.0-alpha.0.tgz\n```\n\nRun the build commands in the source checkout, then install the resulting tarball in your application. For a new application, run `npm init --yes` first. For TypeScript files run directly with Node 24, set `type: module` with `npm pkg set type=module`. The artifact version is `0.1.0-alpha.0`; this version alone does not prove the artifact includes the latest gateway changes. Record its source revision.\n\n<a id=\"server-credentials\"></a>\n\n## Configure server credentials\n\nStore provider keys in your application's server secret store or server environment. The SDK accepts keys explicitly; it does not load environment files or read environment variables itself.\n\n**credentials.ts · server**\n\n```typescript\nconst apiKey = process.env.CONTEXT_API_KEY;\nif (!apiKey) throw new Error('CONTEXT_API_KEY is required');\n```\n\nFor local development, add `.env` to your server project's `.gitignore`, then put `CONTEXT_API_KEY=your-provider-key` in that local file. Run your server example with `node --env-file=.env search.ts`. Node loads the file; the SDK does not. In production, inject `CONTEXT_API_KEY` through your host's server secret configuration.\n\nDo not prefix provider credentials with `VITE_` or another public environment prefix. The hosted playground accepts request-scoped keys and calls providers from its server. The separate key-free demo uses fixtures. Call your own authenticated server route when building a browser application.\n\n<a id=\"imports\"></a>\n\n## Choose the right import\n\n| Import | Purpose |\n| --- | --- |\n| `@belweave/search-sdk` | `createSearch`, `SearchError`, and public normalized types |\n| `@belweave/search-sdk/context` | Context.dev adapter and provider-specific exports |\n| `@belweave/search-sdk/tinyfish` | TinyFish adapter and provider-specific exports |\n| `@belweave/search-sdk/testing` | `createMockProvider` and fixture types |\n\n- [Make your first request](https://searchsdk.dev/docs/quickstart)\n\n<a id=\"pack-locally\"></a>\n\n## Rebuild the source artifact\n\nRebuild the local tarball when you change the SDK source. Use the checkout's `.nvmrc` and locked dependencies. This command does not publish the package.\n\n**Source checkout · terminal**\n\n```bash\ngit clone https://github.com/Belweave/searchSDK.git\ncd searchSDK\nnvm use\nnpm ci\nnpm run build:sdk\nnpm pack -w @belweave/search-sdk\n\n# In your server application, use the actual generated tarball:\nnpm install /absolute/path/belweave-search-sdk-0.1.0-alpha.0.tgz\n```\n"
    },
    {
      "slug": "sdks/python",
      "title": "searchSDK for Python",
      "description": "Python 3.11+. 14 normalized web-search adapters and 493 retained native bindings across 13 providers; gateway client.",
      "url": "https://searchsdk.dev/docs/sdks/python",
      "markdownPath": "/docs/sdks/python.md",
      "markdownUrl": "https://searchsdk.dev/docs/sdks/python.md",
      "text": "# searchSDK for Python\n\nPython 3.11+. 14 normalized web-search adapters and 493 retained native bindings across 13 providers; gateway client.\n\nCanonical: https://searchsdk.dev/docs/sdks/python\nMarkdown: https://searchsdk.dev/docs/sdks/python.md\n\n<a id=\"install\"></a>\n\n## Install from source\n\nPackage: `searchsdk`, version `0.1.0a0`. This is an alpha source/local-artifact installation. No public registry release or release tag is assumed.\n\n**Get the source**\n\n```bash\ngit clone https://github.com/Belweave/searchSDK.git\ncd searchSDK\n# Record this revision with your application's dependency lock.\ngit rev-parse HEAD\n```\n\n**Build or install the local package**\n\n```bash\npython3 -m venv .venv\n.venv/bin/python -m pip install ./packages/python\n```\n\nRun from the source checkout. pip builds and installs the local Python package. Its build tools are separate from the dependency-free package runtime. Use this virtual environment for the example.\n\n<a id=\"first-search\"></a>\n\n## Make a server-side search\n\nSet provider keys in your application's server environment or secret store. The example below makes a real provider request when invoked and can incur charges. Use the package's fixture consumer for a key-free check.\n\n**search.py**\n\n```python\nimport os\nfrom searchsdk import SearchClient, SearchRequest, exa\n\nsearch = SearchClient(\n    exa(os.environ[\"EXA_API_KEY\"]),\n    timeout_ms=10_000,\n)\nresponse = search.search(SearchRequest(\n    \"SQLite write concurrency\", limit=3,\n))\nfor result in response.results:\n    print(result.url, result.provenance.provider)\n```\n\nSet EXA_API_KEY in the server environment, then run .venv/bin/python search.py. Async search and batches are also available. A real request can incur provider charges.\n\n<a id=\"scope\"></a>\n\n## Supported surface and limits\n\n14 normalized web-search adapters and 493 retained native bindings across 13 providers; gateway client.\n\n- No successful-result cache, in-flight deduplication or durable workflow store in this alpha.\n- Async methods use standard-library workers. Cancellation cannot forcibly terminate custom providers that ignore it.\n\nPreserve result order, provider-native scores and source provenance. Unknown usage is not zero cost. Cancellation and deadlines cannot undo a request already accepted by a remote system or guarantee exactly-once effects.\n\n<a id=\"verify\"></a>\n\n## Verify without provider keys\n\n**Repository checkout · local checks**\n\n```bash\npython3 -m venv packages/python/.build/verify\npackages/python/.build/verify/bin/python -m pip install -r packages/python/requirements-dev.txt\npackages/python/.build/verify/bin/python packages/python/scripts/verify.py\n```\n\nPython 3.11 and 3.15, generated types, fixtures, wheel and source-distribution consumers.\n\nThese are deterministic contract and artifact checks. They do not establish live-provider or account-entitlement verification. Read the package README for precise commands, dependencies and runtime coverage.\n\n<a id=\"next\"></a>\n\n## Continue in your language\n\n- [Python package reference](https://github.com/Belweave/searchSDK/tree/main/packages/python#readme): Complete API, errors, streaming, packaging and platform boundaries.\n- [Compare SDKs](https://searchsdk.dev/docs/sdks)\n- [Choose a provider](https://searchsdk.dev/docs/providers)\n"
    },
    {
      "slug": "sdks/go",
      "title": "searchSDK for Go",
      "description": "Go 1.23+. 14 normalized web-search adapters and 493 retained native bindings across 13 providers; gateway client.",
      "url": "https://searchsdk.dev/docs/sdks/go",
      "markdownPath": "/docs/sdks/go.md",
      "markdownUrl": "https://searchsdk.dev/docs/sdks/go.md",
      "text": "# searchSDK for Go\n\nGo 1.23+. 14 normalized web-search adapters and 493 retained native bindings across 13 providers; gateway client.\n\nCanonical: https://searchsdk.dev/docs/sdks/go\nMarkdown: https://searchsdk.dev/docs/sdks/go.md\n\n<a id=\"install\"></a>\n\n## Install from source\n\nPackage: `github.com/Belweave/searchSDK/packages/go`, version `0.1.0-alpha.1`. This is an alpha source/local-artifact installation. No public registry release or release tag is assumed.\n\n**Get the source**\n\n```bash\ngit clone https://github.com/Belweave/searchSDK.git\ncd searchSDK\n# Record this revision with your application's dependency lock.\ngit rev-parse HEAD\n```\n\n**Build or install the local package**\n\n```bash\n# In your application's existing Go module, for a local checkout:\ngo mod edit -require=github.com/Belweave/searchSDK/packages/go@v0.0.0\ngo mod edit -replace=github.com/Belweave/searchSDK/packages/go=/absolute/path/searchSDK/packages/go\ngo mod tidy\n```\n\nAdd the import shown below before go mod tidy. This local replace is a development installation, not a published module version. Future release tags must use the packages/go/v prefix. The module uses only the standard library.\n\n<a id=\"first-search\"></a>\n\n## Make a server-side search\n\nSet provider keys in your application's server environment or secret store. The example below makes a real provider request when invoked and can incur charges. Use the package's fixture consumer for a key-free check.\n\n**main.go**\n\n```go\npackage main\n\nimport (\n    \"context\"\n    \"fmt\"\n    \"log\"\n    \"os\"\n    \"time\"\n    searchsdk \"github.com/Belweave/searchSDK/packages/go\"\n)\n\nfunc main() {\n    provider, err := searchsdk.NewAdapter(\"exa\", searchsdk.AdapterOptions{\n        APIKey: os.Getenv(\"EXA_API_KEY\"),\n    })\n    if err != nil { log.Fatal(err) }\n    search, err := searchsdk.New(searchsdk.Config{Provider: provider})\n    if err != nil { log.Fatal(err) }\n    ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)\n    defer cancel()\n    response, err := search.Search(ctx, searchsdk.Request{\n        Query: \"SQLite write concurrency\", Limit: 3,\n    })\n    if err != nil { log.Fatal(err) }\n    fmt.Println(response.Results)\n}\n```\n\nSet EXA_API_KEY on your server and run go run . from the application module. Keep context cancellation tied to the incoming request in a service.\n\n<a id=\"scope\"></a>\n\n## Supported surface and limits\n\n14 normalized web-search adapters and 493 retained native bindings across 13 providers; gateway client.\n\n- No cache, deduplication or automatic side-effect recovery.\n- Custom providers and RoundTrippers must honor context.Context; the SDK does not hide uncooperative work in detached workers.\n\nPreserve result order, provider-native scores and source provenance. Unknown usage is not zero cost. Cancellation and deadlines cannot undo a request already accepted by a remote system or guarantee exactly-once effects.\n\n<a id=\"verify\"></a>\n\n## Verify without provider keys\n\n**Repository checkout · local checks**\n\n```bash\ngo -C packages/go test -race -p 2 ./...\ngo -C packages/go vet -p 2 ./...\npython3 -B packages/go/internal/verify_consumer.py\n```\n\nGo 1.23 and 1.27 race checks and an external consumer resolving a local module-proxy ZIP without replace.\n\nThese are deterministic contract and artifact checks. They do not establish live-provider or account-entitlement verification. Read the package README for precise commands, dependencies and runtime coverage.\n\n<a id=\"next\"></a>\n\n## Continue in your language\n\n- [Go package reference](https://github.com/Belweave/searchSDK/tree/main/packages/go#readme): Complete API, errors, streaming, packaging and platform boundaries.\n- [Compare SDKs](https://searchsdk.dev/docs/sdks)\n- [Choose a provider](https://searchsdk.dev/docs/providers)\n"
    },
    {
      "slug": "sdks/java",
      "title": "searchSDK for Java",
      "description": "Java 17+. 14 normalized web-search adapters and 493 retained native bindings across 13 providers; gateway client.",
      "url": "https://searchsdk.dev/docs/sdks/java",
      "markdownPath": "/docs/sdks/java.md",
      "markdownUrl": "https://searchsdk.dev/docs/sdks/java.md",
      "text": "# searchSDK for Java\n\nJava 17+. 14 normalized web-search adapters and 493 retained native bindings across 13 providers; gateway client.\n\nCanonical: https://searchsdk.dev/docs/sdks/java\nMarkdown: https://searchsdk.dev/docs/sdks/java.md\n\n<a id=\"install\"></a>\n\n## Install from source\n\nPackage: `dev.belweave:search-sdk`, version `0.1.0-alpha.0`. This is an alpha source/local-artifact installation. No public registry release or release tag is assumed.\n\n**Get the source**\n\n```bash\ngit clone https://github.com/Belweave/searchSDK.git\ncd searchSDK\n# Record this revision with your application's dependency lock.\ngit rev-parse HEAD\n```\n\n**Build or install the local package**\n\n```bash\nmvn -T 2 -f packages/java/pom.xml install\n\n# Add this dependency to your application's pom.xml:\n# groupId: dev.belweave\n# artifactId: search-sdk\n# version: 0.1.0-alpha.0\n```\n\nMaven install writes to your local Maven repository. It does not publish to Maven Central. The JAR's automatic module is dev.searchsdk, and it has no runtime dependencies. Use Maven 3.9+ and JDK 17+.\n\n<a id=\"first-search\"></a>\n\n## Make a server-side search\n\nSet provider keys in your application's server environment or secret store. The example below makes a real provider request when invoked and can incur charges. Use the package's fixture consumer for a key-free check.\n\n**SearchExample.java**\n\n```java\nimport dev.searchsdk.*;\nimport java.time.Duration;\n\npublic class SearchExample {\n    public static void main(String[] args) {\n        var search = SearchClient.builder(\n            Providers.exa(System.getenv(\"EXA_API_KEY\")))\n            .timeout(Duration.ofSeconds(10))\n            .build();\n        var response = search.search(new SearchRequest(\n            \"SQLite write concurrency\", 3\n        )).toCompletableFuture().join();\n        for (var result : response.results()) {\n            System.out.println(result.url());\n        }\n    }\n}\n```\n\nAdd the local Maven dependency, set EXA_API_KEY in the server environment and run this class with that dependency on the classpath. The service API returns CompletionStage.\n\n<a id=\"scope\"></a>\n\n## Supported surface and limits\n\n14 normalized web-search adapters and 493 retained native bindings across 13 providers; gateway client.\n\n- Compressed HTTP responses are rejected by this alpha transport.\n- Native wire models do not enforce every JSON Schema constraint or establish provider account entitlement.\n\nPreserve result order, provider-native scores and source provenance. Unknown usage is not zero cost. Cancellation and deadlines cannot undo a request already accepted by a remote system or guarantee exactly-once effects.\n\n<a id=\"verify\"></a>\n\n## Verify without provider keys\n\n**Repository checkout · local checks**\n\n```bash\nbash packages/java/scripts/verify.sh\nbash packages/java/scripts/verify-maven.sh\n```\n\nJDK 17, 21, 25 and 27; packed classpath/module consumers and a separate Maven consumer.\n\nThese are deterministic contract and artifact checks. They do not establish live-provider or account-entitlement verification. Read the package README for precise commands, dependencies and runtime coverage.\n\n<a id=\"next\"></a>\n\n## Continue in your language\n\n- [Java package reference](https://github.com/Belweave/searchSDK/tree/main/packages/java#readme): Complete API, errors, streaming, packaging and platform boundaries.\n- [Compare SDKs](https://searchsdk.dev/docs/sdks)\n- [Choose a provider](https://searchsdk.dev/docs/providers)\n"
    },
    {
      "slug": "sdks/rust",
      "title": "searchSDK for Rust",
      "description": "Rust / Cargo 1.98+. 14 normalized web-search adapters and 493 retained native bindings across 13 providers; gateway client.",
      "url": "https://searchsdk.dev/docs/sdks/rust",
      "markdownPath": "/docs/sdks/rust.md",
      "markdownUrl": "https://searchsdk.dev/docs/sdks/rust.md",
      "text": "# searchSDK for Rust\n\nRust / Cargo 1.98+. 14 normalized web-search adapters and 493 retained native bindings across 13 providers; gateway client.\n\nCanonical: https://searchsdk.dev/docs/sdks/rust\nMarkdown: https://searchsdk.dev/docs/sdks/rust.md\n\n<a id=\"install\"></a>\n\n## Install from source\n\nPackage: `searchsdk`, version `0.1.0-alpha.1`. This is an alpha source/local-artifact installation. No public registry release or release tag is assumed.\n\n**Get the source**\n\n```bash\ngit clone https://github.com/Belweave/searchSDK.git\ncd searchSDK\n# Record this revision with your application's dependency lock.\ngit rev-parse HEAD\n```\n\n**Application dependency configuration**\n\n```toml\n[dependencies]\nsearchsdk = { path = \"/absolute/path/searchSDK/packages/rust\" }\ntokio = { version = \"=1.53.1\", features = [\"rt\", \"macros\"] }\n```\n\nAdd these entries to your application's Cargo.toml. This uses the source checkout, not a crates.io release. The SDK uses Tokio, Reqwest with rustls, and Serde; retain Cargo.lock.\n\n<a id=\"first-search\"></a>\n\n## Make a server-side search\n\nSet provider keys in your application's server environment or secret store. The example below makes a real provider request when invoked and can incur charges. Use the package's fixture consumer for a key-free check.\n\n**src/main.rs**\n\n```rust\nuse searchsdk::{Provider, ProviderId, SearchClient, SearchRequest, CallOptions};\n\n#[tokio::main(flavor = \"current_thread\")]\nasync fn main() -> Result<(), Box<dyn std::error::Error>> {\n    let key = std::env::var(\"EXA_API_KEY\")?;\n    let search = SearchClient::new(Provider::new(ProviderId::Exa, key)?)?;\n    let response = search.search(\n        SearchRequest::new(\"SQLite write concurrency\"),\n        CallOptions::default(),\n    ).await?;\n    for result in response.results {\n        println!(\"{}\", result.url);\n    }\n    Ok(())\n}\n```\n\nSet EXA_API_KEY on the server, then cargo run. This request uses the default result limit of five; no network request runs during compilation.\n\n<a id=\"scope\"></a>\n\n## Supported surface and limits\n\n14 normalized web-search adapters and 493 retained native bindings across 13 providers; gateway client.\n\n- Native schema models preserve provider fields but are not an exhaustive runtime JSON Schema validator.\n- Keep provider execution on servers; a Cargo build does not establish mobile, browser or WebAssembly support.\n\nPreserve result order, provider-native scores and source provenance. Unknown usage is not zero cost. Cancellation and deadlines cannot undo a request already accepted by a remote system or guarantee exactly-once effects.\n\n<a id=\"verify\"></a>\n\n## Verify without provider keys\n\n**Repository checkout · local checks**\n\n```bash\ncargo test --manifest-path packages/rust/Cargo.toml --locked -j 2\ncargo clippy --manifest-path packages/rust/Cargo.toml --locked -j 2 -- -D warnings\ncargo package --manifest-path packages/rust/Cargo.toml --locked\n```\n\n534 tests, formatting, Clippy, Cargo packaging and a consumer built from the extracted crate.\n\nThese are deterministic contract and artifact checks. They do not establish live-provider or account-entitlement verification. Read the package README for precise commands, dependencies and runtime coverage.\n\n<a id=\"next\"></a>\n\n## Continue in your language\n\n- [Rust package reference](https://github.com/Belweave/searchSDK/tree/main/packages/rust#readme): Complete API, errors, streaming, packaging and platform boundaries.\n- [Compare SDKs](https://searchsdk.dev/docs/sdks)\n- [Choose a provider](https://searchsdk.dev/docs/providers)\n"
    },
    {
      "slug": "sdks/dotnet",
      "title": "searchSDK for C# / .NET",
      "description": ".NET 10. 14 normalized web-search adapters and 493 retained native bindings across 13 providers; gateway client.",
      "url": "https://searchsdk.dev/docs/sdks/dotnet",
      "markdownPath": "/docs/sdks/dotnet.md",
      "markdownUrl": "https://searchsdk.dev/docs/sdks/dotnet.md",
      "text": "# searchSDK for C# / .NET\n\n.NET 10. 14 normalized web-search adapters and 493 retained native bindings across 13 providers; gateway client.\n\nCanonical: https://searchsdk.dev/docs/sdks/dotnet\nMarkdown: https://searchsdk.dev/docs/sdks/dotnet.md\n\n<a id=\"install\"></a>\n\n## Install from source\n\nPackage: `SearchSdk`, version `0.1.0-alpha.1`. This is an alpha source/local-artifact installation. No public registry release or release tag is assumed.\n\n**Get the source**\n\n```bash\ngit clone https://github.com/Belweave/searchSDK.git\ncd searchSDK\n# Record this revision with your application's dependency lock.\ngit rev-parse HEAD\n```\n\n**Build or install the local package**\n\n```bash\ndotnet pack packages/dotnet/src/SearchSdk/SearchSdk.csproj -c Release -o .local/nuget /m:2\n\n# In your .NET 10 application:\ndotnet add package SearchSdk --version 0.1.0-alpha.1 --source /absolute/path/searchSDK/.local/nuget\n```\n\nThis creates and consumes a local NuGet artifact. No public NuGet release is assumed. The SDK uses HttpClient and System.Text.Json with no runtime NuGet dependencies.\n\n<a id=\"first-search\"></a>\n\n## Make a server-side search\n\nSet provider keys in your application's server environment or secret store. The example below makes a real provider request when invoked and can incur charges. Use the package's fixture consumer for a key-free check.\n\n**Program.cs**\n\n```csharp\nusing SearchSdk;\n\nvar key = Environment.GetEnvironmentVariable(\"EXA_API_KEY\")\n    ?? throw new InvalidOperationException(\"EXA_API_KEY is required\");\nusing var transport = new SearchTransport(new() {\n    Timeout = TimeSpan.FromSeconds(10)\n});\nvar search = new SearchClient(new NormalizedProvider(\"exa\", key, transport));\nvar response = await search.SearchAsync(\n    new SearchRequest(\"SQLite write concurrency\", Limit: 3),\n    CancellationToken.None);\nforeach (var result in response.Results)\n    Console.WriteLine(result.Url);\n```\n\nSet EXA_API_KEY on your server and run dotnet run. In a service, pass the request's CancellationToken instead of CancellationToken.None. The caller owns the transport lifetime.\n\n<a id=\"scope\"></a>\n\n## Supported surface and limits\n\n14 normalized web-search adapters and 493 retained native bindings across 13 providers; gateway client.\n\n- NativeAOT and trimming are unverified. Only net10.0 is targeted.\n- No successful-result cache or in-flight deduplication in this alpha.\n\nPreserve result order, provider-native scores and source provenance. Unknown usage is not zero cost. Cancellation and deadlines cannot undo a request already accepted by a remote system or guarantee exactly-once effects.\n\n<a id=\"verify\"></a>\n\n## Verify without provider keys\n\n**Repository checkout · local checks**\n\n```bash\npackages/dotnet/scripts/verify.sh\n```\n\nLocked .NET 10 Release build, 5,126 assertions and a fresh consumer installed from the NuGet artifact.\n\nThese are deterministic contract and artifact checks. They do not establish live-provider or account-entitlement verification. Read the package README for precise commands, dependencies and runtime coverage.\n\n<a id=\"next\"></a>\n\n## Continue in your language\n\n- [C# / .NET package reference](https://github.com/Belweave/searchSDK/tree/main/packages/dotnet#readme): Complete API, errors, streaming, packaging and platform boundaries.\n- [Compare SDKs](https://searchsdk.dev/docs/sdks)\n- [Choose a provider](https://searchsdk.dev/docs/providers)\n"
    },
    {
      "slug": "sdks/c",
      "title": "searchSDK for C",
      "description": "C11 / POSIX; libcurl 7.85+ for HTTPS. 14 normalized web-search adapters and 493 retained native bindings across 13 providers; gateway client.",
      "url": "https://searchsdk.dev/docs/sdks/c",
      "markdownPath": "/docs/sdks/c.md",
      "markdownUrl": "https://searchsdk.dev/docs/sdks/c.md",
      "text": "# searchSDK for C\n\nC11 / POSIX; libcurl 7.85+ for HTTPS. 14 normalized web-search adapters and 493 retained native bindings across 13 providers; gateway client.\n\nCanonical: https://searchsdk.dev/docs/sdks/c\nMarkdown: https://searchsdk.dev/docs/sdks/c.md\n\n<a id=\"install\"></a>\n\n## Install from source\n\nPackage: `searchsdk::searchsdk / searchsdk::curl`, version `0.1.0-alpha.1`. This is an alpha source/local-artifact installation. No public registry release or release tag is assumed.\n\n**Get the source**\n\n```bash\ngit clone https://github.com/Belweave/searchSDK.git\ncd searchSDK\n# Record this revision with your application's dependency lock.\ngit rev-parse HEAD\n```\n\n**Build or install the local package**\n\n```bash\ncmake -S packages/c -B .local/c-build -DCMAKE_BUILD_TYPE=Release -DSEARCHSDK_TESTS=OFF\ncmake --build .local/c-build --parallel 2\ncmake --install .local/c-build --prefix \"$PWD/.local/c-install\"\n```\n\nUse find_package(searchsdk 0.1 CONFIG REQUIRED) and link searchsdk::curl for HTTPS. Point CMAKE_PREFIX_PATH at the installation prefix. The POSIX core can also use an injected transport; Windows is unsupported.\n\n<a id=\"first-search\"></a>\n\n## Make a server-side search\n\nSet provider keys in your application's server environment or secret store. The example below makes a real provider request when invoked and can incur charges. Use the package's fixture consumer for a key-free check.\n\n**search.c**\n\n```c\n#include <searchsdk/searchsdk.h>\n#include <searchsdk/curl.h>\n\n/* Call after curl_global_init; caller supplies a server-held key. */\nssk_code search_example(const char *key) {\n    ssk_config config;\n    ssk_config_init(&config);\n    config.provider = \"exa\";\n    config.transport = ssk_curl_transport;\n    ssk_client *client = NULL;\n    ssk_error *error = NULL;\n    ssk_response *response = NULL;\n    ssk_code code = ssk_client_new(&config, &client, &error);\n    if (code == SSK_OK) {\n        ssk_call_options call;\n        ssk_call_options_init(&call);\n        call.credential = key;\n        code = ssk_search(client,\n            \"{\\\"query\\\":\\\"SQLite write concurrency\\\",\\\"limit\\\":3}\",\n            &call, &response, &error);\n        /* On success, consume ssk_response_json(response) here. */\n    }\n    ssk_response_free(response);\n    ssk_error_free(error);\n    ssk_client_free(client);\n    return code;\n}\n```\n\nThis is a function for your server application. Initialize libcurl with curl_global_init(CURL_GLOBAL_DEFAULT) before worker threads, then call curl_global_cleanup after all calls finish. Response views are borrowed until the response is freed.\n\n<a id=\"scope\"></a>\n\n## Supported surface and limits\n\n14 normalized web-search adapters and 493 retained native bindings across 13 providers; gateway client.\n\n- C11/POSIX, not a Windows portability claim. ABI version 1 has explicit ownership rules.\n- No hidden executor: synchronous calls and streaming callbacks run on the caller's thread.\n\nPreserve result order, provider-native scores and source provenance. Unknown usage is not zero cost. Cancellation and deadlines cannot undo a request already accepted by a remote system or guarantee exactly-once effects.\n\n<a id=\"verify\"></a>\n\n## Verify without provider keys\n\n**Repository checkout · local checks**\n\n```bash\nsh packages/c/scripts/verify-package.sh\n```\n\nCore assertions, ASan/UBSan, local TLS and installed/extracted-archive consumers; platform CI covers macOS and Linux.\n\nThese are deterministic contract and artifact checks. They do not establish live-provider or account-entitlement verification. Read the package README for precise commands, dependencies and runtime coverage.\n\n<a id=\"next\"></a>\n\n## Continue in your language\n\n- [C package reference](https://github.com/Belweave/searchSDK/tree/main/packages/c#readme): Complete API, errors, streaming, packaging and platform boundaries.\n- [Compare SDKs](https://searchsdk.dev/docs/sdks)\n- [Choose a provider](https://searchsdk.dev/docs/providers)\n"
    },
    {
      "slug": "sdks/cpp",
      "title": "searchSDK for C++",
      "description": "C++17 over the C11 / POSIX ABI. Typed RAII facade over the C SDK: 14 normalized web-search adapters and 493 retained native bindings across 13 providers; gateway client.",
      "url": "https://searchsdk.dev/docs/sdks/cpp",
      "markdownPath": "/docs/sdks/cpp.md",
      "markdownUrl": "https://searchsdk.dev/docs/sdks/cpp.md",
      "text": "# searchSDK for C++\n\nC++17 over the C11 / POSIX ABI. Typed RAII facade over the C SDK: 14 normalized web-search adapters and 493 retained native bindings across 13 providers; gateway client.\n\nCanonical: https://searchsdk.dev/docs/sdks/cpp\nMarkdown: https://searchsdk.dev/docs/sdks/cpp.md\n\n<a id=\"install\"></a>\n\n## Install from source\n\nPackage: `searchsdk::cpp / searchsdk::cpp_curl`, version `0.1.0-alpha.1`. This is an alpha source/local-artifact installation. No public registry release or release tag is assumed.\n\n**Get the source**\n\n```bash\ngit clone https://github.com/Belweave/searchSDK.git\ncd searchSDK\n# Record this revision with your application's dependency lock.\ngit rev-parse HEAD\n```\n\n**Build or install the local package**\n\n```bash\ncmake -S packages/cpp -B .local/cpp-build -DCMAKE_BUILD_TYPE=Release -DSEARCHSDK_CPP_CURL=ON\ncmake --build .local/cpp-build --parallel 2\ncmake --install .local/cpp-build --prefix \"$PWD/.local/cpp-install\"\n```\n\nUse find_package(searchsdk_cpp 0.1 CONFIG REQUIRED) and link searchsdk::cpp_curl. The default build includes the sibling C library; C and C++ compiler, architecture and runtime settings must be compatible.\n\n<a id=\"first-search\"></a>\n\n## Make a server-side search\n\nSet provider keys in your application's server environment or secret store. The example below makes a real provider request when invoked and can incur charges. Use the package's fixture consumer for a key-free check.\n\n**search.cpp**\n\n```cpp\n#include <searchsdk/searchsdk.hpp>\n#include <searchsdk/curl.hpp>\n#include <iostream>\n\nvoid search_example(const std::string& server_key) {\n    searchsdk::Config config;\n    config.provider = \"exa\";\n    config.transport = searchsdk::curl_transport();\n    searchsdk::Client search(std::move(config));\n    searchsdk::CallOptions call;\n    call.credential = server_key;\n    const auto response = search.search(\n        searchsdk::SearchRequest{\"SQLite write concurrency\", 3}, call);\n    for (const auto& result : response.results)\n        std::cout << result.url << '\\n';\n}\n```\n\nCall from your server application with an application-supplied provider key. Configure the curl transport before starting worker threads, and destroy clients after joining their calls. Results own their data.\n\n<a id=\"scope\"></a>\n\n## Supported surface and limits\n\nTyped RAII facade over the C SDK: 14 normalized web-search adapters and 493 retained native bindings across 13 providers; gateway client.\n\n- A C++17 facade over the C ABI, not an independent Windows transport.\n- Synchronous API and owning stream callbacks; no hidden async executor.\n\nPreserve result order, provider-native scores and source provenance. Unknown usage is not zero cost. Cancellation and deadlines cannot undo a request already accepted by a remote system or guarantee exactly-once effects.\n\n<a id=\"verify\"></a>\n\n## Verify without provider keys\n\n**Repository checkout · local checks**\n\n```bash\ncmake -S packages/cpp -B .local/cpp-check -DCMAKE_BUILD_TYPE=Release\ncmake --build .local/cpp-check --parallel 2\nctest --test-dir .local/cpp-check --output-on-failure\n```\n\nTyped wire models, sanitizers, local TLS and consumers using installed C and relocated CPack archives.\n\nThese are deterministic contract and artifact checks. They do not establish live-provider or account-entitlement verification. Read the package README for precise commands, dependencies and runtime coverage.\n\n<a id=\"next\"></a>\n\n## Continue in your language\n\n- [C++ package reference](https://github.com/Belweave/searchSDK/tree/main/packages/cpp#readme): Complete API, errors, streaming, packaging and platform boundaries.\n- [Compare SDKs](https://searchsdk.dev/docs/sdks)\n- [Choose a provider](https://searchsdk.dev/docs/providers)\n"
    },
    {
      "slug": "sdks/swift",
      "title": "searchSDK for Swift",
      "description": "Swift 6 · iOS 16+ · macOS 13+ · tvOS 16+ · watchOS 9+ · visionOS 1+. Normalized search through your application's HTTPS gateway.",
      "url": "https://searchsdk.dev/docs/sdks/swift",
      "markdownPath": "/docs/sdks/swift.md",
      "markdownUrl": "https://searchsdk.dev/docs/sdks/swift.md",
      "text": "# searchSDK for Swift\n\nSwift 6 · iOS 16+ · macOS 13+ · tvOS 16+ · watchOS 9+ · visionOS 1+. Normalized search through your application's HTTPS gateway.\n\nCanonical: https://searchsdk.dev/docs/sdks/swift\nMarkdown: https://searchsdk.dev/docs/sdks/swift.md\n\n<a id=\"install\"></a>\n\n## Install from source\n\nPackage: `SearchSDK`, version `0.1.0-alpha.1`. This is an alpha source/local-artifact installation. No public registry release or release tag is assumed.\n\n**Get the source**\n\n```bash\ngit clone https://github.com/Belweave/searchSDK.git\ncd searchSDK\n# Record this revision with your application's dependency lock.\ngit rev-parse HEAD\n```\n\n**Application dependency configuration**\n\n```swift\n// In Package.swift, add the local checkout as a dependency:\n.package(name: \"SearchSDK\", path: \"/absolute/path/searchSDK\")\n\n// In your target's dependencies:\n.product(name: \"SearchSDK\", package: \"SearchSDK\")\n```\n\nThe repository-root SwiftPM manifest exposes SearchSDK. Xcode can also consume the Git repository at a reviewed revision containing that manifest. No release tag is assumed; Linux and Windows are unsupported.\n\n<a id=\"first-search\"></a>\n\n## Call your application gateway\n\nFirst deploy an [application-owned gateway](https://searchsdk.dev/docs/guides/application-gateway). searchsdk.dev hosts a demonstration playground and documentation MCP service; neither is an application gateway for these SDKs.\n\n**SearchExample.swift**\n\n```swift\nimport SearchSDK\n\nfunc searchExample(\n    endpoint: String,\n    applicationToken: @escaping @Sendable () async throws -> String?\n) async throws {\n    let search = try SearchClient(\n        endpoint: endpoint,\n        applicationToken: applicationToken\n    )\n    let response = try await search.search(\n        SearchRequest(query: \"SQLite write concurrency\", limit: 3)\n    )\n    for result in response.results {\n        print(result.url, result.provenance.provider)\n    }\n}\n```\n\nPass your exact application-owned HTTPS endpoint and a callback that resolves the current application token. Provider selection and provider keys belong on that server. Cancel the caller's Task to cancel search.\n\n<a id=\"scope\"></a>\n\n## Supported surface and limits\n\nNormalized search through your application's HTTPS gateway.\n\n- Gateway search only. No provider-native operations or client-side provider retry/fallback/cache policy.\n- Physical devices and every minimum OS runtime are not covered by the local verification.\n\nPreserve result order, provider-native scores and source provenance. Unknown usage is not zero cost. Cancellation and deadlines cannot undo a request already accepted by a remote system or guarantee exactly-once effects.\n\n<a id=\"verify\"></a>\n\n## Verify without provider keys\n\n**Repository checkout · local checks**\n\n```bash\nxcodebuild -version\nswift test --package-path packages/swift --scratch-path .local/swift-build --jobs 2\nsh packages/swift/Scripts/verify-consumer.sh .local/swift-consumer\n```\n\n29 tests on macOS and an iOS simulator; tvOS, watchOS and visionOS simulator builds; extracted SwiftPM consumer.\n\nThese are deterministic contract and artifact checks. They do not establish live-provider or account-entitlement verification. Read the package README for precise commands, dependencies and runtime coverage.\n\n<a id=\"next\"></a>\n\n## Continue in your language\n\n- [Swift package reference](https://github.com/Belweave/searchSDK/tree/main/packages/swift#readme): Complete API, errors, streaming, packaging and platform boundaries.\n- [Compare SDKs](https://searchsdk.dev/docs/sdks)\n- [Gateway protocol and authorization](https://searchsdk.dev/docs/guides/application-gateway)\n"
    },
    {
      "slug": "sdks/android",
      "title": "searchSDK for Android / Kotlin",
      "description": "Android API 26+. Normalized search through your application's HTTPS gateway.",
      "url": "https://searchsdk.dev/docs/sdks/android",
      "markdownPath": "/docs/sdks/android.md",
      "markdownUrl": "https://searchsdk.dev/docs/sdks/android.md",
      "text": "# searchSDK for Android / Kotlin\n\nAndroid API 26+. Normalized search through your application's HTTPS gateway.\n\nCanonical: https://searchsdk.dev/docs/sdks/android\nMarkdown: https://searchsdk.dev/docs/sdks/android.md\n\n<a id=\"install\"></a>\n\n## Install from source\n\nPackage: `dev.searchsdk:searchsdk-android`, version `0.1.0-alpha.1`. This is an alpha source/local-artifact installation. No public registry release or release tag is assumed.\n\n**Get the source**\n\n```bash\ngit clone https://github.com/Belweave/searchSDK.git\ncd searchSDK\n# Record this revision with your application's dependency lock.\ngit rev-parse HEAD\n```\n\n**Build or install the local package**\n\n```bash\ncd packages/android\n./gradlew publishReleasePublicationToVerificationRepository --no-daemon --max-workers=2\n```\n\nUse JDK 21 and Android SDK 36 for the build. Add the generated packages/android/build/repository as a Maven repository in your app, then implementation(\"dev.searchsdk:searchsdk-android:0.1.0-alpha.1\"). This is a local AAR with explicit coroutine and OkHttp dependencies, not a Maven Central release.\n\n<a id=\"first-search\"></a>\n\n## Call your application gateway\n\nFirst deploy an [application-owned gateway](https://searchsdk.dev/docs/guides/application-gateway). searchsdk.dev hosts a demonstration playground and documentation MCP service; neither is an application gateway for these SDKs.\n\n**SearchExample.kt**\n\n```kotlin\nimport dev.searchsdk.android.SearchClient\nimport dev.searchsdk.android.SearchRequest\n\nsuspend fun searchExample(\n    endpoint: String,\n    applicationToken: suspend () -> String?\n) {\n    val search = SearchClient(endpoint = endpoint, accessToken = applicationToken)\n    try {\n        val response = search.search(\n            SearchRequest(\"SQLite write concurrency\", limit = 3)\n        )\n        for (result in response.results) println(result.url)\n    } finally {\n        search.close()\n    }\n}\n```\n\nInvoke from an application-owned coroutine with your exact HTTPS endpoint and application-token callback. In a UI, reuse a client for its owning component's lifetime and close it when that component is finished.\n\n<a id=\"scope\"></a>\n\n## Supported surface and limits\n\nNormalized search through your application's HTTPS gateway.\n\n- Gateway only; retries, fallback and provider-native operations remain on the server.\n- Minimum-API and physical-device runtime coverage are not claimed. Coroutine cancellation follows Kotlin's structured concurrency.\n\nPreserve result order, provider-native scores and source provenance. Unknown usage is not zero cost. Cancellation and deadlines cannot undo a request already accepted by a remote system or guarantee exactly-once effects.\n\n<a id=\"verify\"></a>\n\n## Verify without provider keys\n\n**Repository checkout · local checks**\n\n```bash\ncd packages/android\n./gradlew testReleaseUnitTest assembleRelease lintRelease publishReleasePublicationToVerificationRepository --no-daemon --max-workers=2\n./gradlew -p consumer testReleaseUnitTest assembleRelease --no-daemon --max-workers=2\n```\n\n29 SDK tests, installed AAR/Maven consumer and three HTTPS instrumentation cases on an Android 16 emulator.\n\nThese are deterministic contract and artifact checks. They do not establish live-provider or account-entitlement verification. Read the package README for precise commands, dependencies and runtime coverage.\n\n<a id=\"next\"></a>\n\n## Continue in your language\n\n- [Android / Kotlin package reference](https://github.com/Belweave/searchSDK/tree/main/packages/android#readme): Complete API, errors, streaming, packaging and platform boundaries.\n- [Compare SDKs](https://searchsdk.dev/docs/sdks)\n- [Gateway protocol and authorization](https://searchsdk.dev/docs/guides/application-gateway)\n"
    },
    {
      "slug": "sdks/react-native",
      "title": "searchSDK for React Native",
      "description": "React Native · iOS 15.1+ · Android API 24+. Normalized search through your application's HTTPS gateway.",
      "url": "https://searchsdk.dev/docs/sdks/react-native",
      "markdownPath": "/docs/sdks/react-native.md",
      "markdownUrl": "https://searchsdk.dev/docs/sdks/react-native.md",
      "text": "# searchSDK for React Native\n\nReact Native · iOS 15.1+ · Android API 24+. Normalized search through your application's HTTPS gateway.\n\nCanonical: https://searchsdk.dev/docs/sdks/react-native\nMarkdown: https://searchsdk.dev/docs/sdks/react-native.md\n\n<a id=\"install\"></a>\n\n## Install from source\n\nPackage: `@belweave/search-sdk-react-native`, version `0.1.0-alpha.0`. This is an alpha source/local-artifact installation. No public registry release or release tag is assumed.\n\n**Get the source**\n\n```bash\ngit clone https://github.com/Belweave/searchSDK.git\ncd searchSDK\n# Record this revision with your application's dependency lock.\ngit rev-parse HEAD\n```\n\n**Build or install the local package**\n\n```bash\nnvm use\nnpm ci\nnpm run build -w @belweave/search-sdk-react-native\nnpm pack -w @belweave/search-sdk-react-native\n\n# In your React Native app:\nnpm install /absolute/path/searchSDK/belweave-search-sdk-react-native-0.1.0-alpha.0.tgz\n# Then install iOS pods and rebuild the native app.\n```\n\nThe npm artifact includes autolinked URLSession and OkHttp bridges. In your app's ios directory, run bundle exec pod install. JavaScript-only reloads do not install native modules. Broader declared peer compatibility is not a complete runtime test matrix.\n\n<a id=\"first-search\"></a>\n\n## Call your application gateway\n\nFirst deploy an [application-owned gateway](https://searchsdk.dev/docs/guides/application-gateway). searchsdk.dev hosts a demonstration playground and documentation MCP service; neither is an application gateway for these SDKs.\n\n**search.ts**\n\n```typescript\nimport { createSearchClient } from '@belweave/search-sdk-react-native';\n\nexport async function searchExample(\n  endpoint: string,\n  accessToken: () => Promise<string>,\n  signal: AbortSignal,\n) {\n  const search = createSearchClient({ endpoint, accessToken, timeoutMs: 10_000 });\n  return search.web.search({\n    query: 'SQLite write concurrency', limit: 3,\n  }, { signal });\n}\n```\n\nYour app supplies an HTTPS gateway URL, its session callback and an AbortSignal tied to screen lifecycle. The callback returns an application token, never a provider key. Reuse the configured client in a real service module.\n\n<a id=\"scope\"></a>\n\n## Supported surface and limits\n\nNormalized search through your application's HTTPS gateway.\n\n- No direct providers or automatic gateway POST retries.\n- A compiled native bridge is required. Ambient native fetch is not used as an insecure fallback.\n\nPreserve result order, provider-native scores and source provenance. Unknown usage is not zero cost. Cancellation and deadlines cannot undo a request already accepted by a remote system or guarantee exactly-once effects.\n\n<a id=\"verify\"></a>\n\n## Verify without provider keys\n\n**Repository checkout · local checks**\n\n```bash\nnpm run test:mobile\nnpm run test:package -w @belweave/search-sdk-react-native\n```\n\n187 JavaScript tests, native transport tests and nine installed release-app cases each on iOS and Android with React Native 0.86.3.\n\nThese are deterministic contract and artifact checks. They do not establish live-provider or account-entitlement verification. Read the package README for precise commands, dependencies and runtime coverage.\n\n<a id=\"next\"></a>\n\n## Continue in your language\n\n- [React Native package reference](https://github.com/Belweave/searchSDK/tree/main/packages/react-native#readme): Complete API, errors, streaming, packaging and platform boundaries.\n- [Compare SDKs](https://searchsdk.dev/docs/sdks)\n- [Gateway protocol and authorization](https://searchsdk.dev/docs/guides/application-gateway)\n"
    },
    {
      "slug": "sdks/expo",
      "title": "searchSDK for Expo",
      "description": "Expo SDK 55–57 · native development builds and web. Normalized search through your application's HTTPS gateway.",
      "url": "https://searchsdk.dev/docs/sdks/expo",
      "markdownPath": "/docs/sdks/expo.md",
      "markdownUrl": "https://searchsdk.dev/docs/sdks/expo.md",
      "text": "# searchSDK for Expo\n\nExpo SDK 55–57 · native development builds and web. Normalized search through your application's HTTPS gateway.\n\nCanonical: https://searchsdk.dev/docs/sdks/expo\nMarkdown: https://searchsdk.dev/docs/sdks/expo.md\n\n<a id=\"install\"></a>\n\n## Install from source\n\nPackage: `@belweave/search-sdk-expo`, version `0.1.0-alpha.0`. This is an alpha source/local-artifact installation. No public registry release or release tag is assumed.\n\n**Get the source**\n\n```bash\ngit clone https://github.com/Belweave/searchSDK.git\ncd searchSDK\n# Record this revision with your application's dependency lock.\ngit rev-parse HEAD\n```\n\n**Build or install the local package**\n\n```bash\nnvm use\nnpm ci\nnpm run build:mobile\nnpm pack -w @belweave/search-sdk-react-native\nnpm pack -w @belweave/search-sdk-expo\n\n# In your existing Expo 55–57 app, install both local artifacts:\nnpm install /absolute/path/searchSDK/belweave-search-sdk-react-native-0.1.0-alpha.0.tgz /absolute/path/searchSDK/belweave-search-sdk-expo-0.1.0-alpha.0.tgz\n# Rebuild with expo run:ios, expo run:android, or your EAS workflow.\n```\n\nExpo is an explicit application peer. Native apps use the sibling React Native bridge; Expo Go cannot load it. The web entry uses Expo streaming fetch and requires your gateway's browser CORS allowlist.\n\n<a id=\"first-search\"></a>\n\n## Call your application gateway\n\nFirst deploy an [application-owned gateway](https://searchsdk.dev/docs/guides/application-gateway). searchsdk.dev hosts a demonstration playground and documentation MCP service; neither is an application gateway for these SDKs.\n\n**search.ts**\n\n```typescript\nimport { createExpoSearchClient } from '@belweave/search-sdk-expo';\n\nexport async function searchExample(\n  endpoint: string,\n  accessToken: () => Promise<string>,\n  signal: AbortSignal,\n) {\n  const search = createExpoSearchClient({ endpoint, accessToken, timeoutMs: 10_000 });\n  return search.web.search({\n    query: 'SQLite write concurrency', limit: 3,\n  }, { signal });\n}\n```\n\nPass your application's HTTPS gateway, session callback and cancellation signal. Provider keys remain server-side. Native use requires a development or production build containing the bridge.\n\n<a id=\"scope\"></a>\n\n## Supported surface and limits\n\nNormalized search through your application's HTTPS gateway.\n\n- Stock Expo Go is unsupported on native platforms.\n- Expo 55/56 native runtime behavior is unverified; source/type checks are narrower evidence.\n\nPreserve result order, provider-native scores and source provenance. Unknown usage is not zero cost. Cancellation and deadlines cannot undo a request already accepted by a remote system or guarantee exactly-once effects.\n\n<a id=\"verify\"></a>\n\n## Verify without provider keys\n\n**Repository checkout · local checks**\n\n```bash\nnpm run test:mobile && npm run test:mobile:package\n```\n\nSource/type compatibility for Expo 55, 56 and 57; Metro web/iOS/Android exports and native runtime coverage for Expo 57 only.\n\nThese are deterministic contract and artifact checks. They do not establish live-provider or account-entitlement verification. Read the package README for precise commands, dependencies and runtime coverage.\n\n<a id=\"next\"></a>\n\n## Continue in your language\n\n- [Expo package reference](https://github.com/Belweave/searchSDK/tree/main/packages/expo#readme): Complete API, errors, streaming, packaging and platform boundaries.\n- [Compare SDKs](https://searchsdk.dev/docs/sdks)\n- [Gateway protocol and authorization](https://searchsdk.dev/docs/guides/application-gateway)\n"
    },
    {
      "slug": "guides/domain-filters",
      "title": "Filter by domain",
      "description": "Validate hostnames before dispatch and check the complete fallback chain.",
      "url": "https://searchsdk.dev/docs/guides/domain-filters",
      "markdownPath": "/docs/guides/domain-filters.md",
      "markdownUrl": "https://searchsdk.dev/docs/guides/domain-filters.md",
      "text": "# Filter by domain\n\nValidate hostnames before dispatch and check the complete fallback chain.\n\nCanonical: https://searchsdk.dev/docs/guides/domain-filters\nMarkdown: https://searchsdk.dev/docs/guides/domain-filters.md\n\n<a id=\"request-hostnames\"></a>\n\n## Request hostnames\n\n> **TypeScript reference**\n> The API names, code and policy behavior in this article describe the TypeScript SDK. See [your language guide](https://searchsdk.dev/docs/sdks) for its supported surface and limits.\n\n**filter.ts · fixture**\n\n```typescript\nimport { createSearch } from '@belweave/search-sdk';\nimport { createMockProvider } from '@belweave/search-sdk/testing';\n\nconst client = createSearch({ provider: createMockProvider() });\nconst response = await client.web.search({\n  query: 'search API reference',\n  limit: 3,\n  includeDomains: ['example.org'],\n  excludeDomains: ['excluded.example.org'],\n});\n\nconsole.log(response.results); // Mock hostname filtering; no live search\n```\n\nUse ASCII hostnames or punycode. Schemes, paths, ports, wildcards, and empty lists are rejected. The SDK lowercases and deduplicates hosts. The same normalized host cannot appear in both lists.\n\n<a id=\"capacity\"></a>\n\n## Check provider capacity\n\n| Adapter | Include / exclude capacity |\n| --- | --- |\n| Valyu | 100 / 100 under SDK policy; web only |\n| Context.dev | 100 / 100 |\n| TinyFish | 100 / 100 — conservative SDK policy |\n| Exa | 1,200 / 1,200 |\n| Tavily | 300 / 150 |\n| Perplexity | 20 include or 20 exclude; mutually exclusive |\n| Parallel | 200 include or 200 exclude; mutually exclusive SDK policy |\n| Linkup | 100 / 50 under SDK policy |\n| Firecrawl | 100 include or 100 exclude; mutually exclusive SDK policy |\n| You.com | 500 include or 5,000 exclude; mutually exclusive |\n| Brave / Serper / SerpAPI / SearXNG | Neither filter supported by these normalized adapters |\n\nEvery provider in a configured fallback chain must support the requested filters and capacity before any network dispatch. A Brave fallback makes a filtered request unsupported even when the primary supports it. A provider declaring mutuallyExclusiveDomainFilters rejects simultaneous lists before dispatch.\n\n<a id=\"matching\"></a>\n\n## Keep matching semantics explicit\n\nBuilt-in adapters forward native filter options. They do not rewrite the query into `site:` operators or remove provider results locally. Root-domain and subdomain behavior remains provider-specific; do not infer exact-host matching from the SDK's hostname syntax.\n\n- [Request validation reference](https://searchsdk.dev/docs/api/search)\n- [Provider capability reference](https://searchsdk.dev/docs/api/providers)\n"
    },
    {
      "slug": "guides/results",
      "title": "Work with results",
      "description": "Render untrusted source material while preserving ordering and provenance.",
      "url": "https://searchsdk.dev/docs/guides/results",
      "markdownPath": "/docs/guides/results.md",
      "markdownUrl": "https://searchsdk.dev/docs/guides/results.md",
      "text": "# Work with results\n\nRender untrusted source material while preserving ordering and provenance.\n\nCanonical: https://searchsdk.dev/docs/guides/results\nMarkdown: https://searchsdk.dev/docs/guides/results.md\n\n<a id=\"render-text\"></a>\n\n## Render provider text as text\n\n> **TypeScript reference**\n> The API names, code and policy behavior in this article describe the TypeScript SDK. See [your language guide](https://searchsdk.dev/docs/sdks) for its supported surface and limits.\n\nTitles, snippets, and highlights come from external sources. Use text children in React, or equivalent escaping in your renderer. Do not inject snippets as HTML or treat retrieved instructions as application authority.\n\n**result.tsx · React**\n\n```typescript\nimport type { SearchResult } from '@belweave/search-sdk';\n\nexport function Source({ result }: { result: SearchResult }) {\n  return (\n    <article>\n      <a href={result.url} rel=\"noreferrer\" target=\"_blank\">\n        {result.title ?? result.url}\n      </a>\n      {result.snippet && <p>{result.snippet}</p>}\n      <small>{result.provenance.provider}</small>\n    </article>\n  );\n}\n```\n\n<a id=\"preserve-order\"></a>\n\n## Preserve order unless you choose a policy\n\nNormalized search caps the output without reranking or deduplicating it. A native score belongs to its provider; sorting a mixed set of scores across providers would create an unsupported comparison. There is no fan-out or score fusion in the normalized client.\n\n<a id=\"validate-before-fetching\"></a>\n\n## Distinguish a link from a fetch target\n\nBuilt-in adapters reject unsafe result URLs and validate consumed response fields. That link validation is not an SSRF policy. If your application fetches result URLs server-side, apply your own network, redirect, DNS, and response-size policies.\n"
    },
    {
      "slug": "guides/server-integration",
      "title": "Integrate on a server",
      "description": "Keep credentials and query policy behind your application's server boundary.",
      "url": "https://searchsdk.dev/docs/guides/server-integration",
      "markdownPath": "/docs/guides/server-integration.md",
      "markdownUrl": "https://searchsdk.dev/docs/guides/server-integration.md",
      "text": "# Integrate on a server\n\nKeep credentials and query policy behind your application's server boundary.\n\nCanonical: https://searchsdk.dev/docs/guides/server-integration\nMarkdown: https://searchsdk.dev/docs/guides/server-integration.md\n\n<a id=\"request-boundary\"></a>\n\n## Put policy at your request boundary\n\n> **TypeScript reference**\n> The API names, code and policy behavior in this article describe the TypeScript SDK. See [your language guide](https://searchsdk.dev/docs/sdks) for its supported surface and limits.\n\n- Authenticate and authorize your application's caller before performing search.\n- Validate application-specific query limits and usage policy before calling the SDK.\n- Pass the incoming request's AbortSignal when your framework exposes one.\n- Return only the fields the browser needs. Keep provider keys and internal account details on the server.\n\n<a id=\"reuse-client\"></a>\n\n## Configure once, call per request\n\nA normalized client holds provider configuration rather than user session state. Create it in server-owned code and pass a new search request and signal for each incoming request. Do not share a queued fixture provider across tests that assume isolated outcomes.\n\n**search-service.ts · server**\n\n```typescript\nimport { createSearch } from '@belweave/search-sdk';\nimport { context } from '@belweave/search-sdk/context';\n\nconst apiKey = process.env.CONTEXT_API_KEY;\nif (!apiKey) throw new Error('CONTEXT_API_KEY is required');\n\nconst client = createSearch({\n  provider: context({ apiKey }),\n  timeoutMs: 10_000,\n});\n\nconst response = await client.web.search({\n  query: 'SQLite write concurrency',\n  limit: 5,\n});\n\nfor (const result of response.results) {\n  console.log(result.title ?? result.url, result.url);\n}\nconsole.log(response.provider, response.attempts);\n```\n\n<a id=\"batch-queries\"></a>\n\n## Run independent queries in a bounded batch\n\nUse web.searchBatch for multiple queries with an explicit worker limit and ordered per-item outcomes. Each query retains the same client policy; successful items survive a sibling failure.\n\n- [Batch query reference and fixture](https://searchsdk.dev/docs/api/search-batch)\n\n<a id=\"operational-controls\"></a>\n\n## Add application controls deliberately\n\nThe normalized client supports opt-in retries, a local successful-result cache, identical in-flight request sharing, and bounded concurrency. Configure these deliberately because queries may contain sensitive material and retries can repeat billable work. Per-user quotas and telemetry remain application policy. Avoid logging full query bodies or transport headers by default.\n\n- [Retry policy](https://searchsdk.dev/docs/reliability/retries)\n- [Caching and request sharing](https://searchsdk.dev/docs/reliability/caching)\n- [Credentials and untrusted data](https://searchsdk.dev/docs/reliability/security)\n"
    },
    {
      "slug": "guides/testing",
      "title": "Test without API keys",
      "description": "Exercise your application's failure paths with deterministic mock outcomes.",
      "url": "https://searchsdk.dev/docs/guides/testing",
      "markdownPath": "/docs/guides/testing.md",
      "markdownUrl": "https://searchsdk.dev/docs/guides/testing.md",
      "text": "# Test without API keys\n\nExercise your application's failure paths with deterministic mock outcomes.\n\nCanonical: https://searchsdk.dev/docs/guides/testing\nMarkdown: https://searchsdk.dev/docs/guides/testing.md\n\n<a id=\"fallback-fixture\"></a>\n\n## Assert fallback behavior\n\n> **TypeScript reference**\n> The API names, code and policy behavior in this article describe the TypeScript SDK. See [your language guide](https://searchsdk.dev/docs/sdks) for its supported surface and limits.\n\n**fallback.test.ts · Node**\n\n```typescript\nimport assert from 'node:assert/strict';\nimport { createSearch } from '@belweave/search-sdk';\nimport { createMockProvider } from '@belweave/search-sdk/testing';\n\nconst primary = createMockProvider({\n  id: 'primary',\n  outcomes: [{ type: 'error', code: 'rate_limit', retryAfterMs: 2_000 }],\n});\nconst backup = createMockProvider({ id: 'backup' });\nconst client = createSearch({ provider: primary, fallback: [backup] });\nconst response = await client.web.search({ query: 'search interfaces' });\n\nassert.equal(response.provider, 'backup');\nassert.equal(response.attempts.length, 2);\nassert.equal(response.warnings[0]?.code, 'fallback_used');\nassert.equal(primary.calls.length, 1);\nassert.equal(backup.calls.length, 1);\n```\n\nEach mock has an independent outcome queue and call history. Outcomes are reserved in invocation order, even if concurrent calls complete in a different order. An exhausted explicit queue returns `configuration`.\n\n<a id=\"fixture-behavior\"></a>\n\n## Understand fixture behavior\n\n- Without an outcome queue, the default success fixture repeats.\n- A success outcome accepts `results`, `usage`, and `delayMs`. Omit provenance; the mock adds it.\n- An error outcome accepts `code`, optional `status`, `retryAfterMs`, and `delayMs`.\n- The mock implements hostname filtering and output limits. Timestamps reflect the actual test clock.\n\n<a id=\"evidence\"></a>\n\n## Keep evidence levels separate\n\n| Check | What it can establish |\n| --- | --- |\n| Application mock | Your consumer's state and error handling. |\n| Injected HTTP fixture | Expected request mapping and response validation. |\n| Authenticated live request | Behavior of a particular provider request at a particular time. |\n| Quality evaluation | Usefulness against a dated query set and explicit rubric. |\n\nPassing fixture tests does not establish live key validity, production availability, billing correctness, or a provider quality ranking.\n"
    },
    {
      "slug": "guides/application-gateway",
      "title": "Connect an app to search",
      "description": "Keep provider keys and search policy on your server while Swift, Android, React Native, Expo and other clients use one normalized HTTPS contract.",
      "url": "https://searchsdk.dev/docs/guides/application-gateway",
      "markdownPath": "/docs/guides/application-gateway.md",
      "markdownUrl": "https://searchsdk.dev/docs/guides/application-gateway.md",
      "text": "# Connect an app to search\n\nKeep provider keys and search policy on your server while Swift, Android, React Native, Expo and other clients use one normalized HTTPS contract.\n\nCanonical: https://searchsdk.dev/docs/guides/application-gateway\nMarkdown: https://searchsdk.dev/docs/guides/application-gateway.md\n\n<a id=\"architecture\"></a>\n\n## Your app, your server, your provider\n\nThe app sends a query and optional normalized filters to the exact HTTPS URL you configure. Your server authenticates the caller, chooses the provider and fallback policy, and returns results with provenance and attempt metadata. The app sends an application token; it never needs a provider key.\n\n- App: owns session refresh, UI state and cancellation.\n- Gateway: owns authorization, per-user access and spending controls, browser origin policy and bounded requests.\n- Provider SDK: owns the configured search calls and explicit reliability policy.\n\n<a id=\"server\"></a>\n\n## Create the server handler\n\nBuild the current [TypeScript artifact](https://searchsdk.dev/docs/sdks/typescript) to use `@belweave/search-sdk/gateway`. Mount the returned Fetch-compatible handler at an exact route in your framework. This example makes application authorization a required dependency.\n\n**search-gateway.ts · server**\n\n```typescript\nimport { createSearch } from '@belweave/search-sdk';\nimport { createSearchGateway } from '@belweave/search-sdk/gateway';\nimport { exa } from '@belweave/search-sdk/exa';\n\nexport function makeSearchHandler(\n  providerKey: string,\n  authorizeApplication: (authorization: string | null, signal: AbortSignal) => Promise<boolean>,\n) {\n  return createSearchGateway({\n    search: createSearch({ provider: exa({ apiKey: providerKey }) }),\n    authorize: ({ headers, signal }) =>\n      authorizeApplication(headers.get('authorization'), signal),\n    allowedOrigins: ['https://app.example.com'],\n    timeoutMs: 10_000,\n    maxConcurrency: 32,\n  });\n}\n```\n\nImplement authorizeApplication with your existing session or access-token verifier. Authorization runs before body reading and provider dispatch. A callback that always returns true is appropriate only for an intentionally public or separately protected route. The SDK does not issue tokens or create an identity service.\n\n<a id=\"app\"></a>\n\n## Connect your app SDK\n\n- [Swift](https://searchsdk.dev/docs/sdks/swift): Swift 6 · iOS 16+ · macOS 13+ · tvOS 16+ · watchOS 9+ · visionOS 1+. Application gateway client.\n- [Android / Kotlin](https://searchsdk.dev/docs/sdks/android): Android API 26+. Application gateway client.\n- [React Native](https://searchsdk.dev/docs/sdks/react-native): React Native · iOS 15.1+ · Android API 24+. Application gateway client.\n- [Expo](https://searchsdk.dev/docs/sdks/expo): Expo SDK 55–57 · native development builds and web. Application gateway client.\n\nSupply the exact HTTPS route and a callback for a fresh application token. No path suffix is appended. Native applications still require authorization even when they send no Origin header. Browser callers need an explicitly allowed HTTPS origin; use the same app origin in the handler's allowedOrigins.\n\n<a id=\"wire\"></a>\n\n## The gateway contract\n\n**POST body · protocol v1**\n\n```json\n{\n  \"query\": \"SQLite write concurrency\",\n  \"limit\": 3,\n  \"includeDomains\": [\"sqlite.org\"]\n}\n```\n\nOnly query, limit, includeDomains and excludeDomains are accepted. Provider names, credentials, arbitrary URLs, retry settings and native operations are not request fields. HTTP 200 returns the normalized response; failures return a sanitized error envelope. The handler sets X-SearchSDK-Protocol: 1 and Cache-Control: no-store.\n\nDefault handler bounds are 64 KiB of request data, 10 MiB of decoded response data, ten seconds for the whole operation and 32 concurrent operations. Overload returns 429. The deadline covers authorization, body reading, provider work, validation and serialization.\n\n<a id=\"deployment\"></a>\n\n## Deploy and verify your boundary\n\n- Mount only the intended route, use HTTPS and map client disconnects to the Fetch Request's signal.\n- Keep provider secrets in server configuration. Do not log authorization headers or provider keys.\n- Test authorization failure before dispatch, cancellation, deadline exhaustion, response ceilings and successful sibling batch outcomes with fixtures.\n- Set your own quotas and spending policy. Retries and fallback can repeat billable work; cancellation does not undo accepted requests.\n\n> **Separate from the hosted playground**\n> The public playground accepts visitor keys for individual demonstrations. The public MCP endpoint serves documentation only. Neither is the authenticated application gateway you deploy for your users.\n\n- [Gateway handler reference](https://github.com/Belweave/searchSDK/blob/main/packages/sdk/GATEWAY.md)\n- [Language-neutral wire protocol](https://github.com/Belweave/searchSDK/tree/main/sdk-contract#readme)\n"
    },
    {
      "slug": "guides/boat",
      "title": "Run searchSDK in Boat",
      "description": "Install the alpha package in your own Boat sandbox, run a fixture, then optionally make one server-side search with your own key.",
      "url": "https://searchsdk.dev/docs/guides/boat",
      "markdownPath": "/docs/guides/boat.md",
      "markdownUrl": "https://searchsdk.dev/docs/guides/boat.md",
      "text": "# Run searchSDK in Boat\n\nInstall the alpha package in your own Boat sandbox, run a fixture, then optionally make one server-side search with your own key.\n\nCanonical: https://searchsdk.dev/docs/guides/boat\nMarkdown: https://searchsdk.dev/docs/guides/boat.md\n\n<a id=\"before-you-start\"></a>\n\n## Before you start\n\n> **TypeScript reference**\n> The API names, code and policy behavior in this article describe the TypeScript SDK. See [your language guide](https://searchsdk.dev/docs/sdks) for its supported surface and limits.\n\nBoat provides Ubuntu sandboxes with SSH and Node. This guide runs searchSDK inside a sandbox you create and control. The downloadable runner uses deterministic fixtures by default. It does not create or manage a sandbox.\n\n- You need your own Boat account and an installed, signed-in Boat CLI. Follow Boat's official quickstart, review its installer before executing it, and check its current billing terms before creating a sandbox.\n- Build the TypeScript SDK from a reviewed source checkout and install its local tarball in the sandbox application. Public npm availability is not assumed.\n- Use Node `24.22.1` or a newer patched Node 24 release. The fixture needs no search-provider key. Optional live search needs your own Context.dev key and can incur provider charges.\n\n> **Verification boundary**\n> The SDK contract and fixture runner are checked locally. A live Boat session and live provider search have not been verified. This is a setup recipe, not a benchmark or a partnership claim.\n\n- [Boat quickstart](https://docs.boat.dev/quickstart)\n- [Boat pricing](https://docs.boat.dev/pricing)\n- [Optional source build](https://searchsdk.dev/docs/installation#pack-locally)\n- [Download search.mjs](https://searchsdk.dev/recipes/boat/search.mjs): Save the file in your sandbox application and inspect it before running. Fixture mode is the default.\n\n<a id=\"open-a-sandbox\"></a>\n\n## 1. Open your sandbox\n\nOn your own computer, after completing Boat's official CLI setup, create a sandbox with a 30-minute auto-stop deadline. `--no-env` prevents Boat from injecting your account's configured secrets, repositories, and agent logins. Keep the printed sandbox ID; replace `YOUR_SANDBOX_ID` below with that actual ID.\n\n**Your computer · Boat CLI**\n\n```bash\nboat status --check\nboat new --type small --ttl 1800 --no-env\n\n# Use the ID printed by boat new:\nboat info YOUR_SANDBOX_ID\nboat ssh YOUR_SANDBOX_ID\n```\n\nThe remaining setup and search commands run inside that SSH shell. SSH work does not extend the auto-stop deadline. Install and run one recipe at a time; leave enough time to clean up before the deadline.\n\n- [Boat SSH access](https://docs.boat.dev/ssh-access)\n- [Boat credential inheritance](https://docs.boat.dev/environments/access)\n\n<a id=\"prepare-node\"></a>\n\n## 2. Check Node inside the sandbox\n\n**Inside the sandbox · check Node**\n\n```bash\nnode --version\nnpm --version\n```\n\nUse Node `24.22.1` or a newer patched Node 24 release before continuing. If you already use nvm, run `nvm install 24.22.1` and `nvm use 24.22.1`. Otherwise, follow Node's official installation instructions for your sandbox architecture.\n\n- [Official Node downloads](https://nodejs.org/en/download)\n\n<a id=\"build-the-alpha\"></a>\n\n## 3. Install searchSDK\n\nBuild the TypeScript SDK from a reviewed checkout, then install its generated artifact in a separate server application. Keep the source revision and application lockfile. This does not require a published npm release.\n\n**Inside the sandbox · Bash**\n\n```bash\ngit clone https://github.com/Belweave/searchSDK.git\ncd searchSDK\ngit rev-parse HEAD\nnpm ci\nnpm run build:sdk\nnpm pack -w @belweave/search-sdk\ncd ..\nmkdir searchsdk-boat\ncd searchsdk-boat\nnpm init --yes\nnpm install ../searchSDK/belweave-search-sdk-0.1.0-alpha.0.tgz\n```\n\n- [Installation and optional source build](https://searchsdk.dev/docs/installation)\n\n<a id=\"run-the-fixture\"></a>\n\n## 4. Inspect and run the recipe\n\nIn `searchsdk-boat`, download the plain ESM file from this documentation site, inspect it, then execute it. It requires no extra runtime dependencies beyond the SDK package. You can also save the linked file locally and copy it with Boat's documented `boat scp` command.\n\n**Inside the sandbox · download for review**\n\n```bash\ncurl --fail --location --show-error https://searchsdk.dev/recipes/boat/search.mjs -o search.mjs\ncat search.mjs\n```\n\n**Inside the sandbox · run after review**\n\n```bash\nnode search.mjs\n```\n\nExpect JSON with `mode: \"fixture\"`, a mock provider, three fixed example-domain results, and source provenance. No search-provider request is sent. Attempt timestamps and durations vary; the fixture is not evidence of live retrieval quality or Boat performance.\n\nThe runner uses the same SDK calls as this complete fixture example. It caps results at three, sets a ten-second total deadline and an eight-second attempt deadline, disables retries, and passes a cancellation signal when interrupted.\n\n**boat-fixture.ts · fixture**\n\n```typescript\nimport { createSearch } from '@belweave/search-sdk';\nimport { createMockProvider } from '@belweave/search-sdk/testing';\n\nconst client = createSearch({\n  provider: createMockProvider(),\n  timeoutMs: 10_000,\n  attemptTimeoutMs: 8_000,\n  retry: { maxRetries: 0 },\n});\nconst response = await client.web.search({ query: 'SQLite write concurrency', limit: 3 });\nconsole.log(response.provider, response.results, response.attempts);\n```\n\n<a id=\"optional-live-search\"></a>\n\n## 5. Optional: one live search\n\nOnly continue if you intend to make a potentially billable Context.dev request. Enter your provider key in the interactive SSH session using this Bash prompt. The key is hidden while typing, stays in the subshell's environment and runner memory, and is removed when they exit. The runner requires `--live`; setting a key alone never enables live search.\n\n**Inside the sandbox · Bash · live opt-in**\n\n```bash\n(\n  set +x\n  ulimit -c 0\n  read -r -s -p 'Context.dev API key (hidden): ' CONTEXT_API_KEY\n  printf '\\n'\n  export CONTEXT_API_KEY\n  node search.mjs --live\n)\n```\n\nThe runner makes one normalized search with no configured fallback or retries. Context.dev can request at least ten native results before the SDK trims the output to three, which can affect credits. Cancellation and deadlines limit local waiting; they cannot guarantee a remote request was not processed or billed.\n\n> **Keep credentials out of disk and logs**\n> Do not put provider or Boat account keys in source, `.env`, shell startup files, command arguments, public client code, or snapshots. Do not pass a provider key through a Boat exec command: command history can retain command text. This recipe writes no credential file, but other processes in the same sandbox may access process memory or environment. Use a sandbox you control and trust.\n\n- [Context.dev adapter and billing boundary](https://searchsdk.dev/docs/providers/context)\n- [SDK cancellation and deadlines](https://searchsdk.dev/docs/reliability/timeouts)\n\n<a id=\"finish-and-clean-up\"></a>\n\n## 6. Finish and clean up\n\nExit SSH and manage the sandbox from your own computer. Choose deletion when you are finished with the disposable environment; the CLI asks for confirmation. Export only non-secret artifacts you need first.\n\n**Your computer · delete the disposable sandbox**\n\n```bash\n# Leave the sandbox SSH shell:\nexit\n\n# On your computer, use your recorded ID:\nboat delete YOUR_SANDBOX_ID\n```\n\nIf you deliberately want to keep the disk instead, run `boat stop YOUR_SANDBOX_ID` and check `boat info YOUR_SANDBOX_ID` until it is stopped. Stopping ends running processes and snapshots disk; it does not erase files or earlier snapshots. Auto-stop has the same persistence caveat. Review Boat's current retention policy before relying on stopped storage.\n\n> **Snapshots are persistent data**\n> Deleting the sandbox starts irreversible background deletion. Follow the deletion operation to completion. Named snapshots, forks, and other shared artifacts can retain data independently and need separate cleanup. If a key was written to disk or logged accidentally, revoke it; deleting a current file or merely stopping the sandbox does not erase older copies.\n\n- [What Boat snapshots save](https://docs.boat.dev/snapshots/whats-saved)\n- [Boat stop and deletion commands](https://docs.boat.dev/cli-reference#boat-delete-id)\n- [Boat deletion API semantics](https://docs.boat.dev/api/reference/sandboxes/permanently-delete-sandbox-data)\n\n<a id=\"programmatic-lifecycle\"></a>\n\n## Automating the lifecycle later\n\nBoat's `@boatdev/sdk` and HTTP API are separate infrastructure clients. searchSDK is the search client running inside the sandbox. For automation, use Boat's official TypeScript guide: keep `BOAT_API_KEY` on the trusted controller, wait for readiness, bound the sandbox lifetime, inspect command exit status, and clean up in `finally`. Its synchronous command API has a separate timeout; keep installation and execution within that timeout or use the documented streaming helper.\n\nProvisioning and live provider execution are intentionally manual in this recipe. No Boat API key is required inside the sandbox. Benchmarks are separate work and are not run by these commands.\n\n- [Boat TypeScript SDK](https://docs.boat.dev/sdks/typescript)\n- [Boat HTTP API](https://docs.boat.dev/api/v1)\n- [Boat documentation index](https://docs.boat.dev/llms.txt)\n- [Test integrations with fixtures](https://searchsdk.dev/docs/guides/testing)\n"
    },
    {
      "slug": "guides/mcp",
      "title": "Use the documentation MCP server",
      "description": "Read documentation, provider capabilities, examples, and one integration skill through the public, unauthenticated MCP endpoint.",
      "url": "https://searchsdk.dev/docs/guides/mcp",
      "markdownPath": "/docs/guides/mcp.md",
      "markdownUrl": "https://searchsdk.dev/docs/guides/mcp.md",
      "text": "# Use the documentation MCP server\n\nRead documentation, provider capabilities, examples, and one integration skill through the public, unauthenticated MCP endpoint.\n\nCanonical: https://searchsdk.dev/docs/guides/mcp\nMarkdown: https://searchsdk.dev/docs/guides/mcp.md\n\n<a id=\"connect\"></a>\n\n## Connect to the public endpoint\n\nConfigure an MCP client that supports protocol revision `2026-07-28` with the Streamable HTTP URL `https://searchsdk.dev/mcp`. `/api/mcp` is an alias. No API key or account is required; send no cookies or Authorization header. The endpoint serves public documentation only; it does not accept provider keys, run live searches, execute examples, or create remote infrastructure.\n\nThis revision uses stateless requests. Every request includes protocol version and client capabilities in `params._meta`; HTTP mirrors the version and method in headers. It does not use the older `initialize` handshake or a session ID. A client that only supports older handshake-based revisions needs a compatible update.\n\n**Discover the server · terminal**\n\n```bash\ncurl --fail-with-body https://searchsdk.dev/mcp \\\n  -H 'Content-Type: application/json' \\\n  -H 'Accept: application/json, text/event-stream' \\\n  -H 'MCP-Protocol-Version: 2026-07-28' \\\n  -H 'Mcp-Method: server/discover' \\\n  --data '{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"server/discover\",\"params\":{\"_meta\":{\"io.modelcontextprotocol/protocolVersion\":\"2026-07-28\",\"io.modelcontextprotocol/clientInfo\":{\"name\":\"docs-reader\",\"version\":\"1.0.0\"},\"io.modelcontextprotocol/clientCapabilities\":{}}}}'\n```\n\nRead `supportedVersions` and `capabilities` from the discovery response, then call `tools/list` to inspect the current tool schemas. `Mcp-Name` is also required for `tools/call` and `resources/read`, matching the tool name or resource URI in the body. Skill discovery uses `Mcp-Method` and the version header; `skills/get` does not require `Mcp-Name`.\n\n- [Official July 2026 MCP introduction](https://modelcontextprotocol.io/docs/2026-07-28/getting-started/intro)\n- [Discovery specification](https://modelcontextprotocol.io/specification/2026-07-28/server/discover)\n- [Streamable HTTP requirements](https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http)\n\n<a id=\"tools\"></a>\n\n## Documentation, providers, and examples\n\n| Tool | Arguments | Result |\n| --- | --- | --- |\n| `search_docs` | `query`, optional `limit` (1–10) | Local lexical search with bounded article snippets; no web-provider request. |\n| `get_doc` | `slug` | Complete article text. Use an empty slug for the introduction. |\n| `list_providers` | Optional opaque `cursor` | Public provider metadata, up to 50 entries per page. |\n| `get_provider` | `id` | One provider, including its supported boundary. |\n| `list_examples` | Optional opaque `cursor` | Documented code examples, up to 50 entries per page. |\n| `get_example` | `id` from the listing | One example with language, source URL, and code. |\n\nUse returned cursors unchanged to fetch later pages. Choose example IDs from `list_examples`; IDs are generated from the article, section, and block position. Titles such as “shape” or “abbreviated” identify examples that are not standalone applications. Review environment requirements before using any code.\n\n**mcp-docs.ts · read public data**\n\n```typescript\nconst endpoint = 'https://searchsdk.dev/mcp';\nconst metadata = {\n  'io.modelcontextprotocol/protocolVersion': '2026-07-28',\n  'io.modelcontextprotocol/clientInfo': { name: 'docs-reader', version: '1.0.0' },\n  'io.modelcontextprotocol/clientCapabilities': {},\n};\nlet requestId = 0;\nasync function rpc(method: string, params: Record<string, unknown> = {}) {\n  const name = method === 'tools/call' ? params.name\n    : method === 'resources/read' ? params.uri : undefined;\n  const headers = new Headers({\n    'Content-Type': 'application/json',\n    Accept: 'application/json, text/event-stream',\n    'MCP-Protocol-Version': '2026-07-28',\n    'Mcp-Method': method,\n  });\n  if (typeof name === 'string') headers.set('Mcp-Name', name);\n  const response = await fetch(endpoint, {\n    method: 'POST', headers, credentials: 'omit', signal: AbortSignal.timeout(10_000),\n    body: JSON.stringify({ jsonrpc: '2.0', id: ++requestId, method,\n      params: { ...params, _meta: metadata } }),\n  });\n  // This endpoint returns JSON. Other MCP servers can return an SSE stream.\n  const message = await response.json();\n  if (!response.ok || message.error) throw new Error('MCP request failed');\n  return message.result;\n}\n\nconsole.log(await rpc('server/discover'));\nconsole.log(await rpc('tools/list'));\nconsole.log(await rpc('tools/call', {\n  name: 'search_docs', arguments: { query: 'fallback cancellation', limit: 3 },\n}));\nconsole.log(await rpc('tools/call', {\n  name: 'get_doc', arguments: { slug: 'quickstart' },\n}));\nconsole.log(await rpc('tools/call', { name: 'list_providers', arguments: {} }));\nconsole.log(await rpc('tools/call', {\n  name: 'get_provider', arguments: { id: 'context' },\n}));\nconsole.log(await rpc('tools/call', { name: 'list_examples', arguments: {} }));\n// Pass a returned example ID to get_example; do not infer an ID or execute it.\nexport {};\n```\n\n> **Verification boundary**\n> The tools read generated, public source material. Fixture tests and documented operation mappings do not establish live provider availability, account permissions, retrieval quality, pricing, or latency. Provider capabilities distinguish normalized web adapters from native clients and corpus retrieval.\n\n<a id=\"limits\"></a>\n\n## Handle request limits\n\nKeep request bodies below 16 KiB. The server allows three seconds to receive the body, a five-second total request deadline, and responses up to 512 KiB. Article text stays below 128 KiB per record. Prefer search snippets and individual articles over fetching the entire catalog.\n\nRate limits apply per server instance: a client socket address has a burst of 30 requests and refills at 60 per minute; the aggregate burst is 120 and refills at 240 per minute. Up to 12 requests run concurrently. Forwarded-address headers are ignored, so clients behind a reverse proxy can share one address bucket. On HTTP 429, respect `Retry-After` before retrying. These limits are local protective bounds, not a guaranteed service quota or availability promise.\n\n<a id=\"resources\"></a>\n\n## Read exact resources\n\nClients can enumerate the exact resource catalog with `resources/list`. There are no resource templates. Read an enumerated URI with `resources/read`. The introduction is `searchsdk://docs/index`; other documentation uses `searchsdk://docs/` followed by `encodeURIComponent(slug)`. Provider and example resources use `searchsdk://providers/` or `searchsdk://examples/` followed by `encodeURIComponent(id)`.\n\n**Resource request · params**\n\n```json\n{\n  \"uri\": \"searchsdk://docs/reliability%2Ffallback\",\n  \"_meta\": {\n    \"io.modelcontextprotocol/protocolVersion\": \"2026-07-28\",\n    \"io.modelcontextprotocol/clientInfo\": { \"name\": \"docs-reader\", \"version\": \"1.0.0\" },\n    \"io.modelcontextprotocol/clientCapabilities\": {}\n  }\n}\n```\n\nSend these params with JSON-RPC method `resources/read`, header `Mcp-Method: resources/read`, and matching header `Mcp-Name: searchsdk://docs/reliability%2Ffallback`. Documentation text is bounded below 128 KiB per article. The endpoint serves exact resources from its generated catalog rather than reading arbitrary filesystem paths.\n\n<a id=\"skill\"></a>\n\n## Load the searchSDK integration skill\n\nThe server publishes one curated skill through the official `io.modelcontextprotocol/skills` extension: `skill://searchsdk/SKILL.md`. It guides provider selection, server integration, fallback, cancellation, errors, and local fixture checks. It does not authorize live provider calls. Directory reads are not supported.\n\nAfter `server/discover` advertises the extension, use `skills/list` or `skills/get` with `{ \"uri\": \"skill://searchsdk/SKILL.md\" }`, including the same required per-request metadata. Read that URI with `resources/read`. The manifest contains the SHA-256 digest and exact UTF-8 byte size of the single file. Skill-capable hosts verify the manifest and frontmatter and apply their skill-loading and approval rules before activation; an ordinary resource read does not activate the skill.\n\n- [Read the public searchSDK skill](https://searchsdk.dev/skills/searchsdk/SKILL.md)\n- [Official Skills over MCP extension](https://modelcontextprotocol.io/extensions/skills/overview)\n- [Agent Skills format](https://agentskills.io/specification)\n\n<a id=\"static-access\"></a>\n\n## Read without an MCP client\n\nEvery public page has a Markdown export discoverable through an HTML `rel=\"alternate\"` link with `type=\"text/markdown\"`. `rel=\"describedby\"` points to `/llms.txt`. The short index links to the main references; `/llms-full.txt` is an optional full-text concatenation, not a required part of the llms.txt proposal. Generated JSON indexes are searchSDK-specific formats, not new MCP or web standards.\n\n- [Agent entry point](https://searchsdk.dev/llms.txt)\n- [All canonical articles and Markdown URLs](https://searchsdk.dev/agent-index.json)\n- [Machine-readable provider capabilities](https://searchsdk.dev/provider-capabilities.json)\n- [Full public MCP dataset](https://searchsdk.dev/mcp-public-data.json)\n- [Canonical sitemap](https://searchsdk.dev/sitemap.xml)\n- [llms.txt proposal](https://llmstxt.org/)\n"
    },
    {
      "slug": "guides/streaming",
      "title": "Consume native streams",
      "description": "Read incremental SSE events with an explicit lifetime and provider-specific event interpretation.",
      "url": "https://searchsdk.dev/docs/guides/streaming",
      "markdownPath": "/docs/guides/streaming.md",
      "markdownUrl": "https://searchsdk.dev/docs/guides/streaming.md",
      "text": "# Consume native streams\n\nRead incremental SSE events with an explicit lifetime and provider-specific event interpretation.\n\nCanonical: https://searchsdk.dev/docs/guides/streaming\nMarkdown: https://searchsdk.dev/docs/guides/streaming.md\n\n<a id=\"events\"></a>\n\n## Events are native data\n\n> **TypeScript reference**\n> The API names, code and policy behavior in this article describe the TypeScript SDK. See [your language guide](https://searchsdk.dev/docs/sdks) for its supported surface and limits.\n\n**consume.ts · shared stream consumer**\n\n```typescript\nimport type { NativeSSEEvent } from '@belweave/search-sdk';\n\nexport async function consume(events: AsyncIterable<NativeSSEEvent>) {\n  for await (const event of events) {\n    console.log(event.event, event.id, event.data);\n    // Interpret data and terminal/error events using the provider contract.\n    // Do not assume every event is JSON or that HTTP 200 means job success.\n  }\n}\n```\n\nAn SSE operation resolves to `{ data, metadata }` after response headers. Iterate `response.data` exactly once. `event.data` is a string; `event`, `id`, and `retry` may be present. The parser handles split UTF-8 and CR/LF boundaries, but provider event schemas still require interpretation.\n\n<a id=\"lifetime\"></a>\n\n## Own the stream lifetime\n\n- Pass an AbortSignal to the operation and abort it when the consumer is done.\n- Breaking a for-await loop cancels the response body.\n- The operation deadline covers the full stream lifetime, including periods when your consumer is idle.\n- Response-byte limits apply to the stream as a whole, rather than restarting for each event.\n\n<a id=\"replay\"></a>\n\n## No automatic reconnect or replay\n\n> **Avoid duplicate remote work**\n> Once streaming headers are returned, stream consumption is not automatically retried. A disconnect can leave a remote job running. Save job IDs when the provider exposes them and reconcile through documented read operations.\n\nThe SSE retry field is preserved as event data. It does not enable EventSource reconnect behavior. An incomplete final event is discarded under the parser's SSE framing rules. Metadata attempts describe connection setup; later iteration errors do not become new HTTP attempts.\n\n- [Native transport reference](https://searchsdk.dev/docs/api/native-transport)\n- [Durable job coordination](https://searchsdk.dev/docs/guides/durable-operations)\n"
    },
    {
      "slug": "guides/durable-operations",
      "title": "Resume durable operations",
      "description": "Persist a remote identifier and resume read-only polling without silently submitting duplicate work.",
      "url": "https://searchsdk.dev/docs/guides/durable-operations",
      "markdownPath": "/docs/guides/durable-operations.md",
      "markdownUrl": "https://searchsdk.dev/docs/guides/durable-operations.md",
      "text": "# Resume durable operations\n\nPersist a remote identifier and resume read-only polling without silently submitting duplicate work.\n\nCanonical: https://searchsdk.dev/docs/guides/durable-operations\nMarkdown: https://searchsdk.dev/docs/guides/durable-operations.md\n\n<a id=\"lifecycle\"></a>\n\n## Persist intent, then the remote ID\n\n> **TypeScript reference**\n> The API names, code and policy behavior in this article describe the TypeScript SDK. See [your language guide](https://searchsdk.dev/docs/sdks) for its supported surface and limits.\n\n`runDurableOperation` coordinates an application-supplied submit callback and read-only poll callback. It saves a submitting intent before dispatch, saves the returned remote ID, and resumes that same ID on later invocations. It is not a managed background worker or a provider-specific job adapter.\n\n**durable.ts · fixture**\n\n```typescript\nimport {\n  createMemoryCheckpointStore, runDurableOperation,\n} from '@belweave/search-sdk/durable';\n\nconst store = createMemoryCheckpointStore(); // Tests only; not disk persistence\nconst options = {\n  key: 'example-job',\n  operation: 'example.fixture',\n  inputFingerprint: 'fixture-v1',\n  store,\n  submit: async () => ({ remoteId: 'fixture-job-1' }),\n  poll: async () => ({ state: 'completed' as const, value: { ok: true } }),\n};\nconst first = await runDurableOperation(options);\nconst resumed = await runDurableOperation(options);\nconsole.log(first.value, resumed.resumed); // { ok: true }, true\n\n```\n\n<a id=\"store\"></a>\n\n## Choose a checkpoint store\n\n| Store | Boundary |\n| --- | --- |\n| `createMemoryCheckpointStore()` | Process-local tests; does not survive exit. |\n| `createFileCheckpointStore({ directory })` | Explicit Node-only subpath /durable-node; pre-existing absolute private local directory. |\n| Custom CheckpointStore | Must implement atomic compareAndSet across every writer and defensive snapshots. |\n\nThe local file store uses exclusive per-key locks, atomic rename, and file/directory fsync. A crashed writer's lock is not stolen automatically. Stop writers and reconcile before removing stale locks. It is designed for trusted local filesystems, not distributed consensus.\n\n<a id=\"reconcile\"></a>\n\n## Fail closed on ambiguous submission\n\n> **No automatic resubmission**\n> A crash or failure after submission intent may leave remote work running without a saved identifier. The coordinator returns ambiguous_submission and refuses to submit again. Cancellation or deadline expiry during submission is also ambiguous. Reconcile with the provider before continuing.\n\n`operation` and `inputFingerprint` bind a checkpoint to the caller's intended work. Fingerprints and keys must be opaque and secret-free. Result checkpoints are JSON snapshots; they can contain sensitive provider data, so control storage access and retention.\n\nAfter independently verifying the remote job belongs to the saved intent, call `attachDurableRemoteId({ store, key, operation, inputFingerprint, remoteId })`. It requires the matching submitting checkpoint and uses compare-and-set to attach the identifier. A later run can resume read-only polling. The helper cannot independently verify provider ownership.\n\n<a id=\"bounds\"></a>\n\n## Bound each invocation\n\nDefaults are a 30-second invocation deadline, one-second poll interval, and 100 polls. Cancellation or deadline expiry while polling and poll-limit failure retain the saved remote identifier for later resumption. Submission interruption instead requires ambiguity reconciliation. Polling is explicit, bounded, and separate from remote cancellation.\n\n- [Durable API and errors](https://searchsdk.dev/docs/api/durable)\n"
    },
    {
      "slug": "api/create-search",
      "title": "createSearch",
      "description": "Configure one normalized search client with explicit providers and time budgets.",
      "url": "https://searchsdk.dev/docs/api/create-search",
      "markdownPath": "/docs/api/create-search.md",
      "markdownUrl": "https://searchsdk.dev/docs/api/create-search.md",
      "text": "# createSearch\n\nConfigure one normalized search client with explicit providers and time budgets.\n\nCanonical: https://searchsdk.dev/docs/api/create-search\nMarkdown: https://searchsdk.dev/docs/api/create-search.md\n\n<a id=\"signature\"></a>\n\n## Signature\n\n> **TypeScript reference**\n> The API names, code and policy behavior in this article describe the TypeScript SDK. See [your language guide](https://searchsdk.dev/docs/sdks) for its supported surface and limits.\n\n**TypeScript**\n\n```typescript\nimport { createSearch } from '@belweave/search-sdk';\nimport type { SearchConfig } from '@belweave/search-sdk';\n\n// createSearch(config: SearchConfig)\n// → { web: { search(request, options?), searchBatch(requests, options?) } }\n```\n\n<a id=\"configuration\"></a>\n\n## Configuration\n\n| Field | Behavior |\n| --- | --- |\n| `provider` | Required SearchProvider; first attempted provider. |\n| `fallback` | Optional ordered array of distinct provider IDs. |\n| `timeoutMs` | Total deadline in integer milliseconds; default 10,000. |\n| `attemptTimeoutMs` | Per-attempt budget; defaults to the total configured budget. |\n| `retry` | Optional additional attempts per provider with bounded backoff; off by default. |\n| `maxConcurrency` | Optional active-operation bound; queue time shares the deadline. |\n| `cache` | Optional `{ ttlMs, maxEntries? }` local successful-response cache. |\n| `deduplicate` | Optional sharing of identical in-flight requests; false by default. |\n\nBoth durations must be between 1 and 2,147,483,647. Unknown configuration fields, duplicate provider IDs, invalid capability descriptors, and invalid budgets are configuration errors. Factory configuration errors can throw synchronously.\n\n<a id=\"example\"></a>\n\n## Example\n\n**client.ts · server**\n\n```typescript\nimport { createSearch } from '@belweave/search-sdk';\nimport { context } from '@belweave/search-sdk/context';\nimport { tinyfish } from '@belweave/search-sdk/tinyfish';\n\nconst contextKey = process.env.CONTEXT_API_KEY;\nconst tinyfishKey = process.env.TINYFISH_API_KEY;\nif (!contextKey || !tinyfishKey) throw new Error('Missing server credentials');\n\nconst client = createSearch({\n  provider: context({ apiKey: contextKey }),\n  fallback: [tinyfish({ apiKey: tinyfishKey })],\n  timeoutMs: 10_000,\n  attemptTimeoutMs: 4_000,\n});\n\nconst response = await client.web.search({ query: 'SQLite write concurrency' });\nconsole.log(response.provider, response.attempts, response.warnings);\n```\n\nSet a smaller per-attempt budget when you need to reserve time for fallback. A total deadline never extends to accommodate another provider.\n"
    },
    {
      "slug": "api/search",
      "title": "web.search",
      "description": "The portable request for ranked web results, with capability checks before dispatch.",
      "url": "https://searchsdk.dev/docs/api/search",
      "markdownPath": "/docs/api/search.md",
      "markdownUrl": "https://searchsdk.dev/docs/api/search.md",
      "text": "# web.search\n\nThe portable request for ranked web results, with capability checks before dispatch.\n\nCanonical: https://searchsdk.dev/docs/api/search\nMarkdown: https://searchsdk.dev/docs/api/search.md\n\n<a id=\"request\"></a>\n\n## Request fields\n\n> **TypeScript reference**\n> The API names, code and policy behavior in this article describe the TypeScript SDK. See [your language guide](https://searchsdk.dev/docs/sdks) for its supported surface and limits.\n\n| Field | Contract |\n| --- | --- |\n| `query: string` | Required, nonblank; forwarded unchanged. |\n| `limit?: number` | Integer 1–20; default 5. Output ceiling. |\n| `includeDomains?: readonly string[]` | Nonempty hostname allowlist within every provider's capacity. |\n| `excludeDomains?: readonly string[]` | Nonempty hostname blocklist within every provider's capacity. |\n\n<a id=\"options\"></a>\n\n## Call options\n\n**TypeScript**\n\n```typescript\nconst controller = new AbortController();\n// client is a configured createSearch() client.\nconst response = await client.web.search(\n  { query: 'SQLite write concurrency', limit: 5 },\n  { signal: controller.signal },\n);\n```\n\nOnly `signal` is accepted in normalized call options. Unknown request or option fields reject with `invalid_request`; a required capability missing from any configured provider rejects with `unsupported_option`. Native options belong on the provider-native surface.\n\n<a id=\"result-count\"></a>\n\n## Result-count behavior\n\nA successful response can contain zero or fewer than the requested number of results. Empty success does not trigger fallback. TinyFish fetches one first page; Context requests at least ten native results and trims to the requested ceiling. The SDK does not silently paginate.\n\n- [Response shape](https://searchsdk.dev/docs/api/response)\n- [Domain filter rules](https://searchsdk.dev/docs/guides/domain-filters)\n"
    },
    {
      "slug": "api/search-batch",
      "title": "web.searchBatch",
      "description": "Run multiple normalized queries with bounded workers and ordered per-item outcomes.",
      "url": "https://searchsdk.dev/docs/api/search-batch",
      "markdownPath": "/docs/api/search-batch.md",
      "markdownUrl": "https://searchsdk.dev/docs/api/search-batch.md",
      "text": "# web.searchBatch\n\nRun multiple normalized queries with bounded workers and ordered per-item outcomes.\n\nCanonical: https://searchsdk.dev/docs/api/search-batch\nMarkdown: https://searchsdk.dev/docs/api/search-batch.md\n\n<a id=\"example\"></a>\n\n## Run independent queries\n\n> **TypeScript reference**\n> The API names, code and policy behavior in this article describe the TypeScript SDK. See [your language guide](https://searchsdk.dev/docs/sdks) for its supported surface and limits.\n\nCall searchBatch on the same web client as search. Results preserve input order even when requests finish out of order. Each item has its original index and either a fulfilled value or a rejected SearchError.\n\n**batch-search.ts · fixture**\n\n```typescript\nimport { createSearch } from '@belweave/search-sdk';\nimport { createMockProvider } from '@belweave/search-sdk/testing';\n\nconst client = createSearch({ provider: createMockProvider() });\nconst outcomes = await client.web.searchBatch(\n  [\n    { query: 'SQLite WAL', limit: 3 },\n    { query: 'SQLite transactions', limit: 3 },\n  ],\n  { concurrency: 2, timeoutMs: 10_000 },\n);\n\nfor (const outcome of outcomes) {\n  if (outcome.status === 'fulfilled') {\n    console.log(outcome.index, outcome.value.results);\n  } else {\n    console.log(outcome.index, outcome.error.code);\n  }\n}\n```\n\n<a id=\"options\"></a>\n\n## Batch options\n\n| Option | Contract |\n| --- | --- |\n| `requests` | Array of up to 1,000 SearchRequest items; empty input returns an empty array. |\n| `concurrency` | Workers per batch, integer 1–64; default 4. |\n| `timeoutMs` | Whole-batch budget including queued items; defaults to the client's total timeoutMs. |\n| `signal` | Optional caller AbortSignal for the entire batch. |\n\nThe client's maxConcurrency still limits active underlying searches. Each item uses the same provider, fallback, retry, cache, and deduplication policy as a single search; concurrency is not a provider-side batch endpoint or a billing discount.\n\n<a id=\"failures\"></a>\n\n## Handle partial failure\n\n- An invalid individual request becomes a rejected item without discarding successful sibling results.\n- An invalid batch envelope or option rejects the batch promise with invalid_request.\n- Caller cancellation or the whole-batch deadline stops new dispatch and rejects unfinished items with aborted or timeout. Completed successful items remain in the ordered output.\n- Client and per-attempt deadlines still apply to each individual search. A total batch budget does not extend them.\n\nCancellation cannot promise that upstream work or billing stops after a request has been dispatched. Inspect each outcome and its attempt trace; persist the results you need before retrying failed items.\n\n- [Single-search contract](https://searchsdk.dev/docs/api/search)\n- [Deadlines and cancellation](https://searchsdk.dev/docs/reliability/timeouts)\n- [Cache and request sharing](https://searchsdk.dev/docs/reliability/caching)\n"
    },
    {
      "slug": "api/response",
      "title": "SearchResponse",
      "description": "Inspect the winner, source material, execution trace, warnings, and reported usage.",
      "url": "https://searchsdk.dev/docs/api/response",
      "markdownPath": "/docs/api/response.md",
      "markdownUrl": "https://searchsdk.dev/docs/api/response.md",
      "text": "# SearchResponse\n\nInspect the winner, source material, execution trace, warnings, and reported usage.\n\nCanonical: https://searchsdk.dev/docs/api/response\nMarkdown: https://searchsdk.dev/docs/api/response.md\n\n<a id=\"shape\"></a>\n\n## Response fields\n\n> **TypeScript reference**\n> The API names, code and policy behavior in this article describe the TypeScript SDK. See [your language guide](https://searchsdk.dev/docs/sdks) for its supported surface and limits.\n\n**TypeScript · shape**\n\n```typescript\ninterface SearchResponse {\n  provider: string;\n  results: readonly SearchResult[];\n  attempts: readonly SearchAttempt[];\n  warnings: readonly {\n    code: 'fallback_used' | 'provider_warning';\n    provider: string;\n  }[];\n  usage: { unit: 'usd' | 'credits'; value: number } | null;\n  reuse?: 'cache' | 'inflight';\n}\n```\n\n<a id=\"result\"></a>\n\n## Result fields\n\n| Field | Meaning |\n| --- | --- |\n| `url` | Validated HTTP(S) source link. |\n| `title?`, `snippet?` | Optional provider text; render as untrusted text. |\n| `highlights?` | Separate passages, preserved as an array. |\n| `score?` | Native score; no cross-provider normalization. |\n| `provenance` | Provider ID, sourceUrl, retrievedAt, optional requestId. |\n\n<a id=\"validation\"></a>\n\n## Validation and omissions\n\nBuilt-in adapters validate consumed fields, including results beyond the output ceiling, before returning. A malformed consumed field rejects with `invalid_response` instead of being silently discarded. Unknown provider fields are ignored. The orchestrator also checks the normalized shape returned by custom providers, including safe URLs, provenance fields, usage, and warnings, and copies only public fields. Structural validation does not prove source truth or attribution.\n\n- [Provenance semantics](https://searchsdk.dev/docs/reliability/provenance)\n- [Warnings and usage](https://searchsdk.dev/docs/reliability/usage)\n"
    },
    {
      "slug": "api/providers",
      "title": "SearchProvider",
      "description": "The normalized adapter interface, capability descriptor, and trust boundary.",
      "url": "https://searchsdk.dev/docs/api/providers",
      "markdownPath": "/docs/api/providers.md",
      "markdownUrl": "https://searchsdk.dev/docs/api/providers.md",
      "text": "# SearchProvider\n\nThe normalized adapter interface, capability descriptor, and trust boundary.\n\nCanonical: https://searchsdk.dev/docs/api/providers\nMarkdown: https://searchsdk.dev/docs/api/providers.md\n\n<a id=\"interface\"></a>\n\n## Interface\n\n> **TypeScript reference**\n> The API names, code and policy behavior in this article describe the TypeScript SDK. See [your language guide](https://searchsdk.dev/docs/sdks) for its supported surface and limits.\n\n**TypeScript · abbreviated**\n\n```typescript\nimport type {\n  ProviderResponse, ValidatedSearchRequest,\n} from '@belweave/search-sdk';\n\ninterface SearchProvider {\n  readonly id: string;\n  readonly capabilities: {\n    readonly domainFilters: boolean;\n    readonly mutuallyExclusiveDomainFilters?: boolean;\n    readonly maxIncludeDomains: number;\n    readonly maxExcludeDomains: number;\n    readonly maxQueryLength?: number;\n  };\n  search(\n    request: ValidatedSearchRequest,\n    options: { signal: AbortSignal },\n  ): Promise<ProviderResponse>;\n}\n```\n\n<a id=\"capabilities\"></a>\n\n## Declare capabilities truthfully\n\nThe orchestrator checks capabilities across the entire fallback chain before dispatch. Capacities are nonnegative integers. An optional `maxQueryLength` must be a positive integer and is measured in UTF-16 code units. Context declares a ceiling of 500. IDs must be 1–64 ASCII letters, digits, hyphens, or underscores.\n\n<a id=\"trust\"></a>\n\n## Custom implementations are trusted code\n\nA custom provider must return the normalized response shape, assign truthful provenance, honor its advertised capabilities, and observe the signal where possible. The orchestrator validates response fields and applies deadlines, fallback policy, and result ceilings. It cannot verify the truth of supplied attribution.\n\nMost hosted adapter options are `{ apiKey, fetch? }`; Valyu adds typed search settings, and SearXNG uses an operator-selected instance. Injected fetch has the shape `(input: string | URL, init?: RequestInit) => Promise<Response>` and is useful for controlled fixtures and server networking policy.\n"
    },
    {
      "slug": "api/errors",
      "title": "SearchError",
      "description": "Stable normalized failure codes with a trace and sanitized diagnostic fields.",
      "url": "https://searchsdk.dev/docs/api/errors",
      "markdownPath": "/docs/api/errors.md",
      "markdownUrl": "https://searchsdk.dev/docs/api/errors.md",
      "text": "# SearchError\n\nStable normalized failure codes with a trace and sanitized diagnostic fields.\n\nCanonical: https://searchsdk.dev/docs/api/errors\nMarkdown: https://searchsdk.dev/docs/api/errors.md\n\n<a id=\"handling\"></a>\n\n## Handle by code\n\n> **TypeScript reference**\n> The API names, code and policy behavior in this article describe the TypeScript SDK. See [your language guide](https://searchsdk.dev/docs/sdks) for its supported surface and limits.\n\n**errors.ts · fixture**\n\n```typescript\nimport { createSearch, SearchError } from '@belweave/search-sdk';\nimport { createMockProvider } from '@belweave/search-sdk/testing';\n\nconst client = createSearch({ provider: createMockProvider({\n  outcomes: [{ type: 'error', code: 'rate_limit', retryAfterMs: 2_000 }],\n}) });\n\ntry {\n  await client.web.search({ query: 'SQLite concurrency' });\n} catch (error) {\n  if (!(error instanceof SearchError)) throw error;\n  console.log(error.code, error.status, error.retryAfterMs);\n  console.log(error.attempts); // Fixed codes and timing, no raw error bodies\n}\n```\n\n<a id=\"codes\"></a>\n\n## Error codes\n\n| Code | Fallback / meaning |\n| --- | --- |\n| `rate_limit` | Yes — HTTP 429. |\n| `network` | Yes — rejected transport, including blocked redirects. |\n| `unavailable` | Yes — HTTP 408 or 5xx. |\n| `attempt_timeout` | Yes — attempt budget elapsed while total time remains. |\n| `timeout` | No — total call budget elapsed. |\n| `aborted` | No — caller cancelled. |\n| `auth` | No — account/auth failures, including HTTP 401/402/403. |\n| `invalid_request` | No — request or call options are invalid. |\n| `unsupported_option` | No — a configured provider cannot satisfy a required option. |\n| `configuration` | No — invalid setup or exhausted fixture outcomes. |\n| `invalid_response` | No — malformed consumed response data. |\n| `provider_error` | No — other rejected requests or custom exceptions. |\n\n<a id=\"diagnostics\"></a>\n\n## Diagnostic fields\n\nRead `code`, `attempts`, optional `status`, and optional `retryAfterMs`. Error messages are fixed by code. Raw provider bodies, transport messages, credentials, and caller abort reasons are excluded. Avoid attaching your own secret-bearing request objects to errors.\n"
    },
    {
      "slug": "api/native-transport",
      "title": "Provider-native transport",
      "description": "Use fixed-origin operations with typed inputs, bounded responses, explicit retries, and sanitized metadata.",
      "url": "https://searchsdk.dev/docs/api/native-transport",
      "markdownPath": "/docs/api/native-transport.md",
      "markdownUrl": "https://searchsdk.dev/docs/api/native-transport.md",
      "text": "# Provider-native transport\n\nUse fixed-origin operations with typed inputs, bounded responses, explicit retries, and sanitized metadata.\n\nCanonical: https://searchsdk.dev/docs/api/native-transport\nMarkdown: https://searchsdk.dev/docs/api/native-transport.md\n\n<a id=\"choose-client\"></a>\n\n## Start with a provider client\n\n> **TypeScript reference**\n> The API names, code and policy behavior in this article describe the TypeScript SDK. See [your language guide](https://searchsdk.dev/docs/sdks) for its supported surface and limits.\n\nProvider client factories bind supported operations to fixed origins and authentication. Use their typed methods for actual provider work. `createNativeTransport` is the lower-level primitive used by those clients; it does not discover endpoints or validate provider JSON schemas.\n\n**native-search.ts · server**\n\n```typescript\nimport { createContextClient } from '@belweave/search-sdk/native-context';\n\nconst apiKey = process.env.CONTEXT_API_KEY;\nif (!apiKey) throw new Error('CONTEXT_API_KEY is required');\n\nconst client = createContextClient({ apiKey, maxConcurrency: 4 });\nconst response = await client.search({\n  body: { query: 'SQLite write concurrency', numResults: 10 },\n  timeoutMs: 8_000,\n});\nconsole.log(response.data.results);\nconsole.log(response.metadata.status, response.metadata.attempts);\n```\n\n<a id=\"operation\"></a>\n\n## Operation and input\n\n| Operation descriptor | Behavior |\n| --- | --- |\n| `id` | Static operation name; never put user input or secrets in it. |\n| `method` | GET, POST, PUT, PATCH, DELETE, or HEAD. |\n| `path` | Relative to the fixed base path; `{name}` placeholders use input.path. |\n| `retryable` | Explicit replay eligibility. Defaults false, even for GET. |\n| `response` | json by default; text, bytes, raw, or sse. |\n\n| Request input | Behavior |\n| --- | --- |\n| `path` | Placeholder values encoded as single path segments; do not pre-encode IDs. |\n| `query` | Scalar values or repeated arrays; null and undefined omitted. |\n| `body` | JSON serialized; cannot coexist with rawBody. |\n| `rawBody` | Fetch BodyInit, including FormData. Streaming request bodies are unsupported. |\n| `headers` | Non-auth endpoint headers; configured headers cannot be overridden. |\n| `signal`, `timeoutMs` | Cancellation and complete-operation deadline. |\n\n<a id=\"response\"></a>\n\n## Data and metadata\n\n**TypeScript · shape**\n\n```typescript\ninterface NativeResponse<T> {\n  data: T;\n  metadata: {\n    provider: string;\n    operation: string;\n    status: number;\n    requestId?: string;\n    attempts: readonly {\n      attempt: number;\n      durationMs: number;\n      outcome: 'success' | 'error';\n      status?: number;\n      code?: string;\n    }[];\n  };\n}\n```\n\nMetadata omits URLs, queries, request input, credentials, provider error bodies, and arbitrary headers. Successful `data` is native provider data and may itself contain sensitive fields. Generic response types are compile-time assertions, not runtime provider schema checks.\n\n<a id=\"bounds\"></a>\n\n## Limits and credentials\n\n| Setting | Default / boundary |\n| --- | --- |\n| `timeoutMs` | 10,000 ms, including queue, backoff, fetch, response parsing, and stream lifetime. |\n| `maxConcurrency` | 8 per transport instance; 1–1,024 when configured. Queue shares the deadline. |\n| `maxResponseBytes` | 10 MiB of decoded response bytes, including streaming data. |\n| `retry.maxRetries` | 0; retries require both opt-in policy and operation eligibility. |\n\nThe base URL must be HTTPS and has no credentials, query, or fragment. Operation input cannot change origin or replace configured authentication. Raw responses are buffered under the size cap. Let Fetch set the multipart boundary for FormData.\n\nThe response cap is not a process-memory limit: decoded strings and parsed objects require additional memory. Uploads are materialized before dispatch and do not have an SDK upload-size cap; bound them in your application.\n\n<a id=\"responses\"></a>\n\n## Response modes\n\n| Mode | Returned data |\n| --- | --- |\n| `json` | Parsed native JSON. Empty 204/205 or HEAD becomes null. |\n| `text` | Decoded text. |\n| `bytes` | Uint8Array. |\n| `raw` | A buffered, bounded Response. |\n| `sse` | AsyncIterable<NativeSSEEvent>; incremental and single-consumer. |\n\n- [Streaming event behavior](https://searchsdk.dev/docs/guides/streaming)\n- [Retry eligibility](https://searchsdk.dev/docs/reliability/retries)\n- [Provider operation inventories](https://searchsdk.dev/docs/providers)\n"
    },
    {
      "slug": "api/durable",
      "title": "Durable operation reference",
      "description": "Checkpoint states, storage requirements, and reconciliation errors for resumable remote work.",
      "url": "https://searchsdk.dev/docs/api/durable",
      "markdownPath": "/docs/api/durable.md",
      "markdownUrl": "https://searchsdk.dev/docs/api/durable.md",
      "text": "# Durable operation reference\n\nCheckpoint states, storage requirements, and reconciliation errors for resumable remote work.\n\nCanonical: https://searchsdk.dev/docs/api/durable\nMarkdown: https://searchsdk.dev/docs/api/durable.md\n\n<a id=\"options\"></a>\n\n## Options\n\n> **TypeScript reference**\n> The API names, code and policy behavior in this article describe the TypeScript SDK. See [your language guide](https://searchsdk.dev/docs/sdks) for its supported surface and limits.\n\n| Field | Contract |\n| --- | --- |\n| `key` | Checkpoint key, 1–200 letters/digits/underscore/dot/colon/hyphen. |\n| `operation` | Static operation identity, 1–128 allowed identifier characters. |\n| `inputFingerprint` | Caller-owned opaque input/account binding; never a credential. |\n| `store` | CheckpointStore with load and atomic compareAndSet. |\n| `submit({ signal })` | One explicit submission returning `{ remoteId }`. |\n| `poll(remoteId, { signal })` | Read-only status; pending, completed with value, or failed. |\n| `timeoutMs`, `pollIntervalMs`, `maxPolls` | Positive integer invocation limits; 30,000 / 1,000 / 100 defaults. |\n| `signal` | Optional caller cancellation. |\n\n<a id=\"states\"></a>\n\n## Checkpoint states\n\n- `submitting`: intent persisted; an unknown outcome requires reconciliation.\n- `submitted`: saved remote ID; safe to resume read-only polling.\n- `completed`: JSON result stored and returned on resume.\n- `failed`: remote failure retained; no automatic resubmission.\n\nA checkpoint has version 1, a monotonically advancing revision, operation/input binding, and an updatedAt timestamp. Remote IDs are present after submission. Results are present only when completed.\n\n<a id=\"attach\"></a>\n\n## Explicit remote-ID reconciliation\n\nImport `attachDurableRemoteId` from `@belweave/search-sdk/durable`. Supply `store`, `key`, `operation`, `inputFingerprint`, and a verified `remoteId`. The helper accepts only a matching submitting checkpoint, atomically advances its revision to submitted, and returns that checkpoint. Missing, mismatched, or concurrently changed state returns checkpoint_conflict.\n\n> **Caller verification is required**\n> Confirm the remote job belongs to this exact operation, account, and input before attaching it. This helper provides local checkpoint consistency; it does not verify remote identity or guarantee exactly-once execution.\n\n<a id=\"errors\"></a>\n\n## DurableOperationError\n\n| Code | Action |\n| --- | --- |\n| `configuration` | Correct invalid options, identifiers, or checkpoint values. |\n| `storage_failure` | Reconcile persisted state before continuing. |\n| `checkpoint_conflict` | Another writer or a different input binding owns the checkpoint. |\n| `ambiguous_submission` | Remote work may exist; do not automatically submit again. |\n| `poll_failed` | Read failed; resume using the saved remote identifier. |\n| `remote_failed` | Provider reported a terminal failure. |\n| `poll_limit` | Resume the saved job in a later bounded invocation. |\n| `aborted`, `timeout` | Persisted state remains; these do not cancel the remote job. |\n\nA remoteId can be exposed on the durable error when submission returned an ID but checkpoint persistence failed. Preserve it for reconciliation. Error messages omit raw storage and provider error details.\n"
    },
    {
      "slug": "providers",
      "title": "Provider reference",
      "description": "All 15 providers, with explicit boundaries between web results, provider-native operations, and corpus retrieval.",
      "url": "https://searchsdk.dev/docs/providers",
      "markdownPath": "/docs/providers.md",
      "markdownUrl": "https://searchsdk.dev/docs/providers.md",
      "text": "# Provider reference\n\nAll 15 providers, with explicit boundaries between web results, provider-native operations, and corpus retrieval.\n\nCanonical: https://searchsdk.dev/docs/providers\nMarkdown: https://searchsdk.dev/docs/providers.md\n\n<a id=\"choose\"></a>\n\n## Choose by operation\n\nUse normalized search when you need a common source-result shape. Use a provider-native client for the provider's own options, jobs, streams, extraction, or synthesis. Similar operation names do not establish equivalent semantics or costs.\n\n<a id=\"catalog\"></a>\n\n## The complete catalog\n\n- [Context.dev](https://searchsdk.dev/docs/providers/context): Web search with optional page content and query-relevant passages.\n- [TinyFish](https://searchsdk.dev/docs/providers/tinyfish): Structured web search with ranked titles, URLs, and snippets.\n- [Exa](https://searchsdk.dev/docs/providers/exa): Web search with query-relevant highlights and native relevance.\n- [Tavily](https://searchsdk.dev/docs/providers/tavily): Agent-oriented web search with relevance-ranked content snippets.\n- [Brave](https://searchsdk.dev/docs/providers/brave): Independent-index web search with descriptions and extra snippets.\n- [Perplexity](https://searchsdk.dev/docs/providers/perplexity): Ranked web results with extracted snippets and search filters.\n- [Parallel](https://searchsdk.dev/docs/providers/parallel): Web retrieval using search queries and an optional research objective.\n- [Linkup](https://searchsdk.dev/docs/providers/linkup): Search with source results, sourced answers, and structured output modes.\n- [Firecrawl](https://searchsdk.dev/docs/providers/firecrawl): Web search with optional scraping of returned pages.\n- [You.com](https://searchsdk.dev/docs/providers/you): Web and news search with snippets and optional page extraction.\n- [Serper](https://searchsdk.dev/docs/providers/serper): Google search results across web and specialized result categories.\n- [SerpAPI](https://searchsdk.dev/docs/providers/serpapi): Structured search results from Google and other supported engines.\n- [Valyu](https://searchsdk.dev/docs/providers/valyu): Web search with source content and provider-native relevance.\n- [SearXNG](https://searchsdk.dev/docs/providers/searxng): Metasearch through an operator-selected SearXNG instance.\n- [WonderSearch](https://searchsdk.dev/docs/providers/wondersearch): Semantic retrieval over your own documents and workspace collections.\n\n<a id=\"shared\"></a>\n\n## Shared reliability\n\nNative responses have `{ data, metadata }`. Normalized responses have results, provenance, attempts, warnings, and reported usage. Each surface has explicit retry and deadline rules; read the corresponding reference before sharing policy between them.\n\n- [Provider-native transport](https://searchsdk.dev/docs/api/native-transport)\n- [Normalized request](https://searchsdk.dev/docs/api/search)\n"
    },
    {
      "slug": "providers/context",
      "title": "Context.dev",
      "description": "Search descriptions, native domain filters, and request-reported credits, with a broader native web-data API.",
      "url": "https://searchsdk.dev/docs/providers/context",
      "markdownPath": "/docs/providers/context.md",
      "markdownUrl": "https://searchsdk.dev/docs/providers/context.md",
      "text": "# Context.dev\n\nSearch descriptions, native domain filters, and request-reported credits, with a broader native web-data API.\n\nCanonical: https://searchsdk.dev/docs/providers/context\nMarkdown: https://searchsdk.dev/docs/providers/context.md\n\n<a id=\"overview\"></a>\n\n## Normalized search\n\n> **TypeScript reference**\n> The API names, code and policy behavior in this article describe the TypeScript SDK. See [your language guide](https://searchsdk.dev/docs/sdks) for its supported surface and limits.\n\nNormalized search maps `description` to snippet, `request_id` to provenance, and `key_metadata.credits_consumed` to credit usage. A returned `partial: true` produces a provider warning. String relevance is not a numeric score.\n\n**context-search.ts · server**\n\n```typescript\nimport { createSearch } from '@belweave/search-sdk';\nimport { context } from '@belweave/search-sdk/context';\n\nconst apiKey = process.env.CONTEXT_API_KEY;\nif (!apiKey) throw new Error('CONTEXT_API_KEY is required');\n\nconst client = createSearch({ provider: context({ apiKey }) });\nconst response = await client.web.search({\n  query: 'SQLite write concurrency',\n  limit: 5,\n});\nconsole.log(response.results, response.attempts);\n```\n\nThe normalized adapter requests at least ten native results because the provider overview and reference disagree on the minimum, then trims to the SDK limit. Those trimmed results can affect reported usage. Optional Markdown and highlight extraction are not enabled by normalized search.\n\n100 include / 100 exclude; 500 UTF-16 code-unit query ceiling.\n\n<a id=\"native-client\"></a>\n\n## Provider-native client\n\n**context-native.ts · server**\n\n```typescript\nimport { createContextClient } from '@belweave/search-sdk/native-context';\n\nconst apiKey = process.env.CONTEXT_API_KEY;\nif (!apiKey) throw new Error('CONTEXT_API_KEY is required');\n\nconst client = createContextClient({ apiKey, timeoutMs: 10_000 });\nconst response = await client.search({ body: { query: 'SQLite write concurrency', numResults: 10 } });\nconsole.log(response.data, response.metadata);\n```\n\nRead provider data from `response.data` and sanitized transport details from `response.metadata`. Native TypeScript response types are not runtime schema validation. Preserve the operation's native response and source identities.\n\n<a id=\"operations\"></a>\n\n## Native operation inventory\n\nMethods available on this native client. Paths are relative to each operation's fixed base; a provider may use more than one origin. Eligible operations retry only when you opt into a client retry policy.\n\n| Method | HTTP / relative path | Response / retry eligibility |\n| --- | --- | --- |\n| `headLogo` | `HEAD /` | raw · eligible |\n| `submitFeedback` | `POST /feedback` | json · no automatic retry |\n| `listLogs` | `GET /org/logs` | json · eligible |\n| `getLog` | `GET /org/logs/{request_id}` | json · eligible |\n| `listProfiles` | `GET /org/browser/profiles` | json · eligible |\n| `getUsage` | `GET /org/usage` | json · eligible |\n| `getUsageHistory` | `GET /org/usage/history` | json · eligible |\n| `listWebhookDeliveries` | `POST /webhooks/deliveries` | json · no automatic retry |\n| `getWebhookDelivery` | `GET /webhooks/deliveries/{delivery_id}` | json · eligible |\n| `listWebhookDeliveryAttempts` | `GET /webhooks/deliveries/{delivery_id}/attempts` | json · eligible |\n| `retryWebhookDelivery` | `POST /webhooks/deliveries/{delivery_id}/retry` | json · no automatic retry |\n| `scrape` | `POST /web/scrape` | json · no automatic retry |\n| `searchNews` | `POST /news/search` | json · no automatic retry |\n| `answers` | `POST /web/answers` | json · no automatic retry |\n| `parse` | `POST /parse` | json · no automatic retry |\n| `map` | `GET /web/urls` | json · eligible |\n| `crawl` | `POST /web/crawl` | json · no automatic retry |\n| `extract` | `POST /web/extract` | json · no automatic retry |\n| `search` | `POST /web/search` | json · no automatic retry |\n| `enrichPerson` | `POST /people/enrich` | json · no automatic retry |\n| `retrieveBrand` | `POST /brand/retrieve` | json · no automatic retry |\n| `searchBrands` | `GET /brand/search` | json · eligible |\n| `styleguide` | `GET /web/styleguide` | json · eligible |\n| `fonts` | `GET /web/fonts` | json · eligible |\n| `classifyNaics` | `GET /web/naics` | json · eligible |\n| `classifySic` | `GET /web/sic` | json · eligible |\n| `prefetch` | `POST /utility/prefetch` | json · no automatic retry |\n| `createMonitor` | `POST /monitors` | json · no automatic retry |\n| `listMonitors` | `GET /monitors` | json · eligible |\n| `getMonitor` | `GET /monitors/{monitor_id}` | json · eligible |\n| `updateMonitor` | `PATCH /monitors/{monitor_id}` | json · no automatic retry |\n| `deleteMonitor` | `DELETE /monitors/{monitor_id}` | json · no automatic retry |\n| `listMonitorRuns` | `GET /monitors/{monitor_id}/runs` | json · eligible |\n| `getMonitorRun` | `GET /monitors/{monitor_id}/runs/{run_id}` | json · eligible |\n| `listMonitorChanges` | `GET /monitors/{monitor_id}/changes` | json · eligible |\n| `listAccountRuns` | `GET /monitors/runs` | json · eligible |\n| `listMonitorCreditUsage` | `GET /monitors/credit-usage` | json · eligible |\n| `getMonitorLimits` | `GET /monitors/limits` | json · eligible |\n| `listChanges` | `GET /monitors/changes` | json · eligible |\n| `getChange` | `GET /monitors/changes/{change_id}` | json · eligible |\n| `runMonitorNow` | `POST /monitors/{monitor_id}/run` | json · no automatic retry |\n| `rotateMonitorWebhookSecret` | `POST /monitors/{monitor_id}/webhook/rotate-secret` | json · no automatic retry |\n| `submitBatch` | `POST /batch/submit` | json · no automatic retry |\n| `listBatches` | `GET /batch/list` | json · eligible |\n| `getBatch` | `GET /batch/{batch_id}` | json · eligible |\n| `deleteBatch` | `DELETE /batch/{batch_id}` | json · no automatic retry |\n| `getBatchResults` | `GET /batch/{batch_id}/results` | json · eligible |\n| `cancelBatch` | `POST /batch/{batch_id}/cancel` | json · no automatic retry |\n| `searchCompanies` | `POST /company/search` | json · no automatic retry |\n\nAdditional client helpers: `logoUrl`. These reuse catalog operations or expose a native output variant. Their input and response types remain in the provider subpath.\n\n<a id=\"lifecycle\"></a>\n\n## Limits and operation lifecycle\n\n- Pass `signal` and per-call `timeoutMs` on native request input when needed.\n- Persist a returned job identifier before explicitly reading or polling the same job. Native clients do not automatically poll.\n- SSE data is incremental provider event text. Parse and validate terminal or error events according to the provider contract; there is no reconnect or replay.\n- Native operations may create, delete, ingest, or incur charges. A successful HTTP response is not proof that a remote job completed.\n\n<a id=\"sources\"></a>\n\n## Official sources\n\nUse the official reference for current schemas, account access, and operation-specific requirements.\n\n- [Search reference](https://docs.context.dev/api-reference/web-scraping/search)\n- [Search overview](https://docs.context.dev/search/overview)\n- [Page content](https://docs.context.dev/search/page-content)\n\n- [Native request and response reference](https://searchsdk.dev/docs/api/native-transport)\n- [All providers](https://searchsdk.dev/docs/providers)\n"
    },
    {
      "slug": "providers/tinyfish",
      "title": "TinyFish",
      "description": "Ranked web sources in normalized search, with separate native search, fetch, browser, and agent operations.",
      "url": "https://searchsdk.dev/docs/providers/tinyfish",
      "markdownPath": "/docs/providers/tinyfish.md",
      "markdownUrl": "https://searchsdk.dev/docs/providers/tinyfish.md",
      "text": "# TinyFish\n\nRanked web sources in normalized search, with separate native search, fetch, browser, and agent operations.\n\nCanonical: https://searchsdk.dev/docs/providers/tinyfish\nMarkdown: https://searchsdk.dev/docs/providers/tinyfish.md\n\n<a id=\"overview\"></a>\n\n## Normalized search\n\n> **TypeScript reference**\n> The API names, code and policy behavior in this article describe the TypeScript SDK. See [your language guide](https://searchsdk.dev/docs/sdks) for its supported surface and limits.\n\nNormalized search requests page zero and `domain_type=web`. It preserves result titles, links, and snippets in order. Position is not a relevance score. Unreported usage remains `null`.\n\n**tinyfish-search.ts · server**\n\n```typescript\nimport { createSearch } from '@belweave/search-sdk';\nimport { tinyfish } from '@belweave/search-sdk/tinyfish';\n\nconst apiKey = process.env.TINYFISH_API_KEY;\nif (!apiKey) throw new Error('TINYFISH_API_KEY is required');\n\nconst client = createSearch({ provider: tinyfish({ apiKey }) });\nconst response = await client.web.search({\n  query: 'SQLite write concurrency',\n  limit: 5,\n});\nconsole.log(response.results, response.attempts);\n```\n\nThe normalized adapter performs one request without a native count parameter or automatic pagination. Provider totals are not a promise that the SDK can return the requested number. Native search options and browser execution are separate operations.\n\n100 include / 100 exclude under a conservative SDK policy; this is not a verified native maximum.\n\n<a id=\"native-client\"></a>\n\n## Provider-native client\n\n**tinyfish-native.ts · server**\n\n```typescript\nimport { createTinyfishClient } from '@belweave/search-sdk/native-tinyfish';\n\nconst apiKey = process.env.TINYFISH_API_KEY;\nif (!apiKey) throw new Error('TINYFISH_API_KEY is required');\n\nconst client = createTinyfishClient({ apiKey, timeoutMs: 10_000 });\nconst response = await client.search({ query: { query: 'SQLite write concurrency', domain_type: 'web', page: 0 } });\nconsole.log(response.data, response.metadata);\n```\n\nRead provider data from `response.data` and sanitized transport details from `response.metadata`. Native TypeScript response types are not runtime schema validation. Preserve the operation's native response and source identities.\n\n<a id=\"operations\"></a>\n\n## Native operation inventory\n\nMethods available on this native client. Paths are relative to each operation's fixed base; a provider may use more than one origin. Eligible operations retry only when you opt into a client retry policy.\n\n| Method | HTTP / relative path | Response / retry eligibility |\n| --- | --- | --- |\n| `runSse` | `POST /v1/automation/run-sse` | SSE stream · no automatic retry |\n| `run` | `POST /v1/automation/run` | json · no automatic retry |\n| `runAsync` | `POST /v1/automation/run-async` | json · no automatic retry |\n| `runBatch` | `POST /v1/automation/run-batch` | json · no automatic retry |\n| `listRuns` | `GET /v1/runs` | json · eligible |\n| `batchGetRuns` | `POST /v1/runs/batch` | json · no automatic retry |\n| `batchCancelRuns` | `POST /v1/runs/batch/cancel` | json · no automatic retry |\n| `getRunById` | `GET /v1/runs/{id}` | json · eligible |\n| `cancelRunById` | `POST /v1/runs/{id}/cancel` | json · no automatic retry |\n| `getStepScreenshot` | `GET /v1/runs/{id}/steps/{stepId}/screenshot` | bytes · eligible |\n| `getStepHtml` | `GET /v1/runs/{id}/steps/{stepId}/html` | text · eligible |\n| `listBrowserContextProfiles` | `GET /v1/profiles` | json · eligible |\n| `createBrowserContextProfile` | `POST /v1/profiles` | json · no automatic retry |\n| `getBrowserContextProfile` | `GET /v1/profiles/{profileId}` | json · eligible |\n| `updateBrowserContextProfile` | `PATCH /v1/profiles/{profileId}` | json · no automatic retry |\n| `deleteBrowserContextProfile` | `DELETE /v1/profiles/{profileId}` | json · no automatic retry |\n| `createBrowserContextProfileSetupSession` | `POST /v1/profiles/{profileId}/setup-session` | json · no automatic retry |\n| `cancelBrowserContextProfileSetupSession` | `POST /v1/profiles/{profileId}/setup-session/cancel` | json · no automatic retry |\n| `saveBrowserContextProfileSetupSession` | `POST /v1/profiles/{profileId}/save` | json · no automatic retry |\n| `uploadBrowserContextProfileState` | `POST /v1/profiles/{profileId}/upload` | json · no automatic retry |\n| `deleteBrowserContextProfileDomain` | `DELETE /v1/profiles/{profileId}/domains/{domain}` | json · no automatic retry |\n| `connectVault` | `POST /v1/vault/connections` | json · no automatic retry |\n| `listVaultConnections` | `GET /v1/vault/connections` | json · eligible |\n| `disconnectVault` | `DELETE /v1/vault/connections/{connectionId}` | json · no automatic retry |\n| `listVaultItems` | `GET /v1/vault/items` | json · eligible |\n| `syncVaultItems` | `POST /v1/vault/items/sync` | json · no automatic retry |\n| `getWallet` | `GET /v1/wallet` | json · eligible |\n| `topUpWallet` | `POST /v1/wallet/top-up` | json · no automatic retry |\n| `search` | `GET /` | json · eligible |\n| `listSearchUsage` | `GET /usage` | json · eligible |\n| `fetchUrls` | `POST /` | json · no automatic retry |\n| `listFetchUsage` | `GET /usage` | json · eligible |\n| `createBrowserSession` | `POST /` | json · no automatic retry |\n| `listBrowserUsage` | `GET /usage` | json · eligible |\n| `deleteBrowserSession` | `DELETE /{sessionId}` | text · no automatic retry |\n| `createMonitor` | `POST /v1/monitors` | json · no automatic retry |\n| `listMonitors` | `GET /v1/monitors` | json · eligible |\n| `getMonitor` | `GET /v1/monitors/{id}` | json · eligible |\n| `updateMonitor` | `PATCH /v1/monitors/{id}` | json · no automatic retry |\n| `deleteMonitor` | `DELETE /v1/monitors/{id}` | json · no automatic retry |\n| `runMonitor` | `POST /v1/monitors/{id}/runs` | json · no automatic retry |\n| `runResearch` | `POST /v1/automation/run-research` | SSE stream · no automatic retry |\n| `startResearchAsync` | `POST /v1/automation/run-research-async` | json · no automatic retry |\n| `streamResearchEvents` | `GET /v1/research-run/{research_run_id}/events` | SSE stream · no automatic retry |\n| `listResearchRuns` | `GET /v1/research-run` | json · eligible |\n| `getResearchRun` | `GET /v1/research-run/{research_run_id}` | json · eligible |\n| `cancelResearchRun` | `POST /v1/research-run/{research_run_id}/cancel` | json · no automatic retry |\n\n<a id=\"lifecycle\"></a>\n\n## Limits and operation lifecycle\n\n- Pass `signal` and per-call `timeoutMs` on native request input when needed.\n- Persist a returned job identifier before explicitly reading or polling the same job. Native clients do not automatically poll.\n- SSE data is incremental provider event text. Parse and validate terminal or error events according to the provider contract; there is no reconnect or replay.\n- Native operations may create, delete, ingest, or incur charges. A successful HTTP response is not proof that a remote job completed.\n\n<a id=\"sources\"></a>\n\n## Official sources\n\nUse the official reference for current schemas, account access, and operation-specific requirements.\n\n- [Search reference](https://docs.tinyfish.ai/search-api/reference)\n- [Search examples](https://docs.tinyfish.ai/search-api/examples)\n- [Full documentation index](https://docs.tinyfish.ai/llms.txt)\n\n- [Native request and response reference](https://searchsdk.dev/docs/api/native-transport)\n- [All providers](https://searchsdk.dev/docs/providers)\n"
    },
    {
      "slug": "providers/exa",
      "title": "Exa",
      "description": "Web search with separate highlights and native relevance, plus native content, answer, and workflow surfaces.",
      "url": "https://searchsdk.dev/docs/providers/exa",
      "markdownPath": "/docs/providers/exa.md",
      "markdownUrl": "https://searchsdk.dev/docs/providers/exa.md",
      "text": "# Exa\n\nWeb search with separate highlights and native relevance, plus native content, answer, and workflow surfaces.\n\nCanonical: https://searchsdk.dev/docs/providers/exa\nMarkdown: https://searchsdk.dev/docs/providers/exa.md\n\n<a id=\"overview\"></a>\n\n## Normalized search\n\n> **TypeScript reference**\n> The API names, code and policy behavior in this article describe the TypeScript SDK. See [your language guide](https://searchsdk.dev/docs/sdks) for its supported surface and limits.\n\nThe normalized adapter uses automatic search and requests highlights. Highlight arrays remain separate from snippets. Native numeric scores are preserved. `requestId` contributes provenance and `costDollars.total` contributes USD usage.\n\n**exa-search.ts · server**\n\n```typescript\nimport { createSearch } from '@belweave/search-sdk';\nimport { exa } from '@belweave/search-sdk/exa';\n\nconst apiKey = process.env.EXA_API_KEY;\nif (!apiKey) throw new Error('EXA_API_KEY is required');\n\nconst client = createSearch({ provider: exa({ apiKey }) });\nconst response = await client.web.search({\n  query: 'SQLite write concurrency',\n  limit: 5,\n});\nconsole.log(response.results, response.attempts);\n```\n\nNative extracted text, answer generation, Websets, monitors, and team management have distinct response and credential requirements. They are not implicitly invoked by normalized search. Provider-native streaming data is not a SearchResponse.\n\n1,200 include / 1,200 exclude.\n\n<a id=\"native-client\"></a>\n\n## Provider-native client\n\n**exa-native.ts · server**\n\n```typescript\nimport { createExaClient } from '@belweave/search-sdk/native-exa';\n\nconst apiKey = process.env.EXA_API_KEY;\nif (!apiKey) throw new Error('EXA_API_KEY is required');\n\nconst client = createExaClient({ apiKey, timeoutMs: 10_000 });\nconst response = await client.search({ body: { query: 'SQLite write concurrency', type: 'auto', numResults: 5 } });\nconsole.log(response.data, response.metadata);\n```\n\nRead provider data from `response.data` and sanitized transport details from `response.metadata`. Native TypeScript response types are not runtime schema validation. Preserve the operation's native response and source identities.\n\n<a id=\"operations\"></a>\n\n## Native operation inventory\n\nMethods available on this native client. Paths are relative to each operation's fixed base; a provider may use more than one origin. Eligible operations retry only when you opt into a client retry policy.\n\n| Method | HTTP / relative path | Response / retry eligibility |\n| --- | --- | --- |\n| `search` | `POST /search` | json · no automatic retry |\n| `searchStream` | `POST /search` | SSE stream · no automatic retry |\n| `getContents` | `POST /contents` | json · no automatic retry |\n| `answer` | `POST /answer` | json · no automatic retry |\n| `answerStream` | `POST /answer` | SSE stream · no automatic retry |\n| `findSimilar` | `POST /findSimilar` | json · no automatic retry |\n| `createMonitor` | `POST /monitors` | json · no automatic retry |\n| `listMonitors` | `GET /monitors` | json · eligible |\n| `batchMonitors` | `POST /monitors/batch` | json · no automatic retry |\n| `getMonitor` | `GET /monitors/{id}` | json · eligible |\n| `updateMonitor` | `PATCH /monitors/{id}` | json · no automatic retry |\n| `deleteMonitor` | `DELETE /monitors/{id}` | json · no automatic retry |\n| `triggerMonitor` | `POST /monitors/{id}/trigger` | json · no automatic retry |\n| `listMonitorRuns` | `GET /monitors/{id}/runs` | json · eligible |\n| `getMonitorRun` | `GET /monitors/{id}/runs/{runId}` | json · eligible |\n| `createAgentRun` | `POST /agent/runs` | json · no automatic retry |\n| `createAgentRunStream` | `POST /agent/runs` | SSE stream · no automatic retry |\n| `listAgentRuns` | `GET /agent/runs` | json · eligible |\n| `getAgentRun` | `GET /agent/runs/{id}` | json · eligible |\n| `deleteAgentRun` | `DELETE /agent/runs/{id}` | json · no automatic retry |\n| `cancelAgentRun` | `POST /agent/runs/{id}/cancel` | json · no automatic retry |\n| `stopAgentRun` | `POST /agent/runs/{id}/stop` | json · no automatic retry |\n| `listAgentRunEvents` | `GET /agent/runs/{id}/events` | json · eligible |\n| `listAgentRunEventsStream` | `GET /agent/runs/{id}/events` | SSE stream · no automatic retry |\n| `createBatch` | `POST /batches` | json · no automatic retry |\n| `listBatches` | `GET /batches` | json · eligible |\n| `getBatch` | `GET /batches/{id}` | json · eligible |\n| `deleteBatch` | `DELETE /batches/{id}` | json · no automatic retry |\n| `cancelBatch` | `POST /batches/{id}/cancel` | json · no automatic retry |\n| `getTeamInfo` | `GET /v0/teams/me` | json · eligible |\n| `createWebset` | `POST /v0/websets` | json · no automatic retry |\n| `listWebsets` | `GET /v0/websets` | json · eligible |\n| `getWebset` | `GET /v0/websets/{id}` | json · eligible |\n| `updateWebset` | `POST /v0/websets/{id}` | json · no automatic retry |\n| `deleteWebset` | `DELETE /v0/websets/{id}` | json · no automatic retry |\n| `cancelWebset` | `POST /v0/websets/{id}/cancel` | json · no automatic retry |\n| `createWebsetSearch` | `POST /v0/websets/{webset}/searches` | json · no automatic retry |\n| `getWebsetSearch` | `GET /v0/websets/{webset}/searches/{id}` | json · eligible |\n| `cancelWebsetSearch` | `POST /v0/websets/{webset}/searches/{id}/cancel` | json · no automatic retry |\n| `createWebsetEnrichment` | `POST /v0/websets/{webset}/enrichments` | json · no automatic retry |\n| `updateWebsetEnrichment` | `PATCH /v0/websets/{webset}/enrichments/{id}` | text · no automatic retry |\n| `getWebsetEnrichment` | `GET /v0/websets/{webset}/enrichments/{id}` | json · eligible |\n| `deleteWebsetEnrichment` | `DELETE /v0/websets/{webset}/enrichments/{id}` | json · no automatic retry |\n| `cancelWebsetEnrichment` | `POST /v0/websets/{webset}/enrichments/{id}/cancel` | json · no automatic retry |\n| `getWebsetItem` | `GET /v0/websets/{webset}/items/{id}` | json · eligible |\n| `deleteWebsetItem` | `DELETE /v0/websets/{webset}/items/{id}` | json · no automatic retry |\n| `listWebsetItems` | `GET /v0/websets/{webset}/items` | json · eligible |\n| `previewWebset` | `POST /v0/websets/preview` | json · no automatic retry |\n| `createWebsetMonitor` | `POST /v0/monitors` | json · no automatic retry |\n| `listWebsetMonitors` | `GET /v0/monitors` | json · eligible |\n| `getWebsetMonitor` | `GET /v0/monitors/{id}` | json · eligible |\n| `updateWebsetMonitor` | `PATCH /v0/monitors/{id}` | json · no automatic retry |\n| `deleteWebsetMonitor` | `DELETE /v0/monitors/{id}` | json · no automatic retry |\n| `listWebsetMonitorRuns` | `GET /v0/monitors/{monitor}/runs` | json · eligible |\n| `getWebsetMonitorRun` | `GET /v0/monitors/{monitor}/runs/{id}` | json · eligible |\n| `createImport` | `POST /v0/imports` | json · no automatic retry |\n| `listImports` | `GET /v0/imports` | json · eligible |\n| `getImport` | `GET /v0/imports/{id}` | json · eligible |\n| `updateImport` | `PATCH /v0/imports/{id}` | json · no automatic retry |\n| `deleteImport` | `DELETE /v0/imports/{id}` | json · no automatic retry |\n| `createWebhook` | `POST /v0/webhooks` | json · no automatic retry |\n| `listWebhooks` | `GET /v0/webhooks` | json · eligible |\n| `getWebhook` | `GET /v0/webhooks/{id}` | json · eligible |\n| `updateWebhook` | `PATCH /v0/webhooks/{id}` | json · no automatic retry |\n| `deleteWebhook` | `DELETE /v0/webhooks/{id}` | json · no automatic retry |\n| `listWebhookAttempts` | `GET /v0/webhooks/{id}/attempts` | json · eligible |\n| `listEvents` | `GET /v0/events` | json · eligible |\n| `getEvent` | `GET /v0/events/{id}` | json · eligible |\n| `createApiKey` | `POST /api-keys` | json · no automatic retry |\n| `listApiKeys` | `GET /api-keys` | json · eligible |\n| `getApiKey` | `GET /api-keys/{id}` | json · eligible |\n| `updateApiKey` | `PUT /api-keys/{id}` | json · no automatic retry |\n| `deleteApiKey` | `DELETE /api-keys/{id}` | json · no automatic retry |\n| `getApiKeyUsage` | `GET /api-keys/{id}/usage` | json · eligible |\n\n<a id=\"lifecycle\"></a>\n\n## Limits and operation lifecycle\n\n- Pass `signal` and per-call `timeoutMs` on native request input when needed.\n- Persist a returned job identifier before explicitly reading or polling the same job. Native clients do not automatically poll.\n- SSE data is incremental provider event text. Parse and validate terminal or error events according to the provider contract; there is no reconnect or replay.\n- Native operations may create, delete, ingest, or incur charges. A successful HTTP response is not proof that a remote job completed.\n\n<a id=\"sources\"></a>\n\n## Official sources\n\nUse the official reference for current schemas, account access, and operation-specific requirements.\n\n- [Search reference](https://exa.ai/docs/reference/search)\n- [API documentation index](https://exa.ai/docs/llms.txt)\n\n- [Native request and response reference](https://searchsdk.dev/docs/api/native-transport)\n- [All providers](https://searchsdk.dev/docs/providers)\n"
    },
    {
      "slug": "providers/tavily",
      "title": "Tavily",
      "description": "Basic normalized retrieval with snippets and reported credits; richer native search and extraction remain explicit.",
      "url": "https://searchsdk.dev/docs/providers/tavily",
      "markdownPath": "/docs/providers/tavily.md",
      "markdownUrl": "https://searchsdk.dev/docs/providers/tavily.md",
      "text": "# Tavily\n\nBasic normalized retrieval with snippets and reported credits; richer native search and extraction remain explicit.\n\nCanonical: https://searchsdk.dev/docs/providers/tavily\nMarkdown: https://searchsdk.dev/docs/providers/tavily.md\n\n<a id=\"overview\"></a>\n\n## Normalized search\n\n> **TypeScript reference**\n> The API names, code and policy behavior in this article describe the TypeScript SDK. See [your language guide](https://searchsdk.dev/docs/sdks) for its supported surface and limits.\n\nNormalized search selects basic depth, disables generated answers and raw content, requests usage, and uses restrictive native domain inclusion. Native content becomes a snippet; score, request ID, and credits retain their provider meaning.\n\n**tavily-search.ts · server**\n\n```typescript\nimport { createSearch } from '@belweave/search-sdk';\nimport { tavily } from '@belweave/search-sdk/tavily';\n\nconst apiKey = process.env.TAVILY_API_KEY;\nif (!apiKey) throw new Error('TAVILY_API_KEY is required');\n\nconst client = createSearch({ provider: tavily({ apiKey }) });\nconst response = await client.web.search({\n  query: 'SQLite write concurrency',\n  limit: 5,\n});\nconsole.log(response.results, response.attempts);\n```\n\nNative search depth and automatic parameter selection can change work and cost. Keep them explicit on the native client. An API account-limit failure is terminal authentication/account authorization, rather than an automatic fallback opportunity.\n\n300 include / 150 exclude.\n\n<a id=\"native-client\"></a>\n\n## Provider-native client\n\n**tavily-native.ts · server**\n\n```typescript\nimport { createTavilyClient } from '@belweave/search-sdk/native-tavily';\n\nconst apiKey = process.env.TAVILY_API_KEY;\nif (!apiKey) throw new Error('TAVILY_API_KEY is required');\n\nconst client = createTavilyClient({ apiKey, timeoutMs: 10_000 });\nconst response = await client.search({ body: { query: 'SQLite write concurrency', search_depth: 'basic', max_results: 5 } });\nconsole.log(response.data, response.metadata);\n```\n\nRead provider data from `response.data` and sanitized transport details from `response.metadata`. Native TypeScript response types are not runtime schema validation. Preserve the operation's native response and source identities.\n\n<a id=\"operations\"></a>\n\n## Native operation inventory\n\nMethods available on this native client. Paths are relative to each operation's fixed base; a provider may use more than one origin. Eligible operations retry only when you opt into a client retry policy.\n\n| Method | HTTP / relative path | Response / retry eligibility |\n| --- | --- | --- |\n| `getPaymentPricing` | `GET /.well-known/pricing` | raw · eligible |\n| `paidSearch` | `POST /search` | json · no automatic retry |\n| `crawl` | `POST /crawl` | json · no automatic retry |\n| `deactivateKeys` | `POST /deactivate-keys` | json · no automatic retry |\n| `extract` | `POST /extract` | json · no automatic retry |\n| `feedback` | `POST /feedback` | json · no automatic retry |\n| `generateKeys` | `POST /generate-keys` | json · no automatic retry |\n| `keyInfo` | `GET /key-info` | json · eligible |\n| `logs` | `POST /logs` | json · no automatic retry |\n| `map` | `POST /map` | json · no automatic retry |\n| `orgUsage` | `POST /org-usage` | json · no automatic retry |\n| `getResearch` | `GET /research/{request_id}` | json · eligible |\n| `research` | `POST /research` | json · no automatic retry |\n| `researchStream` | `POST /research` | SSE stream · no automatic retry |\n| `search` | `POST /search` | json · no automatic retry |\n| `getUsage` | `GET /usage` | json · eligible |\n\n<a id=\"lifecycle\"></a>\n\n## Limits and operation lifecycle\n\n- Pass `signal` and per-call `timeoutMs` on native request input when needed.\n- Persist a returned job identifier before explicitly reading or polling the same job. Native clients do not automatically poll.\n- SSE data is incremental provider event text. Parse and validate terminal or error events according to the provider contract; there is no reconnect or replay.\n- Native operations may create, delete, ingest, or incur charges. A successful HTTP response is not proof that a remote job completed.\n\n<a id=\"sources\"></a>\n\n## Official sources\n\nUse the official reference for current schemas, account access, and operation-specific requirements.\n\n- [Search reference](https://docs.tavily.com/documentation/api-reference/endpoint/search)\n- [API documentation index](https://docs.tavily.com/llms.txt)\n\n- [Native request and response reference](https://searchsdk.dev/docs/api/native-transport)\n- [All providers](https://searchsdk.dev/docs/providers)\n"
    },
    {
      "slug": "providers/brave",
      "title": "Brave",
      "description": "Web results with descriptions and extra snippets; native LLM Context and answer APIs have separate contracts.",
      "url": "https://searchsdk.dev/docs/providers/brave",
      "markdownPath": "/docs/providers/brave.md",
      "markdownUrl": "https://searchsdk.dev/docs/providers/brave.md",
      "text": "# Brave\n\nWeb results with descriptions and extra snippets; native LLM Context and answer APIs have separate contracts.\n\nCanonical: https://searchsdk.dev/docs/providers/brave\nMarkdown: https://searchsdk.dev/docs/providers/brave.md\n\n<a id=\"overview\"></a>\n\n## Normalized search\n\n> **TypeScript reference**\n> The API names, code and policy behavior in this article describe the TypeScript SDK. See [your language guide](https://searchsdk.dev/docs/sdks) for its supported surface and limits.\n\nNormalized search reads `web.results`, maps descriptions to snippets, and retains extra snippets as highlights. A valid query echo without a web section is accepted as empty web results. Unreported usage is `null`.\n\n**brave-search.ts · server**\n\n```typescript\nimport { createSearch } from '@belweave/search-sdk';\nimport { brave } from '@belweave/search-sdk/brave';\n\nconst apiKey = process.env.BRAVE_API_KEY;\nif (!apiKey) throw new Error('BRAVE_API_KEY is required');\n\nconst client = createSearch({ provider: brave({ apiKey }) });\nconst response = await client.web.search({\n  query: 'SQLite write concurrency',\n  limit: 5,\n});\nconsole.log(response.results, response.attempts);\n```\n\nThe normalized adapter does not support domain-filter options. Adding it to a filtered fallback chain fails preflight. Native rich results, local information, images, news, and LLM Context must keep their original shapes.\n\nDomain filters unavailable on the normalized adapter.\n\n<a id=\"native-client\"></a>\n\n## Provider-native client\n\n**brave-native.ts · server**\n\n```typescript\nimport { createBraveClient } from '@belweave/search-sdk/native-brave';\n\nconst apiKey = process.env.BRAVE_API_KEY;\nif (!apiKey) throw new Error('BRAVE_API_KEY is required');\n\nconst client = createBraveClient({ apiKey, timeoutMs: 10_000 });\nconst response = await client.search({ query: { q: 'SQLite write concurrency', count: 5 } });\nconsole.log(response.data, response.metadata);\n```\n\nRead provider data from `response.data` and sanitized transport details from `response.metadata`. Native TypeScript response types are not runtime schema validation. Preserve the operation's native response and source identities.\n\n<a id=\"operations\"></a>\n\n## Native operation inventory\n\nMethods available on this native client. Paths are relative to each operation's fixed base; a provider may use more than one origin. Eligible operations retry only when you opt into a client retry policy.\n\n| Method | HTTP / relative path | Response / retry eligibility |\n| --- | --- | --- |\n| `llmContext` | `GET /v1/llm/context` | json · eligible |\n| `llmContextPost` | `POST /v1/llm/context` | json · no automatic retry |\n| `answers` | `POST /v1/chat/completions` | json · no automatic retry |\n| `answersStream` | `POST /v1/chat/completions` | SSE stream · no automatic retry |\n| `search` | `GET /v1/web/search` | json · eligible |\n| `searchPost` | `POST /v1/web/search` | json · no automatic retry |\n| `localPois` | `GET /v1/local/pois` | json · eligible |\n| `poiDescriptions` | `GET /v1/local/descriptions` | json · eligible |\n| `rich` | `GET /v1/web/rich` | json · eligible |\n| `news` | `GET /v1/news/search` | json · eligible |\n| `newsPost` | `POST /v1/news/search` | json · no automatic retry |\n| `videos` | `GET /v1/videos/search` | json · eligible |\n| `videosPost` | `POST /v1/videos/search` | json · no automatic retry |\n| `images` | `GET /v1/images/search` | json · eligible |\n| `places` | `GET /v1/local/place_search` | json · eligible |\n| `suggest` | `GET /v1/suggest/search` | json · eligible |\n| `spellcheck` | `GET /v1/spellcheck/search` | json · eligible |\n\n<a id=\"lifecycle\"></a>\n\n## Limits and operation lifecycle\n\n- Pass `signal` and per-call `timeoutMs` on native request input when needed.\n- Persist a returned job identifier before explicitly reading or polling the same job. Native clients do not automatically poll.\n- SSE data is incremental provider event text. Parse and validate terminal or error events according to the provider contract; there is no reconnect or replay.\n- Native operations may create, delete, ingest, or incur charges. A successful HTTP response is not proof that a remote job completed.\n\n<a id=\"sources\"></a>\n\n## Official sources\n\nUse the official reference for current schemas, account access, and operation-specific requirements.\n\n- [Web Search documentation](https://api-dashboard.search.brave.com/app/documentation/web-search/get-started)\n\n- [Native request and response reference](https://searchsdk.dev/docs/api/native-transport)\n- [All providers](https://searchsdk.dev/docs/providers)\n"
    },
    {
      "slug": "providers/perplexity",
      "title": "Perplexity",
      "description": "Search API retrieval is separate from Sonar and agent-generated answers.",
      "url": "https://searchsdk.dev/docs/providers/perplexity",
      "markdownPath": "/docs/providers/perplexity.md",
      "markdownUrl": "https://searchsdk.dev/docs/providers/perplexity.md",
      "text": "# Perplexity\n\nSearch API retrieval is separate from Sonar and agent-generated answers.\n\nCanonical: https://searchsdk.dev/docs/providers/perplexity\nMarkdown: https://searchsdk.dev/docs/providers/perplexity.md\n\n<a id=\"overview\"></a>\n\n## Normalized search\n\n> **TypeScript reference**\n> The API names, code and policy behavior in this article describe the TypeScript SDK. See [your language guide](https://searchsdk.dev/docs/sdks) for its supported surface and limits.\n\nThe normalized adapter targets the Search API and source snippets. It does not convert generated answers into web results. Native clients preserve search filters, answer and agent responses, embeddings, and asynchronous operation data.\n\n**perplexity-search.ts · server**\n\n```typescript\nimport { createSearch } from '@belweave/search-sdk';\nimport { perplexity } from '@belweave/search-sdk/perplexity';\n\nconst apiKey = process.env.PERPLEXITY_API_KEY;\nif (!apiKey) throw new Error('PERPLEXITY_API_KEY is required');\n\nconst client = createSearch({ provider: perplexity({ apiKey }) });\nconst response = await client.web.search({\n  query: 'SQLite write concurrency',\n  limit: 5,\n});\nconsole.log(response.results, response.attempts);\n```\n\nSearch, Sonar, agent operations, and asynchronous jobs are distinct provider APIs. Select an operation deliberately, preserve citations, and persist remote identifiers before resuming long-running work.\n\n20 include or 20 exclude; both lists cannot be combined.\n\n<a id=\"native-client\"></a>\n\n## Provider-native client\n\n**perplexity-native.ts · server**\n\n```typescript\nimport { createPerplexityClient } from '@belweave/search-sdk/native-perplexity';\n\nconst apiKey = process.env.PERPLEXITY_API_KEY;\nif (!apiKey) throw new Error('PERPLEXITY_API_KEY is required');\n\nconst client = createPerplexityClient({ apiKey, timeoutMs: 10_000 });\nconst response = await client.search({ body: { query: 'SQLite write concurrency', max_results: 5 } });\nconsole.log(response.data, response.metadata);\n```\n\nRead provider data from `response.data` and sanitized transport details from `response.metadata`. Native TypeScript response types are not runtime schema validation. Preserve the operation's native response and source identities.\n\n<a id=\"operations\"></a>\n\n## Native operation inventory\n\nMethods available on this native client. Paths are relative to each operation's fixed base; a provider may use more than one origin. Eligible operations retry only when you opt into a client retry policy.\n\n| Method | HTTP / relative path | Response / retry eligibility |\n| --- | --- | --- |\n| `chatCompletions` | `POST /v1/sonar` | json · no automatic retry |\n| `chatCompletionsStream` | `POST /v1/sonar` | SSE stream · no automatic retry |\n| `search` | `POST /search` | json · no automatic retry |\n| `createEmbeddings` | `POST /v1/embeddings` | json · no automatic retry |\n| `createContextualizedEmbeddings` | `POST /v1/contextualizedembeddings` | json · no automatic retry |\n| `getAsyncChatCompletion` | `GET /v1/async/sonar/{api_request}` | json · eligible |\n| `listAsyncChatCompletions` | `GET /v1/async/sonar` | json · eligible |\n| `createAsyncChatCompletion` | `POST /v1/async/sonar` | json · no automatic retry |\n| `createAgent` | `POST /v1/agent` | json · no automatic retry |\n| `createAgentStream` | `POST /v1/agent` | SSE stream · no automatic retry |\n| `retrieveAgent` | `GET /v1/agent/{id}` | json · eligible |\n| `listAgentFiles` | `GET /v1/agent/{id}/files` | json · eligible |\n| `downloadAgentFile` | `GET /v1/agent/{id}/files/{file_id}/content` | bytes · eligible |\n| `cancelAgentResponse` | `POST /v1/agent/{id}/cancel` | json · no automatic retry |\n| `listModels` | `GET /v1/models` | json · eligible |\n| `getComputerUsageAnalytics` | `GET /v1/analytics/computer/usage` | json · eligible |\n| `getComputerUsageAnalyticsV2` | `GET /v2/analytics/computer/usage` | json · eligible |\n| `listSkills` | `GET /v1/skills` | json · eligible |\n| `createSkill` | `POST /v1/skills` | json · no automatic retry |\n| `getSkill` | `GET /v1/skills/{skill_id}` | json · eligible |\n| `updateSkill` | `PUT /v1/skills/{skill_id}` | json · no automatic retry |\n| `deleteSkill` | `DELETE /v1/skills/{skill_id}` | json · no automatic retry |\n| `listSkillRevisions` | `GET /v1/skills/{skill_id}/revisions` | json · eligible |\n| `downloadSkill` | `GET /v1/skills/{skill_id}/download` | json · eligible |\n| `answerQuestions` | `POST /v1/decisions` | json · no automatic retry |\n| `routerChatCompletions` | `POST /router/v1/chat/completions` | json · no automatic retry |\n| `routerChatCompletionsStream` | `POST /router/v1/chat/completions` | SSE stream · no automatic retry |\n| `routerResponses` | `POST /router/v1/responses` | json · no automatic retry |\n| `routerResponsesStream` | `POST /router/v1/responses` | SSE stream · no automatic retry |\n| `routerMessages` | `POST /router/v1/messages` | json · no automatic retry |\n| `routerMessagesStream` | `POST /router/v1/messages` | SSE stream · no automatic retry |\n| `listRouterModels` | `GET /router/v1/models` | json · eligible |\n| `getRouterModel` | `GET /router/v1/models/{model}` | json · eligible |\n| `generateAuthToken` | `POST /generate_auth_token` | json · no automatic retry |\n| `revokeAuthToken` | `POST /revoke_auth_token` | text · no automatic retry |\n\n<a id=\"lifecycle\"></a>\n\n## Limits and operation lifecycle\n\n- Pass `signal` and per-call `timeoutMs` on native request input when needed.\n- Persist a returned job identifier before explicitly reading or polling the same job. Native clients do not automatically poll.\n- SSE data is incremental provider event text. Parse and validate terminal or error events according to the provider contract; there is no reconnect or replay.\n- Native operations may create, delete, ingest, or incur charges. A successful HTTP response is not proof that a remote job completed.\n\n<a id=\"sources\"></a>\n\n## Official sources\n\nUse the official reference for current schemas, account access, and operation-specific requirements.\n\n- [Search API reference](https://docs.perplexity.ai/api-reference/search-post)\n- [Complete documentation index](https://docs.perplexity.ai/llms.txt)\n\n- [Native request and response reference](https://searchsdk.dev/docs/api/native-transport)\n- [All providers](https://searchsdk.dev/docs/providers)\n"
    },
    {
      "slug": "providers/parallel",
      "title": "Parallel",
      "description": "Query-based retrieval with excerpts, with separate native objectives, extraction, and task APIs.",
      "url": "https://searchsdk.dev/docs/providers/parallel",
      "markdownPath": "/docs/providers/parallel.md",
      "markdownUrl": "https://searchsdk.dev/docs/providers/parallel.md",
      "text": "# Parallel\n\nQuery-based retrieval with excerpts, with separate native objectives, extraction, and task APIs.\n\nCanonical: https://searchsdk.dev/docs/providers/parallel\nMarkdown: https://searchsdk.dev/docs/providers/parallel.md\n\n<a id=\"overview\"></a>\n\n## Normalized search\n\n> **TypeScript reference**\n> The API names, code and policy behavior in this article describe the TypeScript SDK. See [your language guide](https://searchsdk.dev/docs/sdks) for its supported surface and limits.\n\nThe normalized adapter maps one query into `search_queries` and returns search source excerpts without treating an objective or Task response as an ordinary source list. Native excerpts remain native material rather than a generated answer.\n\n**parallel-search.ts · server**\n\n```typescript\nimport { createSearch } from '@belweave/search-sdk';\nimport { parallel } from '@belweave/search-sdk/parallel';\n\nconst apiKey = process.env.PARALLEL_API_KEY;\nif (!apiKey) throw new Error('PARALLEL_API_KEY is required');\n\nconst client = createSearch({ provider: parallel({ apiKey }) });\nconst response = await client.web.search({\n  query: 'SQLite write concurrency',\n  limit: 5,\n});\nconsole.log(response.results, response.attempts);\n```\n\nNative Search can use an objective in addition to queries. Extract, Tasks, FindAll, and monitoring have different lifecycle models. The normalized client does not silently create or poll them.\n\n200 include or 200 exclude under SDK policy; both lists cannot be combined.\n\n<a id=\"native-client\"></a>\n\n## Provider-native client\n\n**parallel-native.ts · server**\n\n```typescript\nimport { createParallelClient } from '@belweave/search-sdk/native-parallel';\n\nconst apiKey = process.env.PARALLEL_API_KEY;\nif (!apiKey) throw new Error('PARALLEL_API_KEY is required');\n\nconst client = createParallelClient({ apiKey, timeoutMs: 10_000 });\nconst response = await client.search({ body: { search_queries: ['SQLite write concurrency'], mode: 'basic' } });\nconsole.log(response.data, response.metadata);\n```\n\nRead provider data from `response.data` and sanitized transport details from `response.metadata`. Native TypeScript response types are not runtime schema validation. Preserve the operation's native response and source identities.\n\n<a id=\"operations\"></a>\n\n## Native operation inventory\n\nMethods available on this native client. Paths are relative to each operation's fixed base; a provider may use more than one origin. Eligible operations retry only when you opt into a client retry policy.\n\n| Method | HTTP / relative path | Response / retry eligibility |\n| --- | --- | --- |\n| `search` | `POST /v1/search` | json · no automatic retry |\n| `imageSearch` | `POST /v1/images/search` | json · no automatic retry |\n| `extract` | `POST /v1/extract` | json · no automatic retry |\n| `createTaskGroup` | `POST /v1/tasks/groups` | json · no automatic retry |\n| `retrieveTaskGroup` | `GET /v1/tasks/groups/{taskgroup_id}` | json · eligible |\n| `streamTaskGroupEvents` | `GET /v1/tasks/groups/{taskgroup_id}/events` | SSE stream · eligible |\n| `addRunsToTaskGroup` | `POST /v1/tasks/groups/{taskgroup_id}/runs` | json · no automatic retry |\n| `fetchTaskGroupRuns` | `GET /v1/tasks/groups/{taskgroup_id}/runs` | SSE stream · eligible |\n| `retrieveTaskGroupRun` | `GET /v1/tasks/groups/{taskgroup_id}/runs/{run_id}` | json · eligible |\n| `createTaskRun` | `POST /v1/tasks/runs` | json · no automatic retry |\n| `retrieveTaskRun` | `GET /v1/tasks/runs/{run_id}` | json · eligible |\n| `streamTaskRunEvents` | `GET /v1/tasks/runs/{run_id}/events` | SSE stream · eligible |\n| `retrieveTaskRunInput` | `GET /v1/tasks/runs/{run_id}/input` | json · eligible |\n| `retrieveTaskRunResult` | `GET /v1/tasks/runs/{run_id}/result` | json · eligible |\n| `fastEntitySearch` | `POST /v1beta/findall/entity-search` | json · no automatic retry |\n| `ingestFindAllRun` | `POST /v1beta/findall/ingest` | json · no automatic retry |\n| `createFindAllRun` | `POST /v1beta/findall/runs` | json · no automatic retry |\n| `retrieveFindAllRunStatus` | `GET /v1beta/findall/runs/{findall_id}` | json · eligible |\n| `cancelFindAllRun` | `POST /v1beta/findall/runs/{findall_id}/cancel` | json · no automatic retry |\n| `addEnrichmentToFindAllRun` | `POST /v1beta/findall/runs/{findall_id}/enrich` | json · no automatic retry |\n| `streamFindAllEvents` | `GET /v1beta/findall/runs/{findall_id}/events` | SSE stream · eligible |\n| `extendFindAllRun` | `POST /v1beta/findall/runs/{findall_id}/extend` | json · no automatic retry |\n| `findAllRunResult` | `GET /v1beta/findall/runs/{findall_id}/result` | json · eligible |\n| `getFindAllRunSchema` | `GET /v1beta/findall/runs/{findall_id}/schema` | json · eligible |\n| `createMonitor` | `POST /v1/monitors` | json · no automatic retry |\n| `listMonitors` | `GET /v1/monitors` | json · eligible |\n| `monitorStats` | `GET /v1/monitors/stats` | json · eligible |\n| `retrieveMonitor` | `GET /v1/monitors/{monitor_id}` | json · eligible |\n| `cancelMonitor` | `POST /v1/monitors/{monitor_id}/cancel` | json · no automatic retry |\n| `listMonitorEvents` | `GET /v1/monitors/{monitor_id}/events` | json · eligible |\n| `triggerMonitorRun` | `POST /v1/monitors/{monitor_id}/trigger` | json · no automatic retry |\n| `updateMonitor` | `POST /v1/monitors/{monitor_id}/update` | json · no automatic retry |\n| `clearMemory` | `POST /v1beta/memory/clear` | json · no automatic retry |\n| `evictFromMemory` | `POST /v1beta/memory/evict` | json · no automatic retry |\n| `retrieveMemory` | `POST /v1beta/memory/retrieve` | json · no automatic retry |\n| `chatCompletions` | `POST /v1beta/chat/completions` | json · no automatic retry |\n| `chatCompletionsStream` | `POST /v1beta/chat/completions` | SSE stream · no automatic retry |\n| `createResponse` | `POST /v1/responses` | json · no automatic retry |\n| `createResponseStream` | `POST /v1/responses` | SSE stream · no automatic retry |\n\n<a id=\"lifecycle\"></a>\n\n## Limits and operation lifecycle\n\n- Pass `signal` and per-call `timeoutMs` on native request input when needed.\n- Persist a returned job identifier before explicitly reading or polling the same job. Native clients do not automatically poll.\n- SSE data is incremental provider event text. Parse and validate terminal or error events according to the provider contract; there is no reconnect or replay.\n- Native operations may create, delete, ingest, or incur charges. A successful HTTP response is not proof that a remote job completed.\n\n<a id=\"sources\"></a>\n\n## Official sources\n\nUse the official reference for current schemas, account access, and operation-specific requirements.\n\n- [Search reference](https://docs.parallel.ai/api-reference/search/search)\n- [Full documentation index](https://docs.parallel.ai/llms.txt)\n\n- [Native request and response reference](https://searchsdk.dev/docs/api/native-transport)\n- [All providers](https://searchsdk.dev/docs/providers)\n"
    },
    {
      "slug": "providers/linkup",
      "title": "Linkup",
      "description": "Search result sources, sourced answers, and structured outputs remain distinct modes.",
      "url": "https://searchsdk.dev/docs/providers/linkup",
      "markdownPath": "/docs/providers/linkup.md",
      "markdownUrl": "https://searchsdk.dev/docs/providers/linkup.md",
      "text": "# Linkup\n\nSearch result sources, sourced answers, and structured outputs remain distinct modes.\n\nCanonical: https://searchsdk.dev/docs/providers/linkup\nMarkdown: https://searchsdk.dev/docs/providers/linkup.md\n\n<a id=\"overview\"></a>\n\n## Normalized search\n\n> **TypeScript reference**\n> The API names, code and policy behavior in this article describe the TypeScript SDK. See [your language guide](https://searchsdk.dev/docs/sdks) for its supported surface and limits.\n\nNormalized search selects a source-result output with fast depth and no image results. It maps returned source names, URLs, and content. Sourced answers and structured output belong on the native surface.\n\n**linkup-search.ts · server**\n\n```typescript\nimport { createSearch } from '@belweave/search-sdk';\nimport { linkup } from '@belweave/search-sdk/linkup';\n\nconst apiKey = process.env.LINKUP_API_KEY;\nif (!apiKey) throw new Error('LINKUP_API_KEY is required');\n\nconst client = createSearch({ provider: linkup({ apiKey }) });\nconst response = await client.web.search({\n  query: 'SQLite write concurrency',\n  limit: 5,\n});\nconsole.log(response.results, response.attempts);\n```\n\nDepth and outputType change work and response semantics. Do not pass a sourced answer to code expecting source rows. The current native reference uses a JSON body with `q`, `depth`, and `outputType`; older overview examples may differ.\n\n100 include / 50 exclude under SDK policy.\n\n<a id=\"native-client\"></a>\n\n## Provider-native client\n\n**linkup-native.ts · server**\n\n```typescript\nimport { createLinkupClient } from '@belweave/search-sdk/native-linkup';\n\nconst apiKey = process.env.LINKUP_API_KEY;\nif (!apiKey) throw new Error('LINKUP_API_KEY is required');\n\nconst client = createLinkupClient({ apiKey, timeoutMs: 10_000 });\nconst response = await client.search({ body: { q: 'SQLite write concurrency', depth: 'fast', outputType: 'searchResults' } });\nconsole.log(response.data, response.metadata);\n```\n\nRead provider data from `response.data` and sanitized transport details from `response.metadata`. Native TypeScript response types are not runtime schema validation. Preserve the operation's native response and source identities.\n\n<a id=\"operations\"></a>\n\n## Native operation inventory\n\nMethods available on this native client. Paths are relative to each operation's fixed base; a provider may use more than one origin. Eligible operations retry only when you opt into a client retry policy.\n\n| Method | HTTP / relative path | Response / retry eligibility |\n| --- | --- | --- |\n| `balance` | `GET /v1/credits/balance` | json · eligible |\n| `createExtract` | `POST /v1/extract` | json · no automatic retry |\n| `listExtract` | `GET /v1/extract` | json · eligible |\n| `getExtract` | `GET /v1/extract/{id}` | json · eligible |\n| `fetchPage` | `POST /v1/fetch` | json · no automatic retry |\n| `search` | `POST /v1/search` | json · no automatic retry |\n| `createTasks` | `POST /v1/tasks` | json · no automatic retry |\n| `listTasks` | `GET /v1/tasks` | json · eligible |\n| `getTask` | `GET /v1/tasks/{id}` | json · eligible |\n| `responses` | `POST /v1/responses` | json · no automatic retry |\n| `createResearch` | `POST /v1/research` | json · no automatic retry |\n| `listResearch` | `GET /v1/research` | json · eligible |\n| `getResearch` | `GET /v1/research/{id}` | json · eligible |\n| `rewindSearch` | `POST /v1/rewind/search` | json · no automatic retry |\n| `rewindFetch` | `POST /v1/rewind/fetch` | json · no automatic retry |\n\n<a id=\"lifecycle\"></a>\n\n## Limits and operation lifecycle\n\n- Pass `signal` and per-call `timeoutMs` on native request input when needed.\n- Persist a returned job identifier before explicitly reading or polling the same job. Native clients do not automatically poll.\n- SSE data is incremental provider event text. Parse and validate terminal or error events according to the provider contract; there is no reconnect or replay.\n- Native operations may create, delete, ingest, or incur charges. A successful HTTP response is not proof that a remote job completed.\n\n<a id=\"sources\"></a>\n\n## Official sources\n\nUse the official reference for current schemas, account access, and operation-specific requirements.\n\n- [Search overview](https://docs.linkup.so/pages/documentation/endpoints/search/overview)\n- [Documentation index](https://docs.linkup.so/llms.txt)\n\n- [Native request and response reference](https://searchsdk.dev/docs/api/native-transport)\n- [All providers](https://searchsdk.dev/docs/providers)\n"
    },
    {
      "slug": "providers/firecrawl",
      "title": "Firecrawl",
      "description": "Web search with explicitly separate scraping, extraction, crawl, and monitor operations.",
      "url": "https://searchsdk.dev/docs/providers/firecrawl",
      "markdownPath": "/docs/providers/firecrawl.md",
      "markdownUrl": "https://searchsdk.dev/docs/providers/firecrawl.md",
      "text": "# Firecrawl\n\nWeb search with explicitly separate scraping, extraction, crawl, and monitor operations.\n\nCanonical: https://searchsdk.dev/docs/providers/firecrawl\nMarkdown: https://searchsdk.dev/docs/providers/firecrawl.md\n\n<a id=\"overview\"></a>\n\n## Normalized search\n\n> **TypeScript reference**\n> The API names, code and policy behavior in this article describe the TypeScript SDK. See [your language guide](https://searchsdk.dev/docs/sdks) for its supported surface and limits.\n\nNormalized search selects ordinary web sources and caps output. Optional page scraping and other result categories are not folded into web snippets. Provider-native responses keep scrape and per-page outcome information.\n\n**firecrawl-search.ts · server**\n\n```typescript\nimport { createSearch } from '@belweave/search-sdk';\nimport { firecrawl } from '@belweave/search-sdk/firecrawl';\n\nconst apiKey = process.env.FIRECRAWL_API_KEY;\nif (!apiKey) throw new Error('FIRECRAWL_API_KEY is required');\n\nconst client = createSearch({ provider: firecrawl({ apiKey }) });\nconst response = await client.web.search({\n  query: 'SQLite write concurrency',\n  limit: 5,\n});\nconsole.log(response.results, response.attempts);\n```\n\nOpting into scraping adds retrieval work and can produce partial failures. Treat image, news, and specialized indexes as separate material. The native endpoint inventory reflects the pinned SDK mapping rather than a guarantee of every future provider extension.\n\n100 include or 100 exclude under conservative SDK policy; both lists cannot be combined. Query ceiling: 500 UTF-16 code units.\n\n<a id=\"native-client\"></a>\n\n## Provider-native client\n\n**firecrawl-native.ts · server**\n\n```typescript\nimport { createFirecrawlClient } from '@belweave/search-sdk/native-firecrawl';\n\nconst apiKey = process.env.FIRECRAWL_API_KEY;\nif (!apiKey) throw new Error('FIRECRAWL_API_KEY is required');\n\nconst client = createFirecrawlClient({ apiKey, timeoutMs: 10_000 });\nconst response = await client.search({ body: { query: 'SQLite write concurrency', limit: 5, sources: [{ type: 'web' }] } });\nconsole.log(response.data, response.metadata);\n```\n\nRead provider data from `response.data` and sanitized transport details from `response.metadata`. Native TypeScript response types are not runtime schema validation. Preserve the operation's native response and source identities.\n\n<a id=\"operations\"></a>\n\n## Native operation inventory\n\nMethods available on this native client. Paths are relative to each operation's fixed base; a provider may use more than one origin. Eligible operations retry only when you opt into a client retry policy.\n\n| Method | HTTP / relative path | Response / retry eligibility |\n| --- | --- | --- |\n| `createMonitor` | `POST /monitor` | json · no automatic retry |\n| `listMonitors` | `GET /monitor` | json · eligible |\n| `getMonitor` | `GET /monitor/{monitorId}` | json · eligible |\n| `updateMonitor` | `PATCH /monitor/{monitorId}` | json · no automatic retry |\n| `deleteMonitor` | `DELETE /monitor/{monitorId}` | json · no automatic retry |\n| `runMonitor` | `POST /monitor/{monitorId}/run` | json · no automatic retry |\n| `listMonitorChecks` | `GET /monitor/{monitorId}/checks` | json · eligible |\n| `getMonitorCheck` | `GET /monitor/{monitorId}/checks/{checkId}` | json · eligible |\n| `scrape` | `POST /scrape` | json · no automatic retry |\n| `interactWithScrapeBrowserSession` | `POST /scrape/{jobId}/interact` | json · no automatic retry |\n| `stopInteractiveScrapeBrowserSession` | `DELETE /scrape/{jobId}/interact` | json · no automatic retry |\n| `parseFile` | `POST /parse` | json · no automatic retry |\n| `getParseFormats` | `GET /parse/formats` | json · eligible |\n| `batchScrape` | `POST /batch/scrape` | json · no automatic retry |\n| `getBatchScrapeStatus` | `GET /batch/scrape/{id}` | json · eligible |\n| `cancelBatchScrape` | `DELETE /batch/scrape/{id}` | json · no automatic retry |\n| `getBatchScrapeErrors` | `GET /batch/scrape/{id}/errors` | json · eligible |\n| `getCrawlStatus` | `GET /crawl/{id}` | json · eligible |\n| `cancelCrawl` | `DELETE /crawl/{id}` | json · no automatic retry |\n| `getCrawlErrors` | `GET /crawl/{id}/errors` | json · eligible |\n| `crawl` | `POST /crawl` | json · no automatic retry |\n| `crawlParamsPreview` | `POST /crawl/params-preview` | json · no automatic retry |\n| `map` | `POST /map` | json · no automatic retry |\n| `extract` | `POST /extract` | json · no automatic retry |\n| `getExtractStatus` | `GET /extract/{id}` | json · eligible |\n| `listAgents` | `GET /agent` | json · eligible |\n| `startAgent` | `POST /agent` | json · no automatic retry |\n| `getAgentStatus` | `GET /agent/{jobId}` | json · eligible |\n| `cancelAgent` | `DELETE /agent/{jobId}` | json · no automatic retry |\n| `getAgentTrace` | `GET /agent/{jobId}/trace` | json · eligible |\n| `getAgentSnapshot` | `GET /agent/{jobId}/snapshots/{snapshotId}` | json · eligible |\n| `getActiveCrawls` | `GET /crawl/active` | json · eligible |\n| `getCreditUsage` | `GET /team/credit-usage` | json · eligible |\n| `getHistoricalCreditUsage` | `GET /team/credit-usage/historical` | json · eligible |\n| `getTokenUsage` | `GET /team/token-usage` | json · eligible |\n| `getHistoricalTokenUsage` | `GET /team/token-usage/historical` | json · eligible |\n| `getQueueStatus` | `GET /team/queue-status` | json · eligible |\n| `getActivity` | `GET /team/activity` | json · eligible |\n| `search` | `POST /search` | json · no automatic retry |\n| `createBrowserSession` | `POST /interact` | json · no automatic retry |\n| `listBrowserSessions` | `GET /interact` | json · eligible |\n| `executeBrowserCode` | `POST /interact/{sessionId}/execute` | json · no automatic retry |\n| `deleteBrowserSession` | `DELETE /interact/{sessionId}` | json · no automatic retry |\n| `getScrapeStatus` | `GET /scrape/{jobId}` | json · eligible |\n| `submitSearchFeedback` | `POST /search/{jobId}/feedback` | json · no automatic retry |\n| `askSupportAgent` | `POST /support/ask` | json · no automatic retry |\n| `searchSupportDocs` | `POST /support/docs-search` | json · no automatic retry |\n| `researchSearchPapers` | `GET /search/research/papers` | json · eligible |\n| `researchGetPaper` | `GET /search/research/papers/{id}` | json · eligible |\n| `researchRelatedPapers` | `GET /search/research/papers/{id}/similar` | json · eligible |\n| `developerSearch` | `GET /search/developer` | json · eligible |\n| `developerSearchPost` | `POST /search/developer` | json · no automatic retry |\n| `govSearch` | `GET /search/gov` | json · eligible |\n| `govSearchPost` | `POST /search/gov` | json · no automatic retry |\n| `submitEndpointFeedback` | `POST /feedback` | json · no automatic retry |\n| `getThreatProtection` | `GET /team/threat-protection` | json · eligible |\n| `updateThreatProtection` | `PUT /team/threat-protection` | json · no automatic retry |\n\n<a id=\"lifecycle\"></a>\n\n## Limits and operation lifecycle\n\n- Pass `signal` and per-call `timeoutMs` on native request input when needed.\n- Persist a returned job identifier before explicitly reading or polling the same job. Native clients do not automatically poll.\n- SSE data is incremental provider event text. Parse and validate terminal or error events according to the provider contract; there is no reconnect or replay.\n- Native operations may create, delete, ingest, or incur charges. A successful HTTP response is not proof that a remote job completed.\n\n<a id=\"sources\"></a>\n\n## Official sources\n\nUse the official reference for current schemas, account access, and operation-specific requirements.\n\n- [Search documentation](https://docs.firecrawl.dev/features/search)\n- [Documentation index](https://docs.firecrawl.dev/llms.txt)\n\n- [Native request and response reference](https://searchsdk.dev/docs/api/native-transport)\n- [All providers](https://searchsdk.dev/docs/providers)\n"
    },
    {
      "slug": "providers/you",
      "title": "You.com",
      "description": "Web and news retrieval, optional extraction, and separate answer and research APIs.",
      "url": "https://searchsdk.dev/docs/providers/you",
      "markdownPath": "/docs/providers/you.md",
      "markdownUrl": "https://searchsdk.dev/docs/providers/you.md",
      "text": "# You.com\n\nWeb and news retrieval, optional extraction, and separate answer and research APIs.\n\nCanonical: https://searchsdk.dev/docs/providers/you\nMarkdown: https://searchsdk.dev/docs/providers/you.md\n\n<a id=\"overview\"></a>\n\n## Normalized search\n\n> **TypeScript reference**\n> The API names, code and policy behavior in this article describe the TypeScript SDK. See [your language guide](https://searchsdk.dev/docs/sdks) for its supported surface and limits.\n\nNormalized search reads only the web section with snippets. Native count can apply independently to result sections; it is not a combined web-plus-news ceiling. Extraction settings belong to the native request.\n\n**you-search.ts · server**\n\n```typescript\nimport { createSearch } from '@belweave/search-sdk';\nimport { you } from '@belweave/search-sdk/you';\n\nconst apiKey = process.env.YOU_API_KEY;\nif (!apiKey) throw new Error('YOU_API_KEY is required');\n\nconst client = createSearch({ provider: you({ apiKey }) });\nconst response = await client.web.search({\n  query: 'SQLite write concurrency',\n  limit: 5,\n});\nconsole.log(response.results, response.attempts);\n```\n\nDo not flatten news, knowledge, and full-page content into one source shape. Answer and Research are synthesis operations. SDK convenience defaults and raw HTTP defaults can differ; set native extraction behavior deliberately.\n\n500 include or 5,000 exclude; both lists cannot be combined.\n\n<a id=\"native-client\"></a>\n\n## Provider-native client\n\n**you-native.ts · server**\n\n```typescript\nimport { createYouClient } from '@belweave/search-sdk/native-you';\n\nconst apiKey = process.env.YOU_API_KEY;\nif (!apiKey) throw new Error('YOU_API_KEY is required');\n\nconst client = createYouClient({ apiKey, timeoutMs: 10_000 });\nconst response = await client.search({ body: { query: 'SQLite write concurrency', count: 5 } });\nconsole.log(response.data, response.metadata);\n```\n\nRead provider data from `response.data` and sanitized transport details from `response.metadata`. Native TypeScript response types are not runtime schema validation. Preserve the operation's native response and source identities.\n\n<a id=\"operations\"></a>\n\n## Native operation inventory\n\nMethods available on this native client. Paths are relative to each operation's fixed base; a provider may use more than one origin. Eligible operations retry only when you opt into a client retry policy.\n\n| Method | HTTP / relative path | Response / retry eligibility |\n| --- | --- | --- |\n| `search` | `POST /v1/search` | json · no automatic retry |\n| `contents` | `POST /v1/contents` | json · no automatic retry |\n| `answer` | `POST /v1/answer` | json · no automatic retry |\n| `research` | `POST /v1/research` | json · no automatic retry |\n| `getResearchTask` | `GET /v1/research/{task_id}` | json · eligible |\n| `streamResearchTask` | `GET /v1/research/{task_id}/stream` | SSE stream · eligible |\n| `financeResearch` | `POST /v1/finance_research` | json · no automatic retry |\n| `getAccountBalance` | `GET /v1/billing/account_balance` | json · eligible |\n| `images` | `GET /v1/images` | json · eligible |\n\n<a id=\"lifecycle\"></a>\n\n## Limits and operation lifecycle\n\n- Pass `signal` and per-call `timeoutMs` on native request input when needed.\n- Persist a returned job identifier before explicitly reading or polling the same job. Native clients do not automatically poll.\n- SSE data is incremental provider event text. Parse and validate terminal or error events according to the provider contract; there is no reconnect or replay.\n- Native operations may create, delete, ingest, or incur charges. A successful HTTP response is not proof that a remote job completed.\n\n<a id=\"sources\"></a>\n\n## Official sources\n\nUse the official reference for current schemas, account access, and operation-specific requirements.\n\n- [Search API reference](https://you.com/docs/api-reference/search/v1-search)\n- [Documentation index](https://you.com/docs/llms.txt)\n\n- [Native request and response reference](https://searchsdk.dev/docs/api/native-transport)\n- [All providers](https://searchsdk.dev/docs/providers)\n"
    },
    {
      "slug": "providers/serper",
      "title": "Serper",
      "description": "Organic search results plus provider-native SERP verticals and rich response fields.",
      "url": "https://searchsdk.dev/docs/providers/serper",
      "markdownPath": "/docs/providers/serper.md",
      "markdownUrl": "https://searchsdk.dev/docs/providers/serper.md",
      "text": "# Serper\n\nOrganic search results plus provider-native SERP verticals and rich response fields.\n\nCanonical: https://searchsdk.dev/docs/providers/serper\nMarkdown: https://searchsdk.dev/docs/providers/serper.md\n\n<a id=\"overview\"></a>\n\n## Normalized search\n\n> **TypeScript reference**\n> The API names, code and policy behavior in this article describe the TypeScript SDK. See [your language guide](https://searchsdk.dev/docs/sdks) for its supported surface and limits.\n\nNormalized search maps organic title, link, and snippet fields. It does not substitute answer boxes, knowledge graph data, local listings, or shopping results for organic web rows.\n\n**serper-search.ts · server**\n\n```typescript\nimport { createSearch } from '@belweave/search-sdk';\nimport { serper } from '@belweave/search-sdk/serper';\n\nconst apiKey = process.env.SERPER_API_KEY;\nif (!apiKey) throw new Error('SERPER_API_KEY is required');\n\nconst client = createSearch({ provider: serper({ apiKey }) });\nconst response = await client.web.search({\n  query: 'SQLite write concurrency',\n  limit: 5,\n});\nconsole.log(response.results, response.attempts);\n```\n\nUse native operations for result verticals and rich SERP fields. Public examples do not establish account quotas or independent speed and cost comparisons. Endpoint inventory and generated request types describe documented mappings, with live account behavior still unverified.\n\nDomain filters unavailable on the normalized adapter.\n\n<a id=\"native-client\"></a>\n\n## Provider-native client\n\n**serper-native.ts · server**\n\n```typescript\nimport { createSerperClient } from '@belweave/search-sdk/native-serper';\n\nconst apiKey = process.env.SERPER_API_KEY;\nif (!apiKey) throw new Error('SERPER_API_KEY is required');\n\nconst client = createSerperClient({ apiKey, timeoutMs: 10_000 });\nconst response = await client.search({ body: { q: 'SQLite write concurrency', num: 5 } });\nconsole.log(response.data, response.metadata);\n```\n\nRead provider data from `response.data` and sanitized transport details from `response.metadata`. Native TypeScript response types are not runtime schema validation. Preserve the operation's native response and source identities.\n\n<a id=\"operations\"></a>\n\n## Native operation inventory\n\nMethods available on this native client. Paths are relative to each operation's fixed base; a provider may use more than one origin. Eligible operations retry only when you opt into a client retry policy.\n\n| Method | HTTP / relative path | Response / retry eligibility |\n| --- | --- | --- |\n| `search` | `POST /search` | json · no automatic retry |\n| `searchGet` | `GET /search` | json · eligible |\n| `images` | `POST /images` | json · no automatic retry |\n| `imagesGet` | `GET /images` | json · eligible |\n| `videos` | `POST /videos` | json · no automatic retry |\n| `videosGet` | `GET /videos` | json · eligible |\n| `places` | `POST /places` | json · no automatic retry |\n| `placesGet` | `GET /places` | json · eligible |\n| `maps` | `POST /maps` | json · no automatic retry |\n| `mapsGet` | `GET /maps` | json · eligible |\n| `reviews` | `POST /reviews` | json · no automatic retry |\n| `reviewsGet` | `GET /reviews` | json · eligible |\n| `news` | `POST /news` | json · no automatic retry |\n| `newsGet` | `GET /news` | json · eligible |\n| `shopping` | `POST /shopping` | json · no automatic retry |\n| `shoppingGet` | `GET /shopping` | json · eligible |\n| `scholar` | `POST /scholar` | json · no automatic retry |\n| `scholarGet` | `GET /scholar` | json · eligible |\n| `patents` | `POST /patents` | json · no automatic retry |\n| `patentsGet` | `GET /patents` | json · eligible |\n| `autocomplete` | `POST /autocomplete` | json · no automatic retry |\n| `autocompleteGet` | `GET /autocomplete` | json · eligible |\n| `lens` | `POST /lens` | json · no automatic retry |\n| `lensGet` | `GET /lens` | json · eligible |\n| `scrape` | `POST /` | json · no automatic retry |\n| `scrapeGet` | `GET /` | json · eligible |\n\n<a id=\"lifecycle\"></a>\n\n## Limits and operation lifecycle\n\n- Pass `signal` and per-call `timeoutMs` on native request input when needed.\n- Persist a returned job identifier before explicitly reading or polling the same job. Native clients do not automatically poll.\n- SSE data is incremental provider event text. Parse and validate terminal or error events according to the provider contract; there is no reconnect or replay.\n- Native operations may create, delete, ingest, or incur charges. A successful HTTP response is not proof that a remote job completed.\n\n<a id=\"sources\"></a>\n\n## Official sources\n\nUse the official reference for current schemas, account access, and operation-specific requirements.\n\n- [Official product and examples](https://serper.dev/)\n- [Official playground](https://serper.dev/playground)\n\n- [Native request and response reference](https://searchsdk.dev/docs/api/native-transport)\n- [All providers](https://searchsdk.dev/docs/providers)\n"
    },
    {
      "slug": "providers/serpapi",
      "title": "SerpAPI",
      "description": "Structured engine-specific SERP data; normalized search begins with Google organic results.",
      "url": "https://searchsdk.dev/docs/providers/serpapi",
      "markdownPath": "/docs/providers/serpapi.md",
      "markdownUrl": "https://searchsdk.dev/docs/providers/serpapi.md",
      "text": "# SerpAPI\n\nStructured engine-specific SERP data; normalized search begins with Google organic results.\n\nCanonical: https://searchsdk.dev/docs/providers/serpapi\nMarkdown: https://searchsdk.dev/docs/providers/serpapi.md\n\n<a id=\"overview\"></a>\n\n## Normalized search\n\n> **TypeScript reference**\n> The API names, code and policy behavior in this article describe the TypeScript SDK. See [your language guide](https://searchsdk.dev/docs/sdks) for its supported surface and limits.\n\nNormalized search uses synchronous Google search and maps organic results only. It checks provider error/status information even after an HTTP success. Native engine selection preserves engine-specific fields.\n\n**serpapi-search.ts · server**\n\n```typescript\nimport { createSearch } from '@belweave/search-sdk';\nimport { serpapi } from '@belweave/search-sdk/serpapi';\n\nconst apiKey = process.env.SERPAPI_API_KEY;\nif (!apiKey) throw new Error('SERPAPI_API_KEY is required');\n\nconst client = createSearch({ provider: serpapi({ apiKey }) });\nconst response = await client.web.search({\n  query: 'SQLite write concurrency',\n  limit: 5,\n});\nconsole.log(response.results, response.attempts);\n```\n\nSelecting an engine on the native client is not a claim that every engine has an independently tested normalized adapter. Async search, archives, pagination, and rich result categories require their own handling. Provider URLs may contain account-sensitive query parameters; avoid logging them.\n\nDomain filters unavailable on the normalized adapter.\n\n<a id=\"native-client\"></a>\n\n## Provider-native client\n\n**serpapi-native.ts · server**\n\n```typescript\nimport { createSerpApiClient } from '@belweave/search-sdk/native-serpapi';\n\nconst apiKey = process.env.SERPAPI_API_KEY;\nif (!apiKey) throw new Error('SERPAPI_API_KEY is required');\n\nconst client = createSerpApiClient({ apiKey, timeoutMs: 10_000 });\nconst response = await client.search({ query: { engine: 'google', q: 'SQLite write concurrency' } });\nconsole.log(response.data, response.metadata);\n```\n\nRead provider data from `response.data` and sanitized transport details from `response.metadata`. Native TypeScript response types are not runtime schema validation. Preserve the operation's native response and source identities.\n\n<a id=\"operations\"></a>\n\n## Native operation inventory\n\nMethods available on this native client. Paths are relative to each operation's fixed base; a provider may use more than one origin. Eligible operations retry only when you opt into a client retry policy.\n\n| Method | HTTP / relative path | Response / retry eligibility |\n| --- | --- | --- |\n| `search` | `GET /search.json` | json · no automatic retry |\n| `searchHtml` | `GET /search.html` | text · no automatic retry |\n| `searchMarkdown` | `GET /search.md` | text · no automatic retry |\n| `searchPixelPositions` | `GET /search.json_with_pixel_position` | json · no automatic retry |\n| `getSearch` | `GET /searches/{search_id}.json` | json · eligible |\n| `getSearchHtml` | `GET /searches/{search_id}.html` | text · eligible |\n| `getSearchPixelPositions` | `GET /searches/{search_id}.json_with_pixel_position` | json · no automatic retry |\n| `locations` | `GET /locations.json` | json · eligible |\n| `account` | `GET /account.json` | json · eligible |\n| `uploadImage` | `POST /image` | json · no automatic retry |\n\nAdditional client helpers: `google`, `extract`, `extractMarkdown`. These reuse catalog operations or expose a native output variant. Their input and response types remain in the provider subpath.\n\n<a id=\"lifecycle\"></a>\n\n## Limits and operation lifecycle\n\n- Pass `signal` and per-call `timeoutMs` on native request input when needed.\n- Persist a returned job identifier before explicitly reading or polling the same job. Native clients do not automatically poll.\n- SSE data is incremental provider event text. Parse and validate terminal or error events according to the provider contract; there is no reconnect or replay.\n- Native operations may create, delete, ingest, or incur charges. A successful HTTP response is not proof that a remote job completed.\n\n<a id=\"sources\"></a>\n\n## Official sources\n\nUse the official reference for current schemas, account access, and operation-specific requirements.\n\n- [Google Search API reference](https://serpapi.com/search-api)\n\n- [Native request and response reference](https://searchsdk.dev/docs/api/native-transport)\n- [All providers](https://searchsdk.dev/docs/providers)\n"
    },
    {
      "slug": "providers/wondersearch",
      "title": "WonderSearch",
      "description": "Semantic retrieval over ingested documents and workspace collections, with corpus-native citation identities.",
      "url": "https://searchsdk.dev/docs/providers/wondersearch",
      "markdownPath": "/docs/providers/wondersearch.md",
      "markdownUrl": "https://searchsdk.dev/docs/providers/wondersearch.md",
      "text": "# WonderSearch\n\nSemantic retrieval over ingested documents and workspace collections, with corpus-native citation identities.\n\nCanonical: https://searchsdk.dev/docs/providers/wondersearch\nMarkdown: https://searchsdk.dev/docs/providers/wondersearch.md\n\n<a id=\"overview\"></a>\n\n## Corpus retrieval boundary\n\n> **TypeScript reference**\n> The API names, code and policy behavior in this article describe the TypeScript SDK. See [your language guide](https://searchsdk.dev/docs/sdks) for its supported surface and limits.\n\nWonderSearch.ai and WonderSearch.com are one provider. Its native client searches a drive or workspace corpus and preserves provider document, revision, snapshot, and passage data. It is not a normalized open-web adapter.\n\nIngestion readiness is a prerequisite. Preserve passage snapshots and text offsets for citations. A document ID is not a public web URL. Search requires a provider Idempotency-Key; the native client does not invent one or silently resubmit ambiguous work.\n\nCorpus scopes and native metadata filters; normalized web domain filters do not apply.\n\n<a id=\"native-client\"></a>\n\n## Provider-native client\n\n**wondersearch-native.ts · server**\n\n```typescript\nimport { createWonderSearchClient } from '@belweave/search-sdk/native-wondersearch';\n\nconst apiKey = process.env.WONDERSEARCH_API_KEY;\nif (!apiKey) throw new Error('WONDERSEARCH_API_KEY is required');\n\nconst client = createWonderSearchClient({ apiKey, timeoutMs: 10_000 });\nconst response = await client.searchDrive({\n  path: { drive_id: 'your-drive-id' },\n  headers: { 'Idempotency-Key': crypto.randomUUID() },\n  body: { query: 'SQLite write concurrency' },\n});\nconsole.log(response.data, response.metadata);\n```\n\nRead provider data from `response.data` and sanitized transport details from `response.metadata`. Native TypeScript response types are not runtime schema validation. Preserve the operation's native response and source identities.\n\n<a id=\"operations\"></a>\n\n## Native operation inventory\n\nMethods available on this native client. Paths are relative to each operation's fixed base; a provider may use more than one origin. Eligible operations retry only when you opt into a client retry policy.\n\n| Method | HTTP / relative path | Response / retry eligibility |\n| --- | --- | --- |\n| `searchDrive` | `POST /v1/drives/{drive_id}/search` | json · no automatic retry |\n| `getPassage` | `GET /v1/drives/{drive_id}/passages/{passage_id}` | json · eligible |\n| `getCapabilities` | `GET /v1/workspaces/{workspace_id}/capabilities` | json · eligible |\n| `searchWorkspace` | `POST /v1/workspaces/{workspace_id}/search` | json · no automatic retry |\n| `bootstrapAccount` | `POST /v1/account/bootstrap` | json · no automatic retry |\n| `getMe` | `GET /v1/me` | json · eligible |\n| `listOrganizations` | `GET /v1/organizations` | json · eligible |\n| `getOrganization` | `GET /v1/organizations/{organization_id}` | json · eligible |\n| `getOrganizationRaw` | `GET /v1/organizations/{organization_id}` | raw · eligible |\n| `updateOrganization` | `PATCH /v1/organizations/{organization_id}` | json · no automatic retry |\n| `listOrganizationMembers` | `GET /v1/organizations/{organization_id}/members` | json · eligible |\n| `updateOrganizationMember` | `PATCH /v1/organizations/{organization_id}/members/{user_id}` | json · no automatic retry |\n| `deleteOrganizationMember` | `DELETE /v1/organizations/{organization_id}/members/{user_id}` | json · no automatic retry |\n| `listOrganizationWorkspaces` | `GET /v1/organizations/{organization_id}/workspaces` | json · eligible |\n| `createOrganizationWorkspace` | `POST /v1/organizations/{organization_id}/workspaces` | json · no automatic retry |\n| `getWorkspace` | `GET /v1/workspaces/{workspace_id}` | json · eligible |\n| `getWorkspaceRaw` | `GET /v1/workspaces/{workspace_id}` | raw · eligible |\n| `updateWorkspace` | `PATCH /v1/workspaces/{workspace_id}` | json · no automatic retry |\n| `listWorkspaceInheritedMembers` | `GET /v1/workspaces/{workspace_id}/inherited-members` | json · eligible |\n| `listWorkspaceMembers` | `GET /v1/workspaces/{workspace_id}/members` | json · eligible |\n| `createWorkspaceMember` | `POST /v1/workspaces/{workspace_id}/members` | json · no automatic retry |\n| `updateWorkspaceMember` | `PATCH /v1/workspaces/{workspace_id}/members/{user_id}` | json · no automatic retry |\n| `deleteWorkspaceMember` | `DELETE /v1/workspaces/{workspace_id}/members/{user_id}` | json · no automatic retry |\n| `listOrganizationInvitations` | `GET /v1/organizations/{organization_id}/invitations` | json · eligible |\n| `createOrganizationInvitation` | `POST /v1/organizations/{organization_id}/invitations` | json · no automatic retry |\n| `getOrganizationInvitation` | `GET /v1/organizations/{organization_id}/invitations/{invitation_id}` | json · eligible |\n| `getOrganizationInvitationRaw` | `GET /v1/organizations/{organization_id}/invitations/{invitation_id}` | raw · eligible |\n| `deleteOrganizationInvitation` | `DELETE /v1/organizations/{organization_id}/invitations/{invitation_id}` | json · no automatic retry |\n| `resendOrganizationInvitation` | `POST /v1/organizations/{organization_id}/invitations/{invitation_id}/resend` | json · no automatic retry |\n| `previewInvitation` | `POST /v1/invitations/preview` | json · no automatic retry |\n| `acceptInvitation` | `POST /v1/invitations/accept` | json · no automatic retry |\n| `listWorkspaceApiKeys` | `GET /v1/workspaces/{workspace_id}/api-keys` | json · eligible |\n| `createWorkspaceApiKey` | `POST /v1/workspaces/{workspace_id}/api-keys` | json · no automatic retry |\n| `deleteWorkspaceApiKey` | `DELETE /v1/workspaces/{workspace_id}/api-keys/{key_id}` | json · no automatic retry |\n| `getWorkspaceOverview` | `GET /v1/workspaces/{workspace_id}/overview` | json · eligible |\n| `getOrganizationUsage` | `GET /v1/organizations/{organization_id}/usage` | json · eligible |\n| `listWorkspaceDrives` | `GET /v1/workspaces/{workspace_id}/drives` | json · eligible |\n| `createWorkspaceDrive` | `POST /v1/workspaces/{workspace_id}/drives` | json · no automatic retry |\n| `getDrive` | `GET /v1/drives/{drive_id}` | json · eligible |\n| `getDriveRaw` | `GET /v1/drives/{drive_id}` | raw · eligible |\n| `updateDrive` | `PATCH /v1/drives/{drive_id}` | json · no automatic retry |\n| `deleteDrive` | `DELETE /v1/drives/{drive_id}` | json · no automatic retry |\n| `listDriveFolders` | `GET /v1/drives/{drive_id}/folders` | json · eligible |\n| `createDriveFolder` | `POST /v1/drives/{drive_id}/folders` | json · no automatic retry |\n| `getDriveFolder` | `GET /v1/drives/{drive_id}/folders/{folder_id}` | json · eligible |\n| `getDriveFolderRaw` | `GET /v1/drives/{drive_id}/folders/{folder_id}` | raw · eligible |\n| `updateDriveFolder` | `PATCH /v1/drives/{drive_id}/folders/{folder_id}` | json · no automatic retry |\n| `deleteDriveFolder` | `DELETE /v1/drives/{drive_id}/folders/{folder_id}` | json · no automatic retry |\n| `createDriveDocument` | `POST /v1/drives/{drive_id}/documents` | json · no automatic retry |\n| `listDriveDocuments` | `GET /v1/drives/{drive_id}/documents` | json · eligible |\n| `getDriveDocument` | `GET /v1/drives/{drive_id}/documents/{document_id}` | json · eligible |\n| `replaceDocument` | `PUT /v1/drives/{drive_id}/documents/{document_id}` | json · no automatic retry |\n| `deleteDriveDocument` | `DELETE /v1/drives/{drive_id}/documents/{document_id}` | json · no automatic retry |\n| `getDriveDocumentSource` | `GET /v1/drives/{drive_id}/documents/{document_id}/source` | bytes · eligible |\n| `getWorkspaceDefaultDrive` | `GET /v1/workspaces/{workspace_id}/default-drive` | json · eligible |\n| `getWorkspaceDefaultDriveRaw` | `GET /v1/workspaces/{workspace_id}/default-drive` | raw · eligible |\n| `setDefaultDrive` | `PUT /v1/workspaces/{workspace_id}/default-drive` | json · no automatic retry |\n| `getSdkContext` | `GET /v1/sdk/context` | json · eligible |\n| `getDriveUploadCapabilities` | `GET /v1/drives/{drive_id}/uploads/capabilities` | json · eligible |\n| `createUploadBatch` | `POST /v1/drives/{drive_id}/uploads/batch` | json · no automatic retry |\n| `completeUploadBatch` | `POST /v1/drives/{drive_id}/uploads/batch/complete` | json · no automatic retry |\n| `getUploadBatchStatus` | `POST /v1/drives/{drive_id}/uploads/batch/status` | json · no automatic retry |\n| `createDriveUpload` | `POST /v1/drives/{drive_id}/uploads` | json · no automatic retry |\n| `getDriveUpload` | `GET /v1/drives/{drive_id}/uploads/{upload_id}` | json · eligible |\n| `uploadContent` | `PUT /v1/drives/{drive_id}/uploads/{upload_id}/content` | json · no automatic retry |\n| `createUploadTransfer` | `POST /v1/drives/{drive_id}/uploads/{upload_id}/transfer` | json · no automatic retry |\n| `completeUpload` | `POST /v1/drives/{drive_id}/uploads/{upload_id}/complete` | json · no automatic retry |\n| `getWorkspaceOperation` | `GET /v1/workspaces/{workspace_id}/operations/{operation_id}` | json · eligible |\n| `createImport` | `PUT /v1/drives/{drive_id}/imports/{import_id}` | json · no automatic retry |\n| `getImport` | `GET /v1/drives/{drive_id}/imports/{import_id}` | json · eligible |\n| `declareImportChunks` | `POST /v1/drives/{drive_id}/imports/{import_id}/chunks` | json · no automatic retry |\n| `acknowledgeImportChunk` | `POST /v1/drives/{drive_id}/imports/{import_id}/chunks/{sequence}/acknowledge` | json · no automatic retry |\n| `sealImport` | `POST /v1/drives/{drive_id}/imports/{import_id}/seal` | json · no automatic retry |\n| `getIngestionMetrics` | `GET /v1/drives/{drive_id}/ingestion-metrics` | json · eligible |\n| `getOrganizationBilling` | `GET /v1/organizations/{organization_id}/billing` | json · eligible |\n| `setBillingLimits` | `POST /v1/organizations/{organization_id}/billing/limits` | json · no automatic retry |\n| `getOrganizationBillingLimits` | `GET /v1/organizations/{organization_id}/billing/limits` | json · eligible |\n| `getOrganizationBillingUsage` | `GET /v1/organizations/{organization_id}/billing/usage` | json · eligible |\n| `createBillingPortal` | `POST /v1/organizations/{organization_id}/billing/portal` | json · no automatic retry |\n| `getOrganizationBillingWallet` | `GET /v1/organizations/{organization_id}/billing/wallet` | json · eligible |\n| `getOrganizationBillingActivity` | `GET /v1/organizations/{organization_id}/billing/activity` | json · eligible |\n| `createOrganizationBillingPurchase` | `POST /v1/organizations/{organization_id}/billing/purchases` | json · no automatic retry |\n| `getOrganizationBillingPurchase` | `GET /v1/organizations/{organization_id}/billing/purchases/{purchase_id}` | json · eligible |\n| `listOrganizationBillingInvoices` | `GET /v1/organizations/{organization_id}/billing/invoices` | json · eligible |\n| `getWorkspaceStorage` | `GET /v1/workspaces/{workspace_id}/storage` | json · eligible |\n| `setWorkspaceStorage` | `POST /v1/workspaces/{workspace_id}/storage` | json · no automatic retry |\n| `quoteWorkspaceStorage` | `POST /v1/workspaces/{workspace_id}/storage/quote` | json · no automatic retry |\n| `closeImport` | `POST /v1/drives/{drive_id}/imports/{import_id}/close` | json · no automatic retry |\n| `recoverImport` | `POST /v1/drives/{drive_id}/imports/{import_id}/recover` | json · no automatic retry |\n| `retryImportOperation` | `POST /v1/drives/{drive_id}/imports/{import_id}/operations/{operation_id}/retry` | json · no automatic retry |\n| `getAutoTopup` | `GET /v1/organizations/{organization_id}/billing/auto-topup` | json · eligible |\n| `checkoutAutoTopup` | `POST /v1/organizations/{organization_id}/billing/auto-topup/checkout` | json · no automatic retry |\n| `amountAutoTopup` | `POST /v1/organizations/{organization_id}/billing/auto-topup/amount` | json · no automatic retry |\n| `cancelAutoTopup` | `POST /v1/organizations/{organization_id}/billing/auto-topup/cancel` | json · no automatic retry |\n| `resumeAutoTopup` | `POST /v1/organizations/{organization_id}/billing/auto-topup/resume` | json · no automatic retry |\n\n<a id=\"lifecycle\"></a>\n\n## Limits and operation lifecycle\n\n- Pass `signal` and per-call `timeoutMs` on native request input when needed.\n- Persist a returned job identifier before explicitly reading or polling the same job. Native clients do not automatically poll.\n- SSE data is incremental provider event text. Parse and validate terminal or error events according to the provider contract; there is no reconnect or replay.\n- Native operations may create, delete, ingest, or incur charges. A successful HTTP response is not proof that a remote job completed.\n\n<a id=\"sources\"></a>\n\n## Official sources\n\nUse the official reference for current schemas, account access, and operation-specific requirements.\n\n- [Search and passage reference](https://docs.evokoa.com/wondersearch/reference/search-api)\n- [Official product](https://wondersearch.ai/)\n\n- [Native request and response reference](https://searchsdk.dev/docs/api/native-transport)\n- [All providers](https://searchsdk.dev/docs/providers)\n"
    },
    {
      "slug": "providers/valyu",
      "title": "Valyu",
      "description": "Web-only search with content snippets, relevance, reported USD usage, and explicit adapter settings.",
      "url": "https://searchsdk.dev/docs/providers/valyu",
      "markdownPath": "/docs/providers/valyu.md",
      "markdownUrl": "https://searchsdk.dev/docs/providers/valyu.md",
      "text": "# Valyu\n\nWeb-only search with content snippets, relevance, reported USD usage, and explicit adapter settings.\n\nCanonical: https://searchsdk.dev/docs/providers/valyu\nMarkdown: https://searchsdk.dev/docs/providers/valyu.md\n\n<a id=\"overview\"></a>\n\n## Normalized web search\n\n> **TypeScript reference**\n> The API names, code and policy behavior in this article describe the TypeScript SDK. See [your language guide](https://searchsdk.dev/docs/sdks) for its supported surface and limits.\n\nThe adapter sends one POST to `https://api.valyu.ai/v1/search` with `X-API-Key` authentication. It explicitly selects `search_type: 'web'`; the provider's broader dataset search is outside this adapter.\n\n**valyu-search.ts · server**\n\n```typescript\nimport { createSearch } from '@belweave/search-sdk';\nimport { valyu } from '@belweave/search-sdk/valyu';\n\nconst apiKey = process.env.VALYU_API_KEY;\nif (!apiKey) throw new Error('VALYU_API_KEY is required');\n\nconst client = createSearch({ provider: valyu({ apiKey }) });\nconst response = await client.web.search({\n  query: 'SQLite write concurrency',\n  limit: 5,\n});\nconsole.log(response.results, response.usage);\n```\n\nContent maps to snippet, relevance_score to the native score, and tx_id to provenance requestId. Reported total_deduction_dollars maps to USD usage. A missing amount remains unknown. The SDK validates consumed results before applying your output ceiling.\n\n<a id=\"settings\"></a>\n\n## Adapter settings\n\nImport `ValyuOptions` or `ValyuSearchOptions` from the same subpath for typed configuration. The `search` object is fixed when you create the adapter; it does not add fields to the portable SearchRequest.\n\n| Setting | Behavior |\n| --- | --- |\n| `search.maxPrice` | Positive provider-native request budget; not an SDK estimate of USD. |\n| `search.relevanceThreshold` | Native relevance threshold between 0 and 1. |\n| `search.responseLength` | short, medium, large, max, or a positive integer character budget. |\n| `search.fastMode` | Explicit native fast-mode selection. |\n| `search.startDate`, `search.endDate` | YYYY-MM-DD subset with valid dates in ascending order. |\n| `search.instructions` | Nonblank provider ranking instructions, at most 500 characters. |\n\nDomain filters map to included_sources and excluded_sources. Both lists allow up to 100 hostnames under conservative SDK policy; this is not a verified native maximum. No implicit pagination or proprietary dataset access is performed.\n\n<a id=\"raw-response\"></a>\n\n## Preserve provider details\n\nThe adapter also exposes `searchRaw`. It makes the same validated web-only request and returns `{ provider, retrievedAt, data }`, retaining provider fields omitted by normalization. This direct adapter call does not run the createSearch fallback, retry, cache, or deadline policy. The HTTP transport retains its own resource bounds; supply a cancellation signal for your application deadline.\n\n**valyu-raw.ts · server**\n\n```typescript\nimport { valyu } from '@belweave/search-sdk/valyu';\n\nconst apiKey = process.env.VALYU_API_KEY;\nif (!apiKey) throw new Error('VALYU_API_KEY is required');\n\nconst provider = valyu({ apiKey, search: { responseLength: 'short' } });\nconst response = await provider.searchRaw(\n  { query: 'SQLite write concurrency', limit: 5 },\n  { signal: AbortSignal.timeout(10_000) },\n);\n// data is a record of unknown values: validate fields before using them.\nconsole.log(response.provider, response.retrievedAt);\n```\n\n<a id=\"boundaries\"></a>\n\n## Coverage and verification\n\nThis integration has no generated native client or native operation inventory. Contents, generated answers, research jobs, and dataset access are separate Valyu products. Local fixtures establish expected mapping and failure handling; they do not verify live availability, account access, or billing.\n\n- [Official Valyu search reference](https://docs.valyu.ai/api-reference/endpoint/search)\n- [Normalized request reference](https://searchsdk.dev/docs/api/search)\n- [All providers](https://searchsdk.dev/docs/providers)\n"
    },
    {
      "slug": "providers/searxng",
      "title": "SearXNG",
      "description": "Normalized JSON search through a trusted, operator-selected SearXNG instance.",
      "url": "https://searchsdk.dev/docs/providers/searxng",
      "markdownPath": "/docs/providers/searxng.md",
      "markdownUrl": "https://searchsdk.dev/docs/providers/searxng.md",
      "text": "# SearXNG\n\nNormalized JSON search through a trusted, operator-selected SearXNG instance.\n\nCanonical: https://searchsdk.dev/docs/providers/searxng\nMarkdown: https://searchsdk.dev/docs/providers/searxng.md\n\n<a id=\"overview\"></a>\n\n## Choose your instance\n\n> **TypeScript reference**\n> The API names, code and policy behavior in this article describe the TypeScript SDK. See [your language guide](https://searchsdk.dev/docs/sdks) for its supported surface and limits.\n\nSearXNG is metasearch software rather than a single hosted API. Configure the HTTPS baseUrl of an instance you trust on your server. The adapter appends /search and sends a form-encoded POST requesting JSON, page one, and the general category by default. It does not discover or select public instances.\n\n**searxng-search.ts · server**\n\n```typescript\nimport { createSearch } from '@belweave/search-sdk';\nimport { searxng } from '@belweave/search-sdk/searxng';\n\nconst baseUrl = process.env.SEARXNG_BASE_URL;\nif (!baseUrl) throw new Error('SEARXNG_BASE_URL is required');\n\nconst client = createSearch({\n  provider: searxng({ baseUrl }),\n  timeoutMs: 10_000,\n});\nconst response = await client.web.search({\n  query: 'SQLite write concurrency',\n  limit: 5,\n});\nconsole.log(response.results, response.warnings);\n```\n\nJSON output must be enabled by the instance operator. SearXNG documents a 403 response when a requested format is disabled, including on many public instances. Search engines, access requirements, and availability depend on the selected instance.\n\n<a id=\"settings\"></a>\n\n## Instance settings\n\n| Option | Behavior |\n| --- | --- |\n| `baseUrl` | Required trusted HTTPS instance URL; optional base path, no embedded credentials, query, or fragment. |\n| `headers` | Optional server-owned reverse-proxy authentication headers; no standard SearXNG search API key. |\n| `language` | Instance-supported language selection. |\n| `safeSearch` | 0, 1, or 2; engine-dependent behavior. |\n| `timeRange` | day, month, or year; engine-dependent behavior. |\n| `categories` | Instance-specific category names; defaults to general. |\n| `fetch` | Optional trusted transport for tests or server networking policy. |\n\nThe selected URL is a server configuration boundary. Never take baseUrl or authentication headers directly from an untrusted caller. Requests reject redirects. Domain filters are unsupported: the SDK does not rewrite queries into engine-dependent site operators.\n\n<a id=\"results\"></a>\n\n## Keep metasearch semantics visible\n\n- One response page is read. limit caps normalized output and does not request extra pages.\n- Content maps to snippet and a supplied score stays native. Unreported usage is null.\n- Unresponsive engines produce a sanitized provider_warning when reported. A valid source list can be partial.\n- Provider text remains untrusted, including any markup in content.\n\nFor engine attribution, dates, suggestions, or unresponsive-engine details, call the adapter's searchRaw(request, { signal }) method. It returns `{ provider, retrievedAt, data }`; validate unknown raw fields before use. Direct raw calls do not apply createSearch reliability policies; the HTTP transport retains its own resource bounds.\n\n<a id=\"boundaries\"></a>\n\n## Coverage and verification\n\nThis is a normalized adapter with raw JSON access, without a generated native client. Fixture validation does not establish a particular instance's access, engine configuration, privacy policy, or availability.\n\n- [Official SearXNG Search API](https://docs.searxng.org/dev/search_api.html)\n- [Server integration guide](https://searchsdk.dev/docs/guides/server-integration)\n- [All providers](https://searchsdk.dev/docs/providers)\n"
    },
    {
      "slug": "reliability/fallback",
      "title": "Explicit fallback",
      "description": "Choose which providers may receive a query and exactly when the chain may advance.",
      "url": "https://searchsdk.dev/docs/reliability/fallback",
      "markdownPath": "/docs/reliability/fallback.md",
      "markdownUrl": "https://searchsdk.dev/docs/reliability/fallback.md",
      "text": "# Explicit fallback\n\nChoose which providers may receive a query and exactly when the chain may advance.\n\nCanonical: https://searchsdk.dev/docs/reliability/fallback\nMarkdown: https://searchsdk.dev/docs/reliability/fallback.md\n\n<a id=\"configure\"></a>\n\n## Configure an ordered chain\n\n> **TypeScript reference**\n> The API names, code and policy behavior in this article describe the TypeScript SDK. See [your language guide](https://searchsdk.dev/docs/sdks) for its supported surface and limits.\n\n**fallback.ts · server**\n\n```typescript\nimport { createSearch } from '@belweave/search-sdk';\nimport { context } from '@belweave/search-sdk/context';\nimport { tinyfish } from '@belweave/search-sdk/tinyfish';\n\nconst contextKey = process.env.CONTEXT_API_KEY;\nconst tinyfishKey = process.env.TINYFISH_API_KEY;\nif (!contextKey || !tinyfishKey) throw new Error('Missing server credentials');\n\nconst client = createSearch({\n  provider: context({ apiKey: contextKey }),\n  fallback: [tinyfish({ apiKey: tinyfishKey })],\n  timeoutMs: 10_000,\n  attemptTimeoutMs: 4_000,\n});\n\nconst response = await client.web.search({ query: 'SQLite write concurrency' });\nconsole.log(response.provider, response.attempts, response.warnings);\n```\n\nFallback can disclose the same query to another provider and incur additional charges. Providers are attempted sequentially in configured order. Each ID can appear only once.\n\n<a id=\"advance\"></a>\n\n## When the chain advances\n\n- `rate_limit`, `network`, `unavailable`, and `attempt_timeout` may advance to the next configured provider after any explicitly configured retries are exhausted.\n- Authentication, invalid requests, unsupported options, invalid responses, caller cancellation, and the total deadline are terminal.\n- An empty successful result is a success. It does not advance the chain.\n- Same-provider retries are off by default. There are no hedges or quality-triggered fallback.\n\n<a id=\"trace\"></a>\n\n## Inspect the trace\n\nEvery completed attempt records provider, start time, duration, and outcome. Failed attempts can include a code, HTTP status, and parsed Retry-After delay. A successful backup response adds `fallback_used`; a terminal failure exposes the complete trace on SearchError.\n\n- [Reserve a deadline for the chain](https://searchsdk.dev/docs/reliability/timeouts)\n- [Test fallback locally](https://searchsdk.dev/docs/guides/testing)\n"
    },
    {
      "slug": "reliability/timeouts",
      "title": "Deadlines and cancellation",
      "description": "Bound the complete call and each attempt, and stop the chain when callers cancel.",
      "url": "https://searchsdk.dev/docs/reliability/timeouts",
      "markdownPath": "/docs/reliability/timeouts.md",
      "markdownUrl": "https://searchsdk.dev/docs/reliability/timeouts.md",
      "text": "# Deadlines and cancellation\n\nBound the complete call and each attempt, and stop the chain when callers cancel.\n\nCanonical: https://searchsdk.dev/docs/reliability/timeouts\nMarkdown: https://searchsdk.dev/docs/reliability/timeouts.md\n\n<a id=\"budgets\"></a>\n\n## Two budgets, one deadline\n\n> **TypeScript reference**\n> The API names, code and policy behavior in this article describe the TypeScript SDK. See [your language guide](https://searchsdk.dev/docs/sdks) for its supported surface and limits.\n\n`timeoutMs` bounds the complete normalized call, including attempts and JSON parsing. `attemptTimeoutMs` bounds each attempt without extending the total deadline. Both default to the configured total budget; with defaults, a full-budget timeout leaves no time for fallback.\n\n**Configuration**\n\n```typescript\nconst policy = {\n  timeoutMs: 10_000,\n  attemptTimeoutMs: 4_000,\n};\n// Pass these fields alongside provider and optional fallback to createSearch().\n```\n\n<a id=\"cancellation\"></a>\n\n## Cancel with AbortSignal\n\n**cancel.ts · fixture**\n\n```typescript\nimport { createSearch, SearchError } from '@belweave/search-sdk';\nimport { createMockProvider } from '@belweave/search-sdk/testing';\n\nconst controller = new AbortController();\nconst client = createSearch({ provider: createMockProvider({ delayMs: 500 }) });\nconst pending = client.web.search(\n  { query: 'SQLite concurrency' },\n  { signal: controller.signal },\n);\n\ncontroller.abort();\ntry {\n  await pending;\n} catch (error) {\n  if (error instanceof SearchError) console.log(error.code); // aborted\n  else throw error;\n}\n```\n\nCancellation aborts the current attempt and prevents later providers from starting. A pre-aborted signal fails before provider dispatch. The SDK cleans up its own timers and listeners.\n\n<a id=\"transport-limits\"></a>\n\n## Understand resource limits\n\n> **Promise settlement and upstream work**\n> The SDK can settle even when a transport ignores its signal. That underlying I/O may continue. Use signal-aware transports to cancel resources; a local deadline does not guarantee that upstream work or billing stops.\n\nJavaScript timers require the event loop to yield. When provider work eventually settles, elapsed deadlines take precedence over a late success or failure.\n"
    },
    {
      "slug": "reliability/provenance",
      "title": "Source provenance",
      "description": "Keep source identity and retrieval time attached to every normalized result.",
      "url": "https://searchsdk.dev/docs/reliability/provenance",
      "markdownPath": "/docs/reliability/provenance.md",
      "markdownUrl": "https://searchsdk.dev/docs/reliability/provenance.md",
      "text": "# Source provenance\n\nKeep source identity and retrieval time attached to every normalized result.\n\nCanonical: https://searchsdk.dev/docs/reliability/provenance\nMarkdown: https://searchsdk.dev/docs/reliability/provenance.md\n\n<a id=\"fields\"></a>\n\n## Provenance fields\n\n> **TypeScript reference**\n> The API names, code and policy behavior in this article describe the TypeScript SDK. See [your language guide](https://searchsdk.dev/docs/sdks) for its supported surface and limits.\n\n| Field | Meaning |\n| --- | --- |\n| `provider` | Adapter identity for this result. |\n| `sourceUrl` | The source link assigned by the adapter. |\n| `retrievedAt` | SDK retrieval time in ISO 8601, not source publication time. |\n| `requestId?` | Provider request identifier when the adapter has one. |\n\n<a id=\"retain\"></a>\n\n## Retain provenance through your pipeline\n\nWhen storing sources or passing them to an answer-generating step, keep their provenance beside the text. Preserve the original link even when your application derives a citation label. Retrieval time is useful for traceability but does not prove a page is current or substantiate a factual claim.\n\n<a id=\"scores\"></a>\n\n## Keep native relevance in context\n\nExa and Tavily may provide numeric scores. Context's string relevance is not converted into a fabricated number, and TinyFish position is not a score. A missing value should stay absent. Do not compare scores across providers without a separately validated calibration method.\n"
    },
    {
      "slug": "reliability/usage",
      "title": "Usage and warnings",
      "description": "Report what the winning provider supplies, while keeping unknown costs unknown.",
      "url": "https://searchsdk.dev/docs/reliability/usage",
      "markdownPath": "/docs/reliability/usage.md",
      "markdownUrl": "https://searchsdk.dev/docs/reliability/usage.md",
      "text": "# Usage and warnings\n\nReport what the winning provider supplies, while keeping unknown costs unknown.\n\nCanonical: https://searchsdk.dev/docs/reliability/usage\nMarkdown: https://searchsdk.dev/docs/reliability/usage.md\n\n<a id=\"usage\"></a>\n\n## Usage is reported, not estimated\n\n> **TypeScript reference**\n> The API names, code and policy behavior in this article describe the TypeScript SDK. See [your language guide](https://searchsdk.dev/docs/sdks) for its supported surface and limits.\n\n| Adapter | Normalized usage |\n| --- | --- |\n| Context.dev | `credits` from key_metadata.credits_consumed. |\n| Exa | `usd` from costDollars.total. |\n| Tavily | `credits` from usage.credits. |\n| TinyFish / Brave | `null` when not reported. |\n\nExplicit zero usage is preserved. Missing usage becomes `null`. Winning-response usage excludes failed-attempt charges and is not the total cost of a fallback chain.\n\nA reused response retains the original provider's usage, retrieval timestamps, and attempts. Check `response.reuse`: cache or in-flight sharing is not a new provider call, and its retained usage is not a fresh charge.\n\n<a id=\"count\"></a>\n\n## Output count is not a billing unit\n\nContext requests at least ten native results and can trim to a smaller SDK ceiling. TinyFish requests one first page without a native count parameter. Never infer provider charges from `results.length` or treat unknown usage as zero.\n\n<a id=\"warnings\"></a>\n\n## Warnings use stable codes\n\n- `fallback_used`: a later provider succeeded after an earlier failure.\n- `provider_warning`: a provider-specific warning condition, such as Context partial results or Exa warning metadata.\n\nRaw provider warning text is not forwarded through normalized warnings. A warning does not imply that a malformed consumed result was accepted; schema validation still applies.\n"
    },
    {
      "slug": "reliability/security",
      "title": "Credentials and trust",
      "description": "Separate server secrets, external source material, and application authority.",
      "url": "https://searchsdk.dev/docs/reliability/security",
      "markdownPath": "/docs/reliability/security.md",
      "markdownUrl": "https://searchsdk.dev/docs/reliability/security.md",
      "text": "# Credentials and trust\n\nSeparate server secrets, external source material, and application authority.\n\nCanonical: https://searchsdk.dev/docs/reliability/security\nMarkdown: https://searchsdk.dev/docs/reliability/security.md\n\n<a id=\"credentials\"></a>\n\n## Keep credentials server-side\n\n> **TypeScript reference**\n> The API names, code and policy behavior in this article describe the TypeScript SDK. See [your language guide](https://searchsdk.dev/docs/sdks) for its supported surface and limits.\n\nProvider factories receive keys explicitly and never load environment variables. Built-in normalized adapters use fixed provider endpoints and reject redirects. Supply credentials from server-owned configuration. Do not expose them through browser bundles, query logs, or example output.\n\n<a id=\"untrusted\"></a>\n\n## Treat retrieval as untrusted input\n\nProvider text may contain markup, misleading claims, or instructions. Escape it in user interfaces and keep it out of trusted system instructions. A valid source URL does not establish source credibility, ownership, or safe server-side fetch behavior.\n\n<a id=\"custom-transport\"></a>\n\n## Review custom transports\n\nAn injected transport is trusted server code. Preserve request authentication boundaries, AbortSignal, and redirect policy. If you add telemetry or retries, consider that headers may contain keys, query strings can contain search text, and repeated calls can incur extra work.\n\n- [Server integration guide](https://searchsdk.dev/docs/guides/server-integration)\n- [Result rendering guide](https://searchsdk.dev/docs/guides/results)\n"
    },
    {
      "slug": "reliability/verification",
      "title": "Verification and limits",
      "description": "Read validation claims at the right evidence level and evaluate providers on your workload.",
      "url": "https://searchsdk.dev/docs/reliability/verification",
      "markdownPath": "/docs/reliability/verification.md",
      "markdownUrl": "https://searchsdk.dev/docs/reliability/verification.md",
      "text": "# Verification and limits\n\nRead validation claims at the right evidence level and evaluate providers on your workload.\n\nCanonical: https://searchsdk.dev/docs/reliability/verification\nMarkdown: https://searchsdk.dev/docs/reliability/verification.md\n\n<a id=\"fixture-evidence\"></a>\n\n## What fixture validation covers\n\nDeterministic fixtures check protocol mapping, invalid fields, unsafe URLs, filter preflight, errors, fallback, cancellation, and deadlines. Use the repository's latest validation record for the current suite and results.\n\nInjected responses exercise expected contracts without API credentials. They do not establish account readiness, upstream availability, actual billing, or real retrieval usefulness.\n\n<a id=\"evaluate\"></a>\n\n## Evaluate your own workload\n\n- Record dated queries and required source types.\n- Record provider settings, locale, filters, result count, and time budgets.\n- Use a clear rubric for source usefulness and coverage, with human review when needed.\n- Measure latency and observed failures independently from content quality.\n- Keep reported usage separate from estimated total spend.\n\n<a id=\"benchmarks\"></a>\n\n## Benchmark work is in development\n\n> **No published ranking**\n> The benchmark workspace is in development. No universal quality ranking or fabricated latency score is presented here.\n\n- [Benchmark development status](https://searchsdk.dev/benchmarks)\n- [Provider-specific boundaries](https://searchsdk.dev/docs/providers)\n"
    },
    {
      "slug": "reliability/retries",
      "title": "Retry policy",
      "description": "Opt into bounded retries for transient failures while preserving the complete call deadline.",
      "url": "https://searchsdk.dev/docs/reliability/retries",
      "markdownPath": "/docs/reliability/retries.md",
      "markdownUrl": "https://searchsdk.dev/docs/reliability/retries.md",
      "text": "# Retry policy\n\nOpt into bounded retries for transient failures while preserving the complete call deadline.\n\nCanonical: https://searchsdk.dev/docs/reliability/retries\nMarkdown: https://searchsdk.dev/docs/reliability/retries.md\n\n<a id=\"normalized\"></a>\n\n## Normalized search retries\n\n> **TypeScript reference**\n> The API names, code and policy behavior in this article describe the TypeScript SDK. See [your language guide](https://searchsdk.dev/docs/sdks) for its supported surface and limits.\n\n**retry.ts · fixture**\n\n```typescript\nimport { createSearch } from '@belweave/search-sdk';\nimport { createMockProvider } from '@belweave/search-sdk/testing';\n\nconst provider = createMockProvider({ outcomes: [\n  { type: 'error', code: 'rate_limit', retryAfterMs: 10 },\n  { type: 'success' },\n] });\nconst client = createSearch({\n  provider,\n  timeoutMs: 5_000,\n  retry: { maxRetries: 1, baseDelayMs: 25, maxDelayMs: 200 },\n});\nconst response = await client.web.search({ query: 'SQLite concurrency' });\nconsole.log(response.attempts.length); // 2, same provider; no fallback_used\n\n```\n\nAdditional attempts occur per provider before moving to an explicit fallback. Transient categories are `network`, `rate_limit`, `unavailable`, and `attempt_timeout`. Terminal validation, auth, caller cancellation, and total-deadline failures are not retried.\n\n<a id=\"configuration\"></a>\n\n## Backoff settings\n\n| Setting | Contract |\n| --- | --- |\n| `maxRetries` | Additional attempts, integer 0–5; default 0. |\n| `baseDelayMs` | Positive integer starting delay; default 250. |\n| `maxDelayMs` | Positive integer exponential cap; default 5,000; at least baseDelayMs. |\n\nBackoff uses jitter and never shortens a parsed Retry-After value. If the required delay cannot fit inside the remaining deadline, the operation fails with timeout instead of retrying early. Retrying can repeat billable work.\n\n<a id=\"native\"></a>\n\n## Native operations require eligibility too\n\nA native transport retry policy alone does not make every operation replayable. The operation must explicitly declare `retryable: true`; the default is false, including for GET. Provider create/write/delete methods remain non-retrying unless their static mapping deliberately declares otherwise. There is no claim of provider idempotency.\n\nNative retry categories are transport errors and HTTP 429, 408, or 5xx. Malformed JSON, authentication failures, and stream consumption are not retried.\n\n- [Fallback remains separate](https://searchsdk.dev/docs/reliability/fallback)\n- [Native operation inventory](https://searchsdk.dev/docs/providers)\n"
    },
    {
      "slug": "reliability/caching",
      "title": "Cache and share requests",
      "description": "Reuse successful normalized responses locally with explicit TTL, capacity, and independent caller cancellation.",
      "url": "https://searchsdk.dev/docs/reliability/caching",
      "markdownPath": "/docs/reliability/caching.md",
      "markdownUrl": "https://searchsdk.dev/docs/reliability/caching.md",
      "text": "# Cache and share requests\n\nReuse successful normalized responses locally with explicit TTL, capacity, and independent caller cancellation.\n\nCanonical: https://searchsdk.dev/docs/reliability/caching\nMarkdown: https://searchsdk.dev/docs/reliability/caching.md\n\n<a id=\"configure\"></a>\n\n## Configure reuse explicitly\n\n> **TypeScript reference**\n> The API names, code and policy behavior in this article describe the TypeScript SDK. See [your language guide](https://searchsdk.dev/docs/sdks) for its supported surface and limits.\n\n**reuse.ts · fixture**\n\n```typescript\nimport { createSearch } from '@belweave/search-sdk';\nimport { createMockProvider } from '@belweave/search-sdk/testing';\n\nconst client = createSearch({\n  provider: createMockProvider(),\n  cache: { ttlMs: 30_000, maxEntries: 100 },\n  deduplicate: true,\n  maxConcurrency: 4,\n});\nconst request = { query: 'SQLite concurrency', limit: 5 };\nawait client.web.search(request);\nconst reused = await client.web.search(request);\nconsole.log(reused.reuse); // cache\n\n```\n\n<a id=\"cache\"></a>\n\n## Successful-result cache\n\nThe cache is per client and in memory. Only successful responses are stored; errors are not. TTL starts at insertion and cache hits do not extend it. Capacity defaults to 100 entries and uses least-recently-used eviction. Stored and returned responses are defensive snapshots. Entry count is bounded, not total bytes; there is no persistent cache or invalidation API.\n\nKeys reflect the normalized request. Domain lists are sorted for equivalence without rewriting the query. The cached response keeps its original retrieval time, attempt trace, and usage; it does not represent a fresh provider call or fresh charge. Reuse is labeled `reuse: 'cache'`.\n\n<a id=\"inflight\"></a>\n\n## Identical in-flight searches\n\nWith `deduplicate: true`, matching active requests share one execution and each subscriber receives a response snapshot. Joined subscribers receive `reuse: 'inflight'`. Each caller can cancel independently; the shared operation is aborted when no subscribers remain.\n\n> **Shared execution has one upstream lifetime**\n> A later subscriber joins the existing operation and its existing deadline. Joining does not restart or extend upstream work. Your cache and sharing scope should match your application's data-isolation boundary.\n\n<a id=\"concurrency\"></a>\n\n## Bound active operations\n\nNormalized `maxConcurrency` is optional and has no active-operation limit when omitted. When configured, it bounds active SDK operations, including retry/backoff time, and queue time counts toward the caller's total deadline. Native transports separately default to eight active operations per transport instance. FIFO queues allow up to 1,024 waiting operations, then return unavailable.\n\n- [Deadline behavior](https://searchsdk.dev/docs/reliability/timeouts)\n- [Usage on reused responses](https://searchsdk.dev/docs/reliability/usage)\n"
    }
  ],
  "providers": [
    {
      "id": "context",
      "name": "Context.dev",
      "description": "Web search with optional page content and query-relevant passages.",
      "boundary": "Normalized search returns descriptions and credits. Native APIs add scraping, parsing, brand data, batches, monitors, and account operations.",
      "docs": "https://docs.context.dev/api-reference/web-scraping/search",
      "status": "alpha",
      "nativeClient": true,
      "url": "https://searchsdk.dev/docs/providers/context",
      "markdownUrl": "https://searchsdk.dev/docs/providers/context.md",
      "corpus": false,
      "normalizedWebSearch": true,
      "normalizedCapabilities": {
        "domainFilters": true,
        "maxIncludeDomains": 100,
        "maxExcludeDomains": 100,
        "maxQueryLength": 500
      },
      "nativeOperations": [
        {
          "name": "headLogo",
          "method": "HEAD",
          "path": "/",
          "retryable": true,
          "response": "raw"
        },
        {
          "name": "submitFeedback",
          "method": "POST",
          "path": "/feedback",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "listLogs",
          "method": "GET",
          "path": "/org/logs",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "getLog",
          "method": "GET",
          "path": "/org/logs/{request_id}",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "listProfiles",
          "method": "GET",
          "path": "/org/browser/profiles",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "getUsage",
          "method": "GET",
          "path": "/org/usage",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "getUsageHistory",
          "method": "GET",
          "path": "/org/usage/history",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "listWebhookDeliveries",
          "method": "POST",
          "path": "/webhooks/deliveries",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "getWebhookDelivery",
          "method": "GET",
          "path": "/webhooks/deliveries/{delivery_id}",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "listWebhookDeliveryAttempts",
          "method": "GET",
          "path": "/webhooks/deliveries/{delivery_id}/attempts",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "retryWebhookDelivery",
          "method": "POST",
          "path": "/webhooks/deliveries/{delivery_id}/retry",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "scrape",
          "method": "POST",
          "path": "/web/scrape",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "searchNews",
          "method": "POST",
          "path": "/news/search",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "answers",
          "method": "POST",
          "path": "/web/answers",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "parse",
          "method": "POST",
          "path": "/parse",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "map",
          "method": "GET",
          "path": "/web/urls",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "crawl",
          "method": "POST",
          "path": "/web/crawl",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "extract",
          "method": "POST",
          "path": "/web/extract",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "search",
          "method": "POST",
          "path": "/web/search",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "enrichPerson",
          "method": "POST",
          "path": "/people/enrich",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "retrieveBrand",
          "method": "POST",
          "path": "/brand/retrieve",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "searchBrands",
          "method": "GET",
          "path": "/brand/search",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "styleguide",
          "method": "GET",
          "path": "/web/styleguide",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "fonts",
          "method": "GET",
          "path": "/web/fonts",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "classifyNaics",
          "method": "GET",
          "path": "/web/naics",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "classifySic",
          "method": "GET",
          "path": "/web/sic",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "prefetch",
          "method": "POST",
          "path": "/utility/prefetch",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "createMonitor",
          "method": "POST",
          "path": "/monitors",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "listMonitors",
          "method": "GET",
          "path": "/monitors",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "getMonitor",
          "method": "GET",
          "path": "/monitors/{monitor_id}",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "updateMonitor",
          "method": "PATCH",
          "path": "/monitors/{monitor_id}",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "deleteMonitor",
          "method": "DELETE",
          "path": "/monitors/{monitor_id}",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "listMonitorRuns",
          "method": "GET",
          "path": "/monitors/{monitor_id}/runs",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "getMonitorRun",
          "method": "GET",
          "path": "/monitors/{monitor_id}/runs/{run_id}",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "listMonitorChanges",
          "method": "GET",
          "path": "/monitors/{monitor_id}/changes",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "listAccountRuns",
          "method": "GET",
          "path": "/monitors/runs",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "listMonitorCreditUsage",
          "method": "GET",
          "path": "/monitors/credit-usage",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "getMonitorLimits",
          "method": "GET",
          "path": "/monitors/limits",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "listChanges",
          "method": "GET",
          "path": "/monitors/changes",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "getChange",
          "method": "GET",
          "path": "/monitors/changes/{change_id}",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "runMonitorNow",
          "method": "POST",
          "path": "/monitors/{monitor_id}/run",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "rotateMonitorWebhookSecret",
          "method": "POST",
          "path": "/monitors/{monitor_id}/webhook/rotate-secret",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "submitBatch",
          "method": "POST",
          "path": "/batch/submit",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "listBatches",
          "method": "GET",
          "path": "/batch/list",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "getBatch",
          "method": "GET",
          "path": "/batch/{batch_id}",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "deleteBatch",
          "method": "DELETE",
          "path": "/batch/{batch_id}",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "getBatchResults",
          "method": "GET",
          "path": "/batch/{batch_id}/results",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "cancelBatch",
          "method": "POST",
          "path": "/batch/{batch_id}/cancel",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "searchCompanies",
          "method": "POST",
          "path": "/company/search",
          "retryable": false,
          "response": "json"
        }
      ]
    },
    {
      "id": "tinyfish",
      "name": "TinyFish",
      "description": "Structured web search with ranked titles, URLs, and snippets.",
      "boundary": "Normalized search returns one page. Native APIs cover search, fetch, browser sessions, agents, research, and monitors.",
      "docs": "https://docs.tinyfish.ai/search-api/reference",
      "status": "alpha",
      "nativeClient": true,
      "url": "https://searchsdk.dev/docs/providers/tinyfish",
      "markdownUrl": "https://searchsdk.dev/docs/providers/tinyfish.md",
      "corpus": false,
      "normalizedWebSearch": true,
      "normalizedCapabilities": {
        "domainFilters": true,
        "maxIncludeDomains": 100,
        "maxExcludeDomains": 100
      },
      "nativeOperations": [
        {
          "name": "runSse",
          "method": "POST",
          "path": "/v1/automation/run-sse",
          "retryable": false,
          "response": "sse"
        },
        {
          "name": "run",
          "method": "POST",
          "path": "/v1/automation/run",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "runAsync",
          "method": "POST",
          "path": "/v1/automation/run-async",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "runBatch",
          "method": "POST",
          "path": "/v1/automation/run-batch",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "listRuns",
          "method": "GET",
          "path": "/v1/runs",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "batchGetRuns",
          "method": "POST",
          "path": "/v1/runs/batch",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "batchCancelRuns",
          "method": "POST",
          "path": "/v1/runs/batch/cancel",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "getRunById",
          "method": "GET",
          "path": "/v1/runs/{id}",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "cancelRunById",
          "method": "POST",
          "path": "/v1/runs/{id}/cancel",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "getStepScreenshot",
          "method": "GET",
          "path": "/v1/runs/{id}/steps/{stepId}/screenshot",
          "retryable": true,
          "response": "bytes"
        },
        {
          "name": "getStepHtml",
          "method": "GET",
          "path": "/v1/runs/{id}/steps/{stepId}/html",
          "retryable": true,
          "response": "text"
        },
        {
          "name": "listBrowserContextProfiles",
          "method": "GET",
          "path": "/v1/profiles",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "createBrowserContextProfile",
          "method": "POST",
          "path": "/v1/profiles",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "getBrowserContextProfile",
          "method": "GET",
          "path": "/v1/profiles/{profileId}",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "updateBrowserContextProfile",
          "method": "PATCH",
          "path": "/v1/profiles/{profileId}",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "deleteBrowserContextProfile",
          "method": "DELETE",
          "path": "/v1/profiles/{profileId}",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "createBrowserContextProfileSetupSession",
          "method": "POST",
          "path": "/v1/profiles/{profileId}/setup-session",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "cancelBrowserContextProfileSetupSession",
          "method": "POST",
          "path": "/v1/profiles/{profileId}/setup-session/cancel",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "saveBrowserContextProfileSetupSession",
          "method": "POST",
          "path": "/v1/profiles/{profileId}/save",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "uploadBrowserContextProfileState",
          "method": "POST",
          "path": "/v1/profiles/{profileId}/upload",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "deleteBrowserContextProfileDomain",
          "method": "DELETE",
          "path": "/v1/profiles/{profileId}/domains/{domain}",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "connectVault",
          "method": "POST",
          "path": "/v1/vault/connections",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "listVaultConnections",
          "method": "GET",
          "path": "/v1/vault/connections",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "disconnectVault",
          "method": "DELETE",
          "path": "/v1/vault/connections/{connectionId}",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "listVaultItems",
          "method": "GET",
          "path": "/v1/vault/items",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "syncVaultItems",
          "method": "POST",
          "path": "/v1/vault/items/sync",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "getWallet",
          "method": "GET",
          "path": "/v1/wallet",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "topUpWallet",
          "method": "POST",
          "path": "/v1/wallet/top-up",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "search",
          "method": "GET",
          "path": "/",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "listSearchUsage",
          "method": "GET",
          "path": "/usage",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "fetchUrls",
          "method": "POST",
          "path": "/",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "listFetchUsage",
          "method": "GET",
          "path": "/usage",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "createBrowserSession",
          "method": "POST",
          "path": "/",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "listBrowserUsage",
          "method": "GET",
          "path": "/usage",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "deleteBrowserSession",
          "method": "DELETE",
          "path": "/{sessionId}",
          "retryable": false,
          "response": "text"
        },
        {
          "name": "createMonitor",
          "method": "POST",
          "path": "/v1/monitors",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "listMonitors",
          "method": "GET",
          "path": "/v1/monitors",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "getMonitor",
          "method": "GET",
          "path": "/v1/monitors/{id}",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "updateMonitor",
          "method": "PATCH",
          "path": "/v1/monitors/{id}",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "deleteMonitor",
          "method": "DELETE",
          "path": "/v1/monitors/{id}",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "runMonitor",
          "method": "POST",
          "path": "/v1/monitors/{id}/runs",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "runResearch",
          "method": "POST",
          "path": "/v1/automation/run-research",
          "retryable": false,
          "response": "sse"
        },
        {
          "name": "startResearchAsync",
          "method": "POST",
          "path": "/v1/automation/run-research-async",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "streamResearchEvents",
          "method": "GET",
          "path": "/v1/research-run/{research_run_id}/events",
          "retryable": false,
          "response": "sse"
        },
        {
          "name": "listResearchRuns",
          "method": "GET",
          "path": "/v1/research-run",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "getResearchRun",
          "method": "GET",
          "path": "/v1/research-run/{research_run_id}",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "cancelResearchRun",
          "method": "POST",
          "path": "/v1/research-run/{research_run_id}/cancel",
          "retryable": false,
          "response": "json"
        }
      ]
    },
    {
      "id": "exa",
      "name": "Exa",
      "description": "Web search with query-relevant highlights and native relevance.",
      "boundary": "Normalized sources and reported USD usage. Native APIs include content, answers, research, Websets, monitors, and management.",
      "docs": "https://exa.ai/docs/reference/search",
      "status": "alpha",
      "nativeClient": true,
      "url": "https://searchsdk.dev/docs/providers/exa",
      "markdownUrl": "https://searchsdk.dev/docs/providers/exa.md",
      "corpus": false,
      "normalizedWebSearch": true,
      "normalizedCapabilities": {
        "domainFilters": true,
        "maxIncludeDomains": 1200,
        "maxExcludeDomains": 1200
      },
      "nativeOperations": [
        {
          "name": "search",
          "method": "POST",
          "path": "/search",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "searchStream",
          "method": "POST",
          "path": "/search",
          "retryable": false,
          "response": "sse"
        },
        {
          "name": "getContents",
          "method": "POST",
          "path": "/contents",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "answer",
          "method": "POST",
          "path": "/answer",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "answerStream",
          "method": "POST",
          "path": "/answer",
          "retryable": false,
          "response": "sse"
        },
        {
          "name": "findSimilar",
          "method": "POST",
          "path": "/findSimilar",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "createMonitor",
          "method": "POST",
          "path": "/monitors",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "listMonitors",
          "method": "GET",
          "path": "/monitors",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "batchMonitors",
          "method": "POST",
          "path": "/monitors/batch",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "getMonitor",
          "method": "GET",
          "path": "/monitors/{id}",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "updateMonitor",
          "method": "PATCH",
          "path": "/monitors/{id}",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "deleteMonitor",
          "method": "DELETE",
          "path": "/monitors/{id}",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "triggerMonitor",
          "method": "POST",
          "path": "/monitors/{id}/trigger",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "listMonitorRuns",
          "method": "GET",
          "path": "/monitors/{id}/runs",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "getMonitorRun",
          "method": "GET",
          "path": "/monitors/{id}/runs/{runId}",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "createAgentRun",
          "method": "POST",
          "path": "/agent/runs",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "createAgentRunStream",
          "method": "POST",
          "path": "/agent/runs",
          "retryable": false,
          "response": "sse"
        },
        {
          "name": "listAgentRuns",
          "method": "GET",
          "path": "/agent/runs",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "getAgentRun",
          "method": "GET",
          "path": "/agent/runs/{id}",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "deleteAgentRun",
          "method": "DELETE",
          "path": "/agent/runs/{id}",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "cancelAgentRun",
          "method": "POST",
          "path": "/agent/runs/{id}/cancel",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "stopAgentRun",
          "method": "POST",
          "path": "/agent/runs/{id}/stop",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "listAgentRunEvents",
          "method": "GET",
          "path": "/agent/runs/{id}/events",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "listAgentRunEventsStream",
          "method": "GET",
          "path": "/agent/runs/{id}/events",
          "retryable": false,
          "response": "sse"
        },
        {
          "name": "createBatch",
          "method": "POST",
          "path": "/batches",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "listBatches",
          "method": "GET",
          "path": "/batches",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "getBatch",
          "method": "GET",
          "path": "/batches/{id}",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "deleteBatch",
          "method": "DELETE",
          "path": "/batches/{id}",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "cancelBatch",
          "method": "POST",
          "path": "/batches/{id}/cancel",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "getTeamInfo",
          "method": "GET",
          "path": "/v0/teams/me",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "createWebset",
          "method": "POST",
          "path": "/v0/websets",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "listWebsets",
          "method": "GET",
          "path": "/v0/websets",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "getWebset",
          "method": "GET",
          "path": "/v0/websets/{id}",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "updateWebset",
          "method": "POST",
          "path": "/v0/websets/{id}",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "deleteWebset",
          "method": "DELETE",
          "path": "/v0/websets/{id}",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "cancelWebset",
          "method": "POST",
          "path": "/v0/websets/{id}/cancel",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "createWebsetSearch",
          "method": "POST",
          "path": "/v0/websets/{webset}/searches",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "getWebsetSearch",
          "method": "GET",
          "path": "/v0/websets/{webset}/searches/{id}",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "cancelWebsetSearch",
          "method": "POST",
          "path": "/v0/websets/{webset}/searches/{id}/cancel",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "createWebsetEnrichment",
          "method": "POST",
          "path": "/v0/websets/{webset}/enrichments",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "updateWebsetEnrichment",
          "method": "PATCH",
          "path": "/v0/websets/{webset}/enrichments/{id}",
          "retryable": false,
          "response": "text"
        },
        {
          "name": "getWebsetEnrichment",
          "method": "GET",
          "path": "/v0/websets/{webset}/enrichments/{id}",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "deleteWebsetEnrichment",
          "method": "DELETE",
          "path": "/v0/websets/{webset}/enrichments/{id}",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "cancelWebsetEnrichment",
          "method": "POST",
          "path": "/v0/websets/{webset}/enrichments/{id}/cancel",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "getWebsetItem",
          "method": "GET",
          "path": "/v0/websets/{webset}/items/{id}",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "deleteWebsetItem",
          "method": "DELETE",
          "path": "/v0/websets/{webset}/items/{id}",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "listWebsetItems",
          "method": "GET",
          "path": "/v0/websets/{webset}/items",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "previewWebset",
          "method": "POST",
          "path": "/v0/websets/preview",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "createWebsetMonitor",
          "method": "POST",
          "path": "/v0/monitors",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "listWebsetMonitors",
          "method": "GET",
          "path": "/v0/monitors",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "getWebsetMonitor",
          "method": "GET",
          "path": "/v0/monitors/{id}",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "updateWebsetMonitor",
          "method": "PATCH",
          "path": "/v0/monitors/{id}",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "deleteWebsetMonitor",
          "method": "DELETE",
          "path": "/v0/monitors/{id}",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "listWebsetMonitorRuns",
          "method": "GET",
          "path": "/v0/monitors/{monitor}/runs",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "getWebsetMonitorRun",
          "method": "GET",
          "path": "/v0/monitors/{monitor}/runs/{id}",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "createImport",
          "method": "POST",
          "path": "/v0/imports",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "listImports",
          "method": "GET",
          "path": "/v0/imports",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "getImport",
          "method": "GET",
          "path": "/v0/imports/{id}",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "updateImport",
          "method": "PATCH",
          "path": "/v0/imports/{id}",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "deleteImport",
          "method": "DELETE",
          "path": "/v0/imports/{id}",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "createWebhook",
          "method": "POST",
          "path": "/v0/webhooks",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "listWebhooks",
          "method": "GET",
          "path": "/v0/webhooks",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "getWebhook",
          "method": "GET",
          "path": "/v0/webhooks/{id}",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "updateWebhook",
          "method": "PATCH",
          "path": "/v0/webhooks/{id}",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "deleteWebhook",
          "method": "DELETE",
          "path": "/v0/webhooks/{id}",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "listWebhookAttempts",
          "method": "GET",
          "path": "/v0/webhooks/{id}/attempts",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "listEvents",
          "method": "GET",
          "path": "/v0/events",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "getEvent",
          "method": "GET",
          "path": "/v0/events/{id}",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "createApiKey",
          "method": "POST",
          "path": "/api-keys",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "listApiKeys",
          "method": "GET",
          "path": "/api-keys",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "getApiKey",
          "method": "GET",
          "path": "/api-keys/{id}",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "updateApiKey",
          "method": "PUT",
          "path": "/api-keys/{id}",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "deleteApiKey",
          "method": "DELETE",
          "path": "/api-keys/{id}",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "getApiKeyUsage",
          "method": "GET",
          "path": "/api-keys/{id}/usage",
          "retryable": true,
          "response": "json"
        }
      ]
    },
    {
      "id": "tavily",
      "name": "Tavily",
      "description": "Agent-oriented web search with relevance-ranked content snippets.",
      "boundary": "Normalized basic search and credits. Native APIs preserve extraction, crawl, map, research, and explicit streaming.",
      "docs": "https://docs.tavily.com/documentation/api-reference/endpoint/search",
      "status": "alpha",
      "nativeClient": true,
      "url": "https://searchsdk.dev/docs/providers/tavily",
      "markdownUrl": "https://searchsdk.dev/docs/providers/tavily.md",
      "corpus": false,
      "normalizedWebSearch": true,
      "normalizedCapabilities": {
        "domainFilters": true,
        "maxIncludeDomains": 300,
        "maxExcludeDomains": 150
      },
      "nativeOperations": [
        {
          "name": "getPaymentPricing",
          "method": "GET",
          "path": "/.well-known/pricing",
          "retryable": true,
          "response": "raw"
        },
        {
          "name": "paidSearch",
          "method": "POST",
          "path": "/search",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "crawl",
          "method": "POST",
          "path": "/crawl",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "deactivateKeys",
          "method": "POST",
          "path": "/deactivate-keys",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "extract",
          "method": "POST",
          "path": "/extract",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "feedback",
          "method": "POST",
          "path": "/feedback",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "generateKeys",
          "method": "POST",
          "path": "/generate-keys",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "keyInfo",
          "method": "GET",
          "path": "/key-info",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "logs",
          "method": "POST",
          "path": "/logs",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "map",
          "method": "POST",
          "path": "/map",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "orgUsage",
          "method": "POST",
          "path": "/org-usage",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "getResearch",
          "method": "GET",
          "path": "/research/{request_id}",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "research",
          "method": "POST",
          "path": "/research",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "researchStream",
          "method": "POST",
          "path": "/research",
          "retryable": false,
          "response": "sse"
        },
        {
          "name": "search",
          "method": "POST",
          "path": "/search",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "getUsage",
          "method": "GET",
          "path": "/usage",
          "retryable": true,
          "response": "json"
        }
      ]
    },
    {
      "id": "brave",
      "name": "Brave",
      "description": "Independent-index web search with descriptions and extra snippets.",
      "boundary": "Normalized web results. Native search verticals, LLM Context, answers, suggestions, and enrichment remain separate.",
      "docs": "https://api-dashboard.search.brave.com/app/documentation/web-search/get-started",
      "status": "alpha",
      "nativeClient": true,
      "url": "https://searchsdk.dev/docs/providers/brave",
      "markdownUrl": "https://searchsdk.dev/docs/providers/brave.md",
      "corpus": false,
      "normalizedWebSearch": true,
      "normalizedCapabilities": {
        "domainFilters": false,
        "maxIncludeDomains": 0,
        "maxExcludeDomains": 0
      },
      "nativeOperations": [
        {
          "name": "llmContext",
          "method": "GET",
          "path": "/v1/llm/context",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "llmContextPost",
          "method": "POST",
          "path": "/v1/llm/context",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "answers",
          "method": "POST",
          "path": "/v1/chat/completions",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "answersStream",
          "method": "POST",
          "path": "/v1/chat/completions",
          "retryable": false,
          "response": "sse"
        },
        {
          "name": "search",
          "method": "GET",
          "path": "/v1/web/search",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "searchPost",
          "method": "POST",
          "path": "/v1/web/search",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "localPois",
          "method": "GET",
          "path": "/v1/local/pois",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "poiDescriptions",
          "method": "GET",
          "path": "/v1/local/descriptions",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "rich",
          "method": "GET",
          "path": "/v1/web/rich",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "news",
          "method": "GET",
          "path": "/v1/news/search",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "newsPost",
          "method": "POST",
          "path": "/v1/news/search",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "videos",
          "method": "GET",
          "path": "/v1/videos/search",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "videosPost",
          "method": "POST",
          "path": "/v1/videos/search",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "images",
          "method": "GET",
          "path": "/v1/images/search",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "places",
          "method": "GET",
          "path": "/v1/local/place_search",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "suggest",
          "method": "GET",
          "path": "/v1/suggest/search",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "spellcheck",
          "method": "GET",
          "path": "/v1/spellcheck/search",
          "retryable": true,
          "response": "json"
        }
      ]
    },
    {
      "id": "perplexity",
      "name": "Perplexity",
      "description": "Ranked web results with extracted snippets and search filters.",
      "boundary": "Normalized Search API sources. Native clients preserve Sonar, Agent, embeddings, skills, analytics, and streaming.",
      "docs": "https://docs.perplexity.ai/api-reference/search-post",
      "status": "alpha",
      "nativeClient": true,
      "url": "https://searchsdk.dev/docs/providers/perplexity",
      "markdownUrl": "https://searchsdk.dev/docs/providers/perplexity.md",
      "corpus": false,
      "normalizedWebSearch": true,
      "normalizedCapabilities": {
        "domainFilters": true,
        "maxIncludeDomains": 20,
        "maxExcludeDomains": 20,
        "mutuallyExclusiveDomainFilters": true
      },
      "nativeOperations": [
        {
          "name": "chatCompletions",
          "method": "POST",
          "path": "/v1/sonar",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "chatCompletionsStream",
          "method": "POST",
          "path": "/v1/sonar",
          "retryable": false,
          "response": "sse"
        },
        {
          "name": "search",
          "method": "POST",
          "path": "/search",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "createEmbeddings",
          "method": "POST",
          "path": "/v1/embeddings",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "createContextualizedEmbeddings",
          "method": "POST",
          "path": "/v1/contextualizedembeddings",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "getAsyncChatCompletion",
          "method": "GET",
          "path": "/v1/async/sonar/{api_request}",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "listAsyncChatCompletions",
          "method": "GET",
          "path": "/v1/async/sonar",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "createAsyncChatCompletion",
          "method": "POST",
          "path": "/v1/async/sonar",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "createAgent",
          "method": "POST",
          "path": "/v1/agent",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "createAgentStream",
          "method": "POST",
          "path": "/v1/agent",
          "retryable": false,
          "response": "sse"
        },
        {
          "name": "retrieveAgent",
          "method": "GET",
          "path": "/v1/agent/{id}",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "listAgentFiles",
          "method": "GET",
          "path": "/v1/agent/{id}/files",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "downloadAgentFile",
          "method": "GET",
          "path": "/v1/agent/{id}/files/{file_id}/content",
          "retryable": true,
          "response": "bytes"
        },
        {
          "name": "cancelAgentResponse",
          "method": "POST",
          "path": "/v1/agent/{id}/cancel",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "listModels",
          "method": "GET",
          "path": "/v1/models",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "getComputerUsageAnalytics",
          "method": "GET",
          "path": "/v1/analytics/computer/usage",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "getComputerUsageAnalyticsV2",
          "method": "GET",
          "path": "/v2/analytics/computer/usage",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "listSkills",
          "method": "GET",
          "path": "/v1/skills",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "createSkill",
          "method": "POST",
          "path": "/v1/skills",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "getSkill",
          "method": "GET",
          "path": "/v1/skills/{skill_id}",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "updateSkill",
          "method": "PUT",
          "path": "/v1/skills/{skill_id}",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "deleteSkill",
          "method": "DELETE",
          "path": "/v1/skills/{skill_id}",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "listSkillRevisions",
          "method": "GET",
          "path": "/v1/skills/{skill_id}/revisions",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "downloadSkill",
          "method": "GET",
          "path": "/v1/skills/{skill_id}/download",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "answerQuestions",
          "method": "POST",
          "path": "/v1/decisions",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "routerChatCompletions",
          "method": "POST",
          "path": "/router/v1/chat/completions",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "routerChatCompletionsStream",
          "method": "POST",
          "path": "/router/v1/chat/completions",
          "retryable": false,
          "response": "sse"
        },
        {
          "name": "routerResponses",
          "method": "POST",
          "path": "/router/v1/responses",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "routerResponsesStream",
          "method": "POST",
          "path": "/router/v1/responses",
          "retryable": false,
          "response": "sse"
        },
        {
          "name": "routerMessages",
          "method": "POST",
          "path": "/router/v1/messages",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "routerMessagesStream",
          "method": "POST",
          "path": "/router/v1/messages",
          "retryable": false,
          "response": "sse"
        },
        {
          "name": "listRouterModels",
          "method": "GET",
          "path": "/router/v1/models",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "getRouterModel",
          "method": "GET",
          "path": "/router/v1/models/{model}",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "generateAuthToken",
          "method": "POST",
          "path": "/generate_auth_token",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "revokeAuthToken",
          "method": "POST",
          "path": "/revoke_auth_token",
          "retryable": false,
          "response": "text"
        }
      ]
    },
    {
      "id": "parallel",
      "name": "Parallel",
      "description": "Web retrieval using search queries and an optional research objective.",
      "boundary": "Normalized search excerpts. Native APIs include Extract, Tasks, FindAll, monitors, memory, Chat, and Responses.",
      "docs": "https://docs.parallel.ai/api-reference/search/search",
      "status": "alpha",
      "nativeClient": true,
      "url": "https://searchsdk.dev/docs/providers/parallel",
      "markdownUrl": "https://searchsdk.dev/docs/providers/parallel.md",
      "corpus": false,
      "normalizedWebSearch": true,
      "normalizedCapabilities": {
        "domainFilters": true,
        "maxIncludeDomains": 200,
        "maxExcludeDomains": 200,
        "mutuallyExclusiveDomainFilters": true
      },
      "nativeOperations": [
        {
          "name": "search",
          "method": "POST",
          "path": "/v1/search",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "imageSearch",
          "method": "POST",
          "path": "/v1/images/search",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "extract",
          "method": "POST",
          "path": "/v1/extract",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "createTaskGroup",
          "method": "POST",
          "path": "/v1/tasks/groups",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "retrieveTaskGroup",
          "method": "GET",
          "path": "/v1/tasks/groups/{taskgroup_id}",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "streamTaskGroupEvents",
          "method": "GET",
          "path": "/v1/tasks/groups/{taskgroup_id}/events",
          "retryable": true,
          "response": "sse"
        },
        {
          "name": "addRunsToTaskGroup",
          "method": "POST",
          "path": "/v1/tasks/groups/{taskgroup_id}/runs",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "fetchTaskGroupRuns",
          "method": "GET",
          "path": "/v1/tasks/groups/{taskgroup_id}/runs",
          "retryable": true,
          "response": "sse"
        },
        {
          "name": "retrieveTaskGroupRun",
          "method": "GET",
          "path": "/v1/tasks/groups/{taskgroup_id}/runs/{run_id}",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "createTaskRun",
          "method": "POST",
          "path": "/v1/tasks/runs",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "retrieveTaskRun",
          "method": "GET",
          "path": "/v1/tasks/runs/{run_id}",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "streamTaskRunEvents",
          "method": "GET",
          "path": "/v1/tasks/runs/{run_id}/events",
          "retryable": true,
          "response": "sse"
        },
        {
          "name": "retrieveTaskRunInput",
          "method": "GET",
          "path": "/v1/tasks/runs/{run_id}/input",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "retrieveTaskRunResult",
          "method": "GET",
          "path": "/v1/tasks/runs/{run_id}/result",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "fastEntitySearch",
          "method": "POST",
          "path": "/v1beta/findall/entity-search",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "ingestFindAllRun",
          "method": "POST",
          "path": "/v1beta/findall/ingest",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "createFindAllRun",
          "method": "POST",
          "path": "/v1beta/findall/runs",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "retrieveFindAllRunStatus",
          "method": "GET",
          "path": "/v1beta/findall/runs/{findall_id}",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "cancelFindAllRun",
          "method": "POST",
          "path": "/v1beta/findall/runs/{findall_id}/cancel",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "addEnrichmentToFindAllRun",
          "method": "POST",
          "path": "/v1beta/findall/runs/{findall_id}/enrich",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "streamFindAllEvents",
          "method": "GET",
          "path": "/v1beta/findall/runs/{findall_id}/events",
          "retryable": true,
          "response": "sse"
        },
        {
          "name": "extendFindAllRun",
          "method": "POST",
          "path": "/v1beta/findall/runs/{findall_id}/extend",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "findAllRunResult",
          "method": "GET",
          "path": "/v1beta/findall/runs/{findall_id}/result",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "getFindAllRunSchema",
          "method": "GET",
          "path": "/v1beta/findall/runs/{findall_id}/schema",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "createMonitor",
          "method": "POST",
          "path": "/v1/monitors",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "listMonitors",
          "method": "GET",
          "path": "/v1/monitors",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "monitorStats",
          "method": "GET",
          "path": "/v1/monitors/stats",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "retrieveMonitor",
          "method": "GET",
          "path": "/v1/monitors/{monitor_id}",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "cancelMonitor",
          "method": "POST",
          "path": "/v1/monitors/{monitor_id}/cancel",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "listMonitorEvents",
          "method": "GET",
          "path": "/v1/monitors/{monitor_id}/events",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "triggerMonitorRun",
          "method": "POST",
          "path": "/v1/monitors/{monitor_id}/trigger",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "updateMonitor",
          "method": "POST",
          "path": "/v1/monitors/{monitor_id}/update",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "clearMemory",
          "method": "POST",
          "path": "/v1beta/memory/clear",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "evictFromMemory",
          "method": "POST",
          "path": "/v1beta/memory/evict",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "retrieveMemory",
          "method": "POST",
          "path": "/v1beta/memory/retrieve",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "chatCompletions",
          "method": "POST",
          "path": "/v1beta/chat/completions",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "chatCompletionsStream",
          "method": "POST",
          "path": "/v1beta/chat/completions",
          "retryable": false,
          "response": "sse"
        },
        {
          "name": "createResponse",
          "method": "POST",
          "path": "/v1/responses",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "createResponseStream",
          "method": "POST",
          "path": "/v1/responses",
          "retryable": false,
          "response": "sse"
        }
      ]
    },
    {
      "id": "linkup",
      "name": "Linkup",
      "description": "Search with source results, sourced answers, and structured output modes.",
      "boundary": "Normalized searchResults. Native answers, fetch, research, tasks, and access-gated extraction keep their own shapes.",
      "docs": "https://docs.linkup.so/pages/documentation/endpoints/search/overview",
      "status": "alpha",
      "nativeClient": true,
      "url": "https://searchsdk.dev/docs/providers/linkup",
      "markdownUrl": "https://searchsdk.dev/docs/providers/linkup.md",
      "corpus": false,
      "normalizedWebSearch": true,
      "normalizedCapabilities": {
        "domainFilters": true,
        "maxIncludeDomains": 100,
        "maxExcludeDomains": 50
      },
      "nativeOperations": [
        {
          "name": "balance",
          "method": "GET",
          "path": "/v1/credits/balance",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "createExtract",
          "method": "POST",
          "path": "/v1/extract",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "listExtract",
          "method": "GET",
          "path": "/v1/extract",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "getExtract",
          "method": "GET",
          "path": "/v1/extract/{id}",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "fetchPage",
          "method": "POST",
          "path": "/v1/fetch",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "search",
          "method": "POST",
          "path": "/v1/search",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "createTasks",
          "method": "POST",
          "path": "/v1/tasks",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "listTasks",
          "method": "GET",
          "path": "/v1/tasks",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "getTask",
          "method": "GET",
          "path": "/v1/tasks/{id}",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "responses",
          "method": "POST",
          "path": "/v1/responses",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "createResearch",
          "method": "POST",
          "path": "/v1/research",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "listResearch",
          "method": "GET",
          "path": "/v1/research",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "getResearch",
          "method": "GET",
          "path": "/v1/research/{id}",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "rewindSearch",
          "method": "POST",
          "path": "/v1/rewind/search",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "rewindFetch",
          "method": "POST",
          "path": "/v1/rewind/fetch",
          "retryable": false,
          "response": "json"
        }
      ]
    },
    {
      "id": "firecrawl",
      "name": "Firecrawl",
      "description": "Web search with optional scraping of returned pages.",
      "boundary": "Normalized web results. Native scraping, crawling, extraction, agents, monitors, and account APIs remain explicit.",
      "docs": "https://docs.firecrawl.dev/features/search",
      "status": "alpha",
      "nativeClient": true,
      "url": "https://searchsdk.dev/docs/providers/firecrawl",
      "markdownUrl": "https://searchsdk.dev/docs/providers/firecrawl.md",
      "corpus": false,
      "normalizedWebSearch": true,
      "normalizedCapabilities": {
        "domainFilters": true,
        "maxIncludeDomains": 100,
        "maxExcludeDomains": 100,
        "mutuallyExclusiveDomainFilters": true,
        "maxQueryLength": 500
      },
      "nativeOperations": [
        {
          "name": "createMonitor",
          "method": "POST",
          "path": "/monitor",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "listMonitors",
          "method": "GET",
          "path": "/monitor",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "getMonitor",
          "method": "GET",
          "path": "/monitor/{monitorId}",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "updateMonitor",
          "method": "PATCH",
          "path": "/monitor/{monitorId}",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "deleteMonitor",
          "method": "DELETE",
          "path": "/monitor/{monitorId}",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "runMonitor",
          "method": "POST",
          "path": "/monitor/{monitorId}/run",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "listMonitorChecks",
          "method": "GET",
          "path": "/monitor/{monitorId}/checks",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "getMonitorCheck",
          "method": "GET",
          "path": "/monitor/{monitorId}/checks/{checkId}",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "scrape",
          "method": "POST",
          "path": "/scrape",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "interactWithScrapeBrowserSession",
          "method": "POST",
          "path": "/scrape/{jobId}/interact",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "stopInteractiveScrapeBrowserSession",
          "method": "DELETE",
          "path": "/scrape/{jobId}/interact",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "parseFile",
          "method": "POST",
          "path": "/parse",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "getParseFormats",
          "method": "GET",
          "path": "/parse/formats",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "batchScrape",
          "method": "POST",
          "path": "/batch/scrape",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "getBatchScrapeStatus",
          "method": "GET",
          "path": "/batch/scrape/{id}",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "cancelBatchScrape",
          "method": "DELETE",
          "path": "/batch/scrape/{id}",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "getBatchScrapeErrors",
          "method": "GET",
          "path": "/batch/scrape/{id}/errors",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "getCrawlStatus",
          "method": "GET",
          "path": "/crawl/{id}",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "cancelCrawl",
          "method": "DELETE",
          "path": "/crawl/{id}",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "getCrawlErrors",
          "method": "GET",
          "path": "/crawl/{id}/errors",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "crawl",
          "method": "POST",
          "path": "/crawl",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "crawlParamsPreview",
          "method": "POST",
          "path": "/crawl/params-preview",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "map",
          "method": "POST",
          "path": "/map",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "extract",
          "method": "POST",
          "path": "/extract",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "getExtractStatus",
          "method": "GET",
          "path": "/extract/{id}",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "listAgents",
          "method": "GET",
          "path": "/agent",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "startAgent",
          "method": "POST",
          "path": "/agent",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "getAgentStatus",
          "method": "GET",
          "path": "/agent/{jobId}",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "cancelAgent",
          "method": "DELETE",
          "path": "/agent/{jobId}",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "getAgentTrace",
          "method": "GET",
          "path": "/agent/{jobId}/trace",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "getAgentSnapshot",
          "method": "GET",
          "path": "/agent/{jobId}/snapshots/{snapshotId}",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "getActiveCrawls",
          "method": "GET",
          "path": "/crawl/active",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "getCreditUsage",
          "method": "GET",
          "path": "/team/credit-usage",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "getHistoricalCreditUsage",
          "method": "GET",
          "path": "/team/credit-usage/historical",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "getTokenUsage",
          "method": "GET",
          "path": "/team/token-usage",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "getHistoricalTokenUsage",
          "method": "GET",
          "path": "/team/token-usage/historical",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "getQueueStatus",
          "method": "GET",
          "path": "/team/queue-status",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "getActivity",
          "method": "GET",
          "path": "/team/activity",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "search",
          "method": "POST",
          "path": "/search",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "createBrowserSession",
          "method": "POST",
          "path": "/interact",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "listBrowserSessions",
          "method": "GET",
          "path": "/interact",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "executeBrowserCode",
          "method": "POST",
          "path": "/interact/{sessionId}/execute",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "deleteBrowserSession",
          "method": "DELETE",
          "path": "/interact/{sessionId}",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "getScrapeStatus",
          "method": "GET",
          "path": "/scrape/{jobId}",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "submitSearchFeedback",
          "method": "POST",
          "path": "/search/{jobId}/feedback",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "askSupportAgent",
          "method": "POST",
          "path": "/support/ask",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "searchSupportDocs",
          "method": "POST",
          "path": "/support/docs-search",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "researchSearchPapers",
          "method": "GET",
          "path": "/search/research/papers",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "researchGetPaper",
          "method": "GET",
          "path": "/search/research/papers/{id}",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "researchRelatedPapers",
          "method": "GET",
          "path": "/search/research/papers/{id}/similar",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "developerSearch",
          "method": "GET",
          "path": "/search/developer",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "developerSearchPost",
          "method": "POST",
          "path": "/search/developer",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "govSearch",
          "method": "GET",
          "path": "/search/gov",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "govSearchPost",
          "method": "POST",
          "path": "/search/gov",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "submitEndpointFeedback",
          "method": "POST",
          "path": "/feedback",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "getThreatProtection",
          "method": "GET",
          "path": "/team/threat-protection",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "updateThreatProtection",
          "method": "PUT",
          "path": "/team/threat-protection",
          "retryable": false,
          "response": "json"
        }
      ]
    },
    {
      "id": "you",
      "name": "You.com",
      "description": "Web and news search with snippets and optional page extraction.",
      "boundary": "Normalized web sources. Native Contents, Answer, Research, finance, images, and account balance retain their own shapes.",
      "docs": "https://you.com/docs/api-reference/search/v1-search",
      "status": "alpha",
      "nativeClient": true,
      "url": "https://searchsdk.dev/docs/providers/you",
      "markdownUrl": "https://searchsdk.dev/docs/providers/you.md",
      "corpus": false,
      "normalizedWebSearch": true,
      "normalizedCapabilities": {
        "domainFilters": true,
        "maxIncludeDomains": 500,
        "maxExcludeDomains": 5000,
        "mutuallyExclusiveDomainFilters": true
      },
      "nativeOperations": [
        {
          "name": "search",
          "method": "POST",
          "path": "/v1/search",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "contents",
          "method": "POST",
          "path": "/v1/contents",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "answer",
          "method": "POST",
          "path": "/v1/answer",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "research",
          "method": "POST",
          "path": "/v1/research",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "getResearchTask",
          "method": "GET",
          "path": "/v1/research/{task_id}",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "streamResearchTask",
          "method": "GET",
          "path": "/v1/research/{task_id}/stream",
          "retryable": true,
          "response": "sse"
        },
        {
          "name": "financeResearch",
          "method": "POST",
          "path": "/v1/finance_research",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "getAccountBalance",
          "method": "GET",
          "path": "/v1/billing/account_balance",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "images",
          "method": "GET",
          "path": "/v1/images",
          "retryable": true,
          "response": "json"
        }
      ]
    },
    {
      "id": "serper",
      "name": "Serper",
      "description": "Google search results across web and specialized result categories.",
      "boundary": "Normalized organic web hits. Native Google verticals, batches, GET/POST variants, and scraping use provider options.",
      "docs": "https://serper.dev/",
      "status": "alpha",
      "nativeClient": true,
      "url": "https://searchsdk.dev/docs/providers/serper",
      "markdownUrl": "https://searchsdk.dev/docs/providers/serper.md",
      "corpus": false,
      "normalizedWebSearch": true,
      "normalizedCapabilities": {
        "domainFilters": false,
        "maxIncludeDomains": 0,
        "maxExcludeDomains": 0
      },
      "nativeOperations": [
        {
          "name": "search",
          "method": "POST",
          "path": "/search",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "searchGet",
          "method": "GET",
          "path": "/search",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "images",
          "method": "POST",
          "path": "/images",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "imagesGet",
          "method": "GET",
          "path": "/images",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "videos",
          "method": "POST",
          "path": "/videos",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "videosGet",
          "method": "GET",
          "path": "/videos",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "places",
          "method": "POST",
          "path": "/places",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "placesGet",
          "method": "GET",
          "path": "/places",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "maps",
          "method": "POST",
          "path": "/maps",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "mapsGet",
          "method": "GET",
          "path": "/maps",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "reviews",
          "method": "POST",
          "path": "/reviews",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "reviewsGet",
          "method": "GET",
          "path": "/reviews",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "news",
          "method": "POST",
          "path": "/news",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "newsGet",
          "method": "GET",
          "path": "/news",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "shopping",
          "method": "POST",
          "path": "/shopping",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "shoppingGet",
          "method": "GET",
          "path": "/shopping",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "scholar",
          "method": "POST",
          "path": "/scholar",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "scholarGet",
          "method": "GET",
          "path": "/scholar",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "patents",
          "method": "POST",
          "path": "/patents",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "patentsGet",
          "method": "GET",
          "path": "/patents",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "autocomplete",
          "method": "POST",
          "path": "/autocomplete",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "autocompleteGet",
          "method": "GET",
          "path": "/autocomplete",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "lens",
          "method": "POST",
          "path": "/lens",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "lensGet",
          "method": "GET",
          "path": "/lens",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "scrape",
          "method": "POST",
          "path": "/",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "scrapeGet",
          "method": "GET",
          "path": "/",
          "retryable": true,
          "response": "json"
        }
      ]
    },
    {
      "id": "serpapi",
      "name": "SerpAPI",
      "description": "Structured search results from Google and other supported engines.",
      "boundary": "Normalized Google organic hits, one page. Native engine gateway, archives, locations, uploads, and Extract families.",
      "docs": "https://serpapi.com/search-api",
      "status": "alpha",
      "nativeClient": true,
      "url": "https://searchsdk.dev/docs/providers/serpapi",
      "markdownUrl": "https://searchsdk.dev/docs/providers/serpapi.md",
      "corpus": false,
      "normalizedWebSearch": true,
      "normalizedCapabilities": {
        "domainFilters": false,
        "maxIncludeDomains": 0,
        "maxExcludeDomains": 0
      },
      "nativeOperations": [
        {
          "name": "search",
          "method": "GET",
          "path": "/search.json",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "searchHtml",
          "method": "GET",
          "path": "/search.html",
          "retryable": false,
          "response": "text"
        },
        {
          "name": "searchMarkdown",
          "method": "GET",
          "path": "/search.md",
          "retryable": false,
          "response": "text"
        },
        {
          "name": "searchPixelPositions",
          "method": "GET",
          "path": "/search.json_with_pixel_position",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "getSearch",
          "method": "GET",
          "path": "/searches/{search_id}.json",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "getSearchHtml",
          "method": "GET",
          "path": "/searches/{search_id}.html",
          "retryable": true,
          "response": "text"
        },
        {
          "name": "getSearchPixelPositions",
          "method": "GET",
          "path": "/searches/{search_id}.json_with_pixel_position",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "locations",
          "method": "GET",
          "path": "/locations.json",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "account",
          "method": "GET",
          "path": "/account.json",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "uploadImage",
          "method": "POST",
          "path": "/image",
          "retryable": false,
          "response": "json"
        }
      ]
    },
    {
      "id": "valyu",
      "name": "Valyu",
      "description": "Web search with source content and provider-native relevance.",
      "boundary": "Normalized web search only. Typed adapter options and raw response access preserve provider-specific details; no generated native client.",
      "docs": "https://docs.valyu.ai/api-reference/endpoint/search",
      "status": "alpha",
      "nativeClient": false,
      "url": "https://searchsdk.dev/docs/providers/valyu",
      "markdownUrl": "https://searchsdk.dev/docs/providers/valyu.md",
      "corpus": false,
      "normalizedWebSearch": true,
      "normalizedCapabilities": {
        "domainFilters": true,
        "maxIncludeDomains": 100,
        "maxExcludeDomains": 100
      },
      "nativeOperations": []
    },
    {
      "id": "searxng",
      "name": "SearXNG",
      "description": "Metasearch through an operator-selected SearXNG instance.",
      "boundary": "Normalized JSON web results only. Your server chooses the instance; JSON search must be enabled by its operator. No generated native client.",
      "docs": "https://docs.searxng.org/dev/search_api.html",
      "status": "alpha",
      "nativeClient": false,
      "url": "https://searchsdk.dev/docs/providers/searxng",
      "markdownUrl": "https://searchsdk.dev/docs/providers/searxng.md",
      "corpus": false,
      "normalizedWebSearch": true,
      "normalizedCapabilities": {
        "domainFilters": false,
        "maxIncludeDomains": 0,
        "maxExcludeDomains": 0
      },
      "nativeOperations": []
    },
    {
      "id": "wondersearch",
      "name": "WonderSearch",
      "description": "Semantic retrieval over your own documents and workspace collections.",
      "boundary": "Corpus-only native client: passages, content, access, uploads, ingestion, and billing. Never relabeled as open-web results.",
      "docs": "https://docs.evokoa.com/wondersearch/reference/search-api",
      "status": "native",
      "nativeClient": true,
      "url": "https://searchsdk.dev/docs/providers/wondersearch",
      "markdownUrl": "https://searchsdk.dev/docs/providers/wondersearch.md",
      "corpus": true,
      "normalizedWebSearch": false,
      "nativeOperations": [
        {
          "name": "searchDrive",
          "method": "POST",
          "path": "/v1/drives/{drive_id}/search",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "getPassage",
          "method": "GET",
          "path": "/v1/drives/{drive_id}/passages/{passage_id}",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "getCapabilities",
          "method": "GET",
          "path": "/v1/workspaces/{workspace_id}/capabilities",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "searchWorkspace",
          "method": "POST",
          "path": "/v1/workspaces/{workspace_id}/search",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "bootstrapAccount",
          "method": "POST",
          "path": "/v1/account/bootstrap",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "getMe",
          "method": "GET",
          "path": "/v1/me",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "listOrganizations",
          "method": "GET",
          "path": "/v1/organizations",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "getOrganization",
          "method": "GET",
          "path": "/v1/organizations/{organization_id}",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "getOrganizationRaw",
          "method": "GET",
          "path": "/v1/organizations/{organization_id}",
          "retryable": true,
          "response": "raw"
        },
        {
          "name": "updateOrganization",
          "method": "PATCH",
          "path": "/v1/organizations/{organization_id}",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "listOrganizationMembers",
          "method": "GET",
          "path": "/v1/organizations/{organization_id}/members",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "updateOrganizationMember",
          "method": "PATCH",
          "path": "/v1/organizations/{organization_id}/members/{user_id}",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "deleteOrganizationMember",
          "method": "DELETE",
          "path": "/v1/organizations/{organization_id}/members/{user_id}",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "listOrganizationWorkspaces",
          "method": "GET",
          "path": "/v1/organizations/{organization_id}/workspaces",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "createOrganizationWorkspace",
          "method": "POST",
          "path": "/v1/organizations/{organization_id}/workspaces",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "getWorkspace",
          "method": "GET",
          "path": "/v1/workspaces/{workspace_id}",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "getWorkspaceRaw",
          "method": "GET",
          "path": "/v1/workspaces/{workspace_id}",
          "retryable": true,
          "response": "raw"
        },
        {
          "name": "updateWorkspace",
          "method": "PATCH",
          "path": "/v1/workspaces/{workspace_id}",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "listWorkspaceInheritedMembers",
          "method": "GET",
          "path": "/v1/workspaces/{workspace_id}/inherited-members",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "listWorkspaceMembers",
          "method": "GET",
          "path": "/v1/workspaces/{workspace_id}/members",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "createWorkspaceMember",
          "method": "POST",
          "path": "/v1/workspaces/{workspace_id}/members",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "updateWorkspaceMember",
          "method": "PATCH",
          "path": "/v1/workspaces/{workspace_id}/members/{user_id}",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "deleteWorkspaceMember",
          "method": "DELETE",
          "path": "/v1/workspaces/{workspace_id}/members/{user_id}",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "listOrganizationInvitations",
          "method": "GET",
          "path": "/v1/organizations/{organization_id}/invitations",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "createOrganizationInvitation",
          "method": "POST",
          "path": "/v1/organizations/{organization_id}/invitations",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "getOrganizationInvitation",
          "method": "GET",
          "path": "/v1/organizations/{organization_id}/invitations/{invitation_id}",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "getOrganizationInvitationRaw",
          "method": "GET",
          "path": "/v1/organizations/{organization_id}/invitations/{invitation_id}",
          "retryable": true,
          "response": "raw"
        },
        {
          "name": "deleteOrganizationInvitation",
          "method": "DELETE",
          "path": "/v1/organizations/{organization_id}/invitations/{invitation_id}",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "resendOrganizationInvitation",
          "method": "POST",
          "path": "/v1/organizations/{organization_id}/invitations/{invitation_id}/resend",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "previewInvitation",
          "method": "POST",
          "path": "/v1/invitations/preview",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "acceptInvitation",
          "method": "POST",
          "path": "/v1/invitations/accept",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "listWorkspaceApiKeys",
          "method": "GET",
          "path": "/v1/workspaces/{workspace_id}/api-keys",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "createWorkspaceApiKey",
          "method": "POST",
          "path": "/v1/workspaces/{workspace_id}/api-keys",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "deleteWorkspaceApiKey",
          "method": "DELETE",
          "path": "/v1/workspaces/{workspace_id}/api-keys/{key_id}",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "getWorkspaceOverview",
          "method": "GET",
          "path": "/v1/workspaces/{workspace_id}/overview",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "getOrganizationUsage",
          "method": "GET",
          "path": "/v1/organizations/{organization_id}/usage",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "listWorkspaceDrives",
          "method": "GET",
          "path": "/v1/workspaces/{workspace_id}/drives",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "createWorkspaceDrive",
          "method": "POST",
          "path": "/v1/workspaces/{workspace_id}/drives",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "getDrive",
          "method": "GET",
          "path": "/v1/drives/{drive_id}",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "getDriveRaw",
          "method": "GET",
          "path": "/v1/drives/{drive_id}",
          "retryable": true,
          "response": "raw"
        },
        {
          "name": "updateDrive",
          "method": "PATCH",
          "path": "/v1/drives/{drive_id}",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "deleteDrive",
          "method": "DELETE",
          "path": "/v1/drives/{drive_id}",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "listDriveFolders",
          "method": "GET",
          "path": "/v1/drives/{drive_id}/folders",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "createDriveFolder",
          "method": "POST",
          "path": "/v1/drives/{drive_id}/folders",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "getDriveFolder",
          "method": "GET",
          "path": "/v1/drives/{drive_id}/folders/{folder_id}",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "getDriveFolderRaw",
          "method": "GET",
          "path": "/v1/drives/{drive_id}/folders/{folder_id}",
          "retryable": true,
          "response": "raw"
        },
        {
          "name": "updateDriveFolder",
          "method": "PATCH",
          "path": "/v1/drives/{drive_id}/folders/{folder_id}",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "deleteDriveFolder",
          "method": "DELETE",
          "path": "/v1/drives/{drive_id}/folders/{folder_id}",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "createDriveDocument",
          "method": "POST",
          "path": "/v1/drives/{drive_id}/documents",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "listDriveDocuments",
          "method": "GET",
          "path": "/v1/drives/{drive_id}/documents",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "getDriveDocument",
          "method": "GET",
          "path": "/v1/drives/{drive_id}/documents/{document_id}",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "replaceDocument",
          "method": "PUT",
          "path": "/v1/drives/{drive_id}/documents/{document_id}",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "deleteDriveDocument",
          "method": "DELETE",
          "path": "/v1/drives/{drive_id}/documents/{document_id}",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "getDriveDocumentSource",
          "method": "GET",
          "path": "/v1/drives/{drive_id}/documents/{document_id}/source",
          "retryable": true,
          "response": "bytes"
        },
        {
          "name": "getWorkspaceDefaultDrive",
          "method": "GET",
          "path": "/v1/workspaces/{workspace_id}/default-drive",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "getWorkspaceDefaultDriveRaw",
          "method": "GET",
          "path": "/v1/workspaces/{workspace_id}/default-drive",
          "retryable": true,
          "response": "raw"
        },
        {
          "name": "setDefaultDrive",
          "method": "PUT",
          "path": "/v1/workspaces/{workspace_id}/default-drive",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "getSdkContext",
          "method": "GET",
          "path": "/v1/sdk/context",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "getDriveUploadCapabilities",
          "method": "GET",
          "path": "/v1/drives/{drive_id}/uploads/capabilities",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "createUploadBatch",
          "method": "POST",
          "path": "/v1/drives/{drive_id}/uploads/batch",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "completeUploadBatch",
          "method": "POST",
          "path": "/v1/drives/{drive_id}/uploads/batch/complete",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "getUploadBatchStatus",
          "method": "POST",
          "path": "/v1/drives/{drive_id}/uploads/batch/status",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "createDriveUpload",
          "method": "POST",
          "path": "/v1/drives/{drive_id}/uploads",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "getDriveUpload",
          "method": "GET",
          "path": "/v1/drives/{drive_id}/uploads/{upload_id}",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "uploadContent",
          "method": "PUT",
          "path": "/v1/drives/{drive_id}/uploads/{upload_id}/content",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "createUploadTransfer",
          "method": "POST",
          "path": "/v1/drives/{drive_id}/uploads/{upload_id}/transfer",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "completeUpload",
          "method": "POST",
          "path": "/v1/drives/{drive_id}/uploads/{upload_id}/complete",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "getWorkspaceOperation",
          "method": "GET",
          "path": "/v1/workspaces/{workspace_id}/operations/{operation_id}",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "createImport",
          "method": "PUT",
          "path": "/v1/drives/{drive_id}/imports/{import_id}",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "getImport",
          "method": "GET",
          "path": "/v1/drives/{drive_id}/imports/{import_id}",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "declareImportChunks",
          "method": "POST",
          "path": "/v1/drives/{drive_id}/imports/{import_id}/chunks",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "acknowledgeImportChunk",
          "method": "POST",
          "path": "/v1/drives/{drive_id}/imports/{import_id}/chunks/{sequence}/acknowledge",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "sealImport",
          "method": "POST",
          "path": "/v1/drives/{drive_id}/imports/{import_id}/seal",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "getIngestionMetrics",
          "method": "GET",
          "path": "/v1/drives/{drive_id}/ingestion-metrics",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "getOrganizationBilling",
          "method": "GET",
          "path": "/v1/organizations/{organization_id}/billing",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "setBillingLimits",
          "method": "POST",
          "path": "/v1/organizations/{organization_id}/billing/limits",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "getOrganizationBillingLimits",
          "method": "GET",
          "path": "/v1/organizations/{organization_id}/billing/limits",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "getOrganizationBillingUsage",
          "method": "GET",
          "path": "/v1/organizations/{organization_id}/billing/usage",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "createBillingPortal",
          "method": "POST",
          "path": "/v1/organizations/{organization_id}/billing/portal",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "getOrganizationBillingWallet",
          "method": "GET",
          "path": "/v1/organizations/{organization_id}/billing/wallet",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "getOrganizationBillingActivity",
          "method": "GET",
          "path": "/v1/organizations/{organization_id}/billing/activity",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "createOrganizationBillingPurchase",
          "method": "POST",
          "path": "/v1/organizations/{organization_id}/billing/purchases",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "getOrganizationBillingPurchase",
          "method": "GET",
          "path": "/v1/organizations/{organization_id}/billing/purchases/{purchase_id}",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "listOrganizationBillingInvoices",
          "method": "GET",
          "path": "/v1/organizations/{organization_id}/billing/invoices",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "getWorkspaceStorage",
          "method": "GET",
          "path": "/v1/workspaces/{workspace_id}/storage",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "setWorkspaceStorage",
          "method": "POST",
          "path": "/v1/workspaces/{workspace_id}/storage",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "quoteWorkspaceStorage",
          "method": "POST",
          "path": "/v1/workspaces/{workspace_id}/storage/quote",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "closeImport",
          "method": "POST",
          "path": "/v1/drives/{drive_id}/imports/{import_id}/close",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "recoverImport",
          "method": "POST",
          "path": "/v1/drives/{drive_id}/imports/{import_id}/recover",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "retryImportOperation",
          "method": "POST",
          "path": "/v1/drives/{drive_id}/imports/{import_id}/operations/{operation_id}/retry",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "getAutoTopup",
          "method": "GET",
          "path": "/v1/organizations/{organization_id}/billing/auto-topup",
          "retryable": true,
          "response": "json"
        },
        {
          "name": "checkoutAutoTopup",
          "method": "POST",
          "path": "/v1/organizations/{organization_id}/billing/auto-topup/checkout",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "amountAutoTopup",
          "method": "POST",
          "path": "/v1/organizations/{organization_id}/billing/auto-topup/amount",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "cancelAutoTopup",
          "method": "POST",
          "path": "/v1/organizations/{organization_id}/billing/auto-topup/cancel",
          "retryable": false,
          "response": "json"
        },
        {
          "name": "resumeAutoTopup",
          "method": "POST",
          "path": "/v1/organizations/{organization_id}/billing/auto-topup/resume",
          "retryable": false,
          "response": "json"
        }
      ]
    }
  ],
  "examples": [
    {
      "id": "quickstart/try-without-credentials/3",
      "title": "first-search.mjs · fixture",
      "description": "Your first TypeScript search: Try without credentials. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "typescript",
      "code": "import { createSearch } from '@belweave/search-sdk';\nimport { createMockProvider } from '@belweave/search-sdk/testing';\n\nconst provider = createMockProvider();\nconst client = createSearch({ provider });\nconst response = await client.web.search({ query: 'SQLite concurrency' });\n\nconsole.log(response.results); // Fixed example-domain fixtures\nconsole.log(provider.calls.length); // 1; no network requests",
      "url": "https://searchsdk.dev/docs/quickstart#try-without-credentials"
    },
    {
      "id": "quickstart/connect-context/2",
      "title": "search.mjs · server",
      "description": "Your first TypeScript search: Connect Context.dev. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "typescript",
      "code": "import { createSearch } from '@belweave/search-sdk';\nimport { context } from '@belweave/search-sdk/context';\n\nconst apiKey = process.env.CONTEXT_API_KEY;\nif (!apiKey) throw new Error('CONTEXT_API_KEY is required');\n\nconst client = createSearch({\n  provider: context({ apiKey }),\n  timeoutMs: 10_000,\n});\n\nconst response = await client.web.search({\n  query: 'SQLite write concurrency',\n  limit: 5,\n});\n\nfor (const result of response.results) {\n  console.log(result.title ?? result.url, result.url);\n}\nconsole.log(response.provider, response.attempts);",
      "url": "https://searchsdk.dev/docs/quickstart#connect-context"
    },
    {
      "id": "sdks/availability/2",
      "title": "Get the source",
      "description": "Choose your SDK: Alpha availability. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "bash",
      "code": "git clone https://github.com/Belweave/searchSDK.git\ncd searchSDK\n# Record this revision with your application's dependency lock.\ngit rev-parse HEAD",
      "url": "https://searchsdk.dev/docs/sdks#availability"
    },
    {
      "id": "installation/pack-locally/1",
      "title": "Source checkout",
      "description": "Install an SDK: Build from a reviewed checkout. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "bash",
      "code": "git clone https://github.com/Belweave/searchSDK.git\ncd searchSDK\n# Record this revision with your application's dependency lock.\ngit rev-parse HEAD",
      "url": "https://searchsdk.dev/docs/installation#pack-locally"
    },
    {
      "id": "sdks/typescript/install/1",
      "title": "Terminal",
      "description": "searchSDK for TypeScript and JavaScript: Install. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "bash",
      "code": "git clone https://github.com/Belweave/searchSDK.git\ncd searchSDK\nnvm use\nnpm ci\nnpm run build:sdk\nnpm pack -w @belweave/search-sdk\n\n# In your Node server application:\nnpm install /absolute/path/searchSDK/belweave-search-sdk-0.1.0-alpha.0.tgz",
      "url": "https://searchsdk.dev/docs/sdks/typescript#install"
    },
    {
      "id": "sdks/typescript/server-credentials/2",
      "title": "credentials.ts · server",
      "description": "searchSDK for TypeScript and JavaScript: Configure server credentials. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "typescript",
      "code": "const apiKey = process.env.CONTEXT_API_KEY;\nif (!apiKey) throw new Error('CONTEXT_API_KEY is required');",
      "url": "https://searchsdk.dev/docs/sdks/typescript#server-credentials"
    },
    {
      "id": "sdks/typescript/pack-locally/2",
      "title": "Source checkout · terminal",
      "description": "searchSDK for TypeScript and JavaScript: Rebuild the source artifact. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "bash",
      "code": "git clone https://github.com/Belweave/searchSDK.git\ncd searchSDK\nnvm use\nnpm ci\nnpm run build:sdk\nnpm pack -w @belweave/search-sdk\n\n# In your server application, use the actual generated tarball:\nnpm install /absolute/path/belweave-search-sdk-0.1.0-alpha.0.tgz",
      "url": "https://searchsdk.dev/docs/sdks/typescript#pack-locally"
    },
    {
      "id": "sdks/python/install/2",
      "title": "Get the source",
      "description": "searchSDK for Python: Install from source. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "bash",
      "code": "git clone https://github.com/Belweave/searchSDK.git\ncd searchSDK\n# Record this revision with your application's dependency lock.\ngit rev-parse HEAD",
      "url": "https://searchsdk.dev/docs/sdks/python#install"
    },
    {
      "id": "sdks/python/install/3",
      "title": "Build or install the local package",
      "description": "searchSDK for Python: Install from source. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "bash",
      "code": "python3 -m venv .venv\n.venv/bin/python -m pip install ./packages/python",
      "url": "https://searchsdk.dev/docs/sdks/python#install"
    },
    {
      "id": "sdks/python/first-search/2",
      "title": "search.py",
      "description": "searchSDK for Python: Make a server-side search. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "python",
      "code": "import os\nfrom searchsdk import SearchClient, SearchRequest, exa\n\nsearch = SearchClient(\n    exa(os.environ[\"EXA_API_KEY\"]),\n    timeout_ms=10_000,\n)\nresponse = search.search(SearchRequest(\n    \"SQLite write concurrency\", limit=3,\n))\nfor result in response.results:\n    print(result.url, result.provenance.provider)",
      "url": "https://searchsdk.dev/docs/sdks/python#first-search"
    },
    {
      "id": "sdks/python/verify/1",
      "title": "Repository checkout · local checks",
      "description": "searchSDK for Python: Verify without provider keys. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "bash",
      "code": "python3 -m venv packages/python/.build/verify\npackages/python/.build/verify/bin/python -m pip install -r packages/python/requirements-dev.txt\npackages/python/.build/verify/bin/python packages/python/scripts/verify.py",
      "url": "https://searchsdk.dev/docs/sdks/python#verify"
    },
    {
      "id": "sdks/go/install/2",
      "title": "Get the source",
      "description": "searchSDK for Go: Install from source. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "bash",
      "code": "git clone https://github.com/Belweave/searchSDK.git\ncd searchSDK\n# Record this revision with your application's dependency lock.\ngit rev-parse HEAD",
      "url": "https://searchsdk.dev/docs/sdks/go#install"
    },
    {
      "id": "sdks/go/install/3",
      "title": "Build or install the local package",
      "description": "searchSDK for Go: Install from source. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "bash",
      "code": "# In your application's existing Go module, for a local checkout:\ngo mod edit -require=github.com/Belweave/searchSDK/packages/go@v0.0.0\ngo mod edit -replace=github.com/Belweave/searchSDK/packages/go=/absolute/path/searchSDK/packages/go\ngo mod tidy",
      "url": "https://searchsdk.dev/docs/sdks/go#install"
    },
    {
      "id": "sdks/go/first-search/2",
      "title": "main.go",
      "description": "searchSDK for Go: Make a server-side search. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "go",
      "code": "package main\n\nimport (\n    \"context\"\n    \"fmt\"\n    \"log\"\n    \"os\"\n    \"time\"\n    searchsdk \"github.com/Belweave/searchSDK/packages/go\"\n)\n\nfunc main() {\n    provider, err := searchsdk.NewAdapter(\"exa\", searchsdk.AdapterOptions{\n        APIKey: os.Getenv(\"EXA_API_KEY\"),\n    })\n    if err != nil { log.Fatal(err) }\n    search, err := searchsdk.New(searchsdk.Config{Provider: provider})\n    if err != nil { log.Fatal(err) }\n    ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)\n    defer cancel()\n    response, err := search.Search(ctx, searchsdk.Request{\n        Query: \"SQLite write concurrency\", Limit: 3,\n    })\n    if err != nil { log.Fatal(err) }\n    fmt.Println(response.Results)\n}",
      "url": "https://searchsdk.dev/docs/sdks/go#first-search"
    },
    {
      "id": "sdks/go/verify/1",
      "title": "Repository checkout · local checks",
      "description": "searchSDK for Go: Verify without provider keys. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "bash",
      "code": "go -C packages/go test -race -p 2 ./...\ngo -C packages/go vet -p 2 ./...\npython3 -B packages/go/internal/verify_consumer.py",
      "url": "https://searchsdk.dev/docs/sdks/go#verify"
    },
    {
      "id": "sdks/java/install/2",
      "title": "Get the source",
      "description": "searchSDK for Java: Install from source. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "bash",
      "code": "git clone https://github.com/Belweave/searchSDK.git\ncd searchSDK\n# Record this revision with your application's dependency lock.\ngit rev-parse HEAD",
      "url": "https://searchsdk.dev/docs/sdks/java#install"
    },
    {
      "id": "sdks/java/install/3",
      "title": "Build or install the local package",
      "description": "searchSDK for Java: Install from source. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "bash",
      "code": "mvn -T 2 -f packages/java/pom.xml install\n\n# Add this dependency to your application's pom.xml:\n# groupId: dev.belweave\n# artifactId: search-sdk\n# version: 0.1.0-alpha.0",
      "url": "https://searchsdk.dev/docs/sdks/java#install"
    },
    {
      "id": "sdks/java/first-search/2",
      "title": "SearchExample.java",
      "description": "searchSDK for Java: Make a server-side search. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "java",
      "code": "import dev.searchsdk.*;\nimport java.time.Duration;\n\npublic class SearchExample {\n    public static void main(String[] args) {\n        var search = SearchClient.builder(\n            Providers.exa(System.getenv(\"EXA_API_KEY\")))\n            .timeout(Duration.ofSeconds(10))\n            .build();\n        var response = search.search(new SearchRequest(\n            \"SQLite write concurrency\", 3\n        )).toCompletableFuture().join();\n        for (var result : response.results()) {\n            System.out.println(result.url());\n        }\n    }\n}",
      "url": "https://searchsdk.dev/docs/sdks/java#first-search"
    },
    {
      "id": "sdks/java/verify/1",
      "title": "Repository checkout · local checks",
      "description": "searchSDK for Java: Verify without provider keys. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "bash",
      "code": "bash packages/java/scripts/verify.sh\nbash packages/java/scripts/verify-maven.sh",
      "url": "https://searchsdk.dev/docs/sdks/java#verify"
    },
    {
      "id": "sdks/rust/install/2",
      "title": "Get the source",
      "description": "searchSDK for Rust: Install from source. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "bash",
      "code": "git clone https://github.com/Belweave/searchSDK.git\ncd searchSDK\n# Record this revision with your application's dependency lock.\ngit rev-parse HEAD",
      "url": "https://searchsdk.dev/docs/sdks/rust#install"
    },
    {
      "id": "sdks/rust/install/3",
      "title": "Application dependency configuration",
      "description": "searchSDK for Rust: Install from source. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "toml",
      "code": "[dependencies]\nsearchsdk = { path = \"/absolute/path/searchSDK/packages/rust\" }\ntokio = { version = \"=1.53.1\", features = [\"rt\", \"macros\"] }",
      "url": "https://searchsdk.dev/docs/sdks/rust#install"
    },
    {
      "id": "sdks/rust/first-search/2",
      "title": "src/main.rs",
      "description": "searchSDK for Rust: Make a server-side search. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "rust",
      "code": "use searchsdk::{Provider, ProviderId, SearchClient, SearchRequest, CallOptions};\n\n#[tokio::main(flavor = \"current_thread\")]\nasync fn main() -> Result<(), Box<dyn std::error::Error>> {\n    let key = std::env::var(\"EXA_API_KEY\")?;\n    let search = SearchClient::new(Provider::new(ProviderId::Exa, key)?)?;\n    let response = search.search(\n        SearchRequest::new(\"SQLite write concurrency\"),\n        CallOptions::default(),\n    ).await?;\n    for result in response.results {\n        println!(\"{}\", result.url);\n    }\n    Ok(())\n}",
      "url": "https://searchsdk.dev/docs/sdks/rust#first-search"
    },
    {
      "id": "sdks/rust/verify/1",
      "title": "Repository checkout · local checks",
      "description": "searchSDK for Rust: Verify without provider keys. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "bash",
      "code": "cargo test --manifest-path packages/rust/Cargo.toml --locked -j 2\ncargo clippy --manifest-path packages/rust/Cargo.toml --locked -j 2 -- -D warnings\ncargo package --manifest-path packages/rust/Cargo.toml --locked",
      "url": "https://searchsdk.dev/docs/sdks/rust#verify"
    },
    {
      "id": "sdks/dotnet/install/2",
      "title": "Get the source",
      "description": "searchSDK for C# / .NET: Install from source. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "bash",
      "code": "git clone https://github.com/Belweave/searchSDK.git\ncd searchSDK\n# Record this revision with your application's dependency lock.\ngit rev-parse HEAD",
      "url": "https://searchsdk.dev/docs/sdks/dotnet#install"
    },
    {
      "id": "sdks/dotnet/install/3",
      "title": "Build or install the local package",
      "description": "searchSDK for C# / .NET: Install from source. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "bash",
      "code": "dotnet pack packages/dotnet/src/SearchSdk/SearchSdk.csproj -c Release -o .local/nuget /m:2\n\n# In your .NET 10 application:\ndotnet add package SearchSdk --version 0.1.0-alpha.1 --source /absolute/path/searchSDK/.local/nuget",
      "url": "https://searchsdk.dev/docs/sdks/dotnet#install"
    },
    {
      "id": "sdks/dotnet/first-search/2",
      "title": "Program.cs",
      "description": "searchSDK for C# / .NET: Make a server-side search. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "csharp",
      "code": "using SearchSdk;\n\nvar key = Environment.GetEnvironmentVariable(\"EXA_API_KEY\")\n    ?? throw new InvalidOperationException(\"EXA_API_KEY is required\");\nusing var transport = new SearchTransport(new() {\n    Timeout = TimeSpan.FromSeconds(10)\n});\nvar search = new SearchClient(new NormalizedProvider(\"exa\", key, transport));\nvar response = await search.SearchAsync(\n    new SearchRequest(\"SQLite write concurrency\", Limit: 3),\n    CancellationToken.None);\nforeach (var result in response.Results)\n    Console.WriteLine(result.Url);",
      "url": "https://searchsdk.dev/docs/sdks/dotnet#first-search"
    },
    {
      "id": "sdks/dotnet/verify/1",
      "title": "Repository checkout · local checks",
      "description": "searchSDK for C# / .NET: Verify without provider keys. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "bash",
      "code": "packages/dotnet/scripts/verify.sh",
      "url": "https://searchsdk.dev/docs/sdks/dotnet#verify"
    },
    {
      "id": "sdks/c/install/2",
      "title": "Get the source",
      "description": "searchSDK for C: Install from source. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "bash",
      "code": "git clone https://github.com/Belweave/searchSDK.git\ncd searchSDK\n# Record this revision with your application's dependency lock.\ngit rev-parse HEAD",
      "url": "https://searchsdk.dev/docs/sdks/c#install"
    },
    {
      "id": "sdks/c/install/3",
      "title": "Build or install the local package",
      "description": "searchSDK for C: Install from source. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "bash",
      "code": "cmake -S packages/c -B .local/c-build -DCMAKE_BUILD_TYPE=Release -DSEARCHSDK_TESTS=OFF\ncmake --build .local/c-build --parallel 2\ncmake --install .local/c-build --prefix \"$PWD/.local/c-install\"",
      "url": "https://searchsdk.dev/docs/sdks/c#install"
    },
    {
      "id": "sdks/c/first-search/2",
      "title": "search.c",
      "description": "searchSDK for C: Make a server-side search. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "c",
      "code": "#include <searchsdk/searchsdk.h>\n#include <searchsdk/curl.h>\n\n/* Call after curl_global_init; caller supplies a server-held key. */\nssk_code search_example(const char *key) {\n    ssk_config config;\n    ssk_config_init(&config);\n    config.provider = \"exa\";\n    config.transport = ssk_curl_transport;\n    ssk_client *client = NULL;\n    ssk_error *error = NULL;\n    ssk_response *response = NULL;\n    ssk_code code = ssk_client_new(&config, &client, &error);\n    if (code == SSK_OK) {\n        ssk_call_options call;\n        ssk_call_options_init(&call);\n        call.credential = key;\n        code = ssk_search(client,\n            \"{\\\"query\\\":\\\"SQLite write concurrency\\\",\\\"limit\\\":3}\",\n            &call, &response, &error);\n        /* On success, consume ssk_response_json(response) here. */\n    }\n    ssk_response_free(response);\n    ssk_error_free(error);\n    ssk_client_free(client);\n    return code;\n}",
      "url": "https://searchsdk.dev/docs/sdks/c#first-search"
    },
    {
      "id": "sdks/c/verify/1",
      "title": "Repository checkout · local checks",
      "description": "searchSDK for C: Verify without provider keys. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "bash",
      "code": "sh packages/c/scripts/verify-package.sh",
      "url": "https://searchsdk.dev/docs/sdks/c#verify"
    },
    {
      "id": "sdks/cpp/install/2",
      "title": "Get the source",
      "description": "searchSDK for C++: Install from source. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "bash",
      "code": "git clone https://github.com/Belweave/searchSDK.git\ncd searchSDK\n# Record this revision with your application's dependency lock.\ngit rev-parse HEAD",
      "url": "https://searchsdk.dev/docs/sdks/cpp#install"
    },
    {
      "id": "sdks/cpp/install/3",
      "title": "Build or install the local package",
      "description": "searchSDK for C++: Install from source. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "bash",
      "code": "cmake -S packages/cpp -B .local/cpp-build -DCMAKE_BUILD_TYPE=Release -DSEARCHSDK_CPP_CURL=ON\ncmake --build .local/cpp-build --parallel 2\ncmake --install .local/cpp-build --prefix \"$PWD/.local/cpp-install\"",
      "url": "https://searchsdk.dev/docs/sdks/cpp#install"
    },
    {
      "id": "sdks/cpp/first-search/2",
      "title": "search.cpp",
      "description": "searchSDK for C++: Make a server-side search. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "cpp",
      "code": "#include <searchsdk/searchsdk.hpp>\n#include <searchsdk/curl.hpp>\n#include <iostream>\n\nvoid search_example(const std::string& server_key) {\n    searchsdk::Config config;\n    config.provider = \"exa\";\n    config.transport = searchsdk::curl_transport();\n    searchsdk::Client search(std::move(config));\n    searchsdk::CallOptions call;\n    call.credential = server_key;\n    const auto response = search.search(\n        searchsdk::SearchRequest{\"SQLite write concurrency\", 3}, call);\n    for (const auto& result : response.results)\n        std::cout << result.url << '\\n';\n}",
      "url": "https://searchsdk.dev/docs/sdks/cpp#first-search"
    },
    {
      "id": "sdks/cpp/verify/1",
      "title": "Repository checkout · local checks",
      "description": "searchSDK for C++: Verify without provider keys. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "bash",
      "code": "cmake -S packages/cpp -B .local/cpp-check -DCMAKE_BUILD_TYPE=Release\ncmake --build .local/cpp-check --parallel 2\nctest --test-dir .local/cpp-check --output-on-failure",
      "url": "https://searchsdk.dev/docs/sdks/cpp#verify"
    },
    {
      "id": "sdks/swift/install/2",
      "title": "Get the source",
      "description": "searchSDK for Swift: Install from source. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "bash",
      "code": "git clone https://github.com/Belweave/searchSDK.git\ncd searchSDK\n# Record this revision with your application's dependency lock.\ngit rev-parse HEAD",
      "url": "https://searchsdk.dev/docs/sdks/swift#install"
    },
    {
      "id": "sdks/swift/install/3",
      "title": "Application dependency configuration",
      "description": "searchSDK for Swift: Install from source. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "swift",
      "code": "// In Package.swift, add the local checkout as a dependency:\n.package(name: \"SearchSDK\", path: \"/absolute/path/searchSDK\")\n\n// In your target's dependencies:\n.product(name: \"SearchSDK\", package: \"SearchSDK\")",
      "url": "https://searchsdk.dev/docs/sdks/swift#install"
    },
    {
      "id": "sdks/swift/first-search/2",
      "title": "SearchExample.swift",
      "description": "searchSDK for Swift: Call your application gateway. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "swift",
      "code": "import SearchSDK\n\nfunc searchExample(\n    endpoint: String,\n    applicationToken: @escaping @Sendable () async throws -> String?\n) async throws {\n    let search = try SearchClient(\n        endpoint: endpoint,\n        applicationToken: applicationToken\n    )\n    let response = try await search.search(\n        SearchRequest(query: \"SQLite write concurrency\", limit: 3)\n    )\n    for result in response.results {\n        print(result.url, result.provenance.provider)\n    }\n}",
      "url": "https://searchsdk.dev/docs/sdks/swift#first-search"
    },
    {
      "id": "sdks/swift/verify/1",
      "title": "Repository checkout · local checks",
      "description": "searchSDK for Swift: Verify without provider keys. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "bash",
      "code": "xcodebuild -version\nswift test --package-path packages/swift --scratch-path .local/swift-build --jobs 2\nsh packages/swift/Scripts/verify-consumer.sh .local/swift-consumer",
      "url": "https://searchsdk.dev/docs/sdks/swift#verify"
    },
    {
      "id": "sdks/android/install/2",
      "title": "Get the source",
      "description": "searchSDK for Android / Kotlin: Install from source. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "bash",
      "code": "git clone https://github.com/Belweave/searchSDK.git\ncd searchSDK\n# Record this revision with your application's dependency lock.\ngit rev-parse HEAD",
      "url": "https://searchsdk.dev/docs/sdks/android#install"
    },
    {
      "id": "sdks/android/install/3",
      "title": "Build or install the local package",
      "description": "searchSDK for Android / Kotlin: Install from source. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "bash",
      "code": "cd packages/android\n./gradlew publishReleasePublicationToVerificationRepository --no-daemon --max-workers=2",
      "url": "https://searchsdk.dev/docs/sdks/android#install"
    },
    {
      "id": "sdks/android/first-search/2",
      "title": "SearchExample.kt",
      "description": "searchSDK for Android / Kotlin: Call your application gateway. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "kotlin",
      "code": "import dev.searchsdk.android.SearchClient\nimport dev.searchsdk.android.SearchRequest\n\nsuspend fun searchExample(\n    endpoint: String,\n    applicationToken: suspend () -> String?\n) {\n    val search = SearchClient(endpoint = endpoint, accessToken = applicationToken)\n    try {\n        val response = search.search(\n            SearchRequest(\"SQLite write concurrency\", limit = 3)\n        )\n        for (result in response.results) println(result.url)\n    } finally {\n        search.close()\n    }\n}",
      "url": "https://searchsdk.dev/docs/sdks/android#first-search"
    },
    {
      "id": "sdks/android/verify/1",
      "title": "Repository checkout · local checks",
      "description": "searchSDK for Android / Kotlin: Verify without provider keys. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "bash",
      "code": "cd packages/android\n./gradlew testReleaseUnitTest assembleRelease lintRelease publishReleasePublicationToVerificationRepository --no-daemon --max-workers=2\n./gradlew -p consumer testReleaseUnitTest assembleRelease --no-daemon --max-workers=2",
      "url": "https://searchsdk.dev/docs/sdks/android#verify"
    },
    {
      "id": "sdks/react-native/install/2",
      "title": "Get the source",
      "description": "searchSDK for React Native: Install from source. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "bash",
      "code": "git clone https://github.com/Belweave/searchSDK.git\ncd searchSDK\n# Record this revision with your application's dependency lock.\ngit rev-parse HEAD",
      "url": "https://searchsdk.dev/docs/sdks/react-native#install"
    },
    {
      "id": "sdks/react-native/install/3",
      "title": "Build or install the local package",
      "description": "searchSDK for React Native: Install from source. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "bash",
      "code": "nvm use\nnpm ci\nnpm run build -w @belweave/search-sdk-react-native\nnpm pack -w @belweave/search-sdk-react-native\n\n# In your React Native app:\nnpm install /absolute/path/searchSDK/belweave-search-sdk-react-native-0.1.0-alpha.0.tgz\n# Then install iOS pods and rebuild the native app.",
      "url": "https://searchsdk.dev/docs/sdks/react-native#install"
    },
    {
      "id": "sdks/react-native/first-search/2",
      "title": "search.ts",
      "description": "searchSDK for React Native: Call your application gateway. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "typescript",
      "code": "import { createSearchClient } from '@belweave/search-sdk-react-native';\n\nexport async function searchExample(\n  endpoint: string,\n  accessToken: () => Promise<string>,\n  signal: AbortSignal,\n) {\n  const search = createSearchClient({ endpoint, accessToken, timeoutMs: 10_000 });\n  return search.web.search({\n    query: 'SQLite write concurrency', limit: 3,\n  }, { signal });\n}",
      "url": "https://searchsdk.dev/docs/sdks/react-native#first-search"
    },
    {
      "id": "sdks/react-native/verify/1",
      "title": "Repository checkout · local checks",
      "description": "searchSDK for React Native: Verify without provider keys. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "bash",
      "code": "npm run test:mobile\nnpm run test:package -w @belweave/search-sdk-react-native",
      "url": "https://searchsdk.dev/docs/sdks/react-native#verify"
    },
    {
      "id": "sdks/expo/install/2",
      "title": "Get the source",
      "description": "searchSDK for Expo: Install from source. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "bash",
      "code": "git clone https://github.com/Belweave/searchSDK.git\ncd searchSDK\n# Record this revision with your application's dependency lock.\ngit rev-parse HEAD",
      "url": "https://searchsdk.dev/docs/sdks/expo#install"
    },
    {
      "id": "sdks/expo/install/3",
      "title": "Build or install the local package",
      "description": "searchSDK for Expo: Install from source. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "bash",
      "code": "nvm use\nnpm ci\nnpm run build:mobile\nnpm pack -w @belweave/search-sdk-react-native\nnpm pack -w @belweave/search-sdk-expo\n\n# In your existing Expo 55–57 app, install both local artifacts:\nnpm install /absolute/path/searchSDK/belweave-search-sdk-react-native-0.1.0-alpha.0.tgz /absolute/path/searchSDK/belweave-search-sdk-expo-0.1.0-alpha.0.tgz\n# Rebuild with expo run:ios, expo run:android, or your EAS workflow.",
      "url": "https://searchsdk.dev/docs/sdks/expo#install"
    },
    {
      "id": "sdks/expo/first-search/2",
      "title": "search.ts",
      "description": "searchSDK for Expo: Call your application gateway. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "typescript",
      "code": "import { createExpoSearchClient } from '@belweave/search-sdk-expo';\n\nexport async function searchExample(\n  endpoint: string,\n  accessToken: () => Promise<string>,\n  signal: AbortSignal,\n) {\n  const search = createExpoSearchClient({ endpoint, accessToken, timeoutMs: 10_000 });\n  return search.web.search({\n    query: 'SQLite write concurrency', limit: 3,\n  }, { signal });\n}",
      "url": "https://searchsdk.dev/docs/sdks/expo#first-search"
    },
    {
      "id": "sdks/expo/verify/1",
      "title": "Repository checkout · local checks",
      "description": "searchSDK for Expo: Verify without provider keys. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "bash",
      "code": "npm run test:mobile && npm run test:mobile:package",
      "url": "https://searchsdk.dev/docs/sdks/expo#verify"
    },
    {
      "id": "guides/domain-filters/request-hostnames/2",
      "title": "filter.ts · fixture",
      "description": "Filter by domain: Request hostnames. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "typescript",
      "code": "import { createSearch } from '@belweave/search-sdk';\nimport { createMockProvider } from '@belweave/search-sdk/testing';\n\nconst client = createSearch({ provider: createMockProvider() });\nconst response = await client.web.search({\n  query: 'search API reference',\n  limit: 3,\n  includeDomains: ['example.org'],\n  excludeDomains: ['excluded.example.org'],\n});\n\nconsole.log(response.results); // Mock hostname filtering; no live search",
      "url": "https://searchsdk.dev/docs/guides/domain-filters#request-hostnames"
    },
    {
      "id": "guides/results/render-text/3",
      "title": "result.tsx · React",
      "description": "Work with results: Render provider text as text. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "typescript",
      "code": "import type { SearchResult } from '@belweave/search-sdk';\n\nexport function Source({ result }: { result: SearchResult }) {\n  return (\n    <article>\n      <a href={result.url} rel=\"noreferrer\" target=\"_blank\">\n        {result.title ?? result.url}\n      </a>\n      {result.snippet && <p>{result.snippet}</p>}\n      <small>{result.provenance.provider}</small>\n    </article>\n  );\n}",
      "url": "https://searchsdk.dev/docs/guides/results#render-text"
    },
    {
      "id": "guides/server-integration/reuse-client/2",
      "title": "search-service.ts · server",
      "description": "Integrate on a server: Configure once, call per request. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "typescript",
      "code": "import { createSearch } from '@belweave/search-sdk';\nimport { context } from '@belweave/search-sdk/context';\n\nconst apiKey = process.env.CONTEXT_API_KEY;\nif (!apiKey) throw new Error('CONTEXT_API_KEY is required');\n\nconst client = createSearch({\n  provider: context({ apiKey }),\n  timeoutMs: 10_000,\n});\n\nconst response = await client.web.search({\n  query: 'SQLite write concurrency',\n  limit: 5,\n});\n\nfor (const result of response.results) {\n  console.log(result.title ?? result.url, result.url);\n}\nconsole.log(response.provider, response.attempts);",
      "url": "https://searchsdk.dev/docs/guides/server-integration#reuse-client"
    },
    {
      "id": "guides/testing/fallback-fixture/2",
      "title": "fallback.test.ts · Node",
      "description": "Test without API keys: Assert fallback behavior. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "typescript",
      "code": "import assert from 'node:assert/strict';\nimport { createSearch } from '@belweave/search-sdk';\nimport { createMockProvider } from '@belweave/search-sdk/testing';\n\nconst primary = createMockProvider({\n  id: 'primary',\n  outcomes: [{ type: 'error', code: 'rate_limit', retryAfterMs: 2_000 }],\n});\nconst backup = createMockProvider({ id: 'backup' });\nconst client = createSearch({ provider: primary, fallback: [backup] });\nconst response = await client.web.search({ query: 'search interfaces' });\n\nassert.equal(response.provider, 'backup');\nassert.equal(response.attempts.length, 2);\nassert.equal(response.warnings[0]?.code, 'fallback_used');\nassert.equal(primary.calls.length, 1);\nassert.equal(backup.calls.length, 1);",
      "url": "https://searchsdk.dev/docs/guides/testing#fallback-fixture"
    },
    {
      "id": "guides/application-gateway/server/2",
      "title": "search-gateway.ts · server",
      "description": "Connect an app to search: Create the server handler. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "typescript",
      "code": "import { createSearch } from '@belweave/search-sdk';\nimport { createSearchGateway } from '@belweave/search-sdk/gateway';\nimport { exa } from '@belweave/search-sdk/exa';\n\nexport function makeSearchHandler(\n  providerKey: string,\n  authorizeApplication: (authorization: string | null, signal: AbortSignal) => Promise<boolean>,\n) {\n  return createSearchGateway({\n    search: createSearch({ provider: exa({ apiKey: providerKey }) }),\n    authorize: ({ headers, signal }) =>\n      authorizeApplication(headers.get('authorization'), signal),\n    allowedOrigins: ['https://app.example.com'],\n    timeoutMs: 10_000,\n    maxConcurrency: 32,\n  });\n}",
      "url": "https://searchsdk.dev/docs/guides/application-gateway#server"
    },
    {
      "id": "guides/application-gateway/wire/1",
      "title": "POST body · protocol v1",
      "description": "Connect an app to search: The gateway contract. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "json",
      "code": "{\n  \"query\": \"SQLite write concurrency\",\n  \"limit\": 3,\n  \"includeDomains\": [\"sqlite.org\"]\n}",
      "url": "https://searchsdk.dev/docs/guides/application-gateway#wire"
    },
    {
      "id": "guides/boat/open-a-sandbox/2",
      "title": "Your computer · Boat CLI",
      "description": "Run searchSDK in Boat: 1. Open your sandbox. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "bash",
      "code": "boat status --check\nboat new --type small --ttl 1800 --no-env\n\n# Use the ID printed by boat new:\nboat info YOUR_SANDBOX_ID\nboat ssh YOUR_SANDBOX_ID",
      "url": "https://searchsdk.dev/docs/guides/boat#open-a-sandbox"
    },
    {
      "id": "guides/boat/prepare-node/1",
      "title": "Inside the sandbox · check Node",
      "description": "Run searchSDK in Boat: 2. Check Node inside the sandbox. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "bash",
      "code": "node --version\nnpm --version",
      "url": "https://searchsdk.dev/docs/guides/boat#prepare-node"
    },
    {
      "id": "guides/boat/build-the-alpha/2",
      "title": "Inside the sandbox · Bash",
      "description": "Run searchSDK in Boat: 3. Install searchSDK. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "bash",
      "code": "git clone https://github.com/Belweave/searchSDK.git\ncd searchSDK\ngit rev-parse HEAD\nnpm ci\nnpm run build:sdk\nnpm pack -w @belweave/search-sdk\ncd ..\nmkdir searchsdk-boat\ncd searchsdk-boat\nnpm init --yes\nnpm install ../searchSDK/belweave-search-sdk-0.1.0-alpha.0.tgz",
      "url": "https://searchsdk.dev/docs/guides/boat#build-the-alpha"
    },
    {
      "id": "guides/boat/run-the-fixture/2",
      "title": "Inside the sandbox · download for review",
      "description": "Run searchSDK in Boat: 4. Inspect and run the recipe. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "bash",
      "code": "curl --fail --location --show-error https://searchsdk.dev/recipes/boat/search.mjs -o search.mjs\ncat search.mjs",
      "url": "https://searchsdk.dev/docs/guides/boat#run-the-fixture"
    },
    {
      "id": "guides/boat/run-the-fixture/3",
      "title": "Inside the sandbox · run after review",
      "description": "Run searchSDK in Boat: 4. Inspect and run the recipe. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "bash",
      "code": "node search.mjs",
      "url": "https://searchsdk.dev/docs/guides/boat#run-the-fixture"
    },
    {
      "id": "guides/boat/run-the-fixture/6",
      "title": "boat-fixture.ts · fixture",
      "description": "Run searchSDK in Boat: 4. Inspect and run the recipe. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "typescript",
      "code": "import { createSearch } from '@belweave/search-sdk';\nimport { createMockProvider } from '@belweave/search-sdk/testing';\n\nconst client = createSearch({\n  provider: createMockProvider(),\n  timeoutMs: 10_000,\n  attemptTimeoutMs: 8_000,\n  retry: { maxRetries: 0 },\n});\nconst response = await client.web.search({ query: 'SQLite write concurrency', limit: 3 });\nconsole.log(response.provider, response.results, response.attempts);",
      "url": "https://searchsdk.dev/docs/guides/boat#run-the-fixture"
    },
    {
      "id": "guides/boat/optional-live-search/2",
      "title": "Inside the sandbox · Bash · live opt-in",
      "description": "Run searchSDK in Boat: 5. Optional: one live search. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "bash",
      "code": "(\n  set +x\n  ulimit -c 0\n  read -r -s -p 'Context.dev API key (hidden): ' CONTEXT_API_KEY\n  printf '\\n'\n  export CONTEXT_API_KEY\n  node search.mjs --live\n)",
      "url": "https://searchsdk.dev/docs/guides/boat#optional-live-search"
    },
    {
      "id": "guides/boat/finish-and-clean-up/2",
      "title": "Your computer · delete the disposable sandbox",
      "description": "Run searchSDK in Boat: 6. Finish and clean up. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "bash",
      "code": "# Leave the sandbox SSH shell:\nexit\n\n# On your computer, use your recorded ID:\nboat delete YOUR_SANDBOX_ID",
      "url": "https://searchsdk.dev/docs/guides/boat#finish-and-clean-up"
    },
    {
      "id": "guides/mcp/connect/3",
      "title": "Discover the server · terminal",
      "description": "Use the documentation MCP server: Connect to the public endpoint. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "bash",
      "code": "curl --fail-with-body https://searchsdk.dev/mcp \\\n  -H 'Content-Type: application/json' \\\n  -H 'Accept: application/json, text/event-stream' \\\n  -H 'MCP-Protocol-Version: 2026-07-28' \\\n  -H 'Mcp-Method: server/discover' \\\n  --data '{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"server/discover\",\"params\":{\"_meta\":{\"io.modelcontextprotocol/protocolVersion\":\"2026-07-28\",\"io.modelcontextprotocol/clientInfo\":{\"name\":\"docs-reader\",\"version\":\"1.0.0\"},\"io.modelcontextprotocol/clientCapabilities\":{}}}}'",
      "url": "https://searchsdk.dev/docs/guides/mcp#connect"
    },
    {
      "id": "guides/mcp/tools/3",
      "title": "mcp-docs.ts · read public data",
      "description": "Use the documentation MCP server: Documentation, providers, and examples. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "typescript",
      "code": "const endpoint = 'https://searchsdk.dev/mcp';\nconst metadata = {\n  'io.modelcontextprotocol/protocolVersion': '2026-07-28',\n  'io.modelcontextprotocol/clientInfo': { name: 'docs-reader', version: '1.0.0' },\n  'io.modelcontextprotocol/clientCapabilities': {},\n};\nlet requestId = 0;\nasync function rpc(method: string, params: Record<string, unknown> = {}) {\n  const name = method === 'tools/call' ? params.name\n    : method === 'resources/read' ? params.uri : undefined;\n  const headers = new Headers({\n    'Content-Type': 'application/json',\n    Accept: 'application/json, text/event-stream',\n    'MCP-Protocol-Version': '2026-07-28',\n    'Mcp-Method': method,\n  });\n  if (typeof name === 'string') headers.set('Mcp-Name', name);\n  const response = await fetch(endpoint, {\n    method: 'POST', headers, credentials: 'omit', signal: AbortSignal.timeout(10_000),\n    body: JSON.stringify({ jsonrpc: '2.0', id: ++requestId, method,\n      params: { ...params, _meta: metadata } }),\n  });\n  // This endpoint returns JSON. Other MCP servers can return an SSE stream.\n  const message = await response.json();\n  if (!response.ok || message.error) throw new Error('MCP request failed');\n  return message.result;\n}\n\nconsole.log(await rpc('server/discover'));\nconsole.log(await rpc('tools/list'));\nconsole.log(await rpc('tools/call', {\n  name: 'search_docs', arguments: { query: 'fallback cancellation', limit: 3 },\n}));\nconsole.log(await rpc('tools/call', {\n  name: 'get_doc', arguments: { slug: 'quickstart' },\n}));\nconsole.log(await rpc('tools/call', { name: 'list_providers', arguments: {} }));\nconsole.log(await rpc('tools/call', {\n  name: 'get_provider', arguments: { id: 'context' },\n}));\nconsole.log(await rpc('tools/call', { name: 'list_examples', arguments: {} }));\n// Pass a returned example ID to get_example; do not infer an ID or execute it.\nexport {};",
      "url": "https://searchsdk.dev/docs/guides/mcp#tools"
    },
    {
      "id": "guides/mcp/resources/2",
      "title": "Resource request · params",
      "description": "Use the documentation MCP server: Read exact resources. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "json",
      "code": "{\n  \"uri\": \"searchsdk://docs/reliability%2Ffallback\",\n  \"_meta\": {\n    \"io.modelcontextprotocol/protocolVersion\": \"2026-07-28\",\n    \"io.modelcontextprotocol/clientInfo\": { \"name\": \"docs-reader\", \"version\": \"1.0.0\" },\n    \"io.modelcontextprotocol/clientCapabilities\": {}\n  }\n}",
      "url": "https://searchsdk.dev/docs/guides/mcp#resources"
    },
    {
      "id": "guides/streaming/events/2",
      "title": "consume.ts · shared stream consumer",
      "description": "Consume native streams: Events are native data. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "typescript",
      "code": "import type { NativeSSEEvent } from '@belweave/search-sdk';\n\nexport async function consume(events: AsyncIterable<NativeSSEEvent>) {\n  for await (const event of events) {\n    console.log(event.event, event.id, event.data);\n    // Interpret data and terminal/error events using the provider contract.\n    // Do not assume every event is JSON or that HTTP 200 means job success.\n  }\n}",
      "url": "https://searchsdk.dev/docs/guides/streaming#events"
    },
    {
      "id": "guides/durable-operations/lifecycle/3",
      "title": "durable.ts · fixture",
      "description": "Resume durable operations: Persist intent, then the remote ID. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "typescript",
      "code": "import {\n  createMemoryCheckpointStore, runDurableOperation,\n} from '@belweave/search-sdk/durable';\n\nconst store = createMemoryCheckpointStore(); // Tests only; not disk persistence\nconst options = {\n  key: 'example-job',\n  operation: 'example.fixture',\n  inputFingerprint: 'fixture-v1',\n  store,\n  submit: async () => ({ remoteId: 'fixture-job-1' }),\n  poll: async () => ({ state: 'completed' as const, value: { ok: true } }),\n};\nconst first = await runDurableOperation(options);\nconst resumed = await runDurableOperation(options);\nconsole.log(first.value, resumed.resumed); // { ok: true }, true\n",
      "url": "https://searchsdk.dev/docs/guides/durable-operations#lifecycle"
    },
    {
      "id": "api/create-search/signature/2",
      "title": "TypeScript",
      "description": "createSearch: Signature. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "typescript",
      "code": "import { createSearch } from '@belweave/search-sdk';\nimport type { SearchConfig } from '@belweave/search-sdk';\n\n// createSearch(config: SearchConfig)\n// → { web: { search(request, options?), searchBatch(requests, options?) } }",
      "url": "https://searchsdk.dev/docs/api/create-search#signature"
    },
    {
      "id": "api/create-search/example/1",
      "title": "client.ts · server",
      "description": "createSearch: Example. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "typescript",
      "code": "import { createSearch } from '@belweave/search-sdk';\nimport { context } from '@belweave/search-sdk/context';\nimport { tinyfish } from '@belweave/search-sdk/tinyfish';\n\nconst contextKey = process.env.CONTEXT_API_KEY;\nconst tinyfishKey = process.env.TINYFISH_API_KEY;\nif (!contextKey || !tinyfishKey) throw new Error('Missing server credentials');\n\nconst client = createSearch({\n  provider: context({ apiKey: contextKey }),\n  fallback: [tinyfish({ apiKey: tinyfishKey })],\n  timeoutMs: 10_000,\n  attemptTimeoutMs: 4_000,\n});\n\nconst response = await client.web.search({ query: 'SQLite write concurrency' });\nconsole.log(response.provider, response.attempts, response.warnings);",
      "url": "https://searchsdk.dev/docs/api/create-search#example"
    },
    {
      "id": "api/search/options/1",
      "title": "TypeScript",
      "description": "web.search: Call options. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "typescript",
      "code": "const controller = new AbortController();\n// client is a configured createSearch() client.\nconst response = await client.web.search(\n  { query: 'SQLite write concurrency', limit: 5 },\n  { signal: controller.signal },\n);",
      "url": "https://searchsdk.dev/docs/api/search#options"
    },
    {
      "id": "api/search-batch/example/3",
      "title": "batch-search.ts · fixture",
      "description": "web.searchBatch: Run independent queries. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "typescript",
      "code": "import { createSearch } from '@belweave/search-sdk';\nimport { createMockProvider } from '@belweave/search-sdk/testing';\n\nconst client = createSearch({ provider: createMockProvider() });\nconst outcomes = await client.web.searchBatch(\n  [\n    { query: 'SQLite WAL', limit: 3 },\n    { query: 'SQLite transactions', limit: 3 },\n  ],\n  { concurrency: 2, timeoutMs: 10_000 },\n);\n\nfor (const outcome of outcomes) {\n  if (outcome.status === 'fulfilled') {\n    console.log(outcome.index, outcome.value.results);\n  } else {\n    console.log(outcome.index, outcome.error.code);\n  }\n}",
      "url": "https://searchsdk.dev/docs/api/search-batch#example"
    },
    {
      "id": "api/response/shape/2",
      "title": "TypeScript · shape",
      "description": "SearchResponse: Response fields. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "typescript",
      "code": "interface SearchResponse {\n  provider: string;\n  results: readonly SearchResult[];\n  attempts: readonly SearchAttempt[];\n  warnings: readonly {\n    code: 'fallback_used' | 'provider_warning';\n    provider: string;\n  }[];\n  usage: { unit: 'usd' | 'credits'; value: number } | null;\n  reuse?: 'cache' | 'inflight';\n}",
      "url": "https://searchsdk.dev/docs/api/response#shape"
    },
    {
      "id": "api/providers/interface/2",
      "title": "TypeScript · abbreviated",
      "description": "SearchProvider: Interface. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "typescript",
      "code": "import type {\n  ProviderResponse, ValidatedSearchRequest,\n} from '@belweave/search-sdk';\n\ninterface SearchProvider {\n  readonly id: string;\n  readonly capabilities: {\n    readonly domainFilters: boolean;\n    readonly mutuallyExclusiveDomainFilters?: boolean;\n    readonly maxIncludeDomains: number;\n    readonly maxExcludeDomains: number;\n    readonly maxQueryLength?: number;\n  };\n  search(\n    request: ValidatedSearchRequest,\n    options: { signal: AbortSignal },\n  ): Promise<ProviderResponse>;\n}",
      "url": "https://searchsdk.dev/docs/api/providers#interface"
    },
    {
      "id": "api/errors/handling/2",
      "title": "errors.ts · fixture",
      "description": "SearchError: Handle by code. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "typescript",
      "code": "import { createSearch, SearchError } from '@belweave/search-sdk';\nimport { createMockProvider } from '@belweave/search-sdk/testing';\n\nconst client = createSearch({ provider: createMockProvider({\n  outcomes: [{ type: 'error', code: 'rate_limit', retryAfterMs: 2_000 }],\n}) });\n\ntry {\n  await client.web.search({ query: 'SQLite concurrency' });\n} catch (error) {\n  if (!(error instanceof SearchError)) throw error;\n  console.log(error.code, error.status, error.retryAfterMs);\n  console.log(error.attempts); // Fixed codes and timing, no raw error bodies\n}",
      "url": "https://searchsdk.dev/docs/api/errors#handling"
    },
    {
      "id": "api/native-transport/choose-client/3",
      "title": "native-search.ts · server",
      "description": "Provider-native transport: Start with a provider client. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "typescript",
      "code": "import { createContextClient } from '@belweave/search-sdk/native-context';\n\nconst apiKey = process.env.CONTEXT_API_KEY;\nif (!apiKey) throw new Error('CONTEXT_API_KEY is required');\n\nconst client = createContextClient({ apiKey, maxConcurrency: 4 });\nconst response = await client.search({\n  body: { query: 'SQLite write concurrency', numResults: 10 },\n  timeoutMs: 8_000,\n});\nconsole.log(response.data.results);\nconsole.log(response.metadata.status, response.metadata.attempts);",
      "url": "https://searchsdk.dev/docs/api/native-transport#choose-client"
    },
    {
      "id": "api/native-transport/response/1",
      "title": "TypeScript · shape",
      "description": "Provider-native transport: Data and metadata. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "typescript",
      "code": "interface NativeResponse<T> {\n  data: T;\n  metadata: {\n    provider: string;\n    operation: string;\n    status: number;\n    requestId?: string;\n    attempts: readonly {\n      attempt: number;\n      durationMs: number;\n      outcome: 'success' | 'error';\n      status?: number;\n      code?: string;\n    }[];\n  };\n}",
      "url": "https://searchsdk.dev/docs/api/native-transport#response"
    },
    {
      "id": "providers/context/overview/3",
      "title": "context-search.ts · server",
      "description": "Context.dev: Normalized search. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "typescript",
      "code": "import { createSearch } from '@belweave/search-sdk';\nimport { context } from '@belweave/search-sdk/context';\n\nconst apiKey = process.env.CONTEXT_API_KEY;\nif (!apiKey) throw new Error('CONTEXT_API_KEY is required');\n\nconst client = createSearch({ provider: context({ apiKey }) });\nconst response = await client.web.search({\n  query: 'SQLite write concurrency',\n  limit: 5,\n});\nconsole.log(response.results, response.attempts);",
      "url": "https://searchsdk.dev/docs/providers/context#overview"
    },
    {
      "id": "providers/context/native-client/1",
      "title": "context-native.ts · server",
      "description": "Context.dev: Provider-native client. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "typescript",
      "code": "import { createContextClient } from '@belweave/search-sdk/native-context';\n\nconst apiKey = process.env.CONTEXT_API_KEY;\nif (!apiKey) throw new Error('CONTEXT_API_KEY is required');\n\nconst client = createContextClient({ apiKey, timeoutMs: 10_000 });\nconst response = await client.search({ body: { query: 'SQLite write concurrency', numResults: 10 } });\nconsole.log(response.data, response.metadata);",
      "url": "https://searchsdk.dev/docs/providers/context#native-client"
    },
    {
      "id": "providers/tinyfish/overview/3",
      "title": "tinyfish-search.ts · server",
      "description": "TinyFish: Normalized search. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "typescript",
      "code": "import { createSearch } from '@belweave/search-sdk';\nimport { tinyfish } from '@belweave/search-sdk/tinyfish';\n\nconst apiKey = process.env.TINYFISH_API_KEY;\nif (!apiKey) throw new Error('TINYFISH_API_KEY is required');\n\nconst client = createSearch({ provider: tinyfish({ apiKey }) });\nconst response = await client.web.search({\n  query: 'SQLite write concurrency',\n  limit: 5,\n});\nconsole.log(response.results, response.attempts);",
      "url": "https://searchsdk.dev/docs/providers/tinyfish#overview"
    },
    {
      "id": "providers/tinyfish/native-client/1",
      "title": "tinyfish-native.ts · server",
      "description": "TinyFish: Provider-native client. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "typescript",
      "code": "import { createTinyfishClient } from '@belweave/search-sdk/native-tinyfish';\n\nconst apiKey = process.env.TINYFISH_API_KEY;\nif (!apiKey) throw new Error('TINYFISH_API_KEY is required');\n\nconst client = createTinyfishClient({ apiKey, timeoutMs: 10_000 });\nconst response = await client.search({ query: { query: 'SQLite write concurrency', domain_type: 'web', page: 0 } });\nconsole.log(response.data, response.metadata);",
      "url": "https://searchsdk.dev/docs/providers/tinyfish#native-client"
    },
    {
      "id": "providers/exa/overview/3",
      "title": "exa-search.ts · server",
      "description": "Exa: Normalized search. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "typescript",
      "code": "import { createSearch } from '@belweave/search-sdk';\nimport { exa } from '@belweave/search-sdk/exa';\n\nconst apiKey = process.env.EXA_API_KEY;\nif (!apiKey) throw new Error('EXA_API_KEY is required');\n\nconst client = createSearch({ provider: exa({ apiKey }) });\nconst response = await client.web.search({\n  query: 'SQLite write concurrency',\n  limit: 5,\n});\nconsole.log(response.results, response.attempts);",
      "url": "https://searchsdk.dev/docs/providers/exa#overview"
    },
    {
      "id": "providers/exa/native-client/1",
      "title": "exa-native.ts · server",
      "description": "Exa: Provider-native client. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "typescript",
      "code": "import { createExaClient } from '@belweave/search-sdk/native-exa';\n\nconst apiKey = process.env.EXA_API_KEY;\nif (!apiKey) throw new Error('EXA_API_KEY is required');\n\nconst client = createExaClient({ apiKey, timeoutMs: 10_000 });\nconst response = await client.search({ body: { query: 'SQLite write concurrency', type: 'auto', numResults: 5 } });\nconsole.log(response.data, response.metadata);",
      "url": "https://searchsdk.dev/docs/providers/exa#native-client"
    },
    {
      "id": "providers/tavily/overview/3",
      "title": "tavily-search.ts · server",
      "description": "Tavily: Normalized search. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "typescript",
      "code": "import { createSearch } from '@belweave/search-sdk';\nimport { tavily } from '@belweave/search-sdk/tavily';\n\nconst apiKey = process.env.TAVILY_API_KEY;\nif (!apiKey) throw new Error('TAVILY_API_KEY is required');\n\nconst client = createSearch({ provider: tavily({ apiKey }) });\nconst response = await client.web.search({\n  query: 'SQLite write concurrency',\n  limit: 5,\n});\nconsole.log(response.results, response.attempts);",
      "url": "https://searchsdk.dev/docs/providers/tavily#overview"
    },
    {
      "id": "providers/tavily/native-client/1",
      "title": "tavily-native.ts · server",
      "description": "Tavily: Provider-native client. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "typescript",
      "code": "import { createTavilyClient } from '@belweave/search-sdk/native-tavily';\n\nconst apiKey = process.env.TAVILY_API_KEY;\nif (!apiKey) throw new Error('TAVILY_API_KEY is required');\n\nconst client = createTavilyClient({ apiKey, timeoutMs: 10_000 });\nconst response = await client.search({ body: { query: 'SQLite write concurrency', search_depth: 'basic', max_results: 5 } });\nconsole.log(response.data, response.metadata);",
      "url": "https://searchsdk.dev/docs/providers/tavily#native-client"
    },
    {
      "id": "providers/brave/overview/3",
      "title": "brave-search.ts · server",
      "description": "Brave: Normalized search. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "typescript",
      "code": "import { createSearch } from '@belweave/search-sdk';\nimport { brave } from '@belweave/search-sdk/brave';\n\nconst apiKey = process.env.BRAVE_API_KEY;\nif (!apiKey) throw new Error('BRAVE_API_KEY is required');\n\nconst client = createSearch({ provider: brave({ apiKey }) });\nconst response = await client.web.search({\n  query: 'SQLite write concurrency',\n  limit: 5,\n});\nconsole.log(response.results, response.attempts);",
      "url": "https://searchsdk.dev/docs/providers/brave#overview"
    },
    {
      "id": "providers/brave/native-client/1",
      "title": "brave-native.ts · server",
      "description": "Brave: Provider-native client. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "typescript",
      "code": "import { createBraveClient } from '@belweave/search-sdk/native-brave';\n\nconst apiKey = process.env.BRAVE_API_KEY;\nif (!apiKey) throw new Error('BRAVE_API_KEY is required');\n\nconst client = createBraveClient({ apiKey, timeoutMs: 10_000 });\nconst response = await client.search({ query: { q: 'SQLite write concurrency', count: 5 } });\nconsole.log(response.data, response.metadata);",
      "url": "https://searchsdk.dev/docs/providers/brave#native-client"
    },
    {
      "id": "providers/perplexity/overview/3",
      "title": "perplexity-search.ts · server",
      "description": "Perplexity: Normalized search. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "typescript",
      "code": "import { createSearch } from '@belweave/search-sdk';\nimport { perplexity } from '@belweave/search-sdk/perplexity';\n\nconst apiKey = process.env.PERPLEXITY_API_KEY;\nif (!apiKey) throw new Error('PERPLEXITY_API_KEY is required');\n\nconst client = createSearch({ provider: perplexity({ apiKey }) });\nconst response = await client.web.search({\n  query: 'SQLite write concurrency',\n  limit: 5,\n});\nconsole.log(response.results, response.attempts);",
      "url": "https://searchsdk.dev/docs/providers/perplexity#overview"
    },
    {
      "id": "providers/perplexity/native-client/1",
      "title": "perplexity-native.ts · server",
      "description": "Perplexity: Provider-native client. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "typescript",
      "code": "import { createPerplexityClient } from '@belweave/search-sdk/native-perplexity';\n\nconst apiKey = process.env.PERPLEXITY_API_KEY;\nif (!apiKey) throw new Error('PERPLEXITY_API_KEY is required');\n\nconst client = createPerplexityClient({ apiKey, timeoutMs: 10_000 });\nconst response = await client.search({ body: { query: 'SQLite write concurrency', max_results: 5 } });\nconsole.log(response.data, response.metadata);",
      "url": "https://searchsdk.dev/docs/providers/perplexity#native-client"
    },
    {
      "id": "providers/parallel/overview/3",
      "title": "parallel-search.ts · server",
      "description": "Parallel: Normalized search. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "typescript",
      "code": "import { createSearch } from '@belweave/search-sdk';\nimport { parallel } from '@belweave/search-sdk/parallel';\n\nconst apiKey = process.env.PARALLEL_API_KEY;\nif (!apiKey) throw new Error('PARALLEL_API_KEY is required');\n\nconst client = createSearch({ provider: parallel({ apiKey }) });\nconst response = await client.web.search({\n  query: 'SQLite write concurrency',\n  limit: 5,\n});\nconsole.log(response.results, response.attempts);",
      "url": "https://searchsdk.dev/docs/providers/parallel#overview"
    },
    {
      "id": "providers/parallel/native-client/1",
      "title": "parallel-native.ts · server",
      "description": "Parallel: Provider-native client. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "typescript",
      "code": "import { createParallelClient } from '@belweave/search-sdk/native-parallel';\n\nconst apiKey = process.env.PARALLEL_API_KEY;\nif (!apiKey) throw new Error('PARALLEL_API_KEY is required');\n\nconst client = createParallelClient({ apiKey, timeoutMs: 10_000 });\nconst response = await client.search({ body: { search_queries: ['SQLite write concurrency'], mode: 'basic' } });\nconsole.log(response.data, response.metadata);",
      "url": "https://searchsdk.dev/docs/providers/parallel#native-client"
    },
    {
      "id": "providers/linkup/overview/3",
      "title": "linkup-search.ts · server",
      "description": "Linkup: Normalized search. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "typescript",
      "code": "import { createSearch } from '@belweave/search-sdk';\nimport { linkup } from '@belweave/search-sdk/linkup';\n\nconst apiKey = process.env.LINKUP_API_KEY;\nif (!apiKey) throw new Error('LINKUP_API_KEY is required');\n\nconst client = createSearch({ provider: linkup({ apiKey }) });\nconst response = await client.web.search({\n  query: 'SQLite write concurrency',\n  limit: 5,\n});\nconsole.log(response.results, response.attempts);",
      "url": "https://searchsdk.dev/docs/providers/linkup#overview"
    },
    {
      "id": "providers/linkup/native-client/1",
      "title": "linkup-native.ts · server",
      "description": "Linkup: Provider-native client. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "typescript",
      "code": "import { createLinkupClient } from '@belweave/search-sdk/native-linkup';\n\nconst apiKey = process.env.LINKUP_API_KEY;\nif (!apiKey) throw new Error('LINKUP_API_KEY is required');\n\nconst client = createLinkupClient({ apiKey, timeoutMs: 10_000 });\nconst response = await client.search({ body: { q: 'SQLite write concurrency', depth: 'fast', outputType: 'searchResults' } });\nconsole.log(response.data, response.metadata);",
      "url": "https://searchsdk.dev/docs/providers/linkup#native-client"
    },
    {
      "id": "providers/firecrawl/overview/3",
      "title": "firecrawl-search.ts · server",
      "description": "Firecrawl: Normalized search. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "typescript",
      "code": "import { createSearch } from '@belweave/search-sdk';\nimport { firecrawl } from '@belweave/search-sdk/firecrawl';\n\nconst apiKey = process.env.FIRECRAWL_API_KEY;\nif (!apiKey) throw new Error('FIRECRAWL_API_KEY is required');\n\nconst client = createSearch({ provider: firecrawl({ apiKey }) });\nconst response = await client.web.search({\n  query: 'SQLite write concurrency',\n  limit: 5,\n});\nconsole.log(response.results, response.attempts);",
      "url": "https://searchsdk.dev/docs/providers/firecrawl#overview"
    },
    {
      "id": "providers/firecrawl/native-client/1",
      "title": "firecrawl-native.ts · server",
      "description": "Firecrawl: Provider-native client. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "typescript",
      "code": "import { createFirecrawlClient } from '@belweave/search-sdk/native-firecrawl';\n\nconst apiKey = process.env.FIRECRAWL_API_KEY;\nif (!apiKey) throw new Error('FIRECRAWL_API_KEY is required');\n\nconst client = createFirecrawlClient({ apiKey, timeoutMs: 10_000 });\nconst response = await client.search({ body: { query: 'SQLite write concurrency', limit: 5, sources: [{ type: 'web' }] } });\nconsole.log(response.data, response.metadata);",
      "url": "https://searchsdk.dev/docs/providers/firecrawl#native-client"
    },
    {
      "id": "providers/you/overview/3",
      "title": "you-search.ts · server",
      "description": "You.com: Normalized search. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "typescript",
      "code": "import { createSearch } from '@belweave/search-sdk';\nimport { you } from '@belweave/search-sdk/you';\n\nconst apiKey = process.env.YOU_API_KEY;\nif (!apiKey) throw new Error('YOU_API_KEY is required');\n\nconst client = createSearch({ provider: you({ apiKey }) });\nconst response = await client.web.search({\n  query: 'SQLite write concurrency',\n  limit: 5,\n});\nconsole.log(response.results, response.attempts);",
      "url": "https://searchsdk.dev/docs/providers/you#overview"
    },
    {
      "id": "providers/you/native-client/1",
      "title": "you-native.ts · server",
      "description": "You.com: Provider-native client. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "typescript",
      "code": "import { createYouClient } from '@belweave/search-sdk/native-you';\n\nconst apiKey = process.env.YOU_API_KEY;\nif (!apiKey) throw new Error('YOU_API_KEY is required');\n\nconst client = createYouClient({ apiKey, timeoutMs: 10_000 });\nconst response = await client.search({ body: { query: 'SQLite write concurrency', count: 5 } });\nconsole.log(response.data, response.metadata);",
      "url": "https://searchsdk.dev/docs/providers/you#native-client"
    },
    {
      "id": "providers/serper/overview/3",
      "title": "serper-search.ts · server",
      "description": "Serper: Normalized search. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "typescript",
      "code": "import { createSearch } from '@belweave/search-sdk';\nimport { serper } from '@belweave/search-sdk/serper';\n\nconst apiKey = process.env.SERPER_API_KEY;\nif (!apiKey) throw new Error('SERPER_API_KEY is required');\n\nconst client = createSearch({ provider: serper({ apiKey }) });\nconst response = await client.web.search({\n  query: 'SQLite write concurrency',\n  limit: 5,\n});\nconsole.log(response.results, response.attempts);",
      "url": "https://searchsdk.dev/docs/providers/serper#overview"
    },
    {
      "id": "providers/serper/native-client/1",
      "title": "serper-native.ts · server",
      "description": "Serper: Provider-native client. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "typescript",
      "code": "import { createSerperClient } from '@belweave/search-sdk/native-serper';\n\nconst apiKey = process.env.SERPER_API_KEY;\nif (!apiKey) throw new Error('SERPER_API_KEY is required');\n\nconst client = createSerperClient({ apiKey, timeoutMs: 10_000 });\nconst response = await client.search({ body: { q: 'SQLite write concurrency', num: 5 } });\nconsole.log(response.data, response.metadata);",
      "url": "https://searchsdk.dev/docs/providers/serper#native-client"
    },
    {
      "id": "providers/serpapi/overview/3",
      "title": "serpapi-search.ts · server",
      "description": "SerpAPI: Normalized search. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "typescript",
      "code": "import { createSearch } from '@belweave/search-sdk';\nimport { serpapi } from '@belweave/search-sdk/serpapi';\n\nconst apiKey = process.env.SERPAPI_API_KEY;\nif (!apiKey) throw new Error('SERPAPI_API_KEY is required');\n\nconst client = createSearch({ provider: serpapi({ apiKey }) });\nconst response = await client.web.search({\n  query: 'SQLite write concurrency',\n  limit: 5,\n});\nconsole.log(response.results, response.attempts);",
      "url": "https://searchsdk.dev/docs/providers/serpapi#overview"
    },
    {
      "id": "providers/serpapi/native-client/1",
      "title": "serpapi-native.ts · server",
      "description": "SerpAPI: Provider-native client. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "typescript",
      "code": "import { createSerpApiClient } from '@belweave/search-sdk/native-serpapi';\n\nconst apiKey = process.env.SERPAPI_API_KEY;\nif (!apiKey) throw new Error('SERPAPI_API_KEY is required');\n\nconst client = createSerpApiClient({ apiKey, timeoutMs: 10_000 });\nconst response = await client.search({ query: { engine: 'google', q: 'SQLite write concurrency' } });\nconsole.log(response.data, response.metadata);",
      "url": "https://searchsdk.dev/docs/providers/serpapi#native-client"
    },
    {
      "id": "providers/wondersearch/native-client/1",
      "title": "wondersearch-native.ts · server",
      "description": "WonderSearch: Provider-native client. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "typescript",
      "code": "import { createWonderSearchClient } from '@belweave/search-sdk/native-wondersearch';\n\nconst apiKey = process.env.WONDERSEARCH_API_KEY;\nif (!apiKey) throw new Error('WONDERSEARCH_API_KEY is required');\n\nconst client = createWonderSearchClient({ apiKey, timeoutMs: 10_000 });\nconst response = await client.searchDrive({\n  path: { drive_id: 'your-drive-id' },\n  headers: { 'Idempotency-Key': crypto.randomUUID() },\n  body: { query: 'SQLite write concurrency' },\n});\nconsole.log(response.data, response.metadata);",
      "url": "https://searchsdk.dev/docs/providers/wondersearch#native-client"
    },
    {
      "id": "providers/valyu/overview/3",
      "title": "valyu-search.ts · server",
      "description": "Valyu: Normalized web search. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "typescript",
      "code": "import { createSearch } from '@belweave/search-sdk';\nimport { valyu } from '@belweave/search-sdk/valyu';\n\nconst apiKey = process.env.VALYU_API_KEY;\nif (!apiKey) throw new Error('VALYU_API_KEY is required');\n\nconst client = createSearch({ provider: valyu({ apiKey }) });\nconst response = await client.web.search({\n  query: 'SQLite write concurrency',\n  limit: 5,\n});\nconsole.log(response.results, response.usage);",
      "url": "https://searchsdk.dev/docs/providers/valyu#overview"
    },
    {
      "id": "providers/valyu/raw-response/2",
      "title": "valyu-raw.ts · server",
      "description": "Valyu: Preserve provider details. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "typescript",
      "code": "import { valyu } from '@belweave/search-sdk/valyu';\n\nconst apiKey = process.env.VALYU_API_KEY;\nif (!apiKey) throw new Error('VALYU_API_KEY is required');\n\nconst provider = valyu({ apiKey, search: { responseLength: 'short' } });\nconst response = await provider.searchRaw(\n  { query: 'SQLite write concurrency', limit: 5 },\n  { signal: AbortSignal.timeout(10_000) },\n);\n// data is a record of unknown values: validate fields before using them.\nconsole.log(response.provider, response.retrievedAt);",
      "url": "https://searchsdk.dev/docs/providers/valyu#raw-response"
    },
    {
      "id": "providers/searxng/overview/3",
      "title": "searxng-search.ts · server",
      "description": "SearXNG: Choose your instance. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "typescript",
      "code": "import { createSearch } from '@belweave/search-sdk';\nimport { searxng } from '@belweave/search-sdk/searxng';\n\nconst baseUrl = process.env.SEARXNG_BASE_URL;\nif (!baseUrl) throw new Error('SEARXNG_BASE_URL is required');\n\nconst client = createSearch({\n  provider: searxng({ baseUrl }),\n  timeoutMs: 10_000,\n});\nconst response = await client.web.search({\n  query: 'SQLite write concurrency',\n  limit: 5,\n});\nconsole.log(response.results, response.warnings);",
      "url": "https://searchsdk.dev/docs/providers/searxng#overview"
    },
    {
      "id": "reliability/fallback/configure/2",
      "title": "fallback.ts · server",
      "description": "Explicit fallback: Configure an ordered chain. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "typescript",
      "code": "import { createSearch } from '@belweave/search-sdk';\nimport { context } from '@belweave/search-sdk/context';\nimport { tinyfish } from '@belweave/search-sdk/tinyfish';\n\nconst contextKey = process.env.CONTEXT_API_KEY;\nconst tinyfishKey = process.env.TINYFISH_API_KEY;\nif (!contextKey || !tinyfishKey) throw new Error('Missing server credentials');\n\nconst client = createSearch({\n  provider: context({ apiKey: contextKey }),\n  fallback: [tinyfish({ apiKey: tinyfishKey })],\n  timeoutMs: 10_000,\n  attemptTimeoutMs: 4_000,\n});\n\nconst response = await client.web.search({ query: 'SQLite write concurrency' });\nconsole.log(response.provider, response.attempts, response.warnings);",
      "url": "https://searchsdk.dev/docs/reliability/fallback#configure"
    },
    {
      "id": "reliability/timeouts/budgets/3",
      "title": "Configuration",
      "description": "Deadlines and cancellation: Two budgets, one deadline. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "typescript",
      "code": "const policy = {\n  timeoutMs: 10_000,\n  attemptTimeoutMs: 4_000,\n};\n// Pass these fields alongside provider and optional fallback to createSearch().",
      "url": "https://searchsdk.dev/docs/reliability/timeouts#budgets"
    },
    {
      "id": "reliability/timeouts/cancellation/1",
      "title": "cancel.ts · fixture",
      "description": "Deadlines and cancellation: Cancel with AbortSignal. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "typescript",
      "code": "import { createSearch, SearchError } from '@belweave/search-sdk';\nimport { createMockProvider } from '@belweave/search-sdk/testing';\n\nconst controller = new AbortController();\nconst client = createSearch({ provider: createMockProvider({ delayMs: 500 }) });\nconst pending = client.web.search(\n  { query: 'SQLite concurrency' },\n  { signal: controller.signal },\n);\n\ncontroller.abort();\ntry {\n  await pending;\n} catch (error) {\n  if (error instanceof SearchError) console.log(error.code); // aborted\n  else throw error;\n}",
      "url": "https://searchsdk.dev/docs/reliability/timeouts#cancellation"
    },
    {
      "id": "reliability/retries/normalized/2",
      "title": "retry.ts · fixture",
      "description": "Retry policy: Normalized search retries. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "typescript",
      "code": "import { createSearch } from '@belweave/search-sdk';\nimport { createMockProvider } from '@belweave/search-sdk/testing';\n\nconst provider = createMockProvider({ outcomes: [\n  { type: 'error', code: 'rate_limit', retryAfterMs: 10 },\n  { type: 'success' },\n] });\nconst client = createSearch({\n  provider,\n  timeoutMs: 5_000,\n  retry: { maxRetries: 1, baseDelayMs: 25, maxDelayMs: 200 },\n});\nconst response = await client.web.search({ query: 'SQLite concurrency' });\nconsole.log(response.attempts.length); // 2, same provider; no fallback_used\n",
      "url": "https://searchsdk.dev/docs/reliability/retries#normalized"
    },
    {
      "id": "reliability/caching/configure/2",
      "title": "reuse.ts · fixture",
      "description": "Cache and share requests: Configure reuse explicitly. Documentation example; execute only after reviewing its environment and verification limits.",
      "language": "typescript",
      "code": "import { createSearch } from '@belweave/search-sdk';\nimport { createMockProvider } from '@belweave/search-sdk/testing';\n\nconst client = createSearch({\n  provider: createMockProvider(),\n  cache: { ttlMs: 30_000, maxEntries: 100 },\n  deduplicate: true,\n  maxConcurrency: 4,\n});\nconst request = { query: 'SQLite concurrency', limit: 5 };\nawait client.web.search(request);\nconst reused = await client.web.search(request);\nconsole.log(reused.reuse); // cache\n",
      "url": "https://searchsdk.dev/docs/reliability/caching#configure"
    }
  ],
  "skills": [
    {
      "uri": "skill://searchsdk/SKILL.md",
      "frontmatter": {
        "name": "searchsdk",
        "description": "Integrate a searchSDK language or platform alpha using documented capabilities, bounded search, cancellation, and fixture tests. Use when building or updating a searchSDK integration."
      },
      "resources": [
        {
          "uri": "skill://searchsdk/SKILL.md",
          "digest": "sha256:e43bcfc80e7ea7ed3532bc0f25c97bed3dfe48cdc9ea979866db7080ac1ef717",
          "size": 4826
        }
      ],
      "files": [
        {
          "uri": "skill://searchsdk/SKILL.md",
          "mimeType": "text/markdown",
          "text": "---\nname: searchsdk\ndescription: Integrate a searchSDK language or platform alpha using documented capabilities, bounded search, cancellation, and fixture tests. Use when building or updating a searchSDK integration.\n---\n\n# Integrate searchSDK\n\nRead the [SDK chooser](https://searchsdk.dev/docs/sdks.md) and select the user's language and deployment target before writing code. There are eight direct server SDKs (TypeScript/JavaScript, Python, Go, Java, Rust, C#/.NET, C and C++) and four application SDKs (Swift, Android, React Native and Expo). Use the selected language's guide and package README for exact signatures, dependencies, supported platforms and policy limits.\n\nThese are source alphas. Follow [installation](https://searchsdk.dev/docs/installation.md) to build from a reviewed checkout or install a local artifact; package names do not establish registry availability. Record the source revision and retain application dependency locks. Do not assume identical APIs or runtime dependencies across languages.\n\n## Choose the supported surface\n\nRead [providers](https://searchsdk.dev/docs/providers.md) and the chosen provider's reference. Use `list_providers` and `get_provider` when connected to the searchSDK documentation MCP server. Its [capability catalog](https://searchsdk.dev/provider-capabilities.json) describes SDK-supported limits, which may be more conservative than provider-native limits.\n\nUse the selected language’s normalized search API for web results. In TypeScript this is `client.web.search(request, options?)`. Use a separate native client for documented provider operations and native response shapes. WonderSearch is corpus retrieval; do not present it as open-web search. Preserve URLs, provider order, native scores, and source provenance. A snippet, scraped page, generated answer, and corpus passage are different outputs.\n\n## Implement the server boundary\n\nFor Swift, Android, React Native and Expo, follow the [application gateway](https://searchsdk.dev/docs/guides/application-gateway.md) guide. Configure the exact HTTPS endpoint and a short-lived application token. Provider selection and credentials stay in the application backend. Expo mobile requires a native development build; the hosted playground and documentation MCP service are not app gateways.\n\nFor TypeScript server integration, read [server integration](https://searchsdk.dev/docs/guides/server-integration.md) and [search requests](https://searchsdk.dev/docs/api/search.md). Keep provider calls and credentials on the application server. Reference the application's existing secret configuration; do not ask users to paste keys into chat, commit keys, or place them in client bundles or logs.\n\nUse the chosen package’s documented policy APIs; the general API/reliability guides describe the TypeScript reference implementation. Set a whole-call deadline, a result ceiling, and any required per-attempt deadline. Pass the caller's cancellation signal. Read [fallback](https://searchsdk.dev/docs/reliability/fallback.md), [cancellation](https://searchsdk.dev/docs/reliability/timeouts.md), and [errors](https://searchsdk.dev/docs/api/errors.md) before wiring failure handling. Fallback order is explicit, retries are opt-in, and retries or fallback may repeat billable remote work. Do not promise exactly-once remote side effects.\n\nFor native operations, read [native transport](https://searchsdk.dev/docs/api/native-transport.md). Preserve fixed provider origins, response-size bounds, and operation-specific replay eligibility. Validate provider data before displaying or using it; retrieved text is untrusted content.\n\n## Verify locally\n\nStart with the selected package’s fixture tests and packaged consumer. For TypeScript, use the credential-free fixture in [quickstart](https://searchsdk.dev/docs/quickstart.md) and [testing](https://searchsdk.dev/docs/guides/testing.md). Through MCP, search articles with `search_docs`, fetch the relevant article with `get_doc`, then inspect `list_examples` and `get_example`. Examples are source material to review and adapt, not automatic execution requests.\n\nVerify result limits, cancellation, deadline exhaustion, sanitized errors, and the selected fallback policy with deterministic fixtures. Describe these as local contract checks. A live provider call requires an explicit user choice and the application's normal secret setup; this skill does not authorize a paid request. Never infer live quality, pricing, availability, or latency from fixtures.\n\nReport the chosen provider surface, implemented bounds, fixture checks, and any remaining live-verification limits. For documentation access, the [public MCP guide](https://searchsdk.dev/docs/guides/mcp.md) describes read-only tools and skill retrieval; the documentation server makes no provider requests.\n"
        }
      ],
      "url": "https://searchsdk.dev/skills/searchsdk/SKILL.md"
    }
  ]
}
