Documentation

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.

Base URL: . 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

Independence. The 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.

Quick start

Create a task for the sample validated page, then poll its result every four seconds.

createTask
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}
getTaskResult
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.

Keep the key server-side. Never embed it in a front end or a distributed application. If it leaks, request a rotation: the old key is revoked immediately.

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.

Request
{
  "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"
  }
}
Response
{"errorId": 0, "taskId": 42}

task parameters

FieldTypeRequiredConstraint
typestringyesRecaptchaV3TaskProxyless or RecaptchaV3Task (with proxy)
proxystringif RecaptchaV3Taskscheme://[user:pass@]host:port, scheme http, https or socks5; never logged or retained; rejected on RecaptchaV3TaskProxyless
websiteURLstringyesfull HTTPS URL of the page, without credentials or fragment
websiteKeystringyesthe page's reCAPTCHA sitekey, 20 to 100 characters
minScorenumberyes0.3, 0.7 or 0.9
pageActionstringnothe page's reCAPTCHA action; if omitted, the validated profile's
isEnterprisebooleannotrue for reCAPTCHA Enterprise; default false
apiDomainstringnogoogle.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.

PageSitekeyActionEnterprise
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

Request
{"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
}

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.

getTaskResult with long polling
{"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.

/solve
{"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.

CodeMeaningRecommended actionBilled
ERROR_KEY_DOES_NOT_EXISTmissing or invalid keycheck clientKeyno
ERROR_BAD_REQUESTinvalid JSON, unknown field, out-of-contract value, body too longfix the requestno
ERROR_TASK_NOT_SUPPORTEDunsupported type or apiDomainuse RecaptchaV3TaskProxyless or RecaptchaV3Task, and google.comno
ERROR_PROXY_INVALIDproxy missing or malformed on RecaptchaV3Taskprovide scheme://[user:pass@]host:portno
ERROR_PROXY_NOT_AVAILABLEno "your proxy" capacity available right nowretry, or switch to RecaptchaV3TaskProxylessno
ERROR_QUOTA_EXCEEDEDplan's monthly quota reachedbuy prepaid credits or change planno
ERROR_NO_CREDITSno credits left and no active planbuy credits from your accountno
ERROR_PAGEURLinvalid websiteURLprovide an HTTPS URL without credentialsno
ERROR_RECAPTCHA_INVALID_SITEKEYmalformed websiteKeycheck the sitekeyno
ERROR_PROFILE_NOT_VALIDATEDpage, sitekey, action or mode outside the validated registryrequest validation of the pageno
ERROR_RELEASE_NOT_VALIDATEDGoogle is serving a reCAPTCHA update not yet validatedwait for validation to complete; check the status pageno
ERROR_NO_SLOT_AVAILABLEall concurrent tasks of your plan are busyretry as soon as a task completesno
ERROR_RATE_LIMITEDmore than 120 requests per minute for this keyslow down pollingno
ERROR_NO_SUCH_CAPCHA_IDunknown taskId or one belonging to another keycheck the taskIdno
ERROR_TASK_EXPIREDresult not read within 90 screate a new taskyes
ERROR_TASK_INTERRUPTEDservice restarted before the result was readcreate a new taskno
ERROR_TASK_TIMEOUTtask exceeding 90 screate a new taskno
ERROR_CAPTCHA_UNSOLVABLEno usable token could be producedretry; report if persistentno
ERROR_SERVICE_UNAVAILABLEservice temporarily unavailablecheck /readyz, retry laterno

Only tasks that reached the ready state are billed, whether or not you read the result in time.

Monitoring routes

RouteMethodResponse
/healthzGET{"status":"ok"}: the process is alive
/readyzGET200 {"status":"ready","ready":true} or 503 {"status":"degraded","ready":false}
/docsGETinteractive OpenAPI contract
/openapi.jsonGETraw 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.

  1. Change the base URL: your integration's base URL becomes . The /createTask and /getTaskResult routes are identical.
  2. Remove unsupported fields: softId, callbackUrl, languagePool, and the split fields proxyType/proxyAddress/proxyPort/proxyLogin/proxyPassword. They would be rejected as unknown fields (ERROR_BAD_REQUEST) rather than ignored. To use your proxy, pass type: "RecaptchaV3Task" and a single proxy string.
  3. Check that the page is validated: Capciao does not serve arbitrary pages. If you receive ERROR_PROFILE_NOT_VALIDATED, get the page validated.
Contract differences
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

Guarantees and limits

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:

createPageRequest
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).