API documentation
Integrate CaptchaForge in minutes. One endpoint solves image/text CAPTCHAs with AI vision, and reCAPTCHA / hCaptcha / Cloudflare Turnstile via a human-solver network. Base URL: https://tricketapp.com/api
Introduction
Send a CAPTCHA, get the answer. Image & text CAPTCHAs are solved synchronously — you get the solution in the same response. Token CAPTCHAs (reCAPTCHA v2, hCaptcha, Turnstile) are queued to the human-solver network: you receive a taskId and poll /result until a token comes back.
Authentication
Every request needs your API key as a bearer token. You'll be given a key that looks like cf_live_…. For quick testing without a key, the shared demo key cf_demo_live_key also works.
Authorization: Bearer YOUR_API_KEYImage & text CAPTCHAs
POST a base64 data URL (or raw base64). The answer comes back in the same response — no polling.
curl https://tricketapp.com/api/solve \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"type": "image",
"image": "data:image/png;base64,iVBORw0KGgo..."
}'
# Response
{
"status": "solved",
"taskId": "task_xxx",
"solution": "A7K9P",
"engine": "claude-vision",
"confidence": 0.97,
"solveMs": 980
}reCAPTCHA / hCaptcha / Turnstile
Provide the sitekey and pageurl. Supported type values: recaptcha_v2, hcaptcha, turnstile. Poll /result until the token is returned.
# 1) Queue the CAPTCHA (reCAPTCHA v2 / hCaptcha / Turnstile)
curl https://tricketapp.com/api/solve \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"type": "turnstile",
"sitekey": "0x4AAAAAAA...",
"pageurl": "https://yoursite.com/login"
}'
# → { "status": "queued", "taskId": "task_xxx", "pollUrl": "/api/result?id=task_xxx" }
# 2) Poll until solved
curl "https://tricketapp.com/api/result?id=task_xxx" \
-H "Authorization: Bearer YOUR_API_KEY"
# → { "status": "solved", "token": "0.cf-..." }Proxy fetch + solve
POST /api/fetch retrieves a URL through a proxy you supply (your own, or a licensed proxy provider), returns the page, and detects which CAPTCHA it presents. With solveCaptcha: true it queues the detected token CAPTCHA to the solver network and returns a taskId to poll. You then submit the token to the target yourself.
Note: browser-integrity challenges (Cloudflare "checking your browser", Bot Fight) are detected and reported (status: "blocked") — they are not bypassed. Use an authorized proxy/session for the target.
# Fetch a URL through YOUR proxy and detect/solve any CAPTCHA on it
curl https://tricketapp.com/api/fetch \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://target.com/page",
"proxy": "http://user:pass@proxy-host:port",
"solveCaptcha": true,
"includeHtml": false
}'
# Response
{
"status": "ok", # or "blocked" (anti-bot challenge detected)
"httpStatus": 200,
"finalUrl": "https://target.com/page",
"via": "proxy",
"fetchMs": 1840,
"captcha": { # present only if a CAPTCHA was found
"type": "turnstile",
"sitekey": "0x4AAA...",
"solve": { "taskId": "task_xxx", "pollUrl": "/api/result?id=task_xxx", "status": "queued" }
},
"html": "<!doctype html>..." # preview unless includeHtml:true
}
# Then poll /result for the token and submit it to the target yourself.Node.js client
const API = "https://tricketapp.com/api";
const KEY = process.env.TRICKET_API_KEY; // the key shared with you
const headers = { "Content-Type": "application/json", Authorization: `Bearer ${KEY}` };
// Image / text CAPTCHA — one call, synchronous
async function solveImage(base64DataUrl) {
const r = await fetch(`${API}/solve`, {
method: "POST", headers,
body: JSON.stringify({ type: "image", image: base64DataUrl }),
});
const j = await r.json();
if (j.status !== "solved") throw new Error(j.error || "solve failed");
return j.solution;
}
// Token CAPTCHA — queue then poll
async function solveToken(type, sitekey, pageurl) {
const q = await (await fetch(`${API}/solve`, {
method: "POST", headers, body: JSON.stringify({ type, sitekey, pageurl }),
})).json();
if (!q.taskId) throw new Error(q.error || "could not queue");
for (let i = 0; i < 60; i++) {
await new Promise((res) => setTimeout(res, 3000));
const r = await (await fetch(`${API}/result?id=${q.taskId}`, { headers })).json();
if (r.status === "solved") return r.token;
if (r.status === "failed") throw new Error("solve failed");
}
throw new Error("timed out");
}
// Fetch a page through YOUR proxy, then solve any token CAPTCHA on it
async function fetchAndSolve(url, proxy) {
const f = await (await fetch(`${API}/fetch`, {
method: "POST", headers,
body: JSON.stringify({ url, proxy, solveCaptcha: true, includeHtml: true }),
})).json();
if (f.status === "blocked") throw new Error("anti-bot challenge: " + f.blocked);
if (!f.captcha?.solve) return { html: f.html, token: null }; // no captcha on page
const taskId = f.captcha.solve.taskId;
for (let i = 0; i < 60; i++) {
await new Promise((res) => setTimeout(res, 3000));
const r = await (await fetch(`${API}/result?id=${taskId}`, { headers })).json();
if (r.status === "solved") return { html: f.html, token: r.token, captcha: f.captcha };
if (r.status === "failed") throw new Error("solve failed");
}
throw new Error("timed out");
}Python client
import os, time, requests
API = "https://tricketapp.com/api"
KEY = os.environ["TRICKET_API_KEY"]
H = {"Authorization": f"Bearer {KEY}", "Content-Type": "application/json"}
def solve_image(base64_data_url: str) -> str:
r = requests.post(f"{API}/solve",
json={"type": "image", "image": base64_data_url}, headers=H).json()
if r["status"] != "solved":
raise RuntimeError(r.get("error", "solve failed"))
return r["solution"]
def solve_token(captcha_type: str, sitekey: str, pageurl: str) -> str:
q = requests.post(f"{API}/solve",
json={"type": captcha_type, "sitekey": sitekey, "pageurl": pageurl}, headers=H).json()
task_id = q.get("taskId")
for _ in range(60):
time.sleep(3)
r = requests.get(f"{API}/result", params={"id": task_id}, headers=H).json()
if r["status"] == "solved":
return r["token"]
if r["status"] == "failed":
raise RuntimeError("solve failed")
raise TimeoutError()
def fetch_and_solve(url: str, proxy: str):
f = requests.post(f"{API}/fetch",
json={"url": url, "proxy": proxy, "solveCaptcha": True, "includeHtml": True},
headers=H).json()
if f["status"] == "blocked":
raise RuntimeError("anti-bot challenge: " + str(f.get("blocked")))
solve = (f.get("captcha") or {}).get("solve")
if not solve:
return {"html": f["html"], "token": None} # no captcha on page
for _ in range(60):
time.sleep(3)
r = requests.get(f"{API}/result", params={"id": solve["taskId"]}, headers=H).json()
if r["status"] == "solved":
return {"html": f["html"], "token": r["token"], "captcha": f["captcha"]}
if r["status"] == "failed":
raise RuntimeError("solve failed")
raise TimeoutError()Request parameters
POST /api/solve
| Field | Required | Description |
|---|---|---|
| type | yes | image | text | recaptcha_v2 | hcaptcha | turnstile |
| image | image/text | Base64 data URL or raw base64 of the CAPTCHA |
| sitekey | token types | The site's CAPTCHA sitekey |
| pageurl | token types | URL of the page the CAPTCHA appears on |
POST /api/fetch
| Field | Required | Description |
|---|---|---|
| url | yes | Target URL (http/https; internal/loopback hosts blocked) |
| proxy | no | Your proxy: http://user:pass@host:port (CONNECT-tunneled for https) |
| method | no | HTTP method — default GET |
| headers | no | Object of extra request headers |
| body | no | Request body (for POST/PUT) |
| solveCaptcha | no | true → auto-queue a detected token CAPTCHA, returns a taskId |
| includeHtml | no | true → full body; default returns a 2 KB preview |
API reference
| Method | Path | Purpose |
|---|---|---|
| POST | /api/solve | Solve image, or queue a token CAPTCHA |
| POST | /api/fetch | Fetch a URL via your proxy + detect/solve CAPTCHA |
| GET | /api/result?id= | Poll a queued task for its token/solution |
| GET | /api/usage | Your usage stats |
| GET | /api/health | Service status & engines |
Status & errors
| status | Meaning |
|---|---|
| solved | Done — read solution (image) or token (token captcha) |
| queued / processing | Token captcha in progress — keep polling /result |
| failed | Could not solve — not charged; retry |
| error | Bad request (e.g. 401 invalid key, 400 missing field) |
401 — invalid/missing key. 400 — missing/invalid field. Failed solves are not billed. If a client repeatedly fails, those errors are recorded in our logs so we can investigate and improve the service.
Acceptable use
Use this API for accessibility, QA automation, monitoring and authorized automation on sites you own or have permission to automate. Fraud, spam, and circumventing the access controls of services you are not authorized to use are prohibited.