API Documentation
From a URL to usable data. Start with one request, then add structured extraction, browser rendering or background jobs.
On this page
Base URL
https://api.finedata.ai Quick Start
Create an account, copy your API key from the dashboard, and replace fd_your_api_key below. This request reads a public page and returns markdown.
curl
curl -X POST https://api.finedata.ai/api/v1/scrape \
-H "Content-Type: application/json" \
-H "x-api-key: fd_your_api_key" \
-d '{"url": "https://example.com", "formats": ["markdown"]}' Python · requests
Install with pip install requests. Run on your server, not in a public client.
import requests
resp = requests.post(
"https://api.finedata.ai/api/v1/scrape",
headers={"x-api-key": "fd_your_api_key"},
json={"url": "https://example.com", "formats": ["markdown"]},
timeout=130,
)
resp.raise_for_status()
data = resp.json()
if data["success"] is False:
raise RuntimeError(data)
print(data["data"]["markdown"]) JavaScript · Node.js 18+
Run as an ES module on your server. Never expose your API key in browser code.
const resp = await fetch("https://api.finedata.ai/api/v1/scrape", {
method: "POST",
headers: { "Content-Type": "application/json", "x-api-key": "fd_your_api_key" },
body: JSON.stringify({ url: "https://example.com", formats: ["markdown"] })
});
if (resp.ok === false) throw new Error(await resp.text());
const data = await resp.json();
if (data.success === false) throw new Error(JSON.stringify(data));
console.log(data.data.markdown); Authentication
All requests require one of:
API Key (recommended)
curl -X POST https://api.finedata.ai/api/v1/scrape \
-H "x-api-key: fd_your_api_key" \
-H "Content-Type: application/json" \
-d '{"url":"https://example.com","formats":["markdown"]}' JWT Bearer Token
curl -X POST https://api.finedata.ai/api/v1/scrape \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"url":"https://example.com","formats":["markdown"]}' Token Pricing
Tokens are API usage credits, not LLM input tokens. A default request uses 3: 1 base + 2 for TLS fingerprinting. Failed scrapes are not billed. Add one rendering mode and any routing, extraction or action costs you need.
use_antibot: false = 1 ·
With antibot = 3 ·
JS render = 8 ·
Stealth + residential = 13 ·
Stealth Headful = 28 Examples assume no retries or extraction. A domain-specific strategy may change the engine or routing: use the response's
tokens_used as the actual charge. A Google SERP request is a flat 10 tokens, reported as tokens_charged; a blocked or empty Google response is not billed and gl, hl and start do not change the price. Scrape Endpoint
/api/v1/scrape Send a JSON body with a target URL. Add only the options your page needs.
{
"url": "https://example.com",
"formats": ["markdown"],
"only_main_content": true
} Request options
- url
- Required target URL. The API call itself is always POST; method selects the request sent to the target.
- method · headers · body
- GET by default. For a write request, pass its method, target headers and a string body.
- timeout
- 120 seconds by default; allowed range 5–300. Set your HTTP client timeout slightly higher.
- max_retries · auto_retry
- max_retries: 5 by default (1–10). auto_retry: true; actual retries add 1 token each.
Rendering options
- use_antibot · tls_profile
- TLS fingerprinting is on by default, with chrome136 (+2 tokens).
- use_js_render
- Render JavaScript (+5). Use for pages whose content loads in the browser.
- stealth_antibot · stealth_antibot_headful
- Stronger browser emulation (+7) or a full headful browser (+25).
- stealth_premium · stealth_premium_headful
- Premium fingerprint emulation (+20), or its headful mode (+30).
- stealth_new
- Experimental rendering mode (+15). Choose one rendering mode rather than stacking flags.
- js_wait_for · js_scroll · js_actions
- Wait for a load event or selector, scroll, or run up to 10 browser actions (+2 each).
Routing and output options
- use_isp · use_residential · use_mobile
- Choose one proxy type: ISP (+2), residential (+3), or mobile (+4). Datacenter is the default.
- proxy_country · proxy_profile_id
- Choose a country or a saved BYOP profile, not both. See Proxy & Geo-Targeting below.
- session_id · session_ttl · proxy_sticky
- Reuse a session (TTL: 60–86,400 seconds; default 1,800) and request a sticky exit IP.
- formats · only_main_content · raw_output
- Select output fields, remove page chrome, or return one format without the JSON wrapper.
- extract_rules · extract_prompt · extract_schema
- Extract with CSS/XPath selectors or AI. See working examples below.
For every field and constraint, use the interactive reference or OpenAPI schema.
Response
Illustrative response, shortened for readability. Only requested output fields are populated.
{
"success": true,
"status_code": 200,
"body": "<html>...</html>",
"data": {
"markdown": "# Example Domain\n\nThis domain is for use..."
},
"meta": {"url": "https://example.com", "elapsed_ms": 1250},
"tokens_used": 3
} Check the API HTTP status first, then success. The JSON field status_code is the target page's status, not the API's. Read content from data.markdown and actual usage from tokens_used.
Google SERP
/api/v1/serp Run a Google search server-side and get the results as JSON. It uses the same API-key authentication as /api/v1/scrape. The API builds the Google URL from your query, so you never send a target URL. Use it to monitor the ranking and visibility of your own domains and brand queries. Follow the Acceptable Use Policy: the permitted case is SEO and SERP tracking for your own domains.
curl -X POST https://api.finedata.ai/api/v1/serp \
-H "Content-Type: application/json" \
-H "x-api-key: fd_your_api_key" \
-d '{"q": "rank tracking tool", "gl": "us", "hl": "en", "start": 0}' | Field | Type | Description |
|---|---|---|
q | string | Required search query, 1–2048 characters. |
gl | string | Google country as an ISO 3166-1 alpha-2 code, e.g. us. Defaults to us. |
hl | string | Google interface language, e.g. en or en-GB. Defaults to en. |
start | integer | Result offset for paging: 0–90 in steps of 10. 10 results per page; defaults to 0. |
device | string | Only desktop is supported. |
include_html | boolean | Also return the raw Google HTML in raw_html. Defaults to false. |
Response
Illustrative response, shortened for readability. Blocks such as ads, answer_box, knowledge_graph, top_stories, local_results, people_also_ask, related_searches, shopping_results and video_results appear only when the page carries them.
{
"search_metadata": {
"id": "3f6c1e9a-…",
"status": "ok",
"created_at": "2026-10-13T12:00:00+00:00",
"processing_time_ms": 1840,
"google_url": "<google search url built from q, gl, hl, start>"
},
"search_information": {
"query_displayed": "rank tracking tool",
"total_results": 412000000
},
"organic_results": [
{
"position": 1,
"title": "Rank Tracking Tool — Example",
"link": "https://example.com/rank-tracker",
"displayed_link": "example.com › rank-tracker",
"snippet": "Track keyword positions for your own domains…",
"sitelinks": [
{"title": "Pricing", "link": "https://example.com/pricing"}
]
}
],
"tokens_charged": 10
} Each request costs a flat 10 tokens, reported as tokens_charged; gl, hl and start do not change the price. Links resolve away from Google's redirect wrapper, so organic_results[].link is the destination URL. A blocked or unparseable Google page costs nothing.
| Code | Error | Action |
|---|---|---|
402 | trial_exhausted · token_limit_exceeded | Upgrade the plan or add tokens |
502 | serp_blocked · serp_empty | Retry later; nothing was charged |
503 | Worker pool busy | Retry after a short delay |
Over MCP the same search is the google_search tool with arguments q, gl, hl and start; it needs the scrape:write scope. See MCP Integration.
Output Formats
Use the formats array to control what appears in data.
| Format | Returns | Best for |
|---|---|---|
markdown | Clean Markdown | LLM input, content extraction |
text | Plain text | Search indexing, NLP |
rawHtml | HTML in data.raw_html | HTML parsing |
links | Array of URLs | Crawling, link analysis |
screenshot | Base64 PNG; requires browser rendering | Visual verification |
csv | CSV string in data.csv | AI extraction to a table (sync only) |
xlsx | Base64 workbook in data.xlsx | AI extraction to a spreadsheet (sync only) |
Content without the wrapper
REST returns raw HTML in body if you omit formats. Request a format explicitly. For content-only output, add raw_output: true with exactly one format.
{
"url": "https://example.com",
"formats": ["markdown"],
"raw_output": true
} The response is markdown, not JSON. Metadata moves to X-Tokens-Used, X-Request-Id and X-Status-Code headers. CSV/XLSX require extract_prompt or extract_schema; use the synchronous endpoint for these exports.
AI Extraction
Extract with CSS/XPath selectors (no extra extraction fee) or AI (+5 tokens). AI-only results are in data.extract; when combined with selector results, AI data is nested under data.extract.ai_extract. These product URLs and selectors are illustrative.
CSS Selectors (no extra fee)
{
"url": "https://example.com/product",
"extract_rules": {
"title": "h1",
"price": ".product-price",
"images": {"selector": "img.product-image", "type": "list", "output": "@src"}
}
} AI with Natural Language (+5 tokens)
{
"url": "https://example.com/product",
"formats": ["markdown"],
"extract_prompt": "Extract product name, price, rating, and availability"
} AI with JSON Schema (+5 tokens)
{
"url": "https://example.com/product",
"extract_schema": {
"type": "object",
"properties": {
"name": {"type": "string"},
"price": {"type": "number"},
"in_stock": {"type": "boolean"}
}
}
} For AI extraction, ai_content_mode: "full" is the default and includes sidebars and structured data. Use "main" for article-focused extraction. Check extracted fields against your application's requirements before relying on them.
Render, wait, then extract
For JavaScript pages, wait for the content you need rather than adding an arbitrary delay. This illustrative sequence expands a product description before extraction; replace the URL and selectors with your page's.
{
"url": "https://example.com/product",
"use_js_render": true,
"js_wait_for": "selector:.product",
"js_actions": [
{"action": "click", "selector": ".expand-description"},
{"action": "wait_for", "selector": ".description-expanded"}
],
"extract_prompt": "Extract the product name and full description"
} Up to 10 actions: click, wait, wait_for, scroll, type, hover, screenshot, evaluate. Browser interactions can change the target site: use only actions you are authorized to perform.
Async & Batch Scraping
Background processing for large-scale scraping or slow pages.
/api/v1/async/scrape Submit a job, get job_id immediately. Use webhook or poll for results.
{
"url": "https://example.com",
"formats": ["markdown"]
} /api/v1/async/jobs/{job_id} Poll status: pending, processing, completed, failed, cancelled
/api/v1/async/jobs List your jobs with pagination
/api/v1/async/jobs/{job_id} Cancel a pending job. A processing job cannot be cancelled and returns HTTP 400.
/api/v1/async/batch Submit up to 100 URLs in one request
Submit a batch and collect results
POST this body to /api/v1/async/batch. REST uses requests, an array of request objects; the MCP batch_scrape tool uses urls instead.
{
"requests": [
{"url": "https://example.com", "formats": ["markdown"]},
{"url": "https://example.org", "formats": ["markdown"]}
]
} Save the returned batch_id. Poll with a delay between requests, adding include_results=true to retrieve individual results.
curl "https://api.finedata.ai/api/v1/async/batch/YOUR_BATCH_ID?include_results=true" \
-H "x-api-key: fd_your_api_key" Stop polling at completed, partial or failed. For a single job, terminal states are completed, failed and cancelled; completed output is in result.data. An optional callback_url notifies your public endpoint when work finishes.
Captcha Solving
Set solve_captcha: true to auto-detect and solve (+10 tokens).
TLS Profiles
Set tls_profile to mimic a browser fingerprint.
Chrome
chrome136 (default)chrome131chrome124chrome123chrome120 Firefox · Safari · Mobile
firefox133safari184safari18_0safari17_0chrome131_androidsafari18_0_ios VIP (Premium auto-rotate)
vipvip:iosvip:androidvip:windowsvip:mobile Proxy & Geo-Targeting
Geo-Targeting
Set proxy_country to an ISO-2 country code to request a proxy exit IP from that country.
Works with datacenter, residential, ISP, and mobile proxies at no extra cost. Returns 422 if
the country isn't currently supported for the resolved proxy type.
{
"url": "https://example.com",
"use_residential": true,
"proxy_country": "DE"
} Bring Your Own Proxy (BYOP)
Save your own proxy list as a profile in the dashboard, then reference it with proxy_profile_id.
Proxies are encrypted at rest. BYOP charges a flat +1 token instead of the vendor proxy surcharge,
and is mutually exclusive with use_residential / use_isp /
use_mobile / proxy_country.
{
"url": "https://example.com",
"proxy_profile_id": 42,
"proxy_sticky": true
}
Available on PAYG, Team S/M/L and Scaling, or with an account override. Combine with proxy_sticky: true
to keep the same exit IP for an entire browser session — useful for anti-bot flows where warmup and API calls must share one IP.
Error Codes
These are API HTTP errors. Inspect the response's detail for the cause. A target-page failure can instead arrive in a scrape result with success: false; inspect its status_code and metadata before retrying.
| Code | Description | Action |
|---|---|---|
401 | Invalid or missing API key / JWT token | Check your API key |
402 | Payment required | Upgrade plan or pay invoices |
403 | Account or feature access denied | Read the error; check plan, scopes or account status |
422 | Validation error | Check request parameters |
429 | Rate limit exceeded | Reduce request frequency; respect Retry-After when present |
500 | Internal server error | Retry or contact support |
503 | Service unavailable | Retry after a moment |
MCP Integration
Connect FineData to Claude Desktop, Cursor IDE, and other AI agents via MCP (v0.3.1). Full setup, tool reference, OAuth sign-in and cost guidance: the MCP server page. Tools: scrape_url (GET), send_http_request (POST/PUT/PATCH/DELETE), scrape_async, get_job_status, cancel_job, list_jobs, batch_scrape, get_batch_status, get_usage. Start with a default request. Add rendering or routing only when the page needs it; use the tool's error hints rather than enabling the most expensive mode by default.
{
"mcpServers": {
"finedata": {
"command": "npx",
"args": ["-y", "@finedata/mcp-server"],
"env": { "FINEDATA_API_KEY": "fd_your_api_key" }
}
}
} Remote (Streamable HTTP):
{
"mcpServers": {
"finedata": {
"url": "https://mcp.finedata.ai/mcp",
"headers": { "Authorization": "Bearer fd_your_api_key" }
}
}
} Rate Limits
| Plan | Requests/second | Tokens/month | Overage |
|---|---|---|---|
| Free Trial | 5 | 10,000 | Blocked |
| Free | 2 | 1,000 | Blocked |
| PAYG | 10 | Unlimited | $0.55/1K |
| Personal | 20 | 100,000 | $0.55/1K |
| Team S | 50 | 1,000,000 | $0.55/1K |
| Team M | 100 | 3,000,000 | $0.55/1K |
| Team L | 200 | 5,000,000 | $0.55/1K |
| Scaling | 400 | 10,000,000 | $0.55/1K |
Free plans block when exhausted. Paid plans allow overage at $0.55/1K tokens.