Ninetile

Complete guide for AI agents

Copy the complete API guide below and give it to your coding agent. It contains the same reference text as the pages in this section.

Open the plain Markdown version

# Ninetile complete API guide

Canonical: https://ninetile.io/docs/agent-guide

# Getting started

Ninetile exposes JSON over HTTPS at https://api.ninetile.io/v1. Use the Token API to request an hCaptcha token or the Recognition API to request answers for a challenge you already have.

## 1. Create an account and a key

Create an account at https://ninetile.io/signup, add prepaid balance, and create an API key in the dashboard. The key is displayed once. Keep it server-side: do not embed it in a public website, repository, screenshot, or log.

Each key may have Token and/or Recognition permissions, an IP allow-list, and a spend limit. A lost key cannot be recovered; revoke and replace it.

## 2. Authenticate

Send `Authorization: Bearer <API_KEY>` with each authenticated request. `x-api-key` is also accepted. JSON requests must include `Content-Type: application/json`. Health is available without a key at `GET /v1/status`.

## 3. Check your account

```sh
curl https://api.ninetile.io/v1/me -H 'Authorization: Bearer YOUR_API_KEY'
```

`balance_usd` is the prepaid balance; `available_usd` excludes reservations for work in progress. `GET /v1/usage?days=7` reports daily usage.

## 4. Choose a task

- [Token API](https://ninetile.io/docs/token-api): submit a sitekey and URL, then wait for or poll a solve.
- [Recognition API](https://ninetile.io/docs/recognition-api): send a challenge's instruction and images and receive an answer synchronously.
- [Errors and limits](https://ninetile.io/docs/errors-and-limits): handle validation, rate limits, and terminal failures.

Use the API only on systems where you have permission. The Chrome extension is not published yet.

---

# Token API

`POST https://api.ninetile.io/v1/solves` creates a solve. A successful solve returns a token and the user agent used. It does not guarantee acceptance by a target.

## Request fields

- `type` (required): `hcaptcha` or `hcaptcha_enterprise`.
- `sitekey` (required): the hCaptcha widget's UUID; reCAPTCHA keys are not supported.
- `url` (required): the HTTP or HTTPS page where the challenge appears; at most 2,048 characters.
- `rqdata` (optional): fresh request data when supplied by the page, at most 16,384 characters.
- `user_agent` (optional): browser user agent, at most 512 characters.
- `proxy` (optional): an HTTP(S) proxy string or object with `host`, `port`, `scheme`, `username`, and `password`. The proxy host must be public. Without it, the service uses its own proxy pool.

```sh
curl 'https://api.ninetile.io/v1/solves?wait=60' \
  -H 'Authorization: Bearer YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{"type":"hcaptcha","sitekey":"f5ab1c2d-7e8f-4a9b-b1c2-d3e4f5a6b7c8","url":"https://example.com/"}'
```

Never paste a real API key or proxy password into shared examples. Sitekeys and URLs here are placeholders.

## Waiting and polling

`wait` is an optional whole number from 1 to 90 seconds on create or retrieve. Without it, creation returns HTTP 202 with a solve ID. With it, a completed solve returns HTTP 200; a solve still running returns 202. Use `GET /v1/solves/{id}?wait=60` to poll the same solve rather than creating repeated tasks.

Statuses are `pending`, `solving`, `solved`, `failed`, `cancelled`, and `expired`. A solved response contains `id`, `status`, `token`, `user_agent`, timestamps, and `charged_usd`. Running or failed solves have no token. A terminal failure includes `error.code`, `message`, `reason`, and `retryable`. Retry only when appropriate and create a fresh solve for a retry.

## Manage and report

- `GET /v1/solves`: newest-first list; supports `limit` (1–100), `starting_after`, `status`, and `type`.
- `DELETE /v1/solves/{id}`: cancel a running solve.
- `POST /v1/solves/{id}/feedback`: report one outcome.
- `POST /v1/feedback`: report up to 500 items in a `feedback` array with `solve_id`, `outcome` and optional `reason`. Outcomes: `accepted`, `rejected`, `unknown`, `unused`, `error`.

A solve reserves its price while in progress. Solved work is charged; failed, cancelled and expired solves release the reservation. The current displayed price is $0.75 per 1,000 solved tokens. Tokens are single-use and short-lived; stored tokens are cleared after seven days.

## Solve response fields

The object contains `id`, `object`, `type`, `status`, `sitekey`, `url`, `token`, `user_agent`, `error`, `charged_usd`, `created_at`, `started_at`, `finished_at`, `queue_ms` and `resolve_ms`. The token is present only after success, and a pending charge is not yet settled. Do not log tokens.

For feedback, the first report must arrive within 30 days of a successful solve. Optional `reason`, `context` and ISO 8601 `reported_at` fields supply context. Only the account owning a solved task can report it.

---

# Recognition API

`POST https://api.ninetile.io/v1/recognize` accepts one challenge and returns an answer synchronously. It does not return a token. An answered request is charged at $0.30 per 1,000 answers; a puzzle that cannot be answered returns `422 recognition_failed` without a charge.

## Simple grid and area-select form

- `type`: `hcaptcha` for a grid or `hcaptcha_area_select` for a point challenge.
- `task`: English instruction, nonempty and at most 500 characters.
- `image_data` or `image_urls`: images in task order. Grid accepts 1–27 images; area-select accepts exactly one.
- `image_examples` (optional): 1–3 reference images.

Images may be bare base64 or a base64 data URI. URLs must be HTTPS on `hcaptcha.com` or a subdomain; arbitrary URLs are not fetched. PNG, JPEG, GIF and WebP are supported. Each image is limited to 1.5 MiB and 1 megapixel; all images together are limited to 12 megapixels and the request to 12 MiB.

```json
{
  "type": "hcaptcha",
  "task": "Select all bicycles",
  "image_data": ["<BASE64_IMAGE_1>", "<BASE64_IMAGE_2>"]
}
```

Send this JSON to `https://api.ninetile.io/v1/recognize` with an API key and JSON content type. The placeholders must be replaced with actual image data.

## Full challenge form

Use `{"data": {...}}` for the full challenge object. `data.request_type` is one of:

- `image_label_binary`: up to 27 tasks.
- `image_label_area_select`: up to 5 tasks.
- `image_drag_drop`: up to 5 tasks; each drag task needs an `entities` array.

`data.requester_question.en` must contain the instruction. Each `data.tasklist` item needs a nonempty `task_key` and `datapoint_uri`. Drag entities use `entity_uri`; keep the challenge's entity identifiers intact. Image restrictions also apply to these fields.

## Answer shapes

For a simple grid, `data` is a boolean for each tile in the same order. For simple area select, `data` contains `x`, `y`, `w: 0`, and `h: 0`, with `points` listing all click positions. Coordinates are percentages of image dimensions. Drag answers contain each entity ID and its box in percentage coordinates; the drop centre is `(x + w/2, y + h/2)`. The full challenge form returns answers grouped by task.

Responses also include an `id` and `charged_usd`. Optionally report `{"id":"rec_...","result":"solved"}` or `"failed"` to `POST /v1/recognize/outcome`; reporting an outcome does not change billing. Video challenges are not accepted by the HTTP Recognition API.

## Illustrative responses

A simple grid response preserves input order:

~~~json
{"id":"rec_example","data":[true,false],"charged_usd":0.0003}
~~~

For an area task, a response may include:

~~~json
{"id":"rec_example","data":{"x":25,"y":60,"w":0,"h":0},"points":[{"x":25,"y":60}],"charged_usd":0.0003}
~~~

These IDs and coordinates are examples, not actual solutions. Full-form area responses contain one `data` entry and one `points` list per task. A full grid response groups boolean answers by page. Drag results preserve the predictor's boxes and entity identifiers. An outcome report returns `id`, `result` and `refunded_usd: 0`.

## Full-form request structure

~~~json
{"data":{"request_type":"image_label_binary","requester_question":{"en":"Select all bicycles"},"tasklist":[{"task_key":"task-1","datapoint_uri":"<BASE64_IMAGE>"}]}}
~~~

This is a structural example; replace the placeholder with real image data. For drag tasks use `image_drag_drop` and provide each task's `entities` array with entity image URIs and identifiers. Do not substitute a made-up entity ID for the challenge's ID.

---

# Billing and API key security

Ninetile uses prepaid US dollars, not a monthly plan. The current published rates are $0.75 per 1,000 successful token solves and $0.30 per 1,000 successful recognition answers. Failed requests are not charged.

## Balance and reservations

A solve reserves its price when admitted. While it is running, the reservation reduces available balance. A success settles the charge; failure, cancellation or expiry releases it. `GET /v1/me` exposes balance and available balance. `GET /v1/usage?days=7` reports daily usage.

## Key restrictions

Generate keys in the customer dashboard. A key can have Token, Recognition or both permissions. You may restrict source IPs or set a key-specific spend limit. An exhausted key returns `key_credit_limit_exceeded`; insufficient available account funds return `insufficient_credits`.

Store keys in a secret manager or server environment, never in client-side code or logs. A key is shown only once. Revoke it immediately if exposed and issue a replacement. API keys are separate from dashboard sessions.

## Adding balance

Use the billing page for the currently available top-up method. Cryptocurrency support is being prepared and will not appear until it is configured and enabled. A redirect from a payment provider alone is not proof that a balance was credited; check your billing history.

---

# Errors and limits

Every non-2xx native API response contains an `error` object with `code`, `message`, `param` and `request_id`. Responses include `X-Request-Id`; provide it when contacting support. A `Retry-After` header indicates how long to wait when present.

```json
{"error":{"code":"insufficient_credits","message":"The balance does not cover this call.","param":null,"request_id":"example-request-id"}}
```

## Common HTTP errors

- `400 invalid_request`: malformed JSON or request body.
- `401 unauthorized`: missing, malformed, unknown or revoked key.
- `402 insufficient_credits` or `key_credit_limit_exceeded`: add balance or review the key limit.
- `403 account_locked` or `forbidden`: account lock, key scope or IP restriction.
- `404 not_found`: unknown route or object on this account.
- `409 conflict`: operation conflicts with the current state.
- `413 payload_too_large`, `415 unsupported_media_type`: reduce the body or use a JSON content type.
- `422 validation_error` or `recognition_failed`: correct the named field or load a fresh challenge.
- `429 rate_limited`, `rate_capped` or `concurrency_limit_exceeded`: respect `Retry-After` and account limits.
- `500 internal_error`, `503 maintenance`, `capacity_exhausted` or `proxy_pool_depleted`: a service-side problem; retry later when appropriate.

## Solve failures are not always HTTP errors

A successfully created solve may later end with `failed`, `cancelled` or `expired`. Inspect the solve's `error` and `retryable` fields. Possible codes include `challenge_not_loaded`, `token_not_granted`, `challenge_expired`, `proxy_error`, `vision_error`, `unsolvable_variant`, `capacity_exhausted` and `internal_error`. No charge is made for these failed solves.

## Limits

Account concurrency and requests per minute are shown in dashboard settings. New solves are capped per account and sitekey at 120 per minute. Recognition image and request size limits are listed in the Recognition API guide. Ignore fields you do not recognize: fields can be added within v1.

---

# Compatibility APIs

Compatibility routes share your Ninetile account, balance, limits and API key. They support hCaptcha, not every task offered by the original services. Review the native API reference for billing and task behavior.

- 2Captcha-style: `https://api.ninetile.io/compat/2captcha` using `in.php` and `res.php`.
- CapSolver-style: `https://api.ninetile.io/compat/capsolver` using `createTask`, `getTaskResult` and `getBalance`. Equivalent route prefixes include `/compat/anticaptcha` and `/compat/capmonster`.
- NopeCHA-style token API: `https://api.ninetile.io/compat/nopecha`.

Pass your Ninetile `nt_live_` key where the compatible client expects a key. Use the native endpoints for the complete Ninetile-specific response, feedback and usage capabilities. Unsupported task types or options are not guaranteed to work.

## Supported createTask task types

The createTask adapter accepts `HCaptchaTask`, `HCaptchaTaskProxyless`, `HCaptchaEnterpriseTask`, `HCaptchaEnterpriseTaskProxyless`, `HCaptchaTurboTask` and `HCaptchaTurboTaskProxyless`. Proxyless tasks use the service pool; non-proxyless tasks require proxy fields or a proxy string. Set `websiteKey` and `websiteURL`; enterprise data may be passed as `enterprisePayload.rqdata`.

Send `clientKey` and `task` to createTask; then send `clientKey` and `taskId` to getTaskResult. Processing responses use `status: processing`; ready responses contain `solution.token`, `solution.gRecaptchaResponse`, and `solution.userAgent`. These dialects use their own error envelopes. The solver does not return a `resp_key`.