# Capsola API — документация целиком # Введение Источник: https://capsola.space/docs/ ## Введение Capsola — сервис распознавания капч по API. Вы отправляете задачу, мы возвращаем решение. Оплачиваются только успешные решения. ### Как начать 1. Зарегистрируйтесь — стартовый баланс начисляется автоматически, платить сразу не нужно. 2. Скопируйте API-ключ в личном кабинете, на странице «Обзор». 3. Отправьте первую задачу — примеры запросов в разделах по типам капч. ### Адрес API Все запросы идут на один адрес: ``` https://api.capsola.cloud ``` Ключ передаётся в заголовке `X-API-Key`, тело запроса — JSON: ```http POST /create HTTP/1.1 Host: api.capsola.cloud X-API-Key: API_KEY Content-Type: application/json ``` ### Ограничение доступа по IP По умолчанию ключ работает с любого адреса. Если в кабинете, в разделе «Белый список», добавить хотя бы один IP, запросы будут приниматься только с перечисленных адресов. Пустой список означает «отовсюду» — это важно помнить, удаляя последнюю запись. ### Что дальше - **[Интеграция](/docs/integration)** — как опрашивать результат, держать соединение и обрабатывать ошибки - **[Силуэты](/docs/smartcaptcha)** — клик по силуэтам на картинке - **[Калейдоскоп](/docs/pazlcaptcha)** — сдвиньте элемент до совпадения - **[Текстовая](/docs/textcaptcha)** — текст с картинки - **[Баланс](/docs/balance)** — проверка остатка на счету - **[Коды ошибок](/docs/errors)** — что означает каждый ответ --- # Интеграция Источник: https://capsola.space/docs/integration На этой странице — правила, от которых зависит скорость и надёжность: когда опрашивать результат, как держать соединение, что делать с каждой ошибкой. Если интеграцию пишет ИИ-ассистент, дайте ему эту страницу целиком — в конце есть готовое задание для него. ## Как проходит задача 1. `POST /create` принимает капчу и сразу возвращает идентификатор задачи. 2. `POST /result` по этому идентификатору возвращает ответ или `CAPCHA_NOT_READY`, если задача ещё решается. Сколько ждать ответа, зависит от капчи: | Капча | Когда готов ответ | | --- | --- | | Большинство | меньше чем за секунду | | Сложные | несколько секунд | Поэтому главное правило — **первый опрос через 1 секунду** после `/create`: к этому моменту ответ обычно уже готов, а пауза длиннее — потеря времени на каждой задаче. ## Что отправлять Тело `/create` — JSON с полем `type` и полями своего типа капчи. Остальное — опрос, соединение, ошибки — у всех типов одинаковое. | Капча | `type` | Поля `/create` | Ответ `/result` | | --- | --- | --- | --- | | [Силуэты](/docs/smartcaptcha) | `SmartCaptcha` | `click`, `task` — картинки | координаты точек в порядке клика: `coordinates:x=..,y=..;...` | | [Калейдоскоп](/docs/pazlcaptcha), версия 1 | `PazlCaptcha` | `task` — HTML страницы | номер шага, на котором пазл сложен | | [Калейдоскоп](/docs/pazlcaptcha), версия 2 | `PazlCaptchaV2` | `image` — картинка, `task` — список перестановок | номер шага, на котором пазл сложен | | [Текстовая](/docs/textcaptcha) | `TextCaptcha` | `task` — картинка | текст с картинки | Картинки и HTML передаются в Base64. У всех типов есть необязательное поле `app_id` — идентификатор приложения разработчика. ## График опроса | Шаг | Когда | Зачем | | --- | --- | --- | | 1 | через 1 с после ответа `/create` | забрать ответ — обычно он уже готов | | 2 | дальше каждые 2 с | дождаться решения сложной капчи | | — | после 90 с без ответа | прекратить опрос, взять у сайта новую капчу | Опрашивать чаще, чем раз в 2 секунды, не нужно: сложные капчи решаются секундами, и частый опрос их не ускорит. Опрос заканчивается, как только пришёл `status: 1` или любой ответ, кроме `CAPCHA_NOT_READY`. Каждую принятую задачу опрашивайте до конца — не бросайте её на середине. ## Соединение - **Одно соединение на все запросы.** Создайте HTTP-клиент один раз и переиспользуйте его: `requests.Session` в Python, общий `fetch` или agent в Node, один дескриптор cURL в PHP, один `HttpClient` в C#, один `http.Client` в Go. Новое TLS-соединение на каждый запрос — это лишние десятки миллисекунд на каждом шаге опроса. - **HTTP/2 поддерживается** — можно отправлять много запросов параллельно по одному соединению. - **Сервер закрывает простаивающее соединение примерно через 10 секунд.** Клиент должен уметь открыть его заново: почти все HTTP-библиотеки делают это сами, если не держать сокет вручную. - **Таймауты:** подключение — 5 с, ответ на `/create` — 15 с, на `/result` — 10 с. Без таймаутов зависший запрос остановит всю очередь задач. ## Запрос - Ключ — только в заголовке `X-API-Key`. - Тело — JSON с заголовком `Content-Type: application/json`. - Картинки — **исходные байты в Base64**, без префикса `data:image/...`. Не пересжимайте и не перерисовывайте их: пересжатие теряет детали, и капча решается дольше и хуже. - Форматы — PNG или JPEG, до 2 МБ на картинку. Если JPEG отвергается с `ERROR_IMAGE_TYPE_NOT_SUPPORTED`, отправьте его в PNG. ## Ошибки и повторы | Ответ | Что делать | | --- | --- | | `CAPCHA_NOT_READY` | продолжить опрос по графику | | `CAPCHA_NOT_AVAILABLE` на `/result` | капча не решена — взять новую и создать новую задачу | | `ERROR_NO_SUCH_TASK_ID` | задачи нет или она устарела — создать новую | | `TOO_MANY_REQUESTS`, `SERVER_ERROR`, `ERROR_SERVER`, `ERROR_NO_ACTIVE_SERVER` на `/create`, обрыв сети, таймаут | повторить тот же запрос через 1, 2, 4 с; после трёх неудач — остановиться | | `ERROR_TASK_LOOP_DETECTED` | перестать отправлять эту капчу — взять у сайта новую | | `ERROR_ZERO_BALANCE` | остановить отправку до пополнения баланса | | `ERROR_KEY_DOES_NOT_EXIST`, `ERROR_IP_NOT_ALLOWED`, `ERROR_USER_DISABLED` | остановиться: это настройка, а не сбой | | ошибки картинок (`ERROR_IMAGE_…`, `ERROR_BODY_…`, `ERROR_EMPTY_BODY`, `ERROR_DUPLICATE_DATA`) | исправить запрос, повторять без изменений бессмысленно | Полный список — в [кодах ошибок](/docs/errors). Повтор `/result` после обрыва сети безопасен: для одной задачи он всегда возвращает один и тот же ответ. **Не отправляйте одну и ту же капчу по кругу.** Если сайт не принял ответ, возьмите у него новую капчу. Десять одинаковых задач подряд с одного адреса без успешного результата блокируют эту капчу на 15 минут (`ERROR_TASK_LOOP_DETECTED`). А если ответ оказался неверным — отметьте задачу кнопкой «Неверный ответ» в личном кабинете, на странице [«Задачи за сегодня»](/dashboard/tasks): так капча быстрее перестанет решаться неправильно. ## Чек-лист - [ ] Ключ в заголовке `X-API-Key`, тело — JSON. - [ ] Картинки отправляются исходными байтами, без пересжатия. - [ ] Первый `/result` — через 1 с после `/create`. - [ ] Дальше — каждые 2 с, не дольше 90 с. - [ ] Один HTTP-клиент на все запросы, с таймаутами. - [ ] Сетевые ошибки и `TOO_MANY_REQUESTS` повторяются с паузой, остальные ошибки — по таблице. - [ ] Одна и та же капча не отправляется по кругу. ## Пример ::code-group ```python [Python] import base64 import time import requests API = 'https://api.capsola.cloud' # Один клиент на все запросы: соединение переиспользуется. session = requests.Session() session.headers['X-API-Key'] = 'API_KEY' # Опрос: через 1 с, дальше каждые 2 с — всего около 90 с. POLL_DELAYS = [1] + [2] * 45 RETRYABLE = {'TOO_MANY_REQUESTS', 'SERVER_ERROR', 'ERROR_SERVER'} # ERROR_NO_ACTIVE_SERVER на /create — все решатели заняты, повторяем, как SERVER_ERROR. # На /result он значит «капча не решена», и повтор не поможет. RETRYABLE_CREATE = RETRYABLE | {'ERROR_NO_ACTIVE_SERVER'} def call(path, payload, timeout): """Запрос с повтором при сетевых сбоях: паузы 1, 2, 4 с.""" retryable = RETRYABLE_CREATE if path == '/create' else RETRYABLE for pause in (1, 2, 4, None): try: answer = session.post(f'{API}{path}', json=payload, timeout=(5, timeout)).json() if answer.get('response') not in retryable: return answer except requests.RequestException: pass if pause is None: raise RuntimeError(f'{path}: сервис не отвечает') time.sleep(pause) def solve(payload): created = call('/create', payload, 15) if created['status'] != 1: raise RuntimeError(created['response']) for delay in POLL_DELAYS: time.sleep(delay) result = call('/result', {'id': created['response']}, 10) if result['status'] == 1: return result['response'] if result['response'] != 'CAPCHA_NOT_READY': raise RuntimeError(result['response']) raise TimeoutError('нет ответа за 90 секунд') def b64(url): return base64.b64encode(requests.get(url, timeout=15).content).decode() # Тело /create зависит от типа капчи — см. «Что отправлять». print(solve({ 'type': 'SmartCaptcha', 'click': b64('https://capsola.cloud/examples/smart/click.png'), 'task': b64('https://capsola.cloud/examples/smart/task.png'), })) ``` ```js [Nodejs] // Node 18+: встроенный fetch сам переиспользует соединение. const API = "https://api.capsola.cloud"; const HEADERS = { "Content-Type": "application/json", "X-API-Key": "API_KEY" }; // Опрос: через 1 с, дальше каждые 2 с — всего около 90 с. const POLL_DELAYS = [1000, ...Array(45).fill(2000)]; const RETRYABLE = new Set(["TOO_MANY_REQUESTS", "SERVER_ERROR", "ERROR_SERVER"]); // ERROR_NO_ACTIVE_SERVER на /create — все решатели заняты, повторяем, как SERVER_ERROR. // На /result он значит «капча не решена», и повтор не поможет. const RETRYABLE_CREATE = new Set([...RETRYABLE, "ERROR_NO_ACTIVE_SERVER"]); const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms)); // Запрос с повтором при сетевых сбоях: паузы 1, 2, 4 с. async function call(path, payload, timeoutMs) { const retryable = path === "/create" ? RETRYABLE_CREATE : RETRYABLE; for (const pause of [1000, 2000, 4000, null]) { try { const res = await fetch(API + path, { method: "POST", headers: HEADERS, body: JSON.stringify(payload), signal: AbortSignal.timeout(timeoutMs), }); const answer = await res.json(); if (!retryable.has(answer.response)) return answer; } catch { // сеть или таймаут — повторим } if (pause === null) throw new Error(`${path}: сервис не отвечает`); await sleep(pause); } } async function solve(payload) { const created = await call("/create", payload, 15000); if (created.status !== 1) throw new Error(created.response); for (const delay of POLL_DELAYS) { await sleep(delay); const result = await call("/result", { id: created.response }, 10000); if (result.status === 1) return result.response; if (result.response !== "CAPCHA_NOT_READY") throw new Error(result.response); } throw new Error("нет ответа за 90 секунд"); } async function b64(url) { return Buffer.from(await (await fetch(url)).arrayBuffer()).toString("base64"); } async function main() { // Тело /create зависит от типа капчи — см. «Что отправлять». const answer = await solve({ type: "SmartCaptcha", click: await b64("https://capsola.cloud/examples/smart/click.png"), task: await b64("https://capsola.cloud/examples/smart/task.png"), }); console.log(answer); } main().catch(console.error); ``` ```php [PHP] 'https://api.capsola.cloud' . $path, CURLOPT_POST => true, CURLOPT_POSTFIELDS => json_encode($payload), CURLOPT_HTTPHEADER => ['Content-Type: application/json', 'X-API-Key: API_KEY'], CURLOPT_RETURNTRANSFER => true, CURLOPT_CONNECTTIMEOUT => 5, CURLOPT_TIMEOUT => $timeout, ]); $answer = json_decode((string) curl_exec($ch), true); if (is_array($answer) && !in_array($answer['response'] ?? '', $retryable, true)) { return $answer; } if ($pause === null) { throw new RuntimeException("$path: сервис не отвечает"); } sleep($pause); } } function solve($ch, array $payload): string { $created = call($ch, '/create', $payload, 15); if ($created['status'] !== 1) { throw new RuntimeException($created['response']); } // Опрос: через 1 с, дальше каждые 2 с — всего около 90 с. $delays = array_merge([1], array_fill(0, 45, 2)); foreach ($delays as $delay) { usleep((int) ($delay * 1000000)); $result = call($ch, '/result', ['id' => $created['response']], 10); if ($result['status'] === 1) { return $result['response']; } if ($result['response'] !== 'CAPCHA_NOT_READY') { throw new RuntimeException($result['response']); } } throw new RuntimeException('нет ответа за 90 секунд'); } // Тело /create зависит от типа капчи — см. «Что отправлять». echo solve($ch, [ 'type' => 'SmartCaptcha', 'click' => base64_encode(file_get_contents('https://capsola.cloud/examples/smart/click.png')), 'task' => base64_encode(file_get_contents('https://capsola.cloud/examples/smart/task.png')), ]), PHP_EOL; ``` ```csharp [C#] // .NET 6+, консольное приложение. using System.Net.Http.Json; using System.Text.Json; const string Api = "https://api.capsola.cloud"; string[] retryable = { "TOO_MANY_REQUESTS", "SERVER_ERROR", "ERROR_SERVER" }; // ERROR_NO_ACTIVE_SERVER на /create — все решатели заняты, повторяем, как SERVER_ERROR. // На /result он значит «капча не решена», и повтор не поможет. var retryableCreate = retryable.Append("ERROR_NO_ACTIVE_SERVER").ToArray(); // Один HttpClient на всё приложение: соединение переиспользуется. var http = new HttpClient(new SocketsHttpHandler { ConnectTimeout = TimeSpan.FromSeconds(5) }); http.DefaultRequestHeaders.Add("X-API-Key", "API_KEY"); // Запрос с повтором при сетевых сбоях: паузы 1, 2, 4 с. async Task Call(string path, object payload, int timeoutSeconds) { var retry = path == "/create" ? retryableCreate : retryable; for (var attempt = 0; ; attempt++) { try { using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(timeoutSeconds)); using var res = await http.PostAsJsonAsync(Api + path, payload, cts.Token); var answer = await res.Content.ReadFromJsonAsync(cancellationToken: cts.Token); if (!retry.Contains(answer.GetProperty("response").GetString())) return answer; } catch (Exception e) when (e is HttpRequestException or TaskCanceledException or JsonException) { } if (attempt == 3) throw new Exception($"{path}: сервис не отвечает"); await Task.Delay(TimeSpan.FromSeconds(1 << attempt)); } } async Task Solve(object payload) { var created = await Call("/create", payload, 15); var id = created.GetProperty("response").GetString()!; if (created.GetProperty("status").GetInt32() != 1) throw new Exception(id); // Опрос: через 1 с, дальше каждые 2 с — всего около 90 с. var delays = new[] { 1000 }.Concat(Enumerable.Repeat(2000, 45)); foreach (var delay in delays) { await Task.Delay(delay); var result = await Call("/result", new { id }, 10); var response = result.GetProperty("response").GetString()!; if (result.GetProperty("status").GetInt32() == 1) return response; if (response != "CAPCHA_NOT_READY") throw new Exception(response); } throw new TimeoutException("нет ответа за 90 секунд"); } async Task B64(string url) => Convert.ToBase64String(await http.GetByteArrayAsync(url)); // Тело /create зависит от типа капчи — см. «Что отправлять». Console.WriteLine(await Solve(new { type = "SmartCaptcha", click = await B64("https://capsola.cloud/examples/smart/click.png"), task = await B64("https://capsola.cloud/examples/smart/task.png"), })); ``` ```go [Go] package main import ( "bytes" "context" "encoding/base64" "encoding/json" "errors" "fmt" "io" "net" "net/http" "time" ) const ( api = "https://api.capsola.cloud" apiKey = "API_KEY" ) // Один клиент на все запросы: соединение переиспользуется. var client = newClient() func newClient() *http.Client { transport := http.DefaultTransport.(*http.Transport).Clone() transport.DialContext = (&net.Dialer{Timeout: 5 * time.Second}).DialContext return &http.Client{Transport: transport} } var retryable = map[string]bool{"TOO_MANY_REQUESTS": true, "SERVER_ERROR": true, "ERROR_SERVER": true} // ERROR_NO_ACTIVE_SERVER на /create — все решатели заняты, повторяем, как SERVER_ERROR. // На /result он значит «капча не решена», и повтор не поможет. func shouldRetry(path, response string) bool { return retryable[response] || (path == "/create" && response == "ERROR_NO_ACTIVE_SERVER") } type answer struct { Status int `json:"status"` Response string `json:"response"` } func post(path string, body []byte, timeout time.Duration) (answer, error) { ctx, cancel := context.WithTimeout(context.Background(), timeout) defer cancel() req, err := http.NewRequestWithContext(ctx, http.MethodPost, api+path, bytes.NewReader(body)) if err != nil { return answer{}, err } req.Header.Set("Content-Type", "application/json") req.Header.Set("X-API-Key", apiKey) res, err := client.Do(req) if err != nil { return answer{}, err } defer res.Body.Close() var a answer err = json.NewDecoder(res.Body).Decode(&a) return a, err } // Запрос с повтором при сетевых сбоях: паузы 1, 2, 4 с. func call(path string, payload any, timeout time.Duration) (answer, error) { body, err := json.Marshal(payload) if err != nil { return answer{}, err } for attempt := 0; ; attempt++ { a, err := post(path, body, timeout) if err == nil && !shouldRetry(path, a.Response) { return a, nil } if attempt == 3 { return answer{}, fmt.Errorf("%s: сервис не отвечает", path) } time.Sleep(time.Second << attempt) } } func solve(payload map[string]string) (string, error) { created, err := call("/create", payload, 15*time.Second) if err != nil { return "", err } if created.Status != 1 { return "", errors.New(created.Response) } // Опрос: через 1 с, дальше каждые 2 с — всего около 90 с. delays := []time.Duration{time.Second} for i := 0; i < 45; i++ { delays = append(delays, 2*time.Second) } for _, delay := range delays { time.Sleep(delay) result, err := call("/result", map[string]string{"id": created.Response}, 10*time.Second) if err != nil { return "", err } if result.Status == 1 { return result.Response, nil } if result.Response != "CAPCHA_NOT_READY" { return "", errors.New(result.Response) } } return "", errors.New("нет ответа за 90 секунд") } func b64(url string) string { res, err := client.Get(url) if err != nil { panic(err) } defer res.Body.Close() data, err := io.ReadAll(res.Body) if err != nil { panic(err) } return base64.StdEncoding.EncodeToString(data) } func main() { // Тело /create зависит от типа капчи — см. «Что отправлять». answer, err := solve(map[string]string{ "type": "SmartCaptcha", "click": b64("https://capsola.cloud/examples/smart/click.png"), "task": b64("https://capsola.cloud/examples/smart/task.png"), }) if err != nil { fmt.Println(err) return } fmt.Println(answer) } ``` :: ## Задание для ИИ-ассистента Если интеграцию пишет ИИ, скопируйте ему этот текст — вместе со ссылкой на документацию одним файлом: [`/llms-full.txt`](/llms-full.txt). ```text Подключи Capsola API для решения капчи. Документация целиком: https://front.capsola.space/llms-full.txt Прежде чем писать код, спроси меня, какую капчу нужно решать, если я не указал это сам: - SmartCaptcha — Силуэты, клик по иконкам; - PazlCaptcha или PazlCaptchaV2 — Калейдоскоп, сдвиг слайдера; - TextCaptcha — Текстовая, текст с картинки. Поля запроса и формат ответа возьми со страницы этого типа. Обязательные правила: 1. POST https://api.capsola.cloud/create, тело JSON с полем "type" и полями выбранного типа, ключ — в заголовке X-API-Key. Картинки — исходные байты в Base64, без пересжатия и без префикса data:. 2. Первый POST /result {"id": ""} — через 1 с после /create. Если CAPCHA_NOT_READY — дальше каждые 2 с, не дольше 90 с. Чаще раза в 2 секунды не опрашивать. 3. Один HTTP-клиент на все запросы (keep-alive), таймауты: подключение 5 с, /create 15 с, /result 10 с. Клиент должен переоткрывать соединение, закрытое сервером после ~10 с простоя. 4. TOO_MANY_REQUESTS, SERVER_ERROR, ERROR_SERVER, ERROR_NO_ACTIVE_SERVER на /create, сетевые ошибки — повтор того же запроса через 1, 2, 4 с, потом остановка. CAPCHA_NOT_AVAILABLE на /result — новая капча и новая задача. ERROR_TASK_LOOP_DETECTED — не отправлять эту капчу снова. Ошибки ключа, IP, баланса и картинок — не повторять. 5. Ответ /result зависит от типа: SmartCaptcha — строка "coordinates:x=..,y=..;..." (точки в порядке клика), PazlCaptcha и PazlCaptchaV2 — номер шага, TextCaptcha — текст с картинки. 6. Логировать id задачи, время /create и время получения ответа. ``` --- # SmartCaptcha (Силуэты) Источник: https://capsola.space/docs/smartcaptcha ::captcha-preview --- image: /preview/smart/click.png task: /preview/smart/task.png variant: click --- :: ### 1. Создание задачи ::api-endpoint{method="POST" url="https://api.capsola.cloud/create"} :: #### Запрос Ключ передаётся в заголовке `X-API-Key`, тело — JSON. ```json { "type": "SmartCaptcha", "click": "CLICK_BASE_64", "task": "TASK_BASE_64" } ``` :::api-params ::api-param{name="type" type="string" required} Тип задачи — `SmartCaptcha`. :: ::api-param{name="click" type="base64" required} Изображение области клика. :: ::api-param{name="task" type="base64" required} Изображение с порядком задания. :: ::api-param{name="app_id" type="string"} Идентификатор приложения разработчика — выдаётся в [партнёрском разделе](/dashboard/referrals/apps). :: ::: Изображения надёжнее скачивать с источника и кодировать в Base64 самостоятельно. Пересжатие теряет детали, и задача решается хуже. #### Ответ ```json { "status": 1, "response": "9051d4b4-0000-44d3-a4c2-db0215227862" } ``` :::api-params ::api-param{name="status" type="number"} `1` — задача принята, `0` — ошибка. :: ::api-param{name="response" type="string"} Идентификатор задачи или [код ошибки](/docs/errors). :: ::: ### 2. Получение результата ::api-endpoint{method="POST" url="https://api.capsola.cloud/result"} :: #### Запрос ```json { "id": "9051d4b4-0000-44d3-a4c2-db0215227862" } ``` :::api-params ::api-param{name="id" type="string" required} Идентификатор задачи из ответа на `/create`. :: ::: #### Ответ ```json { "status": 1, "response": "coordinates:x=34.7,y=108.0;x=234.3,y=72.3;x=149.1,y=107.7" } ``` :::api-params ::api-param{name="status" type="number"} `1` — задача решена, `0` — ошибка. :: ::api-param{name="response" type="string"} Координаты точек в порядке нажатия или [код ошибки](/docs/errors). :: ::: Ответ `CAPCHA_NOT_READY` означает, что задача ещё решается. Опрашивайте так: 1. первый запрос — **через 1 секунду** после `/create`: у большинства капч ответ к этому моменту уже готов; 2. дальше — каждые 2 секунды, пока не придёт ответ или другая ошибка, но не дольше 90 секунд. Подробнее — про соединение, таймауты и повторы — в разделе [«Интеграция»](/docs/integration). --- ### Примеры использования ::code-group ```python [Python] import base64 import time import requests API = 'https://api.capsola.cloud' # Один клиент на все запросы — соединение переиспользуется. session = requests.Session() session.headers['X-API-Key'] = 'API_KEY' def b64(url): return base64.b64encode(requests.get(url, timeout=15).content).decode() created = session.post(f'{API}/create', json={ 'type': 'SmartCaptcha', 'click': b64('https://capsola.cloud/examples/smart/click.png'), 'task': b64('https://capsola.cloud/examples/smart/task.png'), }, timeout=15).json() print(created) if created['status'] == 1: # Через 1 с, дальше каждые 2 с — не дольше 90 с. for delay in [1] + [2] * 45: time.sleep(delay) result = session.post(f'{API}/result', json={'id': created['response']}, timeout=10).json() print(result) if result['status'] == 1 or result['response'] != 'CAPCHA_NOT_READY': break ``` ```php [PHP] 'https://api.capsola.cloud' . $path, CURLOPT_POST => true, CURLOPT_POSTFIELDS => json_encode($payload), CURLOPT_HTTPHEADER => ['Content-Type: application/json', 'X-API-Key: API_KEY'], CURLOPT_RETURNTRANSFER => true, CURLOPT_CONNECTTIMEOUT => 5, CURLOPT_TIMEOUT => 15, ]); return json_decode((string) curl_exec($ch), true); } $created = call($ch, '/create', [ 'type' => 'SmartCaptcha', 'click' => base64_encode(file_get_contents('https://capsola.cloud/examples/smart/click.png')), 'task' => base64_encode(file_get_contents('https://capsola.cloud/examples/smart/task.png')), ]); var_dump($created); if ($created['status'] === 1) { // Через 1 с, дальше каждые 2 с — не дольше 90 с. foreach (array_merge([1], array_fill(0, 45, 2)) as $delay) { usleep((int) ($delay * 1000000)); $result = call($ch, '/result', ['id' => $created['response']]); var_dump($result); if ($result['status'] === 1 || $result['response'] !== 'CAPCHA_NOT_READY') { break; } } } ``` ```js [Nodejs] // Node 18+: встроенный fetch сам переиспользует соединение. const API = "https://api.capsola.cloud"; const HEADERS = { "Content-Type": "application/json", "X-API-Key": "API_KEY" }; const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms)); async function call(path, payload) { const res = await fetch(API + path, { method: "POST", headers: HEADERS, body: JSON.stringify(payload), signal: AbortSignal.timeout(15000), }); return res.json(); } async function b64(url) { return Buffer.from(await (await fetch(url)).arrayBuffer()).toString("base64"); } async function main() { const created = await call("/create", { type: "SmartCaptcha", click: await b64("https://capsola.cloud/examples/smart/click.png"), task: await b64("https://capsola.cloud/examples/smart/task.png"), }); console.log(created); if (created.status !== 1) return; // Через 1 с, дальше каждые 2 с — не дольше 90 с. for (const delay of [1000, ...Array(45).fill(2000)]) { await sleep(delay); const result = await call("/result", { id: created.response }); console.log(result); if (result.status === 1 || result.response !== "CAPCHA_NOT_READY") break; } } main().catch(console.error); ``` ```csharp [C#] // .NET 6+, консольное приложение. using System.Net.Http.Json; using System.Text.Json; const string Api = "https://api.capsola.cloud"; // Один HttpClient на всё приложение — соединение переиспользуется. var http = new HttpClient { Timeout = TimeSpan.FromSeconds(15) }; http.DefaultRequestHeaders.Add("X-API-Key", "API_KEY"); async Task Call(string path, object payload) { using var res = await http.PostAsJsonAsync(Api + path, payload); return await res.Content.ReadFromJsonAsync(); } async Task B64(string url) => Convert.ToBase64String(await http.GetByteArrayAsync(url)); var created = await Call("/create", new { type = "SmartCaptcha", click = await B64("https://capsola.cloud/examples/smart/click.png"), task = await B64("https://capsola.cloud/examples/smart/task.png"), }); Console.WriteLine(created); if (created.GetProperty("status").GetInt32() == 1) { // Через 1 с, дальше каждые 2 с — не дольше 90 с. foreach (var delay in new[] { 1000 }.Concat(Enumerable.Repeat(2000, 45))) { await Task.Delay(delay); var result = await Call("/result", new { id = created.GetProperty("response").GetString() }); Console.WriteLine(result); if (result.GetProperty("status").GetInt32() == 1 || result.GetProperty("response").GetString() != "CAPCHA_NOT_READY") break; } } ``` ```go [Go] package main import ( "bytes" "encoding/base64" "encoding/json" "fmt" "io" "net/http" "time" ) const api = "https://api.capsola.cloud" // Один клиент на все запросы — соединение переиспользуется. var client = &http.Client{Timeout: 15 * time.Second} type answer struct { Status int `json:"status"` Response string `json:"response"` } func call(path string, payload any) (a answer, err error) { body, _ := json.Marshal(payload) req, _ := http.NewRequest(http.MethodPost, api+path, bytes.NewReader(body)) req.Header.Set("Content-Type", "application/json") req.Header.Set("X-API-Key", "API_KEY") res, err := client.Do(req) if err != nil { return a, err } defer res.Body.Close() err = json.NewDecoder(res.Body).Decode(&a) return a, err } func b64(url string) string { res, err := client.Get(url) if err != nil { panic(err) } defer res.Body.Close() data, _ := io.ReadAll(res.Body) return base64.StdEncoding.EncodeToString(data) } func main() { created, err := call("/create", map[string]string{ "type": "SmartCaptcha", "click": b64("https://capsola.cloud/examples/smart/click.png"), "task": b64("https://capsola.cloud/examples/smart/task.png"), }) fmt.Printf("%+v %v\n", created, err) if err != nil || created.Status != 1 { return } // Через 1 с, дальше каждые 2 с — не дольше 90 с. delays := []time.Duration{time.Second} for i := 0; i < 45; i++ { delays = append(delays, 2*time.Second) } for _, delay := range delays { time.Sleep(delay) result, err := call("/result", map[string]string{"id": created.Response}) fmt.Printf("%+v %v\n", result, err) if err != nil || result.Status == 1 || result.Response != "CAPCHA_NOT_READY" { break } } } ``` :: --- # PazlCaptcha (Калейдоскоп) Источник: https://capsola.space/docs/pazlcaptcha ::captcha-preview --- image: /preview/pazl/task.png variant: slider label: Перемещайте слайдер --- :: ### 1. Создание задачи, версия 1 ::api-endpoint{method="POST" url="https://api.capsola.cloud/create"} :: #### Запрос Ключ передаётся в заголовке `X-API-Key`, тело — JSON. ```json { "type": "PazlCaptcha", "task": "TASK_BASE_64" } ``` :::api-params ::api-param{name="type" type="string" required} Тип задачи — `PazlCaptcha`. :: ::api-param{name="task" type="base64" required} Полный HTML-код страницы. :: ::api-param{name="app_id" type="string"} Идентификатор приложения разработчика — выдаётся в [партнёрском разделе](/dashboard/referrals/apps). :: ::: #### Ответ ```json { "status": 1, "response": "9051d4b4-0000-44d3-a4c2-db0215227862" } ``` :::api-params ::api-param{name="status" type="number"} `1` — задача принята, `0` — ошибка. :: ::api-param{name="response" type="string"} Идентификатор задачи или [код ошибки](/docs/errors). :: ::: ### 1.1. Создание задачи, версия 2 Версия 2 принимает готовое изображение и список перестановок — HTML страницы не нужен. ::api-endpoint{method="POST" url="https://api.capsola.cloud/create"} :: #### Запрос ```json { "type": "PazlCaptchaV2", "image": "IMAGE_BASE_64", "task": "[23,12,12,23]" } ``` :::api-params ::api-param{name="type" type="string" required} Тип задачи — `PazlCaptchaV2`. :: ::api-param{name="image" type="base64" required} Изображение капчи. :: ::api-param{name="task" type="string" required} Порядковый список перестановок. :: ::api-param{name="app_id" type="string"} Идентификатор приложения разработчика — выдаётся в [партнёрском разделе](/dashboard/referrals/apps). :: ::: #### Ответ ```json { "status": 1, "response": "9051d4b4-0000-44d3-a4c2-db0215227862" } ``` :::api-params ::api-param{name="status" type="number"} `1` — задача принята, `0` — ошибка. :: ::api-param{name="response" type="string"} Идентификатор задачи или [код ошибки](/docs/errors). :: ::: ### 2. Получение результата ::api-endpoint{method="POST" url="https://api.capsola.cloud/result"} :: #### Запрос ```json { "id": "9051d4b4-0000-44d3-a4c2-db0215227862" } ``` :::api-params ::api-param{name="id" type="string" required} Идентификатор задачи из ответа на `/create`. :: ::: #### Ответ ```json { "status": 1, "response": "12" } ``` :::api-params ::api-param{name="status" type="number"} `1` — задача решена, `0` — ошибка. :: ::api-param{name="response" type="string"} Номер шага, на котором пазл сложен, — цикл кликов начинайте с 1. Либо [код ошибки](/docs/errors). :: ::: Ответ `CAPCHA_NOT_READY` означает, что задача ещё решается. Опрашивайте так: 1. первый запрос — **через 1 секунду** после `/create`: у большинства капч ответ к этому моменту уже готов; 2. дальше — каждые 2 секунды, пока не придёт ответ или другая ошибка, но не дольше 90 секунд. Подробнее — про соединение, таймауты и повторы — в разделе [«Интеграция»](/docs/integration). --- ### Примеры использования Примеры — для версии 2: картинка капчи берётся из файла `pazl.png`, в `task` — список перестановок со страницы. Для версии 1 отличается только тело `/create`: `{"type": "PazlCaptcha", "task": ""}`. ::code-group ```python [Python] import base64 import time import requests API = 'https://api.capsola.cloud' # Один клиент на все запросы — соединение переиспользуется. session = requests.Session() session.headers['X-API-Key'] = 'API_KEY' def b64(path): with open(path, 'rb') as f: return base64.b64encode(f.read()).decode() created = session.post(f'{API}/create', json={ 'type': 'PazlCaptchaV2', 'image': b64('pazl.png'), 'task': '[23,12,12,23]', }, timeout=15).json() print(created) if created['status'] == 1: # Через 1 с, дальше каждые 2 с — не дольше 90 с. for delay in [1] + [2] * 45: time.sleep(delay) result = session.post(f'{API}/result', json={'id': created['response']}, timeout=10).json() print(result) if result['status'] == 1 or result['response'] != 'CAPCHA_NOT_READY': break ``` ```php [PHP] 'https://api.capsola.cloud' . $path, CURLOPT_POST => true, CURLOPT_POSTFIELDS => json_encode($payload), CURLOPT_HTTPHEADER => ['Content-Type: application/json', 'X-API-Key: API_KEY'], CURLOPT_RETURNTRANSFER => true, CURLOPT_CONNECTTIMEOUT => 5, CURLOPT_TIMEOUT => 15, ]); return json_decode((string) curl_exec($ch), true); } $created = call($ch, '/create', [ 'type' => 'PazlCaptchaV2', 'image' => base64_encode(file_get_contents('pazl.png')), 'task' => '[23,12,12,23]', ]); var_dump($created); if ($created['status'] === 1) { // Через 1 с, дальше каждые 2 с — не дольше 90 с. foreach (array_merge([1], array_fill(0, 45, 2)) as $delay) { usleep((int) ($delay * 1000000)); $result = call($ch, '/result', ['id' => $created['response']]); var_dump($result); if ($result['status'] === 1 || $result['response'] !== 'CAPCHA_NOT_READY') { break; } } } ``` ```js [Nodejs] // Node 18+: встроенный fetch сам переиспользует соединение. const API = "https://api.capsola.cloud"; const HEADERS = { "Content-Type": "application/json", "X-API-Key": "API_KEY" }; const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms)); async function call(path, payload) { const res = await fetch(API + path, { method: "POST", headers: HEADERS, body: JSON.stringify(payload), signal: AbortSignal.timeout(15000), }); return res.json(); } function b64(path) { return require("node:fs").readFileSync(path).toString("base64"); } async function main() { const created = await call("/create", { type: "PazlCaptchaV2", image: b64("pazl.png"), task: "[23,12,12,23]", }); console.log(created); if (created.status !== 1) return; // Через 1 с, дальше каждые 2 с — не дольше 90 с. for (const delay of [1000, ...Array(45).fill(2000)]) { await sleep(delay); const result = await call("/result", { id: created.response }); console.log(result); if (result.status === 1 || result.response !== "CAPCHA_NOT_READY") break; } } main().catch(console.error); ``` ```csharp [C#] // .NET 6+, консольное приложение. using System.Net.Http.Json; using System.Text.Json; const string Api = "https://api.capsola.cloud"; // Один HttpClient на всё приложение — соединение переиспользуется. var http = new HttpClient { Timeout = TimeSpan.FromSeconds(15) }; http.DefaultRequestHeaders.Add("X-API-Key", "API_KEY"); async Task Call(string path, object payload) { using var res = await http.PostAsJsonAsync(Api + path, payload); return await res.Content.ReadFromJsonAsync(); } string B64(string path) => Convert.ToBase64String(File.ReadAllBytes(path)); var created = await Call("/create", new { type = "PazlCaptchaV2", image = B64("pazl.png"), task = "[23,12,12,23]", }); Console.WriteLine(created); if (created.GetProperty("status").GetInt32() == 1) { // Через 1 с, дальше каждые 2 с — не дольше 90 с. foreach (var delay in new[] { 1000 }.Concat(Enumerable.Repeat(2000, 45))) { await Task.Delay(delay); var result = await Call("/result", new { id = created.GetProperty("response").GetString() }); Console.WriteLine(result); if (result.GetProperty("status").GetInt32() == 1 || result.GetProperty("response").GetString() != "CAPCHA_NOT_READY") break; } } ``` ```go [Go] package main import ( "bytes" "encoding/base64" "encoding/json" "fmt" "os" "net/http" "time" ) const api = "https://api.capsola.cloud" // Один клиент на все запросы — соединение переиспользуется. var client = &http.Client{Timeout: 15 * time.Second} type answer struct { Status int `json:"status"` Response string `json:"response"` } func call(path string, payload any) (a answer, err error) { body, _ := json.Marshal(payload) req, _ := http.NewRequest(http.MethodPost, api+path, bytes.NewReader(body)) req.Header.Set("Content-Type", "application/json") req.Header.Set("X-API-Key", "API_KEY") res, err := client.Do(req) if err != nil { return a, err } defer res.Body.Close() err = json.NewDecoder(res.Body).Decode(&a) return a, err } func b64(path string) string { data, err := os.ReadFile(path) if err != nil { panic(err) } return base64.StdEncoding.EncodeToString(data) } func main() { created, err := call("/create", map[string]string{ "type": "PazlCaptchaV2", "image": b64("pazl.png"), "task": "[23,12,12,23]", }) fmt.Printf("%+v %v\n", created, err) if err != nil || created.Status != 1 { return } // Через 1 с, дальше каждые 2 с — не дольше 90 с. delays := []time.Duration{time.Second} for i := 0; i < 45; i++ { delays = append(delays, 2*time.Second) } for _, delay := range delays { time.Sleep(delay) result, err := call("/result", map[string]string{"id": created.Response}) fmt.Printf("%+v %v\n", result, err) if err != nil || result.Status == 1 || result.Response != "CAPCHA_NOT_READY" { break } } } ``` :: --- # TextCaptcha (Текстовая) Источник: https://capsola.space/docs/textcaptcha ::captcha-preview --- image: /examples/text/task.png variant: input label: Введите текст с картинки --- :: ### 1. Создание задачи ::api-endpoint{method="POST" url="https://api.capsola.cloud/create"} :: #### Запрос Ключ передаётся в заголовке `X-API-Key`, тело — JSON. ```json { "type": "TextCaptcha", "task": "IMAGE_BASE_64" } ``` :::api-params ::api-param{name="type" type="string" required} Тип задачи — `TextCaptcha`. :: ::api-param{name="task" type="base64" required} Изображение капчи. :: ::api-param{name="app_id" type="string"} Идентификатор приложения разработчика — выдаётся в [партнёрском разделе](/dashboard/referrals/apps). :: ::: #### Ответ ```json { "status": 1, "response": "9051d4b4-0000-44d3-a4c2-db0215227862" } ``` :::api-params ::api-param{name="status" type="number"} `1` — задача принята, `0` — ошибка. :: ::api-param{name="response" type="string"} Идентификатор задачи или [код ошибки](/docs/errors). :: ::: ### 2. Получение результата ::api-endpoint{method="POST" url="https://api.capsola.cloud/result"} :: #### Запрос ```json { "id": "9051d4b4-0000-44d3-a4c2-db0215227862" } ``` :::api-params ::api-param{name="id" type="string" required} Идентификатор задачи из ответа на `/create`. :: ::: #### Ответ ```json { "status": 1, "response": "Фраза для ввода" } ``` :::api-params ::api-param{name="status" type="number"} `1` — задача решена, `0` — ошибка. :: ::api-param{name="response" type="string"} Текст с картинки или [код ошибки](/docs/errors). :: ::: Ответ `CAPCHA_NOT_READY` означает, что задача ещё решается. Опрашивайте так: 1. первый запрос — **через 1 секунду** после `/create`: у большинства капч ответ к этому моменту уже готов; 2. дальше — каждые 2 секунды, пока не придёт ответ или другая ошибка, но не дольше 90 секунд. Подробнее — про соединение, таймауты и повторы — в разделе [«Интеграция»](/docs/integration). --- ### Примеры использования ::code-group ```python [Python] import base64 import time import requests API = 'https://api.capsola.cloud' # Один клиент на все запросы — соединение переиспользуется. session = requests.Session() session.headers['X-API-Key'] = 'API_KEY' def b64(url): return base64.b64encode(requests.get(url, timeout=15).content).decode() created = session.post(f'{API}/create', json={ 'type': 'TextCaptcha', 'task': b64('https://capsola.cloud/examples/text/task.png'), }, timeout=15).json() print(created) if created['status'] == 1: # Через 1 с, дальше каждые 2 с — не дольше 90 с. for delay in [1] + [2] * 45: time.sleep(delay) result = session.post(f'{API}/result', json={'id': created['response']}, timeout=10).json() print(result) if result['status'] == 1 or result['response'] != 'CAPCHA_NOT_READY': break ``` ```php [PHP] 'https://api.capsola.cloud' . $path, CURLOPT_POST => true, CURLOPT_POSTFIELDS => json_encode($payload), CURLOPT_HTTPHEADER => ['Content-Type: application/json', 'X-API-Key: API_KEY'], CURLOPT_RETURNTRANSFER => true, CURLOPT_CONNECTTIMEOUT => 5, CURLOPT_TIMEOUT => 15, ]); return json_decode((string) curl_exec($ch), true); } $created = call($ch, '/create', [ 'type' => 'TextCaptcha', 'task' => base64_encode(file_get_contents('https://capsola.cloud/examples/text/task.png')), ]); var_dump($created); if ($created['status'] === 1) { // Через 1 с, дальше каждые 2 с — не дольше 90 с. foreach (array_merge([1], array_fill(0, 45, 2)) as $delay) { usleep((int) ($delay * 1000000)); $result = call($ch, '/result', ['id' => $created['response']]); var_dump($result); if ($result['status'] === 1 || $result['response'] !== 'CAPCHA_NOT_READY') { break; } } } ``` ```js [Nodejs] // Node 18+: встроенный fetch сам переиспользует соединение. const API = "https://api.capsola.cloud"; const HEADERS = { "Content-Type": "application/json", "X-API-Key": "API_KEY" }; const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms)); async function call(path, payload) { const res = await fetch(API + path, { method: "POST", headers: HEADERS, body: JSON.stringify(payload), signal: AbortSignal.timeout(15000), }); return res.json(); } async function b64(url) { return Buffer.from(await (await fetch(url)).arrayBuffer()).toString("base64"); } async function main() { const created = await call("/create", { type: "TextCaptcha", task: await b64("https://capsola.cloud/examples/text/task.png"), }); console.log(created); if (created.status !== 1) return; // Через 1 с, дальше каждые 2 с — не дольше 90 с. for (const delay of [1000, ...Array(45).fill(2000)]) { await sleep(delay); const result = await call("/result", { id: created.response }); console.log(result); if (result.status === 1 || result.response !== "CAPCHA_NOT_READY") break; } } main().catch(console.error); ``` ```csharp [C#] // .NET 6+, консольное приложение. using System.Net.Http.Json; using System.Text.Json; const string Api = "https://api.capsola.cloud"; // Один HttpClient на всё приложение — соединение переиспользуется. var http = new HttpClient { Timeout = TimeSpan.FromSeconds(15) }; http.DefaultRequestHeaders.Add("X-API-Key", "API_KEY"); async Task Call(string path, object payload) { using var res = await http.PostAsJsonAsync(Api + path, payload); return await res.Content.ReadFromJsonAsync(); } async Task B64(string url) => Convert.ToBase64String(await http.GetByteArrayAsync(url)); var created = await Call("/create", new { type = "TextCaptcha", task = await B64("https://capsola.cloud/examples/text/task.png"), }); Console.WriteLine(created); if (created.GetProperty("status").GetInt32() == 1) { // Через 1 с, дальше каждые 2 с — не дольше 90 с. foreach (var delay in new[] { 1000 }.Concat(Enumerable.Repeat(2000, 45))) { await Task.Delay(delay); var result = await Call("/result", new { id = created.GetProperty("response").GetString() }); Console.WriteLine(result); if (result.GetProperty("status").GetInt32() == 1 || result.GetProperty("response").GetString() != "CAPCHA_NOT_READY") break; } } ``` ```go [Go] package main import ( "bytes" "encoding/base64" "encoding/json" "fmt" "io" "net/http" "time" ) const api = "https://api.capsola.cloud" // Один клиент на все запросы — соединение переиспользуется. var client = &http.Client{Timeout: 15 * time.Second} type answer struct { Status int `json:"status"` Response string `json:"response"` } func call(path string, payload any) (a answer, err error) { body, _ := json.Marshal(payload) req, _ := http.NewRequest(http.MethodPost, api+path, bytes.NewReader(body)) req.Header.Set("Content-Type", "application/json") req.Header.Set("X-API-Key", "API_KEY") res, err := client.Do(req) if err != nil { return a, err } defer res.Body.Close() err = json.NewDecoder(res.Body).Decode(&a) return a, err } func b64(url string) string { res, err := client.Get(url) if err != nil { panic(err) } defer res.Body.Close() data, _ := io.ReadAll(res.Body) return base64.StdEncoding.EncodeToString(data) } func main() { created, err := call("/create", map[string]string{ "type": "TextCaptcha", "task": b64("https://capsola.cloud/examples/text/task.png"), }) fmt.Printf("%+v %v\n", created, err) if err != nil || created.Status != 1 { return } // Через 1 с, дальше каждые 2 с — не дольше 90 с. delays := []time.Duration{time.Second} for i := 0; i < 45; i++ { delays = append(delays, 2*time.Second) } for _, delay := range delays { time.Sleep(delay) result, err := call("/result", map[string]string{"id": created.Response}) fmt.Printf("%+v %v\n", result, err) if err != nil || result.Status == 1 || result.Response != "CAPCHA_NOT_READY" { break } } } ``` :: --- # Баланс Источник: https://capsola.space/docs/balance Баланс отдают два эндпоинта. Отличаются они только тем, где передаётся ключ. ### Ключ в адресе ::api-endpoint{method="GET" url="https://api.capsola.cloud/getbalance?key=API_KEY"} :: Отвечает одним числом с двумя знаками после запятой — без обёртки, чтобы значение можно было подставить сразу. ``` 20.00 ``` С параметром `json=1` тот же баланс приходит в JSON: ::api-endpoint{method="GET" url="https://api.capsola.cloud/getbalance?key=API_KEY&json=1"} :: ```json { "status": 1, "response": 100 } ``` ### Ключ в заголовке ::api-endpoint{method="GET" url="https://api.capsola.cloud/balance"} :: Принимает GET и POST, тело не нужно. Ключ передаётся в заголовке `X-API-Key`. #### Ответ ```json { "status": 1, "response": 100 } ``` :::api-params ::api-param{name="status" type="number"} `1` — успешно, `0` — ошибка. :: ::api-param{name="response" type="number | string"} Текущий баланс в рублях или [код ошибки](/docs/errors). :: ::: При ошибке `status` равен `0`, а код приходит в `response`: ```json { "status": 0, "response": "ERROR_KEY" } ``` --- ### Примеры использования ::code-group ```python [Python] import requests url = "https://api.capsola.cloud/balance" api_key = "API_KEY" headers = { "Content-Type": "application/json", "X-API-Key": api_key } # Отправка запроса response = requests.get(url, headers=headers) # Обработка ответа if response.status_code == 200: result = response.json() print("Баланс:", result["response"]) else: print("Произошла ошибка:", response.json()["response"]) ``` ```php [PHP] $url = "https://api.capsola.cloud/balance"; $api_key = "API_KEY"; $headers = array( "Content-Type: application/json", "X-API-Key: " . $api_key ); $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response = curl_exec($ch); if ($response === false) { echo "Ошибка Curl: " . curl_error($ch); } else { $result = json_decode($response, true); if ($result["status"] === 1) { echo "Баланс: " . $result["response"]; } else { echo "Произошла ошибка: " . $result["response"]; } } curl_close($ch); ``` ```js [Nodejs] const url = "https://api.capsola.cloud/balance"; const apiKey = "API_KEY"; const headers = { "Content-Type": "application/json", "X-API-Key": apiKey }; // Отправка запроса fetch(url, { method: "GET", headers: headers }) .then(response => response.json()) .then(result => { if (result.status === 1) { console.log("Баланс:", result.response); } else { console.log("Произошла ошибка:", result.response); } }) .catch(error => console.error("Ошибка:", error)); ``` :: --- # Коды ошибок Источник: https://capsola.space/docs/errors Ошибка приходит в том же формате, что и обычный ответ: `status` равен `0`, а в `response` — код ошибки. ```json { "status": 0, "response": "ERROR_ZERO_BALANCE" } ``` За задачи, которые завершились ошибкой, деньги не списываются. ## Любой запрос :::api-params ::api-param{name="ERROR_KEY_DOES_NOT_EXIST"} Ключ не передан, передан не в формате UUID или такого ключа нет. → Проверьте заголовок `X-API-Key`. Ключ — в кабинете, на странице «Обзор». :: ::api-param{name="ERROR_IP_NOT_ALLOWED"} У ключа включён белый список IP, а запрос пришёл с адреса не из него. → Добавьте адрес в [белый список](/dashboard/whitelist) или удалите все записи, чтобы снять ограничение. :: ::api-param{name="BAD_JSON"} Тело запроса — не корректный JSON. → Проверьте тело и заголовок `Content-Type: application/json`. :: ::api-param{name="ERROR_SERVER"} Внутренняя ошибка сервиса. → Повторите запрос через несколько секунд. Если повторяется — напишите в поддержку. :: ::api-param{name="TOO_MANY_REQUESTS"} Слишком много запросов с одного адреса за короткое время. Может прийти и как HTTP 429. → Повторите запрос через 1, 2, 4 секунды. Опрашивайте результат по [графику](/docs/integration#график-опроса), не чаще. :: ::api-param{name="SERVER_ERROR"} Сервис временно недоступен. → Повторите запрос через 1, 2, 4 секунды. Если не проходит — напишите в поддержку. :: ::: ## Создание задачи — `/create` ### Запрос и аккаунт :::api-params ::api-param{name="ERROR_TASK_ABSENT"} Не передан параметр `type`. → Укажите тип задачи. :: ::api-param{name="ERROR_TASK_NOT_SUPPORTED"} Тип в `type` не поддерживается. :: ::api-param{name="ERROR_ZERO_BALANCE"} На балансе не больше цены одного решения. → [Пополните баланс](/dashboard/transactions). :: ::api-param{name="ERROR_USER_DISABLED"} Аккаунт отключён. → Напишите в поддержку. :: ::api-param{name="ERROR_SOFT_NOT_SUPPORTED"} Для приложения из `app_id` этот тип задач отключён. :: ::api-param{name="ERROR_TASK_LOOP_DETECTED"} Одну и ту же капчу с одного IP приняли в работу 10 раз за 5 минут, и ни разу не забрали её решение. Следующие повторы этой капчи с этого IP блокируются на 15 минут. Повторы с разных серверов считаются отдельно, отклонённые запросы — например, с `ERROR_ZERO_BALANCE` — не считаются вовсе. → Забирайте результат через `/result`, прежде чем отправлять ту же капчу снова. Проверьте, не зациклился ли ваш код. :: ::: ### Картинки :::api-params ::api-param{name="ERROR_EMPTY_BODY"} Не переданы картинки: для SmartCaptcha — `click` и `task`, для PazlCaptchaV2 — `image` и `task`, для остальных — `task`. → Передайте все обязательные поля из раздела про ваш тип капчи. :: ::api-param{name="ERROR_IMAGE_TYPE_NOT_SUPPORTED"} Картинка не в формате PNG или JPEG — или к base64 приклеен префикс `data:image/...;base64,`. → Отправляйте исходную картинку с сайта без конвертации, только сам base64. :: ::api-param{name="ERROR_INVALID_IMAGE_DATA"} Строка base64 не раскодировалась в целую картинку. → Проверьте, что картинка скачана целиком и закодирована без потерь. :: ::api-param{name="ERROR_INVALID_BODY · ERROR_BODY_NOT_BASE64"} PazlCaptcha: `task` — не строка или не base64. → Передайте HTML страницы строкой в base64. :: ::api-param{name="ERROR_BODY_TOO_LARGE_B64 · ERROR_BODY_TOO_LARGE_RAW"} Картинка больше 2 МБ — в виде base64 или после раскодирования. → Отправляйте картинку капчи, а не скриншот страницы. :: ::api-param{name="ERROR_DUPLICATE_DATA"} SmartCaptcha: в `click` и `task` одна и та же картинка. → В `click` — картинка капчи, в `task` — полоса с заданием. :: ::: ### Решатели :::api-params ::api-param{name="ERROR_NO_ACTIVE_SERVER"} Все решатели сейчас заняты — задачу не удалось поставить в работу. Деньги не списаны. → Повторите создание задачи через 1, 2, 4 с, как при `SERVER_ERROR`; после трёх неудач остановитесь. :: ::: ## Получение результата — `/result` :::api-params ::api-param{name="CAPCHA_NOT_READY"} Задача ещё решается. Это не ошибка. → Повторите запрос по [графику опроса](/docs/integration#график-опроса): первый — через 1 с после `/create`, дальше каждые 2 с. :: ::api-param{name="CAPCHA_NOT_AVAILABLE"} Капчу решить не удалось. Деньги не списаны. → Создайте новую задачу. :: ::api-param{name="ERROR_INVALID_TASK_ID"} `id` не передан или не в формате UUID. → Передайте идентификатор из ответа `/create`. :: ::api-param{name="ERROR_NO_SUCH_TASK_ID"} Задачи с таким `id` нет у этого ключа — или срок её хранения истёк. → Проверьте `id` и ключ. Забирайте результат вскоре после создания задачи. :: :::