HTTP API for hCaptcha. Hybrid mode for Discord (different client IP vs VPS). Rule-based solver — Ja/Nein, letter swaps, cache. No AI.
pip install -r requirements-client.txtsolver.py + test_register.py to your machine (no Playwright on client)X-API-Key in test_register.py or env API_KEYpython test_register.py — uses hybrid (solve_hybrid), not /v1/solveIf your script and this API are on different IPs, do not call POST /v1/solve directly — Discord returns invalid-response. Hybrid keeps captcha on your IP; API only returns HSW proofs.
Every API request (except / and /v1/health) requires an API key sent as an HTTP header:
X-API-Key: your-api-key-uuid
Requests without a valid X-API-Key header return 401 Unauthorized.
When your Discord client and this API run on different IPs, use hybrid. The captcha token must be created from your machine's IP — only HSW proofs are offloaded to the API.
getcaptcha / checkcaptcha locally (same IP as Discord).req token, call POST /v1/hsw on this API.solve_hybrid().discord_headers.{
"req": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...",
"host": "discord.com"
}
{
"status": "success",
"request_id": "...",
"proof": "eyJ...",
"host": "discord.com",
"elapsed_ms": 42
}
from solver import solve_hybrid
result = solve_hybrid(
sitekey=captcha["captcha_sitekey"],
host="discord.com",
rqdata=captcha["captcha_rqdata"],
rqtoken=captcha.get("captcha_rqtoken"),
session_id=captcha.get("captcha_session_id"),
solver_url="{{ public_url }}/v1/solve",
api_key="YOUR_API_KEY",
user_agent=your_ua,
)
if result["success"]:
headers = result["discord_headers"]
# retry Discord with headers
solver.py (for solve_hybrid) + pip install -r requirements-client.txt. No Playwright or Ollama on client. See test_register.py for a minimal working example.
POST /v1/solve from VPS with a different IP than Discord will return invalid-response. Use hybrid instead.
Full server-side solve. Use only when solver and target share the same egress IP (or you pass matching proxy). Not for Discord client on a different IP.
| Header | Required | Description |
|---|---|---|
Content-Type | Yes | application/json |
X-API-Key | Yes | Your API key (UUID) |
Send a JSON object with the captcha fields from the target service's challenge response. Only the fields below are required — you do not need to send captcha_key or captcha_service.
| Field | Required | Description |
|---|---|---|
captcha_sitekey |
Required | Dynamic hCaptcha site key from the challenge response |
captcha_host |
Required | Target site hostname (e.g. discord.com) — without https:// |
captcha_rqdata |
Required | Enterprise rqdata — must be passed to the challenge or it will fail |
captcha_rqtoken |
Recommended | Challenge request token — echo back to the target API via X-Captcha-Rqtoken |
captcha_session_id |
Recommended | Session ID — echo back via X-Captcha-Session-Id |
proxy |
Optional | Egress proxy (http://user:pass@host:port or host:port:user:pass). Must match target client IP for Discord. |
use_proxy_pool |
Optional | Set true to rotate through proxies.txt on server. Default: false. |
user_agent |
Optional | Browser user-agent for hCaptcha (should match your client) |
{
"captcha_sitekey": "a9b5fb07-92ff-493f-86fe-352a2803b3df",
"captcha_host": "discord.com",
"captcha_rqdata": "NpQAwki50ByiW9bA16ORoLwoqJAK+lli++HGo9JpzGQqlHh5YRJCVgQmZET91Azw8Ew3NvMPFKO5otO13QFlh+p9hQ73jGXELsyzpVrSy7XenLKZjP0ZhXaGpESvM5SiHghRNdqfK4DwFw==eCjJIAfUkwLnY7m/",
"captcha_rqtoken": "Ikk0VU5GVFhMa2p0SFNNSUZiZEF5YWgvdGZ2Wm45MjFiczFzbnM4cjU3Z3A5dkVKYTdIeFVFRlYyYWpUekRIejZCZ3pxTWc9PVZhTnVXL01LWEQ5UlpYWUEi.alFkGQ.erb42PkoZ_BnN_h32eVSB150WGM",
"captcha_session_id": "d857885d-f307-4c13-9b94-0178beed48a6"
}
{
"status": "success",
"request_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
"captcha_token": "P1_eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...",
"captcha_host": "discord.com",
"elapsed_ms": 4821,
"levels_solved": 3,
"discord_headers": {
"X-Captcha-Key": "P1_eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...",
"X-Captcha-Session-Id": "d857885d-f307-4c13-9b94-0178beed48a6",
"X-Captcha-Rqtoken": "Ikk0VU5GVFhMa2p0SFNNSUZiZEF5YWgvdGZ2..."
}
}
{
"status": "error",
"error": "solve_failed",
"message": "Human-readable description",
"request_id": "...",
"elapsed_ms": 12000
}
| error | Meaning |
|---|---|
missing_api_key | No X-API-Key header provided |
invalid_api_key | API key not recognized |
missing_fields | Required JSON fields absent |
invalid_json | Body is not valid JSON |
solve_failed | Captcha could not be solved |
timeout | Solve exceeded time limit |
queue_full | Server at capacity — retry later |
internal_error | Unexpected server error |
| Code | Meaning |
|---|---|
| 200 | Captcha solved successfully |
| 400 | Invalid or incomplete request body |
| 401 | Missing or invalid API key |
| 422 | Solve attempted but failed |
| 503 | Queue full — too many concurrent requests |
| 504 | Solve timed out |
/v1/solve examples below — Discord will return invalid-response because the captcha token IP ≠ your client IP. Use Hybrid mode (solve_hybrid() or POST /v1/hsw) instead.
from solver import solve_hybrid
result = solve_hybrid(
sitekey=captcha["captcha_sitekey"],
host="discord.com",
rqdata=captcha["captcha_rqdata"],
rqtoken=captcha.get("captcha_rqtoken"),
session_id=captcha.get("captcha_session_id"),
solver_url="{{ public_url }}/v1/solve",
api_key="YOUR_API_KEY",
user_agent=your_ua,
)
if result["success"]:
retry = requests.post(
"https://discord.com/api/v9/auth/register",
json=body,
headers={**your_headers, **result["discord_headers"]},
)
Client needs solver.py + pip install -r requirements-client.txt. Captcha HTTP runs on your IP; API only computes HSW proofs.
import requests
resp = requests.post(
"{{ public_url }}/v1/solve",
headers={
"Content-Type": "application/json",
"X-API-Key": "YOUR_API_KEY",
},
json={
"captcha_sitekey": captcha["captcha_sitekey"],
"captcha_host": "discord.com",
"captcha_rqdata": captcha["captcha_rqdata"],
"captcha_rqtoken": captcha.get("captcha_rqtoken"),
"captcha_session_id": captcha.get("captcha_session_id"),
},
timeout=130,
)
data = resp.json()
if data["status"] == "success":
headers = data["discord_headers"]
# Retry your original Discord request with these headers
retry = requests.post(original_url, json=original_body, headers={**your_headers, **headers})
const res = await fetch("{{ public_url }}/v1/solve", {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-API-Key": "YOUR_API_KEY",
},
body: JSON.stringify({
captcha_sitekey: captcha.captcha_sitekey,
captcha_host: "discord.com",
captcha_rqdata: captcha.captcha_rqdata,
captcha_rqtoken: captcha.captcha_rqtoken,
captcha_session_id: captcha.captcha_session_id,
}),
});
const data = await res.json();
When Discord returns a captcha challenge, retry your original request and attach the headers from discord_headers:
| Header | Value |
|---|---|
X-Captcha-Key | The solved captcha_token |
X-Captcha-Session-Id | Same captcha_session_id from the challenge (if present) |
X-Captcha-Rqtoken | Same captcha_rqtoken from the challenge (if present) |
X-Fingerprint | Same fingerprint used in the request body (required for register/login) |
X-Context-Properties | Base64 context for the action (e.g. register) |
POST /v1/solve solves the captcha from the API server IP — Discord binds the token to that IP and rejects it with invalid-response when your client uses another IP.
https://discord.com/register with the same session. Without cookies + X-Fingerprint, Discord may also return invalid-response.
Public health check. Returns solver: "rules". No authentication required.
Batch rule-based answers (optional — hybrid client solves locally by default). Body: {"instruction": "...", "tasks": [{"task_key": "...", "question": "..."}]}
Service statistics (active solves, cache). Requires X-API-Key.