Validate MTCaptcha Success Token

A Verified-Token will be created once a user is verified via captcha. This token must be checked on server side using the corresponding PrivateKey to insure its validity. The standard approach is to use the CheckToken API, for more customized and network sensitive use cases, the token can also be decrypted directly on server side.

Getting the Token

This Verified-Token can be found commonly via

* HTML hidden input form with name ‘mtcaptcha-verifiedtoken’.

<input type=’hidden’ name=’mtcaptcha-verifiedtoken’ … />

and can also be found via

* Javascript method


* part of the status callback argument via verified-callback  (see JS Callbacks for more details)

function mtcaptchaVerifiedCallback( status ) {
   console.log( status.verifiedToken ); 

console.log( status.verifiedToken );  }

Token Constraints

Each verifiedToken is normally valid for a few minutes, and can only be verified once via the CheckToken API to prevent replay attacks.

After you get the verifiedToken, you need to check it within the time limit to ensure the token is still valid. The MTCaptcha javascript widget will insure at least 50 seconds is available for the server to verify.




  • privatekey   : The shared PrivateKey secret between your server and MTCaptcha.  (Required)
  • token           : The VerifiedToken string. (Required)

NOTE: To insure the PrivateKey is kept secret this API should only be called from server side.

For server-side environments that require explicit firewall ACLs for outbound traffic, see:


The API response is a JSON object, sample responses below

  "success": true,
  "tokeninfo": {
    "v": "1.0",
    "code": 201,
    "codeDesc": "valid:captcha-solved",
    "tokID": "ae1e60a1e249c217cb7b05c4dba8dd0d",
    "timestampSec": 1552185983,
    "timestampISO": "2019-03-10T02:46:23Z",
    "hostname": "",
    "isDevHost": false,
    "action": "",
    "ip": ""

Sample Failure Response

  "success": false,
  "fail_codes": [
  "tokeninfo": {
    "v": "1.0",
    "code": 201,
    "codeDesc": "valid:captcha-solved",
    "tokID": "25eff0c56a227781408a95a053c36b65",
    "timestampSec": 1552185729,
    "timestampISO": "2019-03-10T02:42:09Z",
    "hostname": "",
    "isDevHost": false,
    "action": "",
    "ip": ""

CHECKTOKEN API Response Fields

success ‘true’ if the token is valid. ‘false’ otherwise.
fail_codes The code (reason) for validation failure, This field will only exist if success: false.
tokeninfo JSON object with the token metadata decrypted. This field may not exist on certain failures.
tokeninfo.v JThe version of the token format, should be “1.0”
tokeninfo.code The tokencode describing the method of verification. For full list of possible tokeninfo codes, see below.
tokeninfo.codeDesc The tokencode description. For full list of possible codes and descriptions, see below.
tokeninfo.tokID The unique GUID for the token, 128bits Hex/Base16 encoded.
tokeninfo.timestampSec The time stamp when the token was created, in Unix epoch time (in seconds).
tokeninfo.timestampISO The time stamp when the token was created, in ISO 8601 UTC format.
tokeninfo.hostname The hostname of the webpage the captcha was served under.
tokeninfo.isDevHost ‘true’ if the hostname matches ‘development domains’ configured for the site.
Tokeninfo.action The action string used on initialization of the captcha. If not defined defaults to empty string.
tokeninfo.ip The client IP of the user. In String format.

Response Token Info Codes & Descriptions

The codes for tokeninfo.code and tokeninfo.codeDesc

Token Codes Code Description Description
201 valid:captcha-solved Verified via the captcha challenge was solved.
211 valid:ip-whitelisted Verified via the client coming from an IP matching the IP whitelist for the site.
212 valid:low-friction Verified via the client deemed low risk, and the site has low-friction invisible captcha enabled.
301 valid-test:captcha-solved-via-testkey Verified via the TestKey (for automated testing).

Response Fail Codes

Possible response fail_codes

Fail Codes Description
token-expired The token has expired. Commonly 120 seconds. Can be longer depending on captcha type.
token-duplicate-cal The token has been checked already, and thus should not be used.
bad-request General error for unexpected bad/malformed requests.
missing-input-privatekey The parameter ‘privatekey’ is missing
missing-input-token The parameter ‘token’ is missing
invalid-privatekey The privatekey provided is not valid
invalid-token The token is not valid
invalid-token-faildecrypt The token is not valid and failed during decryption
privatekey-mismatch-token The token and the privatekey does not match. ie, the token was crated from another sitekey.
expired-sitekey-or-account The sitekey/privatekey is no longer valid due to expiration or account closure.

CHECKTOKEN API Optional Parameters

For custom use cases, the checktoken API supports these optional parameters.

Parameter Parameter Description
tokenExpireMiniSec Sets the minimum expiration time (TTL) in seconds for the Verified-Token, which effectively allows the token to be valid for longer than the default 60-120 seconds. This custom epxiration duration will only be applied if it is larger than the default MTCaptcha expiration time. The value must be an integer and max allowed value of 1200 (20 minutes). Example: tokenExpireMiniSec=300
tokenDuplicateCallMaxCount Sets the duplicate call threshold from the default of a single (one) checktoken call per token to multiple. The value must be an integer and max allowed value of 20. Example: tokenDuplicateCallMaxCount=5

The use of these optional paramters will add the fields token-callcount and' token_agesec to the CheckToken API response.

  "success": ...,
  "token_callcount": 3,
  "token_agesec": 9,
  "tokeninfo": {

CHECKTOKEN via Server Side Decryption (Without External API Call)

The standard and easiest method of validating the MTCaptcha verifiedToken is via the checktoken API, but you can decrypt and decode the token directly on server side without making any external API calls to You will need the site PrivateKey and the ability to calculate MD5 hash and decrypt with AES cipher. Additional checks for timeout and single use will be needed on the server side to insure proper security.

Decrypt Sample Code

The sample java code to decrypt and decode the token can be found at the github project here :

Verified-Token String Structure

"v1(" [MTCaptcha CheckSum] , [Customer Checksum] , [Sitekey] , [Random Seed] , [Encrypted TokenInfo] ")"
eg: “v1(2f03cc7d,1058dfde,MTPublic-hal9000uJ,34715559cd42d3955114303c925c3582,kSdkIYA..…qOCQ**)”
[MTCaptcha CheckSum] 2f03cc7d
[Customer Checksum] 1058dfde
[Sitekey] MTPublic-hal9000uJ
[Random Seed] 34715559cd42d3955114303c925c3582
[Encrypted TokenInfo] kSdkIYA..…qOCQ**

Verified Token Decryption Logic

[CalculatedCustomerCheckSum] = MD5( [Privatekey] + [SiteKey] + [Random Seed] + [Encrypted TokenInfo] ) .toHexLowercase() .substring(0,8)
[EncryptedTokenInfoBinary] = URLSafeBase64.decode( [Encrypted TokenInfo].replace("*","=") );
[SingleUseDecryptionKey128bit] = MD5( [Privatekey] + [Random Seed] )
[AesIV] = [SingleUseDecryptionKey128bit]
[DecryptedTokenInfoJson] = AES.decrpyt( "CBC/PKCS5Padding", [SingleUseDecryptionKey128bit], [AesIV], [EncryptedTokenInfoBinary] )

Textual Encoding / Decoding Format: UTF-8