Server API
Use the client SDK's device_token to query the device fingerprint and obtain device identification, device information, and risk signals. If client reporting fails, submit the raw SDK geetoken through the same endpoint for fallback analysis. See fp_query fallback mode.
Interface
| Method | Path | Purpose |
|---|---|---|
POST | /api/v2/fp_query/{public_key} | Query device fingerprint |
Where to get input from
| Field | Used in | Where to get |
|---|---|---|
public_key | Path /api/v2/fp_query/{public_key} | Public application identifier from the console, used to locate the application and Region. It is not an authentication key. |
secret | Authorization: Bearer <secret> | Server API authentication secret from the console. |
device_token | Request body | Returned by the client SDK. |
Supported clients
iOS, Android, and Web/H5.
Regional restrictions
Each application belongs to exactly one Region, configured in the dashboard. Send the request to the regional API endpoint for the application's Region.
| Region | Description | API endpoint (HTTPS) |
|---|---|---|
GLB | Global | https://riskct-global.geelabapi.com |
NA | North America | https://riskct-na.geelabapi.com |
EU | Europe | https://riskct-eu.geelabapi.com |
Requests sent to a node in another Region return 404 with message: "integration not found".
Response envelope
Use Content-Type: application/json. The HTTP status code and JSON code have the same value.
Success:
{ "code": 200, "data": {}, "message": "Success" }Failure:
{ "code": 400, "data": {}, "message": "Invalid request" }When validation fails, data contains:
{
"errors": [
{ "field": "device_token", "reason": "Field required", "type": "missing" }
]
}Error code
HTTP / code | message | Meaning |
|---|---|---|
| 400 | Invalid request | The request body is invalid, or device_token is invalid |
| 401 | Invalid bearer token | Authentication failed; check the server-side secret |
| 403 | Forbidden | The application is unavailable, does not pass the IP allowlist check, or fallback mode is disabled |
| 403 | deactivate / quota_exceeded / manual_deactivate | The customer product switch is switch=off; message is the current CustomerProductVersion.status |
| 404 | integration not found | public_key is invalid, or the request was not sent to the regional API endpoint for the application's Region |
| 429 | Too many requests | Fallback analysis exceeded the application's rate limit quota |
| 500 | Internal server error | Server error |
POST /api/v2/fp_query/{public_key}
Query the device fingerprint. Send the device_token returned by the client SDK to retrieve trusted device attributes and risk signals.
| Method | POST |
| Path | /api/v2/fp_query/{public_key} |
| Auth | Authorization: Bearer <secret> |
| Content-Type | application/json |
| Success | HTTP 200, code=200, message=Success |
Request
POST /api/v2/fp_query/{public_key}
Authorization: Bearer <secret>
Content-Type: application/jsonPath
| Field | Type | Required | Meaning | Where to get |
|---|---|---|---|---|
public_key | string | Yes | Application public identifier | Dashboard |
Headers
| Field | Required | Meaning | Where to get it |
|---|---|---|---|
Authorization | Yes | Bearer <secret>, server-side query authentication | Get secret from the dashboard |
Content-Type | Yes | application/json | — |
Body
{
"device_token": "<from-client-sdk>",
"event_type": "login",
"event_time": "2026-08-20T10:30:00+08:00"
}| Field | Type | Required | Meaning | Where to get |
|---|---|---|---|---|
device_token | string | Yes | For a standard query, pass the result token. For fallback analysis, pass the raw SDK geetoken. Both use this field. | Client SDK interface |
event_type | string | No | Business event type, such as login | Caller-provided |
event_time | string | No | Event time in RFC 3339 format (with a time zone or Z) | Caller-provided |
Minimum request body:
{ "device_token": "<from-client-sdk>" }fp_query fallback mode
If the client SDK fails to report data or does not obtain a result token, send the raw geetoken generated by the SDK to your backend. The backend can then use the same POST /api/v2/fp_query/{public_key} endpoint to obtain the device fingerprint and risk signals.
Request method
- Continue using the
device_tokenfield and pass the raw SDKgeetokenas-is. No additional field or mode parameter is required. - Use the same URL, Bearer authentication, and optional parameters as a standard query. Send the request to the API endpoint for the application's Region. Keep
secreton the backend and never expose it to clients.
Example for the Global endpoint (replace it with the North America or Europe endpoint when applicable):
curl -sS -X POST "https://riskct-global.geelabapi.com/api/v2/fp_query/{public_key}" \
-H "Authorization: Bearer {secret}" \
-H "Content-Type: application/json" \
-d '{"device_token":"{sdk_raw_geetoken}"}'The response structure is the same as a standard query; see Response (200). Successful fp_query requests in fallback mode are also billable.
Response (200)
{
"code": 200,
"data": {
"request_id": "req_0198c7a1-5b2e-7c10-8d44-1234567890ab",
"event_id": "evt_0198c7a1-5b2e-7c10-8d44-1234567890ab",
"fp_detail": {
"device_id": "GEE4-xxxxxx",
"version": "1.0"
},
"signals": [
{
"signal": "CLOUD_PHONE",
"level": "HIGH",
"confidence": 0.8
}
],
"detail": {
"client_type": "Android",
"device_basic": {
"os": "Android",
"pla": "arm64-v8a",
"mod": "Pixel 8",
"osv": "14"
},
"ip_info": {
"ip": "1.1.1.1"
}
}
},
"message": "Success"
}data
| Field | Type | Meaning |
|---|---|---|
request_id | string | Analysis ID, formatted as req_ + UUID v7. Standard queries with the same result token return the same value; fallback analysis generates a new value for every request. |
event_id | string | ID of this query, formatted as evt_ + UUID v7. Each query has a different value. |
fp_detail | object | Device fingerprint details |
signals | array | Hit signal list; [] when no signal is hit |
detail | object | Client type, device information, and IP information |
fp_detail
| Field | Type | Meaning |
|---|---|---|
device_id | string | device fingerprint |
version | string | Fingerprint version, currently"1.0" |
signals[]
| Field | Type | Meaning |
|---|---|---|
signal | string | signal identifier, for exampleCLOUD_PHONE |
level | string | LOW/MEDIUM/HIGH |
confidence | number | 0.0–1.0 |
The following table lists the signal values and descriptions currently supported by the Server API.
Signal Reference (40+)
signal | level | Description | Supported platforms |
|---|---|---|---|
BEING_DEBUGGED | HIGH | The device may be under active debugging, which can enable reverse engineering, tampering, or automated device-farm control | Android, iOS, Web |
DEBUG_MODE_OR_TEST_APP | LOW | The device has debugging enabled, or the app is a debug, modified, or non-store build | Android, iOS |
EMULATOR | HIGH | A traditional emulator environment was detected | Android, iOS, Web |
CLOUD_PHONE | HIGH | A cloud device or ARM server environment was detected | Android |
RUNNING_ON_MACOS | MEDIUM | The app is running on macOS | iOS |
VPN_ENABLED | LOW | A VPN connection is enabled on the device | Android, iOS |
NETWORK_PROXY | MEDIUM | A network proxy is configured on the device | Android, iOS |
INVALID_PACKAGE | LOW | The package name may have been modified, or the app may have been repackaged | Android, iOS |
TOKEN_EXPIRED | MEDIUM | The device_token has expired or was reused | Android, iOS, Web |
LIMIT_EXCEED | MEDIUM | A configured limit was exceeded | Android, iOS, Web |
SCREEN_SHARING | LOW | Screen sharing is active on the device | Android, iOS |
VOICE_CONNECTED | LOW | A voice call is active on the device | Android, iOS |
IP_CRAWLER_OR_BOT | MEDIUM | The IP address is associated with malicious cracking, crawler, or bot activity | Android, iOS, Web |
IP_MALICIOUS_ATTACK | HIGH | The IP address is associated with malicious attack activity | Android, iOS, Web |
IP_SUSPICIOUS_PROXY | MEDIUM | The IP address is suspected of being a proxy | Android, iOS, Web |
IDC_IP | MEDIUM | IDC/data center IP | Android, iOS, Web |
DEVICE_JAILBREAK | HIGH | The iOS device is jailbroken | iOS |
DEVICE_ROOTED | HIGH | The Android device is rooted | Android |
SUSPICIOUS_CUSTOM_ROM | HIGH | The Android device is running a suspicious custom ROM | Android |
SUSPICIOUS_OPEN_SOURCE_ROM | HIGH | The Android device is running an Android Open Source Project-based ROM | Android |
BROWSER_COOKIE_FEATURE_DISABLED | MEDIUM | Browser cookies are unavailable or disabled | Web |
PSEUDO_BROWSER_ENV | HIGH | A spoofed browser environment was detected | Web |
BROWSER_INCOGNITO_MODE | LOW | The browser is running in private or incognito mode | Web |
DEVICE_BOOTLOADER_UNLOCKED | HIGH | The device bootloader is unlocked | Android |
SUSPICIOUS_DEVICE_RESET | HIGH | A suspicious device reset was detected | Android, iOS |
SYSTEM_VERSION_TOO_LOW | MEDIUM | The device operating system version is outdated | Android, iOS |
DEVICE_WITHOUT_SIM | LOW | No SIM card was detected in the device | Android, iOS |
HOOK_TAMPERING_LOW | MEDIUM | Low-risk code hooking or tampering was detected; exclude modifications introduced by your own application before acting on this signal | iOS, Web |
HOOK_TAMPERING_MEDIUM | HIGH | Medium-risk code hooking or tampering capable of altering application logic was detected | Android, iOS, Web |
HOOK_TAMPERING_HIGH | HIGH | High-risk code hooking or tampering was detected | Android, iOS |
SUSPICIOUS_DEVICE_INFO_TAMPERED | HIGH | Device information may have been spoofed, or device attributes do not match the fingerprint | Android, iOS |
ANTIDETECT_BROWSER | HIGH | The device is running an anti-detect browser | Web |
APP_CLONE_TOOL_INSTALLED | LOW | An app-cloning tool is installed on the device | Android, Web |
TAMPER_TOOL_INSTALLED | LOW | A device-tampering tool is installed on the device | Android, iOS |
AUTOMATION_TOOL_INSTALLED | LOW | A device-farm or automation tool capable of operating at scale is installed on the device | Android, iOS |
REVERSE_ENGINEERING_TOOL_INSTALLED | LOW | A reverse-engineering tool is installed on the device | Android, iOS, Web |
NETWORK_TAMPER_TOOL_INSTALLED | LOW | A network-tampering tool is installed or may be in use on the device | Android, iOS |
GAME_TAMPER_TOOL_INSTALLED | LOW | A game modification or cheat tool is installed on the device | Android, iOS |
VIRTUAL_LOCATION_TOOL_INSTALLED | LOW | A location-spoofing tool is installed on the device | Android, iOS |
RUNNING_IN_VIRTUAL_MACHINE | HIGH | The device is running in a virtual machine | Android, iOS, Web |
RUNNING_IN_CLONED_APP | HIGH | The app is running in a cloned-app environment | Android, iOS |
USING_DEVICE_TAMPERING_TOOL | HIGH | A device-tampering or other high-risk tool is currently in use | Android |
USING_AUTOMATION_TOOL | HIGH | A device-farm or automation tool is currently in use | Android, iOS |
USING_REVERSE_ENGINEERING_TOOL | HIGH | A reverse-engineering or tampering tool is currently in use | Android |
USING_VIRTUAL_LOCATION | HIGH | A location-spoofing tool is currently in use | Android, iOS |
RUNNING_IN_SYSTEM_CLONED | LOW | A system-level cloned-app environment was detected | Android |
detail
| Field | Type | Meaning |
|---|---|---|
client_type | string | Android, iOS, or Web/H5 |
device_basic | object | Basic device information; its structure varies by client_type |
ip_info | object | { "ip": "<string>" } |
Android/iOS device_basic:
{
"os": "Android",
"pla": "arm64-v8a",
"mod": "Pixel 8",
"osv": "14"
}| Field | Meaning |
|---|---|
os | Operating system |
pla | Architecture |
mod | Model |
osv | System version |
Web/H5device_basic:
{
"browser": { "name": "Chrome", "version": "145.0.0.0", "major": "145" },
"device": { "model": "Macintosh", "vendor": "Apple" },
"os": { "name": "macOS", "version": "10.15.7" }
}Error
The HTTP status code equals code. message is the exact string shown in the table below.
| HTTP | message | data | Meaning |
|---|---|---|---|
| 400 | Invalid request | { "errors": [ { "field", "reason", "type" } ] } | Missing field, wrong type, or invalid event_time |
| 400 | Invalid request | { "errors": [{ "field": "device_token", "reason": "Invalid token", "type": "value_error" }] } | device_token is invalid |
| 401 | Invalid bearer token | {} | Authentication failed |
| 403 | Forbidden | {} | The application is unavailable, does not pass the IP allowlist check, or fallback mode is disabled |
| 403 | deactivate / quota_exceeded / manual_deactivate | {} | The customer product switch is switch=off; message is the current CustomerProductVersion.status, not Forbidden |
| 404 | integration not found | {} | public_key is invalid, or the request was not sent to the regional API endpoint for the application's Region |
| 429 | Too many requests | {} | Fallback analysis exceeded the application's per-minute or per-hour rate limit quota |
| 500 | Internal server error | {} | Server error |
{
"code": 400,
"data": {
"errors": [
{ "field": "device_token", "reason": "Field required", "type": "missing" }
]
},
"message": "Invalid request"
}{
"code": 401,
"data": {},
"message": "Invalid bearer token"
}Example
Copy {public_key} and {secret} from the dashboard. Get {device_token} from the client SDK, and send the request to the regional API endpoint for the application's Region.
curl -sS -X POST "https://{host}/api/v2/fp_query/{public_key}" \
-H "Authorization: Bearer {secret}" \
-H "Content-Type: application/json" \
-d '{
"device_token": "{device_token}",
"event_type": "login",
"event_time": "2026-08-20T10:30:00+08:00"
}'