import type { Metadata } from "next"; import { CodeBlock } from "@/components/ui/code-block"; import { DocPage } from "@/components/docs/doc-page"; import { A, Code, H2, H3, Li, P, Strong, Table, TBody, Td, Th, THead, Tr, Ul } from "@/components/docs/prose"; import { Callout } from "@/components/docs/callout"; import { ParamTable } from "@/components/docs/param-table"; import { CodeTabs } from "@/components/docs/code-tabs"; export const metadata: Metadata = { title: "SDKs", description: "Official JavaScript/TypeScript and Python clients for Fetcha: installation from source, configuration, fetch/text/json helpers, sessions, usage, error classes.", }; const JS_INSTALL = `# From a checkout of the Fetcha repository, inside your project: pnpm add ./packages/sdk # or: npm install ./packages/sdk # Or simply copy the single source file into your codebase: cp packages/sdk/src/index.ts src/lib/fetcha.ts`; const PY_INSTALL = `# From a checkout of the Fetcha repository: pip install ./sdk-python # Requirements: Python >= 3.9, httpx >= 0.27 (installed automatically)`; const JS_USAGE = `import { Fetcha, FetchaError } from "@fetcha/sdk"; const fetcha = new Fetcha({ apiKey: process.env.FETCHA_API_KEY! }); // Full control: every /v1/fetch field is available const r = await fetcha.fetch({ url: "https://example.com/products/42", country: "CA", format: "html", retries: 2 }); console.log(r.success, r.status, r.metadata.network, r.metadata.attempts); console.log(r.content?.slice(0, 200)); // Readable text (format: "text") const text = await fetcha.text("https://example.com/about", { country: "CA" }); // Parsed JSON (format: "json"); the generic sets the return type type Price = { amount: number; currency: string }; const price = await fetcha.json("https://api.example.com/v1/price?sku=42");`; const PY_USAGE = `from fetcha import Fetcha, FetchaError client = Fetcha(api_key=os.environ["FETCHA_API_KEY"]) # Full control: every /v1/fetch field is a keyword argument r = client.fetch("https://example.com/products/42", country="CA", format="html", retries=2) print(r.success, r.status, r.metadata["network"], r.metadata["attempts"]) print(r.content[:200]) # Readable text (format="text") text = client.text("https://example.com/about", country="CA") # Parsed JSON (format="json") price = client.json("https://api.example.com/v1/price?sku=42") # The client owns an httpx.Client; close it when done (or use it as a context manager) with Fetcha(api_key=os.environ["FETCHA_API_KEY"]) as c: print(c.me()["project"]["name"])`; const JS_SESSIONS = `// Create (optionally idempotent), use, inspect, list, close const s = await fetcha.sessions.create({ country: "CA", ttl: 900, label: "user-42" }, "user-42-login"); const page = await fetcha.fetch({ url: "https://www.example.ca/account", session: s.id, cookies: { sid: "…" } }); const same = await fetcha.sessions.get(s.id); // { id, status, network, country, expires_at, created_at, … } const all = await fetcha.sessions.list(); // { data: Session[] } await fetcha.sessions.close(s.id); // { id, status: "closed" }`; const PY_SESSIONS = `# Create, use, inspect, list, close s = client.sessions.create(country="CA", ttl=900, label="user-42") page = client.fetch("https://www.example.ca/account", session=s.id, cookies={"sid": "…"}) same = client.sessions.get(s.id) # Session dataclass; .raw has the full payload all_sessions = client.sessions.list() # list[Session] client.sessions.close(s.id) # {"id": ..., "status": "closed"}`; const JS_ACCOUNT = `const me = await fetcha.me(); // { project: { id, name }, organization: { id, name, plan }, key: { id, name, scopes } } const usage = await fetcha.usage.current(); // { period_start, plan, organization, project, remaining_requests } (see Rate limits)`; const PY_ACCOUNT = `me = client.me() # {"project": {...}, "organization": {..., "plan": "developer"}, "key": {..., "scopes": [...]}} usage = client.usage() # {"period_start": ..., "plan": ..., "organization": ..., "project": ..., "remaining_requests": ...}`; const JS_ERRORS = `try { await fetcha.fetch({ url: "http://169.254.169.254/latest/meta-data/" }); } catch (e) { if (e instanceof FetchaError) { e.code; // "URL_NOT_ALLOWED" e.status; // 400 e.message; // "Requests to local, private or internal hosts are not allowed." e.requestId; // "req_…" | null } }`; const PY_ERRORS = `try: client.fetch("http://169.254.169.254/latest/meta-data/") except FetchaError as e: e.code # "URL_NOT_ALLOWED" e.status # 400 e.message # "Requests to local, private or internal hosts are not allowed." e.request_id # "req_…" or None str(e) # "URL_NOT_ALLOWED: Requests to local, private or internal hosts are not allowed."`; export default function SdksPage() { return ( Both SDKs exist as source in the Fetcha repository (packages/sdk and sdk-python) and are installed from there until the packages are published. The CLI is not available yet. Package names are reserved: @fetcha/sdk on npm and fetcha on PyPI.
SDK Package Version Dependencies Runtime
JavaScript / TypeScript @fetcha/sdk 0.1.0 None (uses the global fetch) Node 18+, Bun, Deno, edge runtimes; ESM; ships TypeScript source
Python fetcha 0.1.0 httpx>=0.27 Python 3.9+; synchronous client

Requests made through the SDKs are tagged with source sdk in your request log (the SDKs send a fetcha-sdk-js/… or fetcha-sdk-python/… User-Agent to the Fetcha API; this does not affect the User-Agent sent to targets).

Installation

The JavaScript package's entry point is its TypeScript source (src/index.ts), so use it from a TypeScript-aware toolchain (tsx, Bun, Deno, Vite, Next.js, esbuild) or copy the file into your own build. It has zero runtime dependencies.

Configuration

JavaScript

Your fch_live_… or fch_test_… key. The constructor throws if it is empty. }, { name: "baseUrl", type: "string", default: '"https://www.fetcha.co"', description: <>API origin. Trailing slash is removed. }, { name: "clientTimeout", type: "number (ms)", default: "150000", description: <>Client-side abort applied on top of the API's own timeout. Keep it above the largest timeout you send. }, { name: "fetch", type: "typeof fetch", default: "globalThis.fetch", description: <>Custom fetch implementation (proxies, instrumentation, tests). }, ]} />

Python

Your API key. ValueError if empty. }, { name: "base_url", type: "str", default: '"https://www.fetcha.co"', description: <>API origin. }, { name: "timeout", type: "float (seconds)", default: "150.0", description: <>httpx timeout for the HTTP call to Fetcha. }, ]} />

Fetching

fetch takes the same fields as POST /v1/fetch and returns the response document unchanged. text and json are shortcuts that set{" "} format and unwrap the corresponding field.

  • JavaScript: fetch(options): Promise<FetchResult>, text(url, options?) returns string (empty when the body was binary),{" "} json<T>(url, options?) returns T (undefined when the body did not parse).
  • Python: fetch(url, **options) returns a FetchResult dataclass (request_id, success, status, url,{" "} final_url, content, content_type, headers, cookies, metadata, text, json, plus{" "} raw with the untouched payload). text() returns str, json() returns the parsed value or None.
  • A fetch that reached the target never raises, even when success is false. Check it.

Sessions

The JavaScript sessions.create(options, idempotencyKey?) second argument sets the Idempotency-Key header. The Python client does not expose the header yet; pass your own de-duplication logic or call the REST endpoint directly for idempotent creation. See Sessions.

Account and usage

Errors

Any non-2xx response is raised as FetchaError with the API's code, the HTTP status, the message and the request id. If the response body is not a Fetcha envelope (for example a gateway error), code is {`"HTTP_ERROR"`}. Transport failures (DNS, connection reset, client-side timeout) surface as the runtime's native error, not as FetchaError.

Types

The JavaScript SDK exports the following types; they mirror the API exactly.

Other languages

There is no official SDK for Go, PHP, Ruby, Java or C# yet. The REST API is small enough that the raw-HTTP samples in this documentation (see the language tabs on the{" "} Fetch API page) are a complete integration. If you publish a community client, tell us at hello@fetcha.co and we will link it here.

CLI

A fetcha command-line tool is planned but not available. Until then, cURL with an exported FETCHA_API_KEY covers interactive use; see the{" "} Quickstart.

); }