Client API¶
The Client API checks a visitor IP (and optional user agent) and returns allow or block. It does not use a campaign ID. You decide what to do with the result in your own app.
- One credit is deducted per
checkcall. action=creditsreturns your balance and does not deduct a credit.- Call it from your server. Never put the token in public JavaScript or a mobile app binary.
Your token and live examples are also on API in the dashboard: https://ai.cloakerly.com/client-api.
Endpoint¶
POST or GET https://api.cloakerly.com/client/v1/
JSON responses. CORS allows browser calls, but the token must stay private — use a backend.
Authentication¶
Send your client token in one of these ways (format api_user_id:api_key):
| Method | Example |
|---|---|
| Request field | client_token=USER_ID:API_KEY (query string or POST body) |
| Header | X-Client-Token: USER_ID:API_KEY |
| Bearer | Authorization: Bearer USER_ID:API_KEY |
Copy the token from API in the dashboard. Do not share it.
Actions¶
action | Uses a credit? | Purpose |
|---|---|---|
check (default) | Yes — 1 credit | Classify the IP and return allow or block |
credits | No | Return remaining credits only |
If credits are 0, check returns HTTP 402 insufficient_credits. Top up on Plans.
Check request¶
| Field | Required | Notes |
|---|---|---|
client_token | Yes (unless sent as a header) | api_user_id:api_key |
ip | Recommended | Visitor IP (IPv4 or IPv6). If omitted, Cloakerly uses the request IP. |
user_agent | No | Used for device / OS in the response |
accept_language | No | Echoed in the response; not used as an allow-list |
allow_vpn | No | 1 / true to not block VPNs. Default off |
allow_datacenter | No | 1 / true to not block hosting / datacenter. Default off |
action | No | check (default) or credits |
You can send GET query parameters, POST form fields, or POST application/json.
Decision rules¶
These rules apply to check. Campaign filters (countries, OS, UTM, affiliate URLs) are not applied.
- Always block: proxy, Tor, scraper, compromised, anonymous, high risk score, and known bad networks
- Block VPN unless
allow_vpn=1 - Block hosting / datacenter unless
allow_datacenter=1
Success response (check)¶
{
"ok": true,
"decision": "block",
"reasons": ["vpn_not_allowed"],
"ip": "203.0.113.10",
"ip_version": "4",
"device": "mobile",
"os": "IOS",
"accept_language": "en-US,en;q=0.9",
"location": {
"country_code": "US",
"country_name": null,
"region_name": null,
"city_name": "Los Angeles",
"timezone": null
},
"network": {
"asn": "AS13335",
"provider": null,
"organisation": null,
"type": "Hosting",
"hostname": null
},
"detections": {
"proxy": false,
"vpn": true,
"hosting": true,
"tor": false,
"scraper": false,
"compromised": false,
"anonymous": false,
"risk_score": 88,
"confidence": null
},
"credits_remaining": 1499,
"response_time_ms": 210
}
| Field | Meaning |
|---|---|
decision | allow or block |
reasons | Why it was blocked (empty when allowed) |
device | mobile or desktop |
os | IOS, ANDROID, WINDOWS, MAC OS, LINUX, UNIX, or unknown |
credits_remaining | Balance after this check |
Common reasons¶
| Reason | Meaning |
|---|---|
proxy_detected | Proxy |
vpn_not_allowed | VPN and allow_vpn is off |
hosting_not_allowed | Hosting / datacenter and allow_datacenter is off |
tor_detected | Tor |
scraper_detected | Scraper |
compromised_detected | Compromised |
anonymous_detected | Anonymous |
high_risk_score_* | Risk score at or above the block threshold |
network_block | Network classified as blocked |
datacenter_block_1 | Datacenter / hosting network |
Credits response¶
{
"ok": true,
"subscription_type": "pay",
"credits_remaining": 1499
}
Errors¶
All errors are JSON: { "ok": false, "error": "...", "message": "..." }.
| HTTP | error | When |
|---|---|---|
| 400 | missing_parameters | No client_token |
| 400 | invalid_ip | IP could not be determined or is invalid |
| 400 | invalid_action | action is not check or credits |
| 401 | invalid_token | Token does not match an account |
| 403 | pay_as_you_go_required | Account is not pay-as-you-go |
| 402 | insufficient_credits | No credits left (credits_remaining is 0) |
| 500 | server_error | Temporary server problem |
Examples¶
Replace USER_ID:API_KEY with the token from API in the dashboard.
cURL — check¶
curl -X POST 'https://api.cloakerly.com/client/v1/' \
-H 'Accept: application/json' \
-d 'client_token=USER_ID:API_KEY' \
-d 'ip=203.0.113.10' \
-d 'user_agent=Mozilla/5.0'
cURL — credits (no deduction)¶
curl 'https://api.cloakerly.com/client/v1/?action=credits&client_token=USER_ID:API_KEY' \
-H 'Accept: application/json'
PHP¶
<?php
$ch = curl_init('https://api.cloakerly.com/client/v1/');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 10,
CURLOPT_HTTPHEADER => ['Accept: application/json'],
CURLOPT_POSTFIELDS => http_build_query([
'client_token' => 'USER_ID:API_KEY',
'ip' => $_SERVER['REMOTE_ADDR'] ?? '',
'user_agent' => $_SERVER['HTTP_USER_AGENT'] ?? '',
]),
]);
$result = json_decode(curl_exec($ch), true);
curl_close($ch);
if (!empty($result['ok']) && ($result['decision'] ?? '') === 'allow') {
// Real visitor
} else {
// Filtered traffic (VPN, proxy, hosting, etc.)
}
Using it with campaigns¶
The Client API is a standalone lookup. It does not redirect to Safe or affiliate URLs. For landing-page filtering with campaigns, use the SCRIPT integration instead — see Integration.