Create a task
POST https://api.noptcha.com/v1/tasks
Native API (v1). Guide. Operation ID createTask.
Creates a task. A task that is already final (solved or failed) is returned with 200; a task that
is still processing with 202. Both carry Location: /v1/tasks/{id}.
Synchronous waiting. With Prefer: wait=N (or ?wait=N), the request waits up to N seconds
(at most 90) for the result: 200 if the task completes in time, otherwise 202 and you poll
GET /v1/tasks/{id}. Preference-Applied: wait=N confirms the wait (N capped at 90). Types solved
synchronously return the result at once anyway. When an organization already has too many waiting
requests, the request returns 202 without waiting and without Preference-Applied.
Idempotency. With Idempotency-Key (1–64 visible ASCII characters, kept for 24 hours per organization),
retrying the same request returns the same task instead of creating and charging a new one; replayed
responses carry Idempotent-Replayed: true. The same key with a body that is not byte-for-byte identical (serialize once, resend the same bytes) is 409 idempotency_conflict; so is a retry while the first request with that key is still being admitted
(retry shortly). When the first request did not create a task (insufficient balance, no capacity,
invalid parameters…) the key is released and can be reused. After the task's result has expired
(10 minutes after completion) a replay is 404 not_found: the task is not created again, use a new key.
Failures. A task that cannot be solved is a successful request: 200 with status: "failed",
error.code and zero cost. 503 service_unavailable means no solver could take the task right now;
nothing was created or charged.
Callbacks. With callback_url, the final result is also POSTed there as a task.solved or
task.failed event (see Webhooks). An invalid URL is 422 invalid_params with pointer /callback_url
and no task is created; a callback_url that is not a string is 400 invalid_request. null and ""
mean no callback.
Every response passes through the per-key create limit and carries RateLimit-Policy and
RateLimit (when rate limiting is enabled), including errors after authentication.
Request
Authentication: Authorization: Bearer <key> (Keys).
| Parameter | In | Description |
|---|---|---|
Preferoptional | header |
|
waitoptional | query | Seconds to wait for the result (capped at 90). Takes precedence over |
Idempotency-Keyoptional | header | 1–64 visible ASCII characters ( |
Body (application/json, required):
One of (selected by type):
CreateCloudflareChallengeTaskRequest— Cloudflare challenge page (cloudflare.challenge, familycloudflare, active). Variants:proxy(params.proxyis required). Tasks not solved within 120 seconds fail withtimeout.CreateFuncaptchaTaskRequest— FunCaptcha (Arkose Labs) (funcaptcha, familyarkose, beta). Variants:proxyless,proxy(theproxyvariant whenparams.proxyis given). Tasks not solved within 180 seconds fail withtimeout.CreateHcaptchaTaskRequest— hCaptcha (hcaptcha, familyhcaptcha, active). Variants:proxyless,proxy(theproxyvariant whenparams.proxyis given). Tasks not solved within 120 seconds fail withtimeout.CreateImageFuncaptchaTaskRequest— FunCaptcha image (image.funcaptcha, familyimage, beta). Variants:proxyless. Tasks not solved within 60 seconds fail withtimeout.CreateImageGridAwsTaskRequest— AWS WAF image grid (image.grid.aws, familyimage, beta). Variants:proxyless. Tasks not solved within 60 seconds fail withtimeout.CreateImageGridHcaptchaTaskRequest— hCaptcha image grid (image.grid.hcaptcha, familyimage, active). Variants:proxyless. Tasks not solved within 60 seconds fail withtimeout.CreateImageGridRecaptchaTaskRequest— reCAPTCHA image grid (image.grid.recaptcha, familyimage, active). Variants:proxyless. Tasks not solved within 60 seconds fail withtimeout.CreateImageTextTaskRequest— Image to text (image.text, familyimage, active). Variants:proxyless. Tasks not solved within 60 seconds fail withtimeout.CreateRecaptchaV2TaskRequest— reCAPTCHA v2 (recaptcha.v2, familyrecaptcha, active). Variants:proxyless,proxy(theproxyvariant whenparams.proxyis given). Tasks not solved within 120 seconds fail withtimeout.CreateRecaptchaV2EnterpriseTaskRequest— reCAPTCHA v2 Enterprise (recaptcha.v2.enterprise, familyrecaptcha, active). Variants:proxyless,proxy(theproxyvariant whenparams.proxyis given). Tasks not solved within 120 seconds fail withtimeout.CreateRecaptchaV3TaskRequest— reCAPTCHA v3 (recaptcha.v3, familyrecaptcha, active). Variants:proxyless. Tasks not solved within 120 seconds fail withtimeout.CreateRecaptchaV3EnterpriseTaskRequest— reCAPTCHA v3 Enterprise (recaptcha.v3.enterprise, familyrecaptcha, active). Variants:proxyless. Tasks not solved within 120 seconds fail withtimeout.CreateTurnstileTaskRequest— Cloudflare Turnstile (turnstile, familycloudflare, active). Variants:proxyless,proxy(theproxyvariant whenparams.proxyis given). Tasks not solved within 120 seconds fail withtimeout.
{ "metadata": { "order": "A-17" }, "params": { "website_key": "6Le-wvkSAAAAAPBMRTvw0Q4Muexq9bi0DJwx_mJ-", "website_url": "https://example.com/login" }, "type": "recaptcha.v2"}Responses
200
The task is final (solved or failed).
Headers: Idempotent-Replayed (optional), Location (optional), Noptcha-Request-Id, Preference-Applied (optional), RateLimit (optional), RateLimit-Policy (optional).
Content: application/json
| Field | Type | Description |
|---|---|---|
completed_atoptional | string | When the task became final; absent while processing. format: date-time · pattern: ^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}\.[0-9]{3}Z$ |
costrequired | object | What the task cost (zero unless solved and charged). |
cost.amountrequired | string | Decimal US dollars with 6 places. pattern: ^-?[0-9]+\.[0-9]{6}$ |
cost.currencyrequired | const "USD" | |
created_atrequired | string | format: date-time · pattern: ^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}\.[0-9]{3}Z$ |
errorrequired | one of | null | Why the task failed when TaskError |
idrequired | string | Task ID (a 53-bit integer as a string). pattern: ^[0-9]+$ |
metadataoptional | object | Your own key-value pairs, returned with the task. At most 16 keys; keys 1–64 characters, values
strings of at most 256 characters (Unicode code points, as JSON Schema counts them). A value that is
not a string is |
metadata.<any key>optional | string | max length 256 |
paramsrequired | object | null | The task's parameters with secrets removed (proxy login and password, cookies where the type marks
them sensitive) and strings longer than 256 bytes (images) replaced by |
sandboxoptional | const true | Present (true) on tasks created with a test key. |
solutionrequired | one of | null | The answer when Solution |
statusrequired | enum | one of "processing", "solved", "failed" |
typerequired | string | Canonical task type, e.g. |
202
The task is still processing; poll Location.
Headers: Idempotent-Replayed (optional), Location (optional), Noptcha-Request-Id, Preference-Applied (optional), RateLimit (optional), RateLimit-Policy (optional).
Content: application/json
| Field | Type | Description |
|---|---|---|
completed_atoptional | string | When the task became final; absent while processing. format: date-time · pattern: ^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}\.[0-9]{3}Z$ |
costrequired | object | What the task cost (zero unless solved and charged). |
cost.amountrequired | string | Decimal US dollars with 6 places. pattern: ^-?[0-9]+\.[0-9]{6}$ |
cost.currencyrequired | const "USD" | |
created_atrequired | string | format: date-time · pattern: ^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}\.[0-9]{3}Z$ |
errorrequired | one of | null | Why the task failed when TaskError |
idrequired | string | Task ID (a 53-bit integer as a string). pattern: ^[0-9]+$ |
metadataoptional | object | Your own key-value pairs, returned with the task. At most 16 keys; keys 1–64 characters, values
strings of at most 256 characters (Unicode code points, as JSON Schema counts them). A value that is
not a string is |
metadata.<any key>optional | string | max length 256 |
paramsrequired | object | null | The task's parameters with secrets removed (proxy login and password, cookies where the type marks
them sensitive) and strings longer than 256 bytes (images) replaced by |
sandboxoptional | const true | Present (true) on tasks created with a test key. |
solutionrequired | one of | null | The answer when Solution |
statusrequired | enum | one of "processing", "solved", "failed" |
typerequired | string | Canonical task type, e.g. |
400
invalid_request: the body is not valid JSON or misses a field, a parameter is wrong, callback_url
is not a string, the result would be too large (usage). unsupported_type: the task type
does not exist or is not available.
Headers: Noptcha-Request-Id, RateLimit (optional), RateLimit-Policy (optional).
Content: application/problem+json
| Field | Type | Description |
|---|---|---|
coderequired | string | Machine-readable error code (see the table). |
detailoptional | string | Human-readable explanation of this occurrence. |
request_idrequired | string | Same as the |
statusrequired | integer | The HTTP status code. |
titlerequired | string | |
typerequired | string | format: uri |
401
unauthorized: the key is malformed, unknown, revoked or expired.
Headers: Noptcha-Request-Id, RateLimit (optional), RateLimit-Policy (optional).
Content: application/problem+json
| Field | Type | Description |
|---|---|---|
coderequired | string | Machine-readable error code (see the table). |
detailoptional | string | Human-readable explanation of this occurrence. |
request_idrequired | string | Same as the |
statusrequired | integer | The HTTP status code. |
titlerequired | string | |
typerequired | string | format: uri |
402
insufficient_balance or budget_exceeded (the key's spending budget for the period is used up).
Headers: Noptcha-Request-Id, RateLimit (optional), RateLimit-Policy (optional).
Content: application/problem+json
| Field | Type | Description |
|---|---|---|
coderequired | string | Machine-readable error code (see the table). |
detailoptional | string | Human-readable explanation of this occurrence. |
request_idrequired | string | Same as the |
statusrequired | integer | The HTTP status code. |
titlerequired | string | |
typerequired | string | format: uri |
403
forbidden: the key lacks the scope this endpoint needs, the client IP is not in the key's allowlist,
the key may not use this task type, or the organization is suspended (detail says which).
Also returned, without detail, when the request did not pass through our edge network.
Headers: Noptcha-Request-Id, RateLimit (optional), RateLimit-Policy (optional).
Content: application/problem+json
| Field | Type | Description |
|---|---|---|
coderequired | string | Machine-readable error code (see the table). |
detailoptional | string | Human-readable explanation of this occurrence. |
request_idrequired | string | Same as the |
statusrequired | integer | The HTTP status code. |
titlerequired | string | |
typerequired | string | format: uri |
404
not_found: no such task, it expired (results are kept 10 minutes after completion) or it belongs to
another organization; or the task created with this Idempotency-Key has expired.
Headers: Noptcha-Request-Id, RateLimit (optional), RateLimit-Policy (optional).
Content: application/problem+json
| Field | Type | Description |
|---|---|---|
coderequired | string | Machine-readable error code (see the table). |
detailoptional | string | Human-readable explanation of this occurrence. |
request_idrequired | string | Same as the |
statusrequired | integer | The HTTP status code. |
titlerequired | string | |
typerequired | string | format: uri |
409
idempotency_conflict: the Idempotency-Key was used with a different body, or the first request with
it is still being processed (retry shortly). task_not_solved: feedback for a task that is not solved
(still processing, or failed).
Headers: Noptcha-Request-Id, RateLimit (optional), RateLimit-Policy (optional).
Content: application/problem+json
| Field | Type | Description |
|---|---|---|
coderequired | string | Machine-readable error code (see the table). |
detailoptional | string | Human-readable explanation of this occurrence. |
request_idrequired | string | Same as the |
statusrequired | integer | The HTTP status code. |
titlerequired | string | |
typerequired | string | format: uri |
413
request_too_large: the body exceeds the limit (1 MB for image types, 64 KB otherwise). Any request
with a body over 1 MB gets this, GET requests included.
Headers: Noptcha-Request-Id, RateLimit (optional), RateLimit-Policy (optional).
Content: application/problem+json
| Field | Type | Description |
|---|---|---|
coderequired | string | Machine-readable error code (see the table). |
detailoptional | string | Human-readable explanation of this occurrence. |
request_idrequired | string | Same as the |
statusrequired | integer | The HTTP status code. |
titlerequired | string | |
typerequired | string | format: uri |
422
invalid_params: params or metadata do not match the schema; errors lists each problem.
Headers: Noptcha-Request-Id, RateLimit (optional), RateLimit-Policy (optional).
Content: application/problem+json
| Field | Type | Description |
|---|---|---|
coderequired | string | Machine-readable error code (see the table). |
detailoptional | string | Human-readable explanation of this occurrence. |
request_idrequired | string | Same as the |
statusrequired | integer | The HTTP status code. |
titlerequired | string | |
typerequired | string | format: uri |
errorsrequired | array of FieldError | One entry per problem, sorted by |
errors.[item]optional | object | |
errors.[item].messagerequired | string | |
errors.[item].pointerrequired | string | JSON Pointer (RFC 6901) to the offending value, from the root of the request body:
|
errors.[item].reasonoptional | enum | Machine-readable kind, present for image problems: |
429
rate_limited: too many tasks created per second by this key, the same task polled too often, the
sandbox's per-organization rate, usage queried too often, the catalog fetched too often from this IP, or
this IP sent too many invalid keys.
concurrency_limited: the organization has too many tasks in flight for this captcha family (or, with a
test key, too many sandbox tasks still processing). Wait Retry-After seconds.
Headers: Noptcha-Request-Id, RateLimit (optional), RateLimit-Policy (optional), Retry-After.
Content: application/problem+json
| Field | Type | Description |
|---|---|---|
coderequired | string | Machine-readable error code (see the table). |
detailoptional | string | Human-readable explanation of this occurrence. |
request_idrequired | string | Same as the |
statusrequired | integer | The HTTP status code. |
titlerequired | string | |
typerequired | string | format: uri |
500
internal: an error on our side.
Headers: Noptcha-Request-Id, RateLimit (optional), RateLimit-Policy (optional).
Content: application/problem+json
| Field | Type | Description |
|---|---|---|
coderequired | string | Machine-readable error code (see the table). |
detailoptional | string | Human-readable explanation of this occurrence. |
request_idrequired | string | Same as the |
statusrequired | integer | The HTTP status code. |
titlerequired | string | |
typerequired | string | format: uri |
503
service_unavailable: no capacity right now (all solvers busy or failing, the gateway is overloaded,
a dependency is unavailable). For POST /v1/tasks nothing was created or charged. Wait Retry-After.
Headers: Noptcha-Request-Id, RateLimit (optional), RateLimit-Policy (optional), Retry-After.
Content: application/problem+json
| Field | Type | Description |
|---|---|---|
coderequired | string | Machine-readable error code (see the table). |
detailoptional | string | Human-readable explanation of this occurrence. |
request_idrequired | string | Same as the |
statusrequired | integer | The HTTP status code. |
titlerequired | string | |
typerequired | string | format: uri |
Header descriptions and every schema: Schemas. Machine-readable: openapi.json, openapi.yaml.