TypeScript 97.5%
SQL 1.4%
Python 0.8%
1import type { Metadata } from "next";2import { CodeBlock } from "@/components/ui/code-block";3import { DocPage } from "@/components/docs/doc-page";4import { A, Code, H2, Li, P, Step, Steps, Strong, Ul } from "@/components/docs/prose";5import { Callout } from "@/components/docs/callout";6import { CodeTabs } from "@/components/docs/code-tabs";7import { ResponseExample } from "@/components/docs/response-example";89export const metadata: Metadata = {10 title: "Quickstart",11 description: "Create an account, generate an API key and make your first Fetcha request in cURL, JavaScript or Python.",12};1314const FIRST_REQUEST_CURL = `curl https://www.fetcha.co/v1/fetch -X POST -H "Authorization: Bearer $FETCHA_API_KEY" -H "Content-Type: application/json" -d '{"url": "https://example.com"}'`;1516const FIRST_REQUEST_JS = `const res = await fetch("https://www.fetcha.co/v1/fetch", {17 method: "POST",18 headers: {19 Authorization: \`Bearer \${process.env.FETCHA_API_KEY}\`,20 "Content-Type": "application/json",21 },22 body: JSON.stringify({ url: "https://example.com" }),23});2425const data = await res.json();26if (!res.ok) throw new Error(\`\${data.error.code}: \${data.error.message}\`);2728console.log(data.status); // 20029console.log(data.metadata.network); // "residential"30console.log(data.content.slice(0, 200));`;3132const FIRST_REQUEST_PY = `import os33import requests3435res = requests.post(36 "https://www.fetcha.co/v1/fetch",37 headers={38 "Authorization": f"Bearer {os.environ['FETCHA_API_KEY']}",39 "Content-Type": "application/json",40 },41 json={"url": "https://example.com"},42)43data = res.json()44if res.status_code >= 400:45 raise RuntimeError(f"{data['error']['code']}: {data['error']['message']}")4647print(data["status"]) # 20048print(data["metadata"]["network"]) # "residential"49print(data["content"][:200])`;5051const RESPONSE = {52 request_id: "req_k3j9d0f2a8b1c7e4",53 success: true,54 status: 200,55 url: "https://example.com",56 final_url: "https://example.com/",57 content: "<!doctype html>\n<html>\n<head>\n <title>Example Domain</title>…",58 content_type: "text/html; charset=UTF-8",59 headers: {60 "content-type": "text/html; charset=UTF-8",61 "cache-control": "max-age=604800",62 date: "Mon, 07 Sep 2026 14:02:11 GMT",63 },64 cookies: [],65 metadata: {66 network: "residential",67 country: null,68 attempts: 1,69 duration_ms: 842,70 bytes: 2331,71 session: null,72 cached: false,73 timing: { dns_ms: 14, proxy_connect_ms: 0, tls_ms: 0, origin_ms: 611, processing_ms: 3, total_ms: 842 },74 },75};7677export default function QuickstartPage() {78 return (79 <DocPage path="/docs/quickstart" title="Quickstart" description="From zero to a fetched page in five steps. You need a Fetcha account, a verified email address and a terminal." status="Stable">80 <Steps>81 <Step title="Create an account">82 <P>83 Sign up at <A href="/signup">fetcha.co/signup</A> with your email address and a password. A personal organization (<Code>Your name's workspace</Code>) and a first project named{" "}84 <Code>Default</Code> are created automatically; you can rename them later in the dashboard.85 </P>86 </Step>87 <Step title="Verify your email">88 <P>89 Open the verification link we send you. Until the email is verified, every API call returns <Code>403 EMAIL_NOT_VERIFIED</Code>. The dashboard Playground works before verification so90 you can explore, but real API keys do not.91 </P>92 </Step>93 <Step title="Create an API key">94 <P>95 In the dashboard, open your project, go to <Strong>API keys</Strong> and create a key. Choose <Code>live</Code> mode (keys start with <Code>fch_live_</Code>) and keep the default scopes{" "}96 <Code>fetch:execute</Code>, <Code>sessions:write</Code> and <Code>usage:read</Code>.97 </P>98 <Callout variant="warning" title="The key is shown once">99 Fetcha stores only a SHA-256 hash of the key. Copy it immediately and put it in an environment variable. If you lose it, rotate the key to get a new one.100 </Callout>101 <CodeBlock lang="bash" code={`export FETCHA_API_KEY="fch_live_..."`} />102 </Step>103 <Step title="Make your first request">104 <P>105 Post a URL to <Code>/v1/fetch</Code>. This exact one-liner is the smallest valid request: no country, no network, default <Code>html</Code> format, 30-second timeout.106 </P>107 <CodeBlock lang="bash" code={FIRST_REQUEST_CURL} title="Terminal" />108 <P>The same request from application code:</P>109 <CodeTabs110 tabs={[111 { label: "cURL", lang: "bash", code: FIRST_REQUEST_CURL },112 { label: "JavaScript", lang: "javascript", code: FIRST_REQUEST_JS },113 { label: "Python", lang: "python", code: FIRST_REQUEST_PY },114 ]}115 />116 </Step>117 <Step title="Read the response">118 <P>119 A fetch returns HTTP <Code>200</Code> whenever Fetcha reached the target, even if the target itself answered with an error. Look at <Code>success</Code> and <Code>status</Code>{" "}120 to know how the origin responded, and at <Code>metadata</Code> to see how the request was routed.121 </P>122 <ResponseExample status={200} body={RESPONSE} />123 <Ul>124 <Li>125 <Code>success</Code> is <Code>true</Code> when the origin answered with a 2xx or 3xx status and the page did not look like a block. A blocked target returns{" "}126 <Code>success: false</Code> with the origin's status (for example 403) and <Code>metadata.attempts</Code> greater than one.127 </Li>128 <Li>129 <Code>content</Code> holds the body as a string for <Code>html</Code>, <Code>json</Code> and <Code>raw</Code> formats. Ask for <Code>{`"format": "text"`}</Code> to receive a readable{" "}130 <Code>text</Code> field instead, or <Code>{`"format": "json"`}</Code> to get a parsed <Code>json</Code> field.131 </Li>132 <Li>133 <Code>metadata.network</Code> is the concrete network class that served the request (<Code>residential</Code> today). <Code>metadata.country</Code> echoes the country you targeted, or{" "}134 <Code>null</Code>.135 </Li>136 <Li>137 <Code>request_id</Code> is what you quote to support. It also appears in the <Code>X-Fetcha-Request-ID</Code> response header.138 </Li>139 </Ul>140 </Step>141 <Step title="Open the Playground">142 <P>143 The dashboard <A href="/dashboard/playground">Playground</A> runs the same pipeline as the API against your current project, without needing a key in your terminal. Use it to try144 countries, formats and sessions, inspect timing, and copy the generated code. Requests made there are counted in your usage and appear in the request log with source{" "}145 <Code>playground</Code>.146 </P>147 </Step>148 </Steps>149150 <H2>Next steps</H2>151 <Ul>152 <Li>153 Target a country with <Code>{`"country": "CA"`}</Code>: see <A href="/docs/geolocation">Geolocation</A>.154 </Li>155 <Li>156 Keep the same exit IP across several requests: see <A href="/docs/sessions">Sessions</A>.157 </Li>158 <Li>159 Understand every field and limit: see the <A href="/docs/fetch">Fetch API reference</A>.160 </Li>161 <Li>162 Handle failures properly: see <A href="/docs/errors">Errors</A> and <A href="/docs/retries">Retries</A>.163 </Li>164 <Li>165 Prefer a typed client: see <A href="/docs/sdks">SDKs</A> (JavaScript/TypeScript and Python, installed from source for now).166 </Li>167 </Ul>168 </DocPage>169 );170}171