По сути миграция с EndCaptcha на CaptchaAI сводится к трём заменам:
- пара «имя пользователя + пароль» → один API-ключ;
- SOAP/XML-вызовы → два REST-эндпоинта,
in.phpиres.php; - разбор XML → разбор JSON.
Логика «отправить задачу → опрашивать результат» остаётся прежней, поэтому переписывать интеграцию с нуля не нужно. Ниже каждый вызов EndCaptcha сопоставлен с эквивалентом CaptchaAI, приведён готовый код на Python и Node.js и план параллельного перехода без простоя.
Чем отличается архитектура API
EndCaptcha построен на SOAP/XML, CaptchaAI — на REST: запрос уходит обычным HTTP-методом, ответ приходит в JSON.
| Аспект | EndCaptcha | CaptchaAI |
|---|---|---|
| Протокол | SOAP/XML или HTTP POST | HTTP POST/GET (REST) |
| Отправка задачи | /Captcha/Upload или WSDL |
https://ocr.captchaai.com/in.php |
| Получение результата | /Captcha/GetText или WSDL |
https://ocr.captchaai.com/res.php |
| Авторизация | Имя пользователя + пароль | API-ключ |
| Формат ответа | XML/собственный | JSON (json=1) или обычный текст |
Соответствие параметров запроса
Главное отличие — вместо двух полей аутентификации у CaptchaAI один key.
| Параметр EndCaptcha | Параметр CaptchaAI | Примечания |
|---|---|---|
username |
key |
В CaptchaAI один API-ключ |
password |
— | Не нужен; аутентификацию покрывает API-ключ |
captchaData (base64) |
body (base64) |
Те же данные изображения в base64 |
captchaType |
method |
Разные идентификаторы типов |
siteKey |
googlekey |
Для типов reCAPTCHA |
pageUrl |
pageurl |
Та же концепция, другой регистр букв |
captchaId |
id |
ID задачи для опроса |
Соответствие типов CAPTCHA
Числовые коды captchaType заменяются именами методов CaptchaAI.
| Тип EndCaptcha | Метод CaptchaAI | Параметры CaptchaAI |
|---|---|---|
| Капча-изображение | method=base64 |
body={base64_image} |
| reCAPTCHA v2 | method=userrecaptcha |
googlekey, pageurl |
Важное отличие в покрытии: hCaptcha CaptchaAI пока не поддерживает (❌), поэтому не переносите вызовы hCaptcha в код миграции — для них понадобится отдельное решение. CaptchaAI решает reCAPTCHA v2/v3, Cloudflare Turnstile и Challenge, GeeTest v3, изображения, grid и BLS.
На что обратить внимание после переноса
Правок в коде чаще всего требуют три вещи: аутентификация, чтение поля ошибки и вспомогательные операции (баланс, жалоба на решение). Держите эту таблицу под рукой, пока переписываете функции.
| Область | EndCaptcha | CaptchaAI |
|---|---|---|
| Аутентификация | Пара «имя пользователя + пароль» | Единый API-ключ |
| Формат ошибки | Собственный JSON с полем error |
Стандартное поле request с кодами ошибок |
| Опрос результата | POST на отдельный эндпоинт | GET-запрос к res.php с параметрами |
| Проверка баланса | Отдельный метод SOAP | res.php?action=getbalance&key=KEY |
| Жалоба на решение | Отдельный метод | res.php?action=reportbad&id=ID&key=KEY |
Перенос кода: до и после
Структура функции не меняется — отправка, цикл опроса, возврат; меняются URL, поля запроса и разбор ответа.
Python: было (EndCaptcha)
import requests
USERNAME = "your_endcaptcha_user"
PASSWORD = "your_endcaptcha_pass"
def solve_image_endcaptcha(image_base64):
# EndCaptcha image solve
resp = requests.post("https://api.endcaptcha.com/Captcha/Upload", data={
"username": USERNAME,
"password": PASSWORD,
"captchaData": image_base64,
"captchaType": "1"
})
result = resp.json()
captcha_id = result.get("captchaId")
import time
for _ in range(30):
time.sleep(5)
poll = requests.post("https://api.endcaptcha.com/Captcha/GetText", data={
"username": USERNAME,
"password": PASSWORD,
"captchaId": captcha_id
})
poll_result = poll.json()
if poll_result.get("text"):
return {"solution": poll_result["text"]}
if poll_result.get("error"):
return {"error": poll_result["error"]}
return {"error": "TIMEOUT"}
Python: стало (CaptchaAI)
import os
import time
import requests
API_KEY = os.environ["CAPTCHAAI_API_KEY"]
def solve_image_captchaai(image_base64):
resp = requests.post("https://ocr.captchaai.com/in.php", data={
"key": API_KEY,
"method": "base64",
"body": image_base64,
"json": 1
})
data = resp.json()
if data.get("status") != 1:
return {"error": data.get("request")}
captcha_id = data["request"]
for _ in range(30):
time.sleep(5)
result = requests.get("https://ocr.captchaai.com/res.php", params={
"key": API_KEY,
"action": "get",
"id": captcha_id,
"json": 1
}).json()
if result.get("status") == 1:
return {"solution": result["request"]}
if result.get("request") != "CAPCHA_NOT_READY":
return {"error": result.get("request")}
return {"error": "TIMEOUT"}
Обратите внимание на разбор ответа: успех — это status == 1, а само решение лежит в поле request, а не в text, как было у EndCaptcha.
Python: reCAPTCHA v2 (CaptchaAI)
def solve_recaptcha_v2(sitekey, pageurl):
resp = requests.post("https://ocr.captchaai.com/in.php", data={
"key": API_KEY,
"method": "userrecaptcha",
"googlekey": sitekey,
"pageurl": pageurl,
"json": 1
})
data = resp.json()
if data.get("status") != 1:
return {"error": data.get("request")}
captcha_id = data["request"]
for _ in range(60):
time.sleep(5)
result = requests.get("https://ocr.captchaai.com/res.php", params={
"key": API_KEY, "action": "get",
"id": captcha_id, "json": 1
}).json()
if result.get("status") == 1:
return {"solution": result["request"]}
if result.get("request") != "CAPCHA_NOT_READY":
return {"error": result.get("request")}
return {"error": "TIMEOUT"}
Для токен-капч (reCAPTCHA, Turnstile) увеличьте число итераций опроса: они решаются дольше, чем изображения, поэтому здесь цикл рассчитан на 60 попыток вместо 30.
JavaScript: было (EndCaptcha)
const axios = require("axios");
const USERNAME = "your_endcaptcha_user";
const PASSWORD = "your_endcaptcha_pass";
async function solveImageEndCaptcha(imageBase64) {
const submit = await axios.post("https://api.endcaptcha.com/Captcha/Upload", {
username: USERNAME,
password: PASSWORD,
captchaData: imageBase64,
captchaType: "1",
});
const captchaId = submit.data.captchaId;
for (let i = 0; i < 30; i++) {
await new Promise((r) => setTimeout(r, 5000));
const poll = await axios.post("https://api.endcaptcha.com/Captcha/GetText", {
username: USERNAME,
password: PASSWORD,
captchaId,
});
if (poll.data.text) return { solution: poll.data.text };
if (poll.data.error) return { error: poll.data.error };
}
return { error: "TIMEOUT" };
}
JavaScript: стало (CaptchaAI)
const axios = require("axios");
const API_KEY = process.env.CAPTCHAAI_API_KEY;
async function solveImageCaptchaAI(imageBase64) {
const submit = await axios.post("https://ocr.captchaai.com/in.php", null, {
params: { key: API_KEY, method: "base64", body: imageBase64, json: 1 },
});
if (submit.data.status !== 1) return { error: submit.data.request };
const captchaId = submit.data.request;
for (let i = 0; i < 30; i++) {
await new Promise((r) => setTimeout(r, 5000));
const poll = await axios.get("https://ocr.captchaai.com/res.php", {
params: { key: API_KEY, action: "get", id: captchaId, json: 1 },
});
if (poll.data.status === 1) return { solution: poll.data.request };
if (poll.data.request !== "CAPCHA_NOT_READY") return { error: poll.data.request };
}
return { error: "TIMEOUT" };
}
Диагностика типичных ошибок
| Проблема | Причина | Решение |
|---|---|---|
ERROR_KEY_DOES_NOT_EXIST |
Используется имя пользователя EndCaptcha вместо API-ключа | Возьмите API-ключ CaptchaAI из панели управления |
| Ошибка разбора ответа | Другая структура JSON | Проверяйте поля status и request, а не captchaId/text |
Отсутствует параметр method |
В EndCaptcha тип задаётся числовым captchaType |
Сопоставьте с именами методов CaptchaAI (base64, userrecaptcha) |
| Тайм-аут на reCAPTCHA | Другие тайм-ауты по умолчанию | Задайте опрос 60 итераций × 5 с для токен-капч |
Чек-лист миграции
| Шаг | Статус |
|---|---|
| Создать аккаунт CaptchaAI и получить API-ключ | ☐ |
| Сопоставить все вызовы EndCaptcha с эквивалентами CaptchaAI | ☐ |
| Заменить аутентификацию (имя пользователя/пароль → API-ключ) | ☐ |
Обновить эндпоинт отправки (/Captcha/Upload → /in.php) |
☐ |
Обновить эндпоинт опроса (/Captcha/GetText → /res.php) |
☐ |
Обновить разбор ответа (status / request) |
☐ |
| Прогнать параллельный тест с обоими провайдерами | ☐ |
| Переключить боевой трафик | ☐ |
| Удалить учётные данные EndCaptcha | ☐ |
Параллельный прогон удобно встроить в существующий пайплайн: например, агентство в Алма-Ате неделю шлёт каждую капчу в оба сервиса, сравнивает решения и время ответа и только потом убирает EndCaptcha. Для команд, выставляющих счета в нестабильной валюте, оплата по потокам в USD (от BASIC — $15/мес, 5 потоков) делает бюджет предсказуемым: вы платите за число одновременных потоков, а не за каждое решение.
Частые вопросы
Нужно ли переписывать логику опроса при переходе на CaptchaAI?
Нет, цикл остаётся тем же: отправили задачу, получили id, опрашиваете res.php. Меняется критерий готовности — вместо поля text проверяете status == 1, а «ещё не готово» приходит как request == "CAPCHA_NOT_READY".
Что делать с hCaptcha после перехода с EndCaptcha?
hCaptcha пока не входит в поддерживаемые типы CaptchaAI (❌), поэтому не переносите такие вызовы «как есть». CaptchaAI решает reCAPTCHA v2/v3, Turnstile и Cloudflare Challenge, GeeTest v3, изображения, grid и BLS; CaptchaFox (beta), Friendly Captcha (beta) и Lemin (beta) — в бета-режиме.
Можно ли оставить ту же настройку прокси?
Да. CaptchaAI принимает proxy=user:pass@host:port и proxytype=HTTP|SOCKS5, как и большинство сервисов. Значения прокси из конфигурации EndCaptcha переносятся напрямую.
Как проверить баланс через API?
Через res.php доступны служебные действия, которые в EndCaptcha были отдельными методами:
action=getbalance— вернуть текущий баланс;action=reportbad&id=ID— пожаловаться на неверное решение.
Тарификация идёт по числу одновременных потоков: поток — это одна капча в обработке, число решений в месяц на поток не ограничено.