Geelab Docs
API Reference

Server

Server-side secondary verification API documentation

Important: Server-side secondary verification is a required security step and cannot be omitted!

API Information

ItemContent
API AddressPlease use the corresponding domain based on the region you selected when registering your ID:
Global: https://cap-global.geelabapi.com/validate
Europe: https://cap-eu.geelabapi.com/validate
North America: https://cap-na.geelabapi.com/validate
Protocol SupportHTTP/HTTPS
Request MethodGET/POST (POST recommended)
Request Formatapplication/x-www-form-urlencoded
Return TypeJSON

It's recommended to use the POST method and include captcha_id as a URL parameter for easier log tracking.

Request Parameters

Required Parameters

ParameterTypeRequiredDescription
captcha_idstringVerification ID, 32-character string
lot_numberstringVerification event serial number, obtained from client
captcha_outputstringVerification output information, obtained from client
pass_tokenstringVerification pass identifier, obtained from client
gen_timestringVerification pass timestamp, must be a pure numeric string
sign_tokenstringVerification 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 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_number completed by the user
  • key: Verification private key captcha_key

Generate Signature

Use the HMAC-SHA256 algorithm for signing.

Code Examples

Python Signature Generation
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)
Node.js Signature Generation
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);
Java Signature Generation
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 Signature Generation
<?php
function generateSignToken($lotNumber, $captchaKey) {
    return hash_hmac('sha256', $lotNumber, $captchaKey);
}

// Usage example
$signToken = generateSignToken($lotNumber, $captchaKey);
?>
Go Signature Generation
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

Success Response
{
    "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

Failure Response
{
    "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 expired
  • lot_number not match - Serial number does not match
  • illegal sign_token - Signature error

Request Exception

Exception Response
{
    "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

FieldTypeDescription
statusstringRequest status: success (successful), error (exception)
resultstringVerification result: success (passed), fail (failed)
reasonstringVerification result description or failure reason
codestringError code (returned only on exception)
msgstringError message (returned only on exception)
captcha_argsobjectVerification details

captcha_args Fields

FieldTypeDescription
used_typestringVerification type used (slide, icon, nine-grid, etc.)
user_ipstringUser IP address
lot_numberstringVerification event serial number
scenestringVerification scenario
refererstringSource page

Complete Request Examples

Python Complete Example
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'}
Node.js Complete Example
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' };
    }
}
Java Complete Example
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 Complete Example
<?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'];
    }
}
?>
Go Complete Example
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 CodeDescriptionSolution
-50005illegal gen_timeCheck if gen_time is a pure numeric string, check request format
-50101not captcha_idMissing verification ID
-50102illegal captcha_idVerification ID format error
-50103not captchaVerification ID does not exist
-50301not proofSerial number information does not exist, may have expired
-50303illegal lot_numberSerial number format error
-50305lot_number ExpiredSerial number has expired

Complete Error Code List

Error CodeError DescriptionError Details
-50000runtime errorUndefined error caused by abnormal process
-50001illegal risk_typeIllegal risk_type parameter passed in risk control mode
-50002param decrypt errorDecryption process exception caused by illegal encrypted parameters
-50003illegal verifyDuplicate verification
-50004jsonp xssXSS exception
-50005illegal gen_timegen_time parameter exception, check secondary verification parameters and request format
-50101not captcha_idMissing verification ID
-50102illegal captcha_idIllegal verification ID
-50103not captchaNon-existent verification ID
-50104captcha_id deletedDeleted verification ID
-50105captcha_id pausedPaused verification ID
-50301not proofSerial number information does not exist, cache expired
-50302not lot_numberMissing serial number
-50303illegal lot_numberIllegal serial number
-50304lot_number not matchSerial number does not match
-50305lot_number ExpiredSerial number has expired
-50306process_token Errorprocess_token error
-50307payload Errorpayload parameter error
-50308payload Usedpayload 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:

  1. Check if the captcha_id used on the frontend is correct
  2. Check if the captcha_id used in backend verification matches the frontend
  3. Confirm that captcha_key is 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_time a 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