# How a task works

> A task's states from queued to succeeded, failed or expired, how long each step takes, how long a token lasts, and what is charged and when.

Source: https://zerocaptcha.io/docs/how-tasks-work

A task is one request to solve one challenge: a Turnstile widget, or a Cloudflare challenge page.
This page follows a task from the moment you create it to the moment its token is deleted, and says
what your balance does at each step. It is the same whichever [format](https://zerocaptcha.io/docs#three-formats-one-api)
you create the task in.

## The life of a task

1. **Created:** the task is `queued`, its price held.
2. **Taken on:** a solver node starts an attempt, and the task is `running`.
3. **Ended:** solved, it is `succeeded`; not solved with attempts and time left, it goes back to
   `queued` for another attempt; not solved after its last attempt, it is `failed`; still
   unsolved at its deadline, queued or running, it is `expired`.

| `status` | What it means | Final |
| --- | --- | --- |
| `queued` | Waiting for a solver with room. A task being retried is back here. | No |
| `running` | A solver node is working on it. | No |
| `succeeded` | Solved. The token is in the task while it is valid, and the price is charged. | Yes |
| `failed` | Not solved: every attempt failed, or a check before an attempt refused it. Nothing is charged. | Yes |
| `expired` | Not solved before its deadline. Nothing is charged. | Yes |

Only these moves happen: `queued` to `running`, `running` back to `queued` for a retry, and
`queued` or `running` to one of the three final states. A final state never changes.

## Timing

- **The deadline.** Every task has one, in its `deadline` field: 150 seconds after it was created,
  by default. A task still unsolved then expires with `ERROR_TASK_TIMEOUT`.
- **Attempts.** A task gets up to 3 solve attempts by default (its `maxAttempts`), and `attempts`
  says how many it has had. An attempt counts once a solver node took the work on; time spent
  waiting for a node with room counts toward the deadline, not the attempts. A task is not retried
  with less than 5 seconds left before its deadline.
- **Checks before each attempt.** Before every attempt the page's domain is checked against the
  blocklist, the account against suspension, and a proxy's name is resolved again and must still
  be public. A task that fails one of these ends `failed` with `ERROR_DOMAIN_BLOCKED`,
  `ERROR_ACCOUNT_SUSPENDED` or `ERROR_PROXY_NOT_ALLOWED`. An owner who deletes the account
  cancels its queued tasks at once, with `ERROR_ACCOUNT_DELETED`.
- **How long it takes.** It depends on the site and the solvers' load; the
  [status page](https://zerocaptcha.io/status) shows the median time to a token over the last 24 hours. Read the task
  every 2 seconds, or have us [call you back](https://zerocaptcha.io/docs/callbacks).

## The token

A solved task carries its result in `solution`:

| Task | `solution.token` | Valid for |
| --- | --- | --- |
| Turnstile | The token for the page's `cf-turnstile-response` field or the widget's callback | 300 seconds from `tokenIssuedAt`, once: Cloudflare accepts each token one time |
| Challenge page | The `cf_clearance` cookie's value, with `solution.userAgent` and `solution.cookie` | As long as the site's Challenge Passage allows (30 minutes by default); we serve it for 30 minutes |

`tokenExpiresAt` says until when the token is served. `tokenState` says where it stands:

| `tokenState` | Meaning |
| --- | --- |
| `pending` | The task has not finished yet. |
| `available` | Solved, and the token is valid: reading the task returns it. |
| `expired` | Solved, but its lifetime has passed. The task stays charged. |
| `deleted` | Solved, and the token was deleted, 10 minutes after it expired. |
| `none` | The task failed or expired, so there is no token. |

Use a token as soon as you have it. A Turnstile token read after it expired cannot be renewed: the
REST API shows `tokenState: "expired"` and no `solution`, and `getTaskResult` answers
`ERROR_TOKEN_EXPIRED`. Either way, the task succeeded and stays charged.

## What is charged, and when

| When | Your balance |
| --- | --- |
| You create a task | Its price is **held**: `available` goes down by the price, `held` goes up by it. |
| It succeeds | The hold becomes a **charge**, once. `cost` on the task becomes its price. |
| It fails or expires | The hold is **released** in full. `cost` stays `0.000000`. |
| A request is refused | Nothing is held or charged, whatever the code. |

- A task is charged the price in effect **when it was created**, which the task shows as `price`.
  Prices are public at [`GET /v1/prices`](https://zerocaptcha.io/docs/reference/api/prices) and on the
  [pricing page](https://zerocaptcha.io/pricing).
- A task your balance cannot cover is refused before it starts, with
  [`insufficient_funds`](https://zerocaptcha.io/docs/reference/errors#insufficient_funds). Prices held for running tasks
  count against your balance.
- A key with a [daily spend cap](https://zerocaptcha.io/docs/keys#cap-a-keys-daily-spend) counts what its tasks hold or
  were charged that UTC day.
- Each task settles exactly once: a solver that answers twice, or a worker that restarts, can
  never charge a task twice or release it after it was charged.

> **Nothing free, nothing wasted**
>
> There is no sandbox or test key: every task solves a real challenge and is charged if it succeeds.
> To try the API cheaply, send one task; it costs one task's price, and only if it is solved.

## Creating the same task twice

Send an `Idempotency-Key` header with every create, one new value per task. If a reply is lost and
you send the same request again with the same key within 24 hours, you get the first reply, with
the same task, instead of a second task and a second charge. See
[Errors and retries](https://zerocaptcha.io/docs/errors-and-retries#idempotency).

## How long tasks are kept

Tasks stay in your task log and in the API for about 90 days: records are deleted a month at a
time, once the month they were created in ended more than 90 days ago. A proxy's password is
deleted as soon as its task finishes, and a token 10 minutes after it expires. Your monthly usage
totals stay.
