Server
Server-side secondary verification API documentation
Important: Server-side secondary verification is a required security step and cannot be omitted!
API Information
| Item | Content |
|---|---|
| API Address | Please use the corresponding domain based on the region you selected when registering your ID: Global: https://cap-global.geelabapi.com/validateEurope: https://cap-eu.geelabapi.com/validateNorth America: https://cap-na.geelabapi.com/validate |
| Protocol Support | HTTP/HTTPS |
| Request Method | GET/POST (POST recommended) |
| Request Format | application/x-www-form-urlencoded |
| Return Type | JSON |
It's recommended to use the POST method and include captcha_id as a URL parameter for easier log tracking.
Request Parameters
Required Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
captcha_id | string | ✅ | Verification ID, 32-character string |
lot_number | string | ✅ | Verification event serial number, obtained from client |
captcha_output | string | ✅ | Verification output information, obtained from client |
pass_token | string | ✅ | Verification pass identifier, obtained from client |
gen_time | string | ✅ | Verification pass timestamp, must be a pure numeric string |
sign_token | string | ✅ | Verification signature, generated using HMAC-SHA256 algorithm |
gen_time must be a pure numeric string and cannot contain other characters, otherwise it will return a -50005 error.
Request Example
curl -X POST 'https://cap-global.geelabapi.com/validate?captcha_id=YOUR_CAPTCHA_ID' \
-H 'Content-Type: application/x-www-form-urlencoded' \
-d 'lot_number=4dc3cfc2cdff448cad8d13107198d473' \
-d 'captcha_output=...' \
-d 'pass_token=...' \
-d 'gen_time=1234567890' \
-d 'sign_token=...'sign_token Generation
sign_token is generated using the HMAC-SHA256 algorithm to verify the authenticity of the request.
Prepare Parameters
- message: The verification event serial number
lot_numbercompleted by the user - key: Verification private key
captcha_key
Generate Signature
Use the HMAC-SHA256 algorithm for signing.
Code Examples
import hmac
import hashlib
def generate_sign_token(lot_number, captcha_key):
"""Generate verification signature"""
sign_token = hmac.new(
captcha_key.encode('utf-8'),
lot_number.encode('utf-8'),
digestmod=hashlib.sha256
).hexdigest()
return sign_token
# Usage example
sign_token = generate_sign_token(lot_number, CAPTCHA_KEY)const crypto = require('crypto');
function generateSignToken(lotNumber, captchaKey) {
return crypto
.createHmac('sha256', captchaKey)
.update(lotNumber)
.digest('hex');
}
// Usage example
const signToken = generateSignToken(lotNumber, CAPTCHA_KEY);import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
public String generateSignToken(String lotNumber, String captchaKey)
throws Exception {
Mac mac = Mac.getInstance("HmacSHA256");
SecretKeySpec secretKey = new SecretKeySpec(
captchaKey.getBytes("UTF-8"),
"HmacSHA256"
);
mac.init(secretKey);
byte[] hash = mac.doFinal(lotNumber.getBytes("UTF-8"));
return bytesToHex(hash);
}
private String bytesToHex(byte[] bytes) {
StringBuilder result = new StringBuilder();
for (byte b : bytes) {
result.append(String.format("%02x", b));
}
return result.toString();
}<?php
function generateSignToken($lotNumber, $captchaKey) {
return hash_hmac('sha256', $lotNumber, $captchaKey);
}
// Usage example
$signToken = generateSignToken($lotNumber, $captchaKey);
?>package main
import (
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
)
func GenerateSignToken(lotNumber, captchaKey string) string {
h := hmac.New(sha256.New, []byte(captchaKey))
h.Write([]byte(lotNumber))
return hex.EncodeToString(h.Sum(nil))
}
// Usage example
signToken := GenerateSignToken(lotNumber, captchaKey)Response Format
Verification Success
{
"status": "success",
"result": "success",
"reason": "",
"captcha_args": {
"used_type": "slide",
"user_ip": "127.0.0.1",
"lot_number": "4dc3cfc2cdff448cad8d13107198d473",
"scene": "Anti-crawler",
"referer": "http://127.0.0.1:8077/"
}
}Verification Failure
{
"status": "success",
"result": "fail",
"reason": "pass_token expire",
"captcha_args": {
"used_type": "slide",
"user_ip": "127.0.0.1",
"lot_number": "4dc3cfc2cdff448cad8d13107198d473"
}
}Common failure reasons:
pass_token expire- Verification has expiredlot_number not match- Serial number does not matchillegal sign_token- Signature error
Request Exception
{
"status": "error",
"code": "-50005",
"msg": "illegal gen_time",
"desc": {
"type": "defined error"
}
}When receiving an exception response, it's recommended to allow the request to avoid blocking business processes.
Response Field Description
| Field | Type | Description |
|---|---|---|
status | string | Request status: success (successful), error (exception) |
result | string | Verification result: success (passed), fail (failed) |
reason | string | Verification result description or failure reason |
code | string | Error code (returned only on exception) |
msg | string | Error message (returned only on exception) |
captcha_args | object | Verification details |
captcha_args Fields
| Field | Type | Description |
|---|---|---|
used_type | string | Verification type used (slide, icon, nine-grid, etc.) |
user_ip | string | User IP address |
lot_number | string | Verification event serial number |
scene | string | Verification scenario |
referer | string | Source page |
Complete Request Examples
import hmac
import hashlib
import requests
def validate_captcha(request_data):
"""Captcha secondary verification"""
# Configuration parameters
CAPTCHA_ID = 'YOUR_CAPTCHA_ID'
CAPTCHA_KEY = 'YOUR_CAPTCHA_KEY'
API_URL = 'https://cap-global.geelabapi.com/validate'
# Get client parameters
lot_number = request_data.get('lot_number')
captcha_output = request_data.get('captcha_output')
pass_token = request_data.get('pass_token')
gen_time = request_data.get('gen_time')
# Generate signature
sign_token = hmac.new(
CAPTCHA_KEY.encode(),
lot_number.encode(),
hashlib.sha256
).hexdigest()
# Construct request parameters
params = {'captcha_id': CAPTCHA_ID}
data = {
'lot_number': lot_number,
'captcha_output': captcha_output,
'pass_token': pass_token,
'gen_time': gen_time,
'sign_token': sign_token
}
# Send request
try:
response = requests.post(API_URL, params=params, data=data, timeout=5)
if response.status_code != 200:
# API exception, recommend allowing
return {'result': 'success', 'reason': 'api error, fallback'}
result = response.json()
return result
except Exception as e:
# Request exception, recommend allowing
print(f'Verification exception: {e}')
return {'result': 'success', 'reason': 'request fail, fallback'}const crypto = require('crypto');
const axios = require('axios');
async function validateCaptcha(requestData) {
// Configuration parameters
const CAPTCHA_ID = 'YOUR_CAPTCHA_ID';
const CAPTCHA_KEY = 'YOUR_CAPTCHA_KEY';
const API_URL = 'https://cap-global.geelabapi.com/validate';
// Get client parameters
const { lot_number, captcha_output, pass_token, gen_time } = requestData;
// Generate signature
const sign_token = crypto
.createHmac('sha256', CAPTCHA_KEY)
.update(lot_number)
.digest('hex');
// Construct request parameters
const params = new URLSearchParams({
lot_number,
captcha_output,
pass_token,
gen_time,
sign_token
});
// Send request
try {
const response = await axios.post(
`${API_URL}?captcha_id=${CAPTCHA_ID}`,
params,
{
timeout: 5000,
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
if (response.status !== 200) {
// API exception, recommend allowing
return { result: 'success', reason: 'api error, fallback' };
}
return response.data;
} catch (error) {
// Request exception, recommend allowing
console.error('Verification exception:', error);
return { result: 'success', reason: 'request fail, fallback' };
}
}import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.net.http.*;
import java.net.URI;
import com.fasterxml.jackson.databind.ObjectMapper;
public class CaptchaValidator {
private static final String CAPTCHA_ID = "YOUR_CAPTCHA_ID";
private static final String CAPTCHA_KEY = "YOUR_CAPTCHA_KEY";
private static final String API_URL = "https://cap-global.geelabapi.com/validate";
public ValidationResult validate(CaptchaRequest request) {
try {
// Generate signature
String signToken = generateSignToken(
request.getLotNumber(),
CAPTCHA_KEY
);
// Construct request parameters
String params = String.format(
"lot_number=%s&captcha_output=%s&pass_token=%s&gen_time=%s&sign_token=%s",
request.getLotNumber(),
request.getCaptchaOutput(),
request.getPassToken(),
request.getGenTime(),
signToken
);
String url = API_URL + "?captcha_id=" + CAPTCHA_ID;
// Send request
HttpClient client = HttpClient.newHttpClient();
HttpRequest httpRequest = HttpRequest.newBuilder()
.uri(URI.create(url))
.header("Content-Type", "application/x-www-form-urlencoded")
.POST(HttpRequest.BodyPublishers.ofString(params))
.timeout(Duration.ofSeconds(5))
.build();
HttpResponse<String> response = client.send(
httpRequest,
HttpResponse.BodyHandlers.ofString()
);
// Handle response
if (response.statusCode() != 200) {
// API exception, recommend allowing
return ValidationResult.fallback();
}
ObjectMapper mapper = new ObjectMapper();
return mapper.readValue(
response.body(),
ValidationResult.class
);
} catch (Exception e) {
// Request exception, recommend allowing
e.printStackTrace();
return ValidationResult.fallback();
}
}
private String generateSignToken(String lotNumber, String key)
throws Exception {
Mac mac = Mac.getInstance("HmacSHA256");
SecretKeySpec secretKey = new SecretKeySpec(
key.getBytes("UTF-8"),
"HmacSHA256"
);
mac.init(secretKey);
byte[] hash = mac.doFinal(lotNumber.getBytes("UTF-8"));
return bytesToHex(hash);
}
private String bytesToHex(byte[] bytes) {
StringBuilder result = new StringBuilder();
for (byte b : bytes) {
result.append(String.format("%02x", b));
}
return result.toString();
}
}<?php
function validateCaptcha($requestData) {
// Configuration parameters
$CAPTCHA_ID = 'YOUR_CAPTCHA_ID';
$CAPTCHA_KEY = 'YOUR_CAPTCHA_KEY';
$API_URL = 'https://cap-global.geelabapi.com/validate';
// Get client parameters
$lot_number = $requestData['lot_number'];
$captcha_output = $requestData['captcha_output'];
$pass_token = $requestData['pass_token'];
$gen_time = $requestData['gen_time'];
// Generate signature
$sign_token = hash_hmac('sha256', $lot_number, $CAPTCHA_KEY);
// Construct request parameters
$params = http_build_query([
'lot_number' => $lot_number,
'captcha_output' => $captcha_output,
'pass_token' => $pass_token,
'gen_time' => $gen_time,
'sign_token' => $sign_token
]);
$url = $API_URL . '?captcha_id=' . $CAPTCHA_ID;
// Send request
$context = stream_context_create([
'http' => [
'method' => 'POST',
'header' => 'Content-Type: application/x-www-form-urlencoded',
'content' => $params,
'timeout' => 5
]
]);
try {
$response = @file_get_contents($url, false, $context);
if ($response === false) {
// Request exception, recommend allowing
return ['result' => 'success', 'reason' => 'request fail, fallback'];
}
$result = json_decode($response, true);
return $result;
} catch (Exception $e) {
// Exception handling, recommend allowing
error_log('Verification exception: ' . $e->getMessage());
return ['result' => 'success', 'reason' => 'exception, fallback'];
}
}
?>package main
import (
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"encoding/json"
"net/http"
"net/url"
"strings"
"time"
)
const (
CAPTCHA_ID = "YOUR_CAPTCHA_ID"
CAPTCHA_KEY = "YOUR_CAPTCHA_KEY"
API_URL = "https://cap-global.geelabapi.com/validate"
)
type ValidationResult struct {
Status string `json:"status"`
Result string `json:"result"`
Reason string `json:"reason"`
Args map[string]interface{} `json:"captcha_args"`
}
func ValidateCaptcha(requestData map[string]string) (*ValidationResult, error) {
// Get client parameters
lotNumber := requestData["lot_number"]
captchaOutput := requestData["captcha_output"]
passToken := requestData["pass_token"]
genTime := requestData["gen_time"]
// Generate signature
h := hmac.New(sha256.New, []byte(CAPTCHA_KEY))
h.Write([]byte(lotNumber))
signToken := hex.EncodeToString(h.Sum(nil))
// Construct request parameters
data := url.Values{}
data.Set("lot_number", lotNumber)
data.Set("captcha_output", captchaOutput)
data.Set("pass_token", passToken)
data.Set("gen_time", genTime)
data.Set("sign_token", signToken)
// Send request
client := &http.Client{Timeout: 5 * time.Second}
apiURL := API_URL + "?captcha_id=" + CAPTCHA_ID
resp, err := client.Post(
apiURL,
"application/x-www-form-urlencoded",
strings.NewReader(data.Encode()),
)
if err != nil || resp.StatusCode != 200 {
// Request exception, recommend allowing
return &ValidationResult{
Result: "success",
Reason: "request fail, fallback",
}, nil
}
defer resp.Body.Close()
var result ValidationResult
json.NewDecoder(resp.Body).Decode(&result)
return &result, nil
}Error Codes
Common Error Codes
| Error Code | Description | Solution |
|---|---|---|
-50005 | illegal gen_time | Check if gen_time is a pure numeric string, check request format |
-50101 | not captcha_id | Missing verification ID |
-50102 | illegal captcha_id | Verification ID format error |
-50103 | not captcha | Verification ID does not exist |
-50301 | not proof | Serial number information does not exist, may have expired |
-50303 | illegal lot_number | Serial number format error |
-50305 | lot_number Expired | Serial number has expired |
Complete Error Code List
| Error Code | Error Description | Error Details |
|---|---|---|
-50000 | runtime error | Undefined error caused by abnormal process |
-50001 | illegal risk_type | Illegal risk_type parameter passed in risk control mode |
-50002 | param decrypt error | Decryption process exception caused by illegal encrypted parameters |
-50003 | illegal verify | Duplicate verification |
-50004 | jsonp xss | XSS exception |
-50005 | illegal gen_time | gen_time parameter exception, check secondary verification parameters and request format |
-50101 | not captcha_id | Missing verification ID |
-50102 | illegal captcha_id | Illegal verification ID |
-50103 | not captcha | Non-existent verification ID |
-50104 | captcha_id deleted | Deleted verification ID |
-50105 | captcha_id paused | Paused verification ID |
-50301 | not proof | Serial number information does not exist, cache expired |
-50302 | not lot_number | Missing serial number |
-50303 | illegal lot_number | Illegal serial number |
-50304 | lot_number not match | Serial number does not match |
-50305 | lot_number Expired | Serial number has expired |
-50306 | process_token Error | process_token error |
-50307 | payload Error | payload parameter error |
-50308 | payload Used | payload parameter expired |
Common Issues
How to handle API exceptions?
When a request exception occurs or the response status is not 200, it's recommended to allow the request to avoid blocking business processes.
try:
response = requests.post(url, data=query, timeout=5)
if response.status_code != 200:
# API exception, allow request
return {'result': 'success', 'reason': 'api error, fallback'}
except Exception as e:
# Request exception, allow request
return {'result': 'success', 'reason': 'request fail, fallback'}Why does pass_token error occur?
Common reason: Inconsistent IDs configured between frontend and backend.
Troubleshooting steps:
- Check if the
captcha_idused on the frontend is correct - Check if the
captcha_idused in backend verification matches the frontend - Confirm that
captcha_keyis configured correctly
If you still have questions, you can provide the lot_number to contact technical support to check the logs.
When does -50005 error occur?
Reason: Incorrect parameter transmission format.
Checklist:
- Is
gen_timea pure numeric string - Is Content-Type set to
application/x-www-form-urlencoded - Are parameters in form data format
How to set a reasonable timeout?
It's recommended to set a 5-second timeout, which is the best balance between user experience and service stability.
Next Steps
- Check Deployment Guide for the complete integration process
- Read Fallback Plan for disaster recovery handling
- Check FAQ to resolve integration issues