API Documentation
Everything you need to integrate uncaptcha.dev into your application.
Base URL: https://api.uncaptcha.dev
Quick Start
Get up and running in under 2 minutes. Three steps to your first CAPTCHA solve.
Create an Account
Sign up for a free account at uncaptcha.dev. The free plan includes 100 solves per month with no credit card required.
curl -X POST https://api.uncaptcha.dev/auth/signup \
-H "Content-Type: application/json" \
-d '{"email": "you@example.com", "password": "your-password"}'Get Your API Key
After signing in, go to your Dashboard and create an API key. The key is shown only once -- store it securely.
# Login to get JWT
TOKEN=$(curl -s -X POST https://api.uncaptcha.dev/auth/login \
-H "Content-Type: application/json" \
-d '{"email": "you@example.com", "password": "your-password"}' \
| jq -r '.token')
# Create API key
curl -X POST https://api.uncaptcha.dev/keys \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"name": "My First Key"}'Solve Your First CAPTCHA
Make a single POST request with the site key and page URL. The API returns the solved token.
curl -X POST https://api.uncaptcha.dev/v1/solve/sync \
-H "X-API-Key: ac-your-api-key" \
-H "Content-Type: application/json" \
-d '{
"type": "recaptcha_v2",
"siteKey": "6Le-wvkSAAAAAPBMRTvw0Q4Muexq9bi0DJwx_mJ-",
"pageUrl": "https://www.google.com/recaptcha/api2/demo"
}'/v1/solve/sync) waits up to 120 seconds and returns the token directly. For fire-and-forget workflows, use the async /v1/solve endpoint and poll with /v1/result/:id.Authentication
uncaptcha.dev uses two authentication methods depending on the endpoint type.
API Key Authentication
All /v1/* endpoints (solve, balance, types, report, history) authenticate via the X-API-Key header. Your API key starts with the prefix ac-.
curl https://api.uncaptcha.dev/v1/balance \
-H "X-API-Key: ac-your-api-key-here"JWT Bearer Token
Account management endpoints (/keys, /auth/me) use JWT Bearer token authentication. Obtain a token by calling POST /auth/login. Tokens expire after 7 days.
curl https://api.uncaptcha.dev/keys \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."Endpoints
CAPTCHA Solving
Submit a CAPTCHA for solving. Returns the result immediately with a taskId for reference. The result is also persisted for later retrieval via GET /v1/result/:id.
Auth: X-API-Key
Request Body
{
"type": "recaptcha_v2",
"siteKey": "6Le-wvkSAAAAAPBMRTvw...",
"pageUrl": "https://example.com/login",
"proxy": "http://user:pass@host:port" // optional
}Response
{
"taskId": "550e8400-e29b-41d4-a716-446655440000",
"status": "solved",
"solution": {
"token": "03AGdBq26Hv8..."
},
"captcha_type": "recaptcha_v2",
"elapsed": 6204
}Synchronous solve endpoint. Blocks until the CAPTCHA is solved or the request times out (120s max). Recommended for most integrations.
Auth: X-API-Key
Request Body
{
"type": "recaptcha_v2",
"siteKey": "6Le-wvkSAAAAAPBMRTvw...",
"pageUrl": "https://example.com/login",
"proxy": "http://user:pass@host:port" // optional
}Response
{
"status": "solved",
"token": "03AGdBq26Hv8...",
"captcha_type": "recaptcha_v2",
"elapsed": 6204,
"taskId": "550e8400-e29b-41d4-a716-446655440000"
}Retrieve a previously completed solve result by its taskId. Results are persisted in the database and scoped to your account.
Auth: X-API-Key
Response
{
"taskId": "550e8400-e29b-41d4-a716-446655440000",
"status": "solved",
"solution": {
"token": "03AGdBq26Hv8..."
},
"captcha_type": "recaptcha_v2",
"elapsed": 6204,
"created_at": "2026-03-28T12:00:00.000Z"
}Account & Usage
Check your current plan, usage statistics, and remaining solve quota for the current billing period.
Auth: X-API-Key
Response
{
"plan": "pro",
"period": "2026-03",
"solves_used": 423,
"solves_included": 5000,
"solves_remaining": 4577,
"cost_usd": 4.23
}List all CAPTCHA types currently supported by the API.
Auth: X-API-Key
Response
{
"types": [
"recaptcha_v2", "recaptcha_v3", "recaptcha_ent",
"turnstile", "funcaptcha",
"geetest_v3", "geetest_v4", "aws_waf", "image_captcha",
"datadome"
],
"count": 10
}Report whether a solve result was correct or incorrect. Used for quality monitoring and feedback.
Auth: X-API-Key
Request Body
{
"taskId": "550e8400-e29b-41d4-a716-446655440000",
"correct": false
}Response
{
"success": true,
"taskId": "550e8400-e29b-41d4-a716-446655440000",
"reported": "bad"
}Retrieve your paginated solve history. Filter by CAPTCHA type and control pagination with limit and offset.
Auth: X-API-Key
Query Parameters
limitintegerNumber of results (default: 50, max: 200)offsetintegerPagination offset (default: 0)typestringFilter by CAPTCHA type (e.g. "turnstile")Response
{
"history": [
{
"id": "uuid",
"task_id": "uuid",
"captcha_type": "recaptcha_v2",
"status": "solved",
"cost_usd": 0.01,
"created_at": "2026-03-28T12:00:00.000Z",
"reported": null
}
],
"limit": 50,
"offset": 0
}Authentication
Register a new account. Automatically creates a free subscription with 100 solves/month.
Request Body
{
"email": "you@example.com",
"password": "your-secure-password",
"country": "US" // optional
}Response
{
"token": "eyJhbGciOiJIUzI1NiIs...",
"user": {
"id": "uuid",
"email": "you@example.com",
"plan_id": "free",
"created_at": "2026-03-28T12:00:00.000Z"
}
}Authenticate with email and password. Returns a JWT token valid for 7 days.
Request Body
{
"email": "you@example.com",
"password": "your-secure-password"
}Response
{
"token": "eyJhbGciOiJIUzI1NiIs...",
"user": {
"id": "uuid",
"email": "you@example.com",
"plan_id": "pro"
}
}API Key Management
Create a new API key. The full key (ac-...) is returned only once in the response -- store it securely.
Auth: Bearer JWT
Request Body
{
"name": "Production" // optional label
}Response
{
"id": "uuid",
"key": "ac-a1b2c3d4e5f6...",
"prefix": "ac-a1b2c3d4e5f6",
"name": "Production",
"created_at": "2026-03-28T12:00:00.000Z"
}List all active API keys for your account. Only the key prefix is shown (the full key is not stored).
Auth: Bearer JWT
Response
{
"keys": [
{
"id": "uuid",
"key_prefix": "ac-a1b2c3d4...",
"name": "Production",
"created_at": "2026-03-28T12:00:00.000Z",
"last_used_at": "2026-03-28T14:30:00.000Z"
}
]
}Revoke (deactivate) an API key. The key will immediately stop working for all requests.
Auth: Bearer JWT
Response
{
"success": true
}CAPTCHA Types
uncaptcha.dev supports 10 CAPTCHA types. Pass the type field in your solve request to specify which CAPTCHA to solve.
| Type | Name | Avg. Time | Required Fields | Description |
|---|---|---|---|---|
recaptcha_v2 | reCAPTCHA v2 | ~18s | siteKey, pageUrl | Standard checkbox and image-challenge reCAPTCHA widget |
recaptcha_v3 | reCAPTCHA v3 | ~10s | siteKey, pageUrl, action?, minScore? | Invisible score-based reCAPTCHA. Supports action and minScore parameters |
recaptcha_ent | reCAPTCHA Enterprise | ~18s | siteKey, pageUrl, enterprisePayload? | Google reCAPTCHA Enterprise edition with enterprise payload support |
turnstile | Cloudflare Turnstile | ~8s | siteKey, pageUrl | Cloudflare's privacy-focused CAPTCHA alternative |
funcaptcha | FunCaptcha | ~15s | siteKey, pageUrl, serviceUrl? | Arkose Labs FunCaptcha interactive challenges |
geetest_v3 | GeeTest v3 | ~12s | siteKey, pageUrl, challenge? | GeeTest slide and click challenges (version 3) |
geetest_v4 | GeeTest v4 | ~12s | siteKey, pageUrl | GeeTest v4 adaptive challenges with captcha_id |
aws_waf | AWS WAF | ~20s | siteKey, pageUrl | Amazon Web Services WAF CAPTCHA protection |
image_captcha | Image CAPTCHA | ~5s | image (base64), pageUrl? | Classic image-to-text OCR recognition (PNG, JPEG, WEBP) |
datadome | DataDome | ~15s | captchaUrl, userAgent, proxy | DataDome slider CAPTCHAs (requires proxy) |
DataDome — Special Parameters
DataDome uses different request fields than other CAPTCHA types. Instead of siteKey and pageUrl, you must supply the full CAPTCHA URL, a user agent, and a proxy. A proxy is required — DataDome does not support proxyless solving.
// POST /v1/solve/sync
{
"type": "datadome",
"captchaUrl": "https://geo.captcha-delivery.com/captcha/?initialCid=...&t=fe&...",
"userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 ...",
"proxy": "host:port:user:pass"
}host:port:user:pass. The captchaUrl is the full URL from the DataDome challenge redirect — it begins with https://geo.captcha-delivery.com/captcha/.SDKs
Official client libraries for Python and Node.js. Both SDKs handle authentication, retries, timeout management, and typed error handling out of the box.
Python SDK
pip install uncaptchaSynchronous Usage
from uncaptcha import Uncaptcha
solver = Uncaptcha("ac-your-api-key")
# reCAPTCHA v2
result = solver.recaptcha(
site_key="6Le-wvkSAAAAAPBMRTvw0Q4Muexq9bi0DJwx_mJ-",
page_url="https://www.google.com/recaptcha/api2/demo",
)
print(result["token"])
# Cloudflare Turnstile
result = solver.turnstile(
site_key="0x4AAAAAAABS7vwvV6VFfMcD",
page_url="https://example.com",
)
# reCAPTCHA v3 with action and score
result = solver.recaptcha(
site_key="6LdyC2cUAAAAACGuDKpXeDorzUDWXmdqeg-xy696",
page_url="https://example.com",
version="v3",
action="login",
min_score=0.9,
)
# Check balance
balance = solver.balance()
print(f"Used {balance['solves_used']} of {balance['solves_included']}")Async Usage
from uncaptcha import AsyncUncaptcha
async with AsyncUncaptcha("ac-your-api-key") as solver:
result = await solver.recaptcha(
site_key="6Le-wvkSAAAAAPBMRTvw0Q4Muexq9bi0DJwx_mJ-",
page_url="https://www.google.com/recaptcha/api2/demo",
)
print(result["token"])pip install uncaptcha[async] for async support (includes aiohttp).Node.js SDK
npm install uncaptchaimport { Uncaptcha } from 'uncaptcha';
const solver = new Uncaptcha('ac-your-api-key');
// reCAPTCHA v2
const { token } = await solver.recaptcha({
siteKey: '6Le-wvkSAAAAAPBMRTvw0Q4Muexq9bi0DJwx_mJ-',
pageUrl: 'https://www.google.com/recaptcha/api2/demo',
});
console.log(token);
// Cloudflare Turnstile
const turnstile = await solver.turnstile({
siteKey: '0x4AAAAAAABS7vwvV6VFfMcD',
pageUrl: 'https://example.com',
});
// reCAPTCHA v3 with action
const v3 = await solver.recaptcha({
siteKey: '6LdyC2cUAAAAACGuDKpXeDorzUDWXmdqeg-xy696',
pageUrl: 'https://example.com',
version: 'v3',
action: 'login',
minScore: 0.9,
});
// Check balance
const balance = await solver.balance();
console.log(`Used ${balance.solves_used} of ${balance.solves_included}`);
// List supported types
const { types } = await solver.types();
console.log('Supported:', types.join(', '));Available Methods
recaptcha(params)Solve reCAPTCHA v2, v3, or Enterpriseturnstile(params)Solve Cloudflare Turnstilehcaptcha(params)Solve hCaptchafuncaptcha(params)Solve FunCaptcha / Arkose Labsgeetest(params)Solve GeeTest v3 or v4awsWaf(params)Solve AWS WAF CAPTCHAimage(params)Solve image CAPTCHA via OCRbalance()Get account balance and usagetypes()List supported CAPTCHA typesMCP Integration
The fastest way to add CAPTCHA solving to your AI agent. One command gives Claude Code or Cursor the ability to solve any CAPTCHA.
Claude Code — Quick Setup (Recommended)
One command configures everything — MCP server, API key, and CLAUDE.md instructions:
npx uncaptcha-mcp setupThis registers the MCP server in Claude Code, prompts for your API key, and adds CAPTCHA-solving instructions to your project's CLAUDE.md so Claude automatically knows how to solve CAPTCHAs.
Manual Setup
Or add the MCP server manually:
claude mcp add uncaptcha -e UNCAPTCHA_API_KEY=ac-your-key -- npx uncaptcha-mcpCursor
Add the following to your .cursor/mcp.json file:
{
"mcpServers": {
"uncaptcha": {
"command": "npx",
"args": ["uncaptcha-mcp"],
"env": {
"UNCAPTCHA_API_KEY": "ac-your-api-key-here"
}
}
}
}Available MCP Tools
captcha_detectcaptcha_detect(url)Auto-detect CAPTCHA type and site key from a page URL. Use this before captcha_solve when you only have the URL. No API key required.
captcha_solvecaptcha_solve(siteKey, pageUrl, type?, action?)Solve any CAPTCHA and return the token. Default type is recaptcha_v2.
captcha_balancecaptcha_balance()Check your plan, usage stats, and remaining solves for the current period.
captcha_typescaptcha_types()List all CAPTCHA types currently supported by the API.
captcha_reportcaptcha_report(taskId, correct)Report a solve as correct or incorrect for quality feedback.
Chrome Extension
The uncaptcha.dev Chrome Extension automatically detects and solves CAPTCHAs as you browse. Supports reCAPTCHA v2, reCAPTCHA v3, Cloudflare Turnstile, and hCaptcha.
Installation
chrome://extensions/ in ChromeHow It Works
Detect
Content script scans the DOM for CAPTCHA widgets using selectors and MutationObserver. Re-scans at 1.5s and 4s for late-loading widgets.
Solve
Sends the site key and page URL to POST /v1/solve/sync via the service worker. Returns a solved token in seconds.
Inject
Injects the token into the page by setting response textareas, firing callbacks, and overriding getResponse() methods.
Proxy Support
Pass a proxy field in your solve request to route the CAPTCHA solving through your own proxy. This is useful for geo-targeting or matching the IP that your application uses.
Supported Formats
// HTTP proxy with authentication
{
"type": "recaptcha_v2",
"siteKey": "6Le-abc...",
"pageUrl": "https://example.com",
"proxy": "http://username:password@proxy-host:8080"
}
// SOCKS5 proxy
{
"type": "turnstile",
"siteKey": "0x4AAA...",
"pageUrl": "https://example.com",
"proxy": "socks5://user:pass@host:1080"
}
// IP:Port only (no auth)
{
"type": "recaptcha_v3",
"siteKey": "6Ldy...",
"pageUrl": "https://example.com",
"proxy": "http://203.0.113.1:3128"
}from uncaptcha import Uncaptcha
solver = Uncaptcha("ac-your-api-key")
result = solver.recaptcha(
site_key="6Le-abc...",
page_url="https://example.com",
proxy="http://user:pass@proxy:8080",
)
print(result["token"])Error Codes
All API responses use standard HTTP status codes. Error responses include a JSON body with an error field describing the issue.
| Code | Status | Description |
|---|---|---|
200 | OK | Request succeeded. The response body contains the requested data. |
400 | Bad Request | Missing or invalid parameters. Check the error message for specifics. |
401 | Unauthorized | Invalid or missing API key (X-API-Key) or JWT (Authorization: Bearer). |
402 | Payment Required | Monthly quota exceeded. Upgrade your plan or wait for the next billing cycle. |
404 | Not Found | The requested task ID does not exist or has expired. |
429 | Too Many Requests | Rate limited (300 req/min per IP). Back off and retry after the Retry-After header value. |
500 | Internal Error | Server error. Contact support if the issue persists. |
Error Response Format
{
"error": "bad_request",
"message": "siteKey and pageUrl are required"
}429 responses, check the Retry-After header for the number of seconds to wait before retrying. The rate limit is 300 requests per minute per IP.Examples
Complete, copy-paste-ready code examples for common use cases.
Python
reCAPTCHA v2 (using SDK)
from uncaptcha import Uncaptcha
solver = Uncaptcha("ac-your-api-key")
# Solve reCAPTCHA v2
result = solver.recaptcha(
site_key="6Le-wvkSAAAAAPBMRTvw0Q4Muexq9bi0DJwx_mJ-",
page_url="https://www.google.com/recaptcha/api2/demo",
)
print(f"Token: {result['token'][:50]}...")
# Use the token in a form submission
import requests
response = requests.post("https://example.com/submit", data={
"g-recaptcha-response": result["token"],
"username": "user",
"password": "pass",
})
print(f"Status: {response.status_code}")Turnstile (using requests directly)
import requests
response = requests.post(
"https://api.uncaptcha.dev/v1/solve/sync",
headers={
"X-API-Key": "ac-your-api-key",
"Content-Type": "application/json",
},
json={
"type": "turnstile",
"siteKey": "0x4AAAAAAABS7vwvV6VFfMcD",
"pageUrl": "https://example.com",
},
timeout=130,
)
data = response.json()
if data.get("status") == "solved":
print(f"Solved in {data['elapsed']}ms")
print(f"Token: {data['token'][:50]}...")
else:
print(f"Failed: {data}")Image CAPTCHA (OCR)
from pathlib import Path
from uncaptcha import Uncaptcha
solver = Uncaptcha("ac-your-api-key")
# From file path
result = solver.image(Path("captcha.png"))
print(f"Text: {result['token']}")
# From base64 string
import base64
with open("captcha.png", "rb") as f:
b64 = base64.b64encode(f.read()).decode()
result = solver.image(b64)
print(f"Text: {result['token']}")Node.js
reCAPTCHA v2 (using SDK)
import { Uncaptcha } from 'uncaptcha';
const solver = new Uncaptcha('ac-your-api-key');
// Solve reCAPTCHA v2
const { token } = await solver.recaptcha({
siteKey: '6Le-wvkSAAAAAPBMRTvw0Q4Muexq9bi0DJwx_mJ-',
pageUrl: 'https://www.google.com/recaptcha/api2/demo',
});
console.log('Token:', token.substring(0, 50) + '...');
// Use the token in a form submission
const response = await fetch('https://example.com/submit', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
'g-recaptcha-response': token,
username: 'user',
password: 'pass',
}),
});
console.log('Status:', response.status);Turnstile (using fetch directly)
const response = await fetch('https://api.uncaptcha.dev/v1/solve/sync', {
method: 'POST',
headers: {
'X-API-Key': 'ac-your-api-key',
'Content-Type': 'application/json',
},
body: JSON.stringify({
type: 'turnstile',
siteKey: '0x4AAAAAAABS7vwvV6VFfMcD',
pageUrl: 'https://example.com',
}),
signal: AbortSignal.timeout(130_000),
});
const data = await response.json();
if (data.status === 'solved') {
console.log(`Solved in ${data.elapsed}ms`);
console.log('Token:', data.token.substring(0, 50) + '...');
} else {
console.error('Failed:', data);
}Error Handling
import { Uncaptcha, AuthenticationError, QuotaExceededError, NetworkError } from 'uncaptcha';
const solver = new Uncaptcha('ac-your-api-key');
try {
const { token } = await solver.recaptcha({
siteKey: '6Le-abc...',
pageUrl: 'https://example.com',
});
console.log('Solved:', token);
} catch (err) {
if (err instanceof AuthenticationError) {
console.error('Invalid API key. Check your dashboard.');
} else if (err instanceof QuotaExceededError) {
console.error('Monthly quota exceeded. Upgrade your plan.');
} else if (err instanceof NetworkError) {
console.error('Network issue. Retrying...');
} else {
console.error('Unexpected error:', err.message);
}
}cURL
Synchronous Solve
curl -X POST https://api.uncaptcha.dev/v1/solve/sync \
-H "X-API-Key: ac-your-api-key" \
-H "Content-Type: application/json" \
-d '{
"type": "recaptcha_v2",
"siteKey": "6Le-wvkSAAAAAPBMRTvw0Q4Muexq9bi0DJwx_mJ-",
"pageUrl": "https://www.google.com/recaptcha/api2/demo"
}'Async Solve + Poll
# Step 1: Submit the solve request
RESPONSE=$(curl -s -X POST https://api.uncaptcha.dev/v1/solve \
-H "X-API-Key: ac-your-api-key" \
-H "Content-Type: application/json" \
-d '{
"type": "turnstile",
"siteKey": "0x4AAAAAAABS7vwvV6VFfMcD",
"pageUrl": "https://example.com"
}')
echo "$RESPONSE"
# Step 2: Extract the taskId and retrieve the result
TASK_ID=$(echo "$RESPONSE" | jq -r '.taskId')
curl -s https://api.uncaptcha.dev/v1/result/$TASK_ID \
-H "X-API-Key: ac-your-api-key" | jq .Check Balance
curl -s https://api.uncaptcha.dev/v1/balance \
-H "X-API-Key: ac-your-api-key" | jq .Report Solve Quality
curl -X POST https://api.uncaptcha.dev/v1/report \
-H "X-API-Key: ac-your-api-key" \
-H "Content-Type: application/json" \
-d '{
"taskId": "550e8400-e29b-41d4-a716-446655440000",
"correct": true
}'View Solve History
# Latest 20 solves
curl -s "https://api.uncaptcha.dev/v1/history?limit=20" \
-H "X-API-Key: ac-your-api-key" | jq .
# Filter by type
curl -s "https://api.uncaptcha.dev/v1/history?type=turnstile&limit=10" \
-H "X-API-Key: ac-your-api-key" | jq .