# 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.

Canonical: https://ninetile.io/docs/recognition-api
