Skip to content

v1: tasks

POST /v1/tasks with type (a task type), params (that type’s parameters) and optional metadata:

Terminal window
export NOPTCHA_KEY=nop_test_... # your test or live key
IDEMPOTENCY_KEY=$(uuidgen) # one key per task you want; a retry of the same request reuses it
curl -s -X POST "https://api.noptcha.com/v1/tasks" \
-H "Authorization: Bearer $NOPTCHA_KEY" \
-H 'Prefer: wait=60' \
-H "Idempotency-Key: $IDEMPOTENCY_KEY" \
-H 'Content-Type: application/json' \
-d @- <<EOF
{
"type": "recaptcha.v2",
"params": {
"website_url": "https://www.google.com/recaptcha/api2/demo",
"website_key": "6Le-wvkSAAAAAPBMRTvw0Q4Muexq9bi0DJwx_mJ-"
},
"metadata": {
"order": "A-17"
}
}
EOF
Response Meaning
200 The task is final: status is solved or failed
202 The task is still processing: poll it
4xx, 503 The request was rejected; no task was created and nothing was charged (Errors)

Both 200 and 202 carry Location: /v1/tasks/{id}. A task that cannot be solved is a successful request: 200 with status: "failed", an error and zero cost.

Set callback_url to also receive the final result as a webhook (task.solved or task.failed).

Add Prefer: wait=N (or ?wait=N) to wait up to N seconds, at most 90, for the result in the same request:

  • the task finishes in time: 200 and the final task;
  • otherwise: 202 and the task in processing; continue with GET /v1/tasks/{id}.

When the wait was applied the response has Preference-Applied: wait=N. If your organization already has too many requests waiting, the request returns 202 at once without that header. Types that are solved synchronously return the result immediately in any case.

GET /v1/tasks/{id} returns the task. With ?wait=N (at most 90) the request waits until the task is final or N seconds pass, so you do not need a tight polling loop:

Terminal window
export NOPTCHA_KEY=nop_test_... # your test or live key
TASK_ID=7259140378796032 # the task ID you got when creating the task
curl -s "https://api.noptcha.com/v1/tasks/$TASK_ID?wait=30" \
-H "Authorization: Bearer $NOPTCHA_KEY"

Polling one task is limited to 5 requests per second (bursts of 10); a long poll counts once. If a long poll returns processing immediately (the waiting slots are full), wait a second before the next poll instead of retrying at once.

Send an Idempotency-Key header (1–64 visible ASCII characters, for example a UUID) with POST /v1/tasks. Use one new key for each task you want, and the same key for every retry of that request. If the request fails on the network and you retry it with the same key and a byte-for-byte identical body, you get the same task back instead of a second, separately charged task. Replayed responses carry Idempotent-Replayed: true.

The body is compared as raw bytes, not as JSON: a body with the same fields in a different order, with different whitespace, or with 0.7 written as 0.70 counts as a different body. Serialize the body once and resend those exact bytes; do not rebuild it for each attempt:

Terminal window
export NOPTCHA_KEY=nop_test_... # your test or live key
IDEMPOTENCY_KEY=$(uuidgen) # one key per task you want; a retry of the same request reuses it
# --retry resends the same bytes with the same key after a timeout or a 408, 429 or 5xx response
curl -s --retry 3 -X POST "https://api.noptcha.com/v1/tasks" \
-H "Authorization: Bearer $NOPTCHA_KEY" \
-H 'Prefer: wait=60' \
-H "Idempotency-Key: $IDEMPOTENCY_KEY" \
-H 'Content-Type: application/json' \
-d @- <<EOF
{
"type": "recaptcha.v2",
"params": {
"website_url": "https://www.google.com/recaptcha/api2/demo",
"website_key": "6Le-wvkSAAAAAPBMRTvw0Q4Muexq9bi0DJwx_mJ-"
},
"metadata": {
"order": "A-17"
}
}
EOF
  • Keys are kept for 24 hours per organization.
  • The same key with a different body (any difference in the bytes) is 409 idempotency_conflict; so is a retry while the first request with that key is still being admitted (retry shortly).
  • If the first request did not create a task (insufficient balance, no capacity, invalid parameters…), the key is released and you can use it again.
  • 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.

metadata is your own string key-value pairs, returned with the task: at most 16 keys; keys 1–64 characters, values at most 256 characters. A value that is not a string is 422 invalid_params with pointer /metadata/<key>.

Pass proxy in params for types that accept one; see Proxies.

Terminal window
export NOPTCHA_KEY=nop_test_... # your test or live key
curl -s -X POST "https://api.noptcha.com/v1/tasks" \
-H "Authorization: Bearer $NOPTCHA_KEY" \
-H 'Content-Type: application/json' \
-d @- <<EOF
{
"type": "recaptcha.v2",
"params": {
"website_url": "https://example.com/login",
"website_key": "6Le-wvkSAAAAAPBMRTvw0Q4Muexq9bi0DJwx_mJ-",
"proxy": {
"type": "http",
"host": "203.0.113.7",
"port": 8080,
"login": "proxyuser",
"password": "proxypass"
}
}
}
EOF

After using a solution, report whether it worked:

Terminal window
export NOPTCHA_KEY=nop_test_... # your test or live key
TASK_ID=7259140378796032 # the task ID you got when creating the task
curl -s -X POST "https://api.noptcha.com/v1/tasks/$TASK_ID/feedback" \
-H "Authorization: Bearer $NOPTCHA_KEY" \
-H 'Content-Type: application/json' \
-d @- <<EOF
{
"correct": false,
"reason": "token rejected by the site"
}
EOF

correct is required; reason is optional and is not stored. Feedback is accepted for solved tasks within 10 minutes after completion and returns {"id": "…", "accepted": true}; only the first report per task is recorded, later ones still succeed. A task that is still processing or failed returns 409 task_not_solved. Feedback is recorded as a quality signal; it does not refund the task.

Terminal window
export NOPTCHA_KEY=nop_test_... # your test or live key
# waits up to 60 s; 200 = finished (solved or failed), 202 = still processing
IDEMPOTENCY_KEY=$(uuidgen) # one key per task you want; a retry of the same request reuses it
curl -s -X POST "https://api.noptcha.com/v1/tasks" \
-H "Authorization: Bearer $NOPTCHA_KEY" \
-H 'Prefer: wait=60' \
-H "Idempotency-Key: $IDEMPOTENCY_KEY" \
-H 'Content-Type: application/json' \
-d @- <<EOF
{
"type": "turnstile",
"params": {
"website_url": "https://example.com/signup",
"website_key": "1x00000000000000000000AA",
"action": "signup"
}
}
EOF
# on 202: long-poll with the "id" from the response
TASK_ID=...
curl -s "https://api.noptcha.com/v1/tasks/$TASK_ID?wait=60" \
-H "Authorization: Bearer $NOPTCHA_KEY"