API reference
Capciao solves reCAPTCHA v3 / Enterprise for pages listed in its validated registry. The contract follows the asynchronous createTask / getTaskResult model: one call creates the task, a second one polls its result until it is ready.
. All requests are JSON POSTs. All business responses return HTTP 200; the error is read from errorId and errorCode. Responses carry Cache-Control: no-store.Overview
createTask / getTaskResult format is the one the ecosystem uses; Capciao adopts it for your existing integrations, and nothing else. The token is issued by Google and handed to you as is.A task goes through three states: processing while it is being solved, then ready with the token, or a terminal error. The token is issued by Google. It is valid for about two minutes on Google's side, cannot be replayed and must be used immediately.
- Two task types:
RecaptchaV3TaskProxyless(our network egress) andRecaptchaV3Task(your own proxy,proxyfield). - A single domain:
google.com. - A registry of validated pages; any other page is rejected before execution.
- No storage of parameters, keys or tokens.
Quick start
Create a task for the sample validated page, then poll its result every four seconds.
curl -sS {{apiPublic}}/createTask \
-H 'content-type: application/json' \
--data '{
"clientKey": "YOUR_PRIVATE_KEY",
"task": {
"type": "RecaptchaV3TaskProxyless",
"websiteURL": "https://www.acehardware.com/user/login",
"websiteKey": "6LeOCzAtAAAAAEMV83_o-Sx6uZsxO_haVNGyojSB",
"minScore": 0.9,
"pageAction": "LOGIN",
"isEnterprise": true,
"apiDomain": "google.com"
}
}'
# → {"errorId":0,"taskId":42}curl -sS {{apiPublic}}/getTaskResult \
-H 'content-type: application/json' \
--data '{"clientKey":"YOUR_PRIVATE_KEY","taskId":42}'
# while running → {"errorId":0,"status":"processing"}
# done → {"errorId":0,"status":"ready","solution":{"gRecaptchaResponse":"03AFcWeA…","token":"03AFcWeA…"},
# "createTime":1757664000,"endTime":1757664012,"solveCount":1}Code generator
Fill in your page, pick the language: the complete code updates, ready to paste. Nothing leaves your browser.
Authentication
Each customer receives a private key of at least 32 characters. It is sent in the clientKey field of the JSON body, never in the URL or in a header. A missing or unknown key returns ERROR_KEY_DOES_NOT_EXIST.
Each key is limited to 120 requests per sliding minute, result polling included. Beyond that, ERROR_RATE_LIMITED is returned until the window clears.
POST/createTask
Creates a solving task. The request is fully validated before being accepted: any unknown field, any out-of-contract value or any page outside the registry is rejected immediately, without using a slot.
{
"clientKey": "YOUR_PRIVATE_KEY",
"task": {
"type": "RecaptchaV3TaskProxyless",
"websiteURL": "https://www.acehardware.com/user/login",
"websiteKey": "6LeOCzAtAAAAAEMV83_o-Sx6uZsxO_haVNGyojSB",
"minScore": 0.9,
"pageAction": "LOGIN",
"isEnterprise": true,
"apiDomain": "google.com"
}
}{"errorId": 0, "taskId": 42}task parameters
| Field | Type | Required | Constraint |
|---|---|---|---|
type | string | yes | RecaptchaV3TaskProxyless or RecaptchaV3Task (with proxy) |
proxy | string | if RecaptchaV3Task | scheme://[user:pass@]host:port, scheme http, https or socks5; never logged or retained; rejected on RecaptchaV3TaskProxyless |
websiteURL | string | yes | full HTTPS URL of the page, without credentials or fragment |
websiteKey | string | yes | the page's reCAPTCHA sitekey, 20 to 100 characters |
minScore | number | yes | 0.3, 0.7 or 0.9 |
pageAction | string | no | the page's reCAPTCHA action; if omitted, the validated profile's |
isEnterprise | boolean | no | true for reCAPTCHA Enterprise; default false |
apiDomain | string | no | google.com only; default google.com |
Any unknown field is rejected (ERROR_BAD_REQUEST). The JSON body is limited to 16 KB.
Validated scope
The API only accepts pages listed in its validated registry. The websiteURL, websiteKey, isEnterprise triple must exactly match an entry, and pageAction must be absent or equal to the registered action. Otherwise the task is rejected with ERROR_PROFILE_NOT_VALIDATED.
| Page | Sitekey | Action | Enterprise |
|---|---|---|---|
| Loading registry… | |||
minScore is accepted for contract compatibility. It is a client request: the API neither measures nor guarantees the score assigned by Google.
POST/getTaskResult
{"clientKey": "YOUR_PRIVATE_KEY", "taskId": 42}{"errorId": 0, "status": "processing"}{
"errorId": 0,
"status": "ready",
"solution": {
"gRecaptchaResponse": "03AFcWeA...",
"token": "03AFcWeA..."
},
"createTime": 1757664000,
"endTime": 1757664012,
"solveCount": 1
}gRecaptchaResponse and token contain the same value. An unknown taskId, or one created with another key, returns ERROR_NO_SUCH_CAPCHA_ID.
Long polling and synchronous call
Add waitSeconds (1 to 30) to getTaskResult: the connection stays open and the response is sent the instant the task completes, with no wasted interval. One call counts as one request against the rate limit. Without waitSeconds, the response is immediate and you need to poll every 3 to 5 seconds.
{"clientKey": "YOUR_PRIVATE_KEY", "taskId": 42, "waitSeconds": 25}POST/solve chains creation and long polling in a single call: same body as createTask, plus an optional waitSeconds (1 to 120, default 100). The response is that of getTaskResult, with the taskId added. If the wait expires, the response is processing with the taskId: continue with getTaskResult. Set a client timeout of at least waitSeconds + 10 s.
{"clientKey": "YOUR_PRIVATE_KEY", "task": { …same content as createTask… }, "waitSeconds": 100}
# → {"errorId":0,"status":"ready","taskId":42,"solution":{"gRecaptchaResponse":"03AFcWeA…","token":"03AFcWeA…"},"createTime":…,"endTime":…,"solveCount":1}A task usually takes 5 to 15 seconds and is abandoned after 90 seconds of execution (ERROR_TASK_TIMEOUT).
Result lifetime
The token remains available for 90 seconds after the task completes, in memory only. After that, getTaskResult returns ERROR_TASK_EXPIRED. A reCAPTCHA v3 token is itself valid for about two minutes on Google's side: fetch it and use it without waiting. A token cannot be replayed; every business submission requires a new task.
Error codes
Error format: {"errorId": 1, "errorCode": "…", "errorDescription": "…"}. Each code identifies a distinct cause and a precise corrective action.
| Code | Meaning | Recommended action | Billed |
|---|---|---|---|
ERROR_KEY_DOES_NOT_EXIST | missing or invalid key | check clientKey | no |
ERROR_BAD_REQUEST | invalid JSON, unknown field, out-of-contract value, body too long | fix the request | no |
ERROR_TASK_NOT_SUPPORTED | unsupported type or apiDomain | use RecaptchaV3TaskProxyless or RecaptchaV3Task, and google.com | no |
ERROR_PROXY_INVALID | proxy missing or malformed on RecaptchaV3Task | provide scheme://[user:pass@]host:port | no |
ERROR_PROXY_NOT_AVAILABLE | no "your proxy" capacity available right now | retry, or switch to RecaptchaV3TaskProxyless | no |
ERROR_QUOTA_EXCEEDED | plan's monthly quota reached | buy prepaid credits or change plan | no |
ERROR_NO_CREDITS | no credits left and no active plan | buy credits from your account | no |
ERROR_PAGEURL | invalid websiteURL | provide an HTTPS URL without credentials | no |
ERROR_RECAPTCHA_INVALID_SITEKEY | malformed websiteKey | check the sitekey | no |
ERROR_PROFILE_NOT_VALIDATED | page, sitekey, action or mode outside the validated registry | request validation of the page | no |
ERROR_RELEASE_NOT_VALIDATED | Google is serving a reCAPTCHA update not yet validated | wait for validation to complete; check the status page | no |
ERROR_NO_SLOT_AVAILABLE | all concurrent tasks of your plan are busy | retry as soon as a task completes | no |
ERROR_RATE_LIMITED | more than 120 requests per minute for this key | slow down polling | no |
ERROR_NO_SUCH_CAPCHA_ID | unknown taskId or one belonging to another key | check the taskId | no |
ERROR_TASK_EXPIRED | result not read within 90 s | create a new task | yes |
ERROR_TASK_INTERRUPTED | service restarted before the result was read | create a new task | no |
ERROR_TASK_TIMEOUT | task exceeding 90 s | create a new task | no |
ERROR_CAPTCHA_UNSOLVABLE | no usable token could be produced | retry; report if persistent | no |
ERROR_SERVICE_UNAVAILABLE | service temporarily unavailable | check /readyz, retry later | no |
Only tasks that reached the ready state are billed, whether or not you read the result in time.
Monitoring routes
| Route | Method | Response |
|---|---|---|
/healthz | GET | {"status":"ok"}: the process is alive |
/readyz | GET | 200 {"status":"ready","ready":true} or 503 {"status":"degraded","ready":false} |
/docs | GET | interactive OpenAPI contract |
/openapi.json | GET | raw OpenAPI contract |
A 503 on /readyz means the service is currently unable to produce tokens. Tasks created in that state fail with ERROR_SERVICE_UNAVAILABLE. It is not a reCAPTCHA verdict.
Complete examples
Each example handles creation, polling every four seconds, terminal errors and a two-minute timeout. Use the generator to adapt them to your page.
Integration and compatibility
Capciao implements the asynchronous createTask / getTaskResult format for RecaptchaV3TaskProxyless and RecaptchaV3Task, in the standard asynchronous format. In most integrations, migration comes down to three points.
- Change the base URL: your integration's base URL becomes
. The/createTaskand/getTaskResultroutes are identical. - Remove unsupported fields:
softId,callbackUrl,languagePool, and the split fieldsproxyType/proxyAddress/proxyPort/proxyLogin/proxyPassword. They would be rejected as unknown fields (ERROR_BAD_REQUEST) rather than ignored. To use your proxy, passtype: "RecaptchaV3Task"and a singleproxystring. - Check that the page is validated: Capciao does not serve arbitrary pages. If you receive
ERROR_PROFILE_NOT_VALIDATED, get the page validated.
Same createTask, getTaskResult, clientKey, taskId, errorId, errorCode,
status "processing" | "ready", solution.gRecaptchaResponse, solution.token,
createTime, endTime, solveCount, in-scope ERROR_* codes.
Not available getBalance, reportCorrect, reportIncorrect, callbackUrl, softId,
any task type other than RecaptchaV3TaskProxyless / RecaptchaV3Task,
the split proxy* fields (replaced by a single proxy string).
Stricter unknown fields rejected; minScore limited to 0.3 / 0.7 / 0.9;
page outside the registry rejected before execution.Client libraries that let you configure the base URL work as is for these two routes. The balance() and report() methods will fail: do not call them.
Best practices
- Create the task at the last moment. The token expires two minutes after it is issued; never stockpile it.
- Use long polling (
waitSeconds) or/solve: the token arrives as soon as it exists and a task costs one or two requests. If you poll without waiting, no faster than every 4 seconds. - Cap at 120 seconds, then create a new task. Never loop indefinitely.
- Handle
ERROR_NO_SLOT_AVAILABLEwith a retry after a 2 to 5 second delay, rather than surfacing an error to the user. - Handle
ERROR_RELEASE_NOT_VALIDATEDwith a pause of a few minutes and a look at the status page. Retrying in a loop will only hit the rate limit. - Read the result once and use it immediately. Do not re-read a
readytask: it has nothing more to give. - Log your
taskIds and error codes, never the tokens or the key.
Guarantees and limits
- A
readytask proves that Google issued a token. Business success on the target site remains the only final oracle. - Tasks are processed in order of arrival; each key has a number of concurrent tasks defined by its plan (see pricing).
- Task parameters, keys and tokens are never written to disk or logged. Only metadata (ID, owner, status, timestamps, error code) is retained.
- A service restart interrupts running or pending tasks; they are not replayed and are not billed.
- No HTTP callback (
callback), no task type other thanRecaptchaV3TaskProxylessandRecaptchaV3Task. - With
RecaptchaV3Task, the task goes out through your proxy: its quality determines the score obtained. The proxy is neither logged nor retained.
Get a page validated
From the Console, "Validated pages" tab, submit a request with the exact URL, the sitekey, the action and the Enterprise mode, as your integration will use them. You then track its progress in the same place: pending, under review, validation in progress, validated or rejected, with the operator's note.
The same request is available through the API to automate it:
curl -sS {{apiPublic}}/createPageRequest \
-H 'content-type: application/json' \
--data '{
"clientKey": "YOUR_PRIVATE_KEY",
"websiteURL": "https://www.example.com/login",
"websiteKey": "6Lxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"pageAction": "LOGIN",
"isEnterprise": true,
"target": "POST /api/login",
"volume": "50,000 / month"
}'
# → {"errorId":0,"duplicate":false,"request":{"id":12,"status":"pending","alreadyValidated":false,…}}
curl -sS {{apiPublic}}/getPageRequests \
-H 'content-type: application/json' --data '{"clientKey":"YOUR_PRIVATE_KEY"}'
# → {"errorId":0,"requests":[…]}An identical request that is still open is not duplicated (duplicate: true). alreadyValidated switches to true as soon as the page is served by the registry, whatever the request status. Validation is performed under real conditions, until success on the target page; it is included in the Pro and Enterprise plans and quoted on Starter (see pricing).