CAPTCHA: explicit task API in TypeScript
Use ctx.captcha() to describe a task, obtain a cost estimate, submit it explicitly and read the answer. This API does not open a website, detect a new CAPTCHA, fill a form or apply a result to a browser. The task type determines both the input fields and the answer format. Export transformations that prohibit host calls cannot use this API.
The same contract works in the cloud and on your agent. No external account, service key or payment token is accepted in a script. Work is charged to the site’s workspace plan and balance. The agent needs a connection to Akmelo; these operations are unavailable offline.
Before submitting
Start with types() and describe(type). They read the current catalog without creating a paid task. Use quote(task) after preparing the fields. A task is created only by createTask(); method names use snake_case in Python. A quote is an estimate, not a reservation or guaranteed future price. Creation also requires CAPTCHA to be enabled for the site and permitted by platform settings.
Do not send passwords, authentication cookies, personal data or unrelated page contents. Send only fields listed in describe(type). Arbitrary endpoints, provider selection, credentials and callbacks are not task options. Types may require different data and are not interchangeable.
For GridTask.previousId, pass the taskId returned by your earlier ready GridTask from the same site and workspace (and the same agent for agent execution). The platform resolves the internal reference; an external identifier or a task from another scope is rejected before submission.
Methods
types()describe()quote()createTask()getTaskResult()waitForResult()reportCorrect()reportIncorrect()
types
await ctx.captcha().types()
Returns {types: [...], languages: [...], unit: 1000000}. Each catalog entry describes an available type; languages lists supported language pool codes. The list reflects this installation: do not treat a separately hard-coded list as authoritative. Plan availability and remaining resources are checked again when creating a task.
describe
await ctx.captcha().describe('ImageToTextTask')
Returns one type’s type, name, kind, parameters, solution and pricing information. parameters lists accepted fields, types, required values and limits; solution describes the answer. Unknown types are rejected. For example, ImageToTextTask accepts base64 in body; AudioTask accepts audio in body and an audio language in lang; this task field is distinct from options.languagePool. Read their schemas for exact limits.
Some descriptions include required_any: provide one complete alternative field set in addition to ordinary required fields. requirements lists conditional requirements, for example for different versions of a task. A list of optional fields alone is insufficient to construct a valid submission. In price, quoted: false means that a technical reservation is used instead of a confirmed price range; available describes price availability, not successful website access.
quote
await ctx.captcha().quote(task)
Validates the fields and returns {minimum, maximum, unit: 1000000}. Amounts use micro-rubles: 1,000,000 units = RUB 1. minimum: null means the lower bound is unknown, not zero. maximum is the upper estimate used for a preliminary reservation. Plan allowances and permission for additional charges are still enforced by the server.
createTask
await ctx.captcha().createTask(task, options = {})
Creates an explicit task. Returns {taskId, status}: taskId is a platform UUID and a new submission has status processing or uncertain. An idempotent retry can return an already completed ready or failed state. Do not use identifiers from another system. Unknown types, fields and invalid values are rejected before submission. uncertain means submission could not be confirmed: keep the identifier and check it instead of creating another paid task.
getTaskResult
await ctx.captcha().getTaskResult(taskId)
Reads an existing task without creating another one. Returns taskId, status, unit and, when available, solution, cost, error. The solution is a type-specific JSON value: object, array, string, number, boolean or null. For example, it can contain text, coordinates, an angle, a token or another documented structure. Do not assume every answer has a text field. Use the safe error field for diagnostics.
waitForResult
await ctx.captcha().waitForResult(taskId, timeoutMs = 120000)
Waits for an existing task. timeoutMs ranges from 0 to 120000; 0 performs one status check. At the end of the wait, returns the last state, including processing or uncertain. This neither cancels the task nor submits another one. Cancellation or the overall run deadline interrupts the wait with an error. Keep taskId to retrieve the result later.
reportCorrect
await ctx.captcha().reportCorrect(taskId)
Reports an answer you have independently verified as correct. Returns {taskId, accepted}. accepted: true only confirms that feedback was accepted; it does not prove a website accepted the result. Do not report success solely because a task became ready.
reportIncorrect
await ctx.captcha().reportIncorrect(taskId)
Reports an answer you have independently verified as incorrect. Returns {taskId, accepted}. Accepted feedback does not guarantee a refund, cancel the task or start another one. A website refusal for another reason does not prove the CAPTCHA answer is wrong.
Creation options
Options keep the same keys in all languages; only Python method names use snake_case.
| Field | Value | Meaning |
|---|---|---|
requestId |
1–128 characters: A–Z, a–z, 0–9, ., _, :, - |
A stable idempotency key for one logical submission within the same run. Reuse it when retrying that same submission. Use a new key for genuinely new input. A new run does not reuse the previous run’s key; read the saved taskId instead of submitting again. |
language |
ru or en |
Short alias for the task language pool. |
languagePool |
Code from types().languages, for example zh |
Language pool for task instructions. Not the website interface language. Do not combine it with a different language value. |
maxCost |
Non-negative integer in micro-rubles | Your per-task ceiling. If the system reservation exceeds it, submission is rejected. It does not change the task price. |
States and billing
| Status | What to do |
|---|---|
processing |
Wait for this task identifier. |
ready |
Read the solution and independently verify its use. |
failed |
Inspect the error; avoid an automatic endless retry loop. |
uncertain |
Submission or its outcome is not confirmed. Recheck this identifier. |
A ready answer can be chargeable even when a website rejects it. The workspace’s ordinary CAPTCHA allowance, balance, reservations and price ceilings apply. cost, when present, is the workspace charge in micro-rubles, not a separate bill from another service. The quote is not the final charge; unused reservations are released after reconciliation. Stopping a run or timing out the wait does not guarantee cancellation or a refund.
Task identifiers are scoped to the same site and workspace. An agent can only retrieve its own agent tasks. Another run of the same permitted site can read an existing task; an identifier alone grants no access. Solutions are retained for 24 hours. After expiry, ready may be returned without solution and with error: result_expired; keep only the business result you need, not reusable authentication material.
Complete example using your fixture
Prepare a small image with known text and put only its base64 contents in the fixture_image_base64 run parameter. No URL or data-URL prefix is needed. By default the example only quotes a task: send_task=false. Set send_task=true only when you intend to submit a chargeable task. Change the request key when changing the fixture. Code validation checks syntax and SDK usage without submitting the task.
async function run(ctx: Akmelo.Context): Promise<void> {
const captcha = ctx.captcha();
const body = ctx.param<string>('fixture_image_base64', '');
if (!body) ctx.abort('Provide base64 of your own test image');
const task = { type: 'ImageToTextTask', body };
const price = await captcha.quote(task);
ctx.log('Maximum reservation: ' + price.maximum + ' micro-rubles');
if (!ctx.param<boolean>('send_task', false)) return;
const created = await captcha.createTask(task, {
requestId: 'fixture-image-001',
language: 'ru',
maxCost: price.maximum,
});
const result = await captcha.waitForResult(created.taskId, 120000);
const solution = result.solution;
if (result.status === 'ready' && solution !== null &&
typeof solution === 'object' && !Array.isArray(solution) &&
typeof solution.text === 'string') {
ctx.emit({ text: solution.text }, 'fixture-001');
} else {
ctx.log('Task state: ' + result.status);
}
}
Other inputs and errors
For audio, first read describe("AudioTask"): provide base64 audio in body and the documented lang value. For other types, read their own parameters and solution schema. Never send a token task as an image task or cast coordinate arrays into a string. Invalid base64, unsupported fields, size limits, a disabled feature, insufficient resources and inaccessible task IDs are distinct failures. Handle them by cause; waiting on an existing identifier is different from a new submission.
This explicit API does not extend the set of automatically detected browser CAPTCHA types. autoCaptcha=false (Python: auto_captcha=False) controls automatic HTTP/browser handling; it does not disable an explicit creation call. To exclude paid submissions, do not call the creation method.