Documentation
Integrate Peak's CAPTCHA solving API in minutes. All endpoints return JSON over HTTPS. You are only charged for successful solves.
The Peak API is a REST API that accepts and returns JSON. Every request is authenticated with an API key. Billing is applied per successful solve only — failed or errored requests are never charged.
Billing
Success only
Format
JSON / HTTPS
Auth
API key
Pass your API key via the X-API-Key header on every request.
headers = {
"X-API-Key": "pk_your_api_key",
"Content-Type": "application/json"
}Solves Cloudflare Turnstile widgets and returns a token you submit as the cf-turnstile-response field. Average response time is under 1 second.
task_typestringyesMust be "turnstiletask"sitekeystringyesCloudflare Turnstile sitekey for the target siteurlstringyesTarget page URL — must end with a trailing slash (/)proxystringyesProxy in http://user:pass@ip:port formatactionstringnoTurnstile action value — must match the value configured on the target sitecdatastringnoTurnstile cdata value — must match the value configured on the target sitehttps://example.com/Request
{
"task_type": "turnstiletask",
"url": "https://example.com/",
"sitekey": "0x4AAAAAAAxxxxx",
"proxy": "http://user:pass@1.2.3.4:8080"
}Response
{
"success": true,
"data": {
"token": "0.AgAAABBqzz..."
}
}import requests url = "https://api.peak.fo/solve" headers = { "X-API-Key": "pk_your_api_key", "Content-Type": "application/json" } payload = { "task_type": "turnstiletask", "sitekey": "0x4AAAAAAA...", "url": "https://example.com/", "proxy": "http://user:pass@1.2.3.4:8080" } response = requests.post(url, json=payload, headers=headers) data = response.json() if data["success"]: token = data["data"]["token"] print(f"Token: {token}") else: print(f"Error: {data['error']}")
Solve Cloudflare's browser integrity check. Returns clearance cookies, a matching user-agent, and form attributes needed to complete the challenge on the target site.
task_typestringyesMust be "cloudflare5stask"urlstringyesTarget page URL — must end with a trailing slash (/)proxystringyesSticky/session proxy in http://user:pass@ip:port formatuser_agentstringnoWindows Chrome user-agent (only Windows Chrome is supported)htmlstringnoPre-fetched page HTML — optional optimisation to skip an initial fetchRequest
{
"task_type": "cloudflare5stask",
"url": "https://example.com/",
"proxy": "http://user:pass@1.2.3.4:8080"
}Response
{
"success": true,
"data": {
"cookies": {
"cf_clearance": "xxx",
"__cf_bm": "xxx"
},
"headers": {
"user-agent": "Mozilla/5.0..."
},
"attributes": {
"md": "xxx",
"r": "xxx"
},
"cf_rt": "challenge_token"
}
}Using the response — 4 steps
POST the attributes as form-encoded body to the target URL with Content-Type: application/x-www-form-urlencoded.Referer header to {url}?__cf_chl_tk={cf_rt}.user-agent from the response for all subsequent requests.import requests TARGET_URL = "https://example.com/" PROXY = "http://user:pass@1.2.3.4:8080" # Sticky session proxy # Step 1: Get WAF solution from Peak API response = requests.post( "https://api.peak.fo/solve", headers={ "X-API-Key": "pk_your_api_key", "Content-Type": "application/json" }, json={ "task_type": "cloudflare5stask", "url": TARGET_URL, "proxy": PROXY } ) data = response.json() if not data["success"]: raise Exception(f"Solve failed: {data['error']}") solution = data["data"] clearance = solution["cookies"]["cf_clearance"] cf_bm = solution["cookies"].get("__cf_bm", "") cf_rt = solution["cf_rt"] attributes = solution["attributes"] user_agent = solution["headers"]["user-agent"] # Step 2: Build attributes as form data form_data = "&".join([f"{k}={v}" for k, v in attributes.items()]) # Step 3: Create session with cookies session = requests.Session() session.cookies.set("cf_clearance", clearance, domain="example.com") if cf_bm: session.cookies.set("__cf_bm", cf_bm, domain="example.com") # Step 4: POST to complete the challenge resp = session.post( TARGET_URL, data=form_data, headers={ "User-Agent": user_agent, "Referer": f"{TARGET_URL}?__cf_chl_tk={cf_rt}", "Content-Type": "application/x-www-form-urlencoded", }, proxies={"http": PROXY, "https": PROXY} ) print(f"Status: {resp.status_code}") # Now you can make requests with the session cookies
Generates an AWS WAF challenge token from the mobile SDK. Attach the token to subsequent requests as a header or cookie.
sdk_url extracted from the mobile app binary.task_typestringyesMust be "awswaftask"urlstringyesTarget application domain URLsdk_urlstringyesAWS WAF SDK endpoint extracted from the mobile app (see below)proxystringyesProxy in http://user:pass@ip:port formatuser_agentstringnoMobile app user-agentosstringno"ios" or "android" — auto-detected from user_agent if omittedFinding the SDK URL
The sdk_url is hardcoded in the mobile app and matches this pattern:
HTTP proxyIntercept app traffic with Charles Proxy or mitmproxy and look for requests matching the pattern above.DecompilationDecompile the APK/IPA and search for the awswaf.com URL string.Pattern matchSearch for "edge.sdk.awswaf.com" in the app binary or network logs.Request
{
"task_type": "awswaftask",
"url": "https://app.example.com/",
"sdk_url": "https://xxxxx.edge.sdk.awswaf.com/xxxxx/xxxxx",
"proxy": "http://user:pass@1.2.3.4:8080",
"os": "android"
}Response
{
"success": true,
"data": {
"token": "eyJxxxxxxxxxxxxxx..."
}
}x-aws-waf-token header, or as the aws-waf-token cookie — whichever the target app expects.import requests # Get token from Peak API response = requests.post( "https://api.peak.fo/solve", headers={ "X-API-Key": "pk_your_api_key", "Content-Type": "application/json" }, json={ "task_type": "awswaftask", "url": "https://app.example.com/", "sdk_url": "https://xxxxx.edge.sdk.awswaf.com/xxxxx/xxxxx", "proxy": "http://user:pass@1.2.3.4:8080", "user_agent": "AppName/1.0 (iOS 17.0)" } ) data = response.json() if data["success"]: token = data["data"]["token"] print(f"Token: {token}") # Use token in your requests: # Header: x-aws-waf-token: {token} # Cookie: aws-waf-token={token} else: print(f"Error: {data['error']}")
Returns the current balance or package status for the authenticated API key. Response shape differs by billing type.
Pay-per-solve key
{
"success": true,
"data": {
"type": "pay_per_solve",
"balance": 12.5
}
}Package key
{
"success": true,
"data": {
"type": "package",
"package_name": "Turnstile 500K",
"remaining_solves": 342819,
"total_solves": 500000,
"allowed_tasks": [
"turnstiletask"
],
"expires_at": "2026-06-25T00:00:00Z",
"days_remaining": 30
}
}All errors return {"success":false,"error":"..."}. A 200 with success: false means a non-fatal solve failure — not billed.
200 (failed)Solve failed — error field explains why. Not billed.400Bad request — missing or invalid fields.401Unauthorized — API key missing, invalid, or expired.402Payment required — insufficient balance or package exhausted.503Service unavailable — task type disabled or no solver capacity.missing API keyAdd X-API-Key header to your request.insufficient balanceTop up your balance or purchase a package.package solves exhaustedPackage fully consumed — purchase a new one.Proxy connection failedCheck proxy format: http://user:pass@ip:port and verify it's reachable.Request timed outUse a faster proxy closer to the target server.IP address is blocked by CloudFlareSwitch to a proxy with a cleaner IP reputation.No WAF challenge detectedTarget page has no active challenge, or the URL is wrong.Invalid sitekeyVerify the sitekey matches the domain — it's domain-scoped.Turnstile challenge was flaggedUse a proxy with a cleaner IP reputation.Unsupported user agentOnly Windows Chrome user-agents are supported for WAF tasks.