# Migrating from CapSolver

> Move reCAPTCHA image grid jobs from CapSolver to Solvecha. The API is different, so this page maps each field.

CapSolver and Solvecha do not share an API, so this is not a drop-in switch. For reCAPTCHA image grids you change a few lines: the URL, the key, the image field, the task text and the way you read the answer.

CapSolver answers inside the `createTask` call. Solvecha returns a job id first. You fetch the answer with a second request.

## Field mapping

| CapSolver | Solvecha |
|---|---|
| `POST https://api.capsolver.com/createTask` | `POST https://api.solvecha.com/v1/recognition/recaptcha` |
| `clientKey` | `key`, or an `Authorization: Bearer` header |
| `task.type` `ReCaptchaV2Classification` | The path ends in `/recaptcha` |
| `task.image` (base64) | `image_data: ["<base64>"]` |
| `task.question` (a category code such as `/m/04_sv`) | `task`: the instruction text, and `grid`: `3x3` or `4x4` |
| `solution.objects` (a list of tile numbers) | `data`: one `true` or `false` per tile, left to right, top to bottom |
| The answer in the `createTask` response | `GET` the same path with `id` until error `14` is gone |

The mapping was read from the CapSolver documentation on 17 October 2026. Check it against their current pages before you rely on it.

## Before and after

```python
import requests

result = requests.post("https://api.capsolver.com/createTask", json={
    "clientKey": "YOUR_CAPSOLVER_KEY",
    "task": {
        "type": "ReCaptchaV2Classification",
        "image": image_b64,
        "question": "/m/04_sv",
    },
}).json()
tiles = result["solution"]["objects"]
```

```python
import time
import requests

headers = {"Authorization": "Bearer YOUR_API_KEY"}
job = requests.post(
    "https://api.solvecha.com/v1/recognition/recaptcha",
    headers=headers,
    json={"task": "Select all images with motorcycles", "grid": "3x3", "image_data": [image_b64]},
).json()

while True:
    time.sleep(1)
    r = requests.get("https://api.solvecha.com/v1/recognition/recaptcha", headers=headers, params={"id": job["data"]})
    if r.status_code != 409:  # error 14: not ready yet
        break
tiles = [i for i, selected in enumerate(r.json()["data"]) if selected]
```

The Solvecha answer has one boolean per tile. The CapSolver answer lists the numbers of the selected tiles, so the loop above turns booleans into tile numbers. Check whether your code counts tiles from 0 or from 1.

## What is different

- **No token API.** Solvecha returns answers for the images you send, not a finished reCAPTCHA token. If you need a token, let the [browser extension](https://solvecha.com/docs/browser-extension.md) click the tiles in a real browser.
- **Price model.** Solvecha is a monthly plan with a daily quota of successful solves. See [Plans and billing](https://solvecha.com/docs/plans-and-billing.md) and the [compare page](https://solvecha.com/compare).
- **Task text.** Send the full instruction sentence, for example `Select all images with motorcycles`.

More on the format: [reCAPTCHA image grids](https://solvecha.com/docs/captcha-types/recaptcha.md) and [Create a reCAPTCHA job](https://solvecha.com/docs/api/create-recaptcha-job.md).
