PureGuard API Documentation
PureGuard is a server-side bot detection engine built for performance media buyers. It analyzes every click through 13+ configurable detection layers and returns a verdict in under 15ms. This documentation covers the REST API, detection engine internals, and integration guides for every major traffic source.
1. Create an account
Register for free to get instant access. Your starter plan includes 100,000 bot checks per month at no cost. No credit card required.
2. Get your API key
After logging in, navigate to Settings to find your API key. The key is a unique
string prefixed with pg_ that authenticates all your requests.
3. Make your first request
curl -X POST https://pureguard.io/api/v1/check \ -H "X-API-Key: pg_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "ip": "1.2.3.4", "ua": "Mozilla/5.0 Chrome/131.0", "url": "https://example.com/offer" }'
The response tells you whether to accept or block the visitor:
{
"verdict": "ACCEPT",
"trust": 7.3,
"confidence": 92,
"signals": ["sec_fetch:+1.0", "residential:+0.3", "real_device:+0.5"],
"ms": 2.3
}
Authentication
All API requests (except GET /api/v1/status) require authentication via the
X-API-Key header. Your API key is available on the
Settings page of your dashboard.
Example authenticated request:
curl -H "X-API-Key: pg_abc123def456" \
https://pureguard.io/api/v1/stats
Requests without a valid key receive a 401 Unauthorized response. Requests that exceed
your plan's monthly quota receive 429 Too Many Requests.
API Reference
Base URL: https://pureguard.io/api/v1. All request and response bodies use JSON.
Times are in UTC.
Bot Check
Evaluate a single visitor. Send the visitor's IP address, user-agent string, and optionally their HTTP headers for maximum detection accuracy. The engine runs all enabled layers and returns a verdict within milliseconds.
Request Body
Full Example
POST /api/v1/check HTTP/1.1
Host: pureguard.io
X-API-Key: pg_abc123def456
Content-Type: application/json
{
"ip": "203.0.113.42",
"ua": "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Mobile Safari/537.36",
"url": "https://example.com/offer?s1=zone_1234",
"headers": {
"Sec-Fetch-Site": "cross-site",
"Sec-Fetch-Mode": "navigate",
"Sec-Fetch-Dest": "document",
"Accept-Language": "th-TH,th;q=0.9,en;q=0.8",
"Accept-Encoding": "gzip, deflate, br"
},
"zone": "zone_1234"
}
{
"verdict": "ACCEPT",
"trust": 7.3,
"confidence": 92,
"signals": [
"sec_fetch:+1.0",
"residential:+0.3",
"real_device:+0.5",
"chrome_build:+0.5",
"lang_match:+0.3"
],
"ms": 2.3
}
Response Fields
{"verdict":"BLOCK","trust":0.0,"confidence":99,"signals":["firehol:KILL"],"ms":0.8}
Traffic Statistics
Returns aggregated traffic statistics for your account. Includes today's counts and a 7-day historical breakdown for charting.
{
"today": {
"checks": 14832,
"accepts": 8291,
"blocks": 6541,
"rate": 55.9
},
"week": [
{ "date": "2026-03-02", "checks": 12480, "accepts": 7120, "blocks": 5360 },
{ "date": "2026-03-03", "checks": 13105, "accepts": 7402, "blocks": 5703 },
{ "date": "2026-03-04", "checks": 11893, "accepts": 6814, "blocks": 5079 },
{ "date": "2026-03-05", "checks": 14220, "accepts": 7988, "blocks": 6232 },
{ "date": "2026-03-06", "checks": 15010, "accepts": 8201, "blocks": 6809 },
{ "date": "2026-03-07", "checks": 13744, "accepts": 7512, "blocks": 6232 },
{ "date": "2026-03-08", "checks": 14832, "accepts": 8291, "blocks": 6541 }
]
}
Zone Data
Returns zone reputation data for all zones seen in your traffic. Use this to identify high-quality and toxic traffic sources programmatically.
{
"zones": [
{
"id": "zone_1234",
"status": "trusted",
"score": 8.2,
"hits": 4521,
"accept_rate": 87.3
},
{
"id": "zone_5678",
"status": "blocked",
"score": 1.4,
"hits": 892,
"accept_rate": 12.1
},
{
"id": "zone_9012",
"status": "neutral",
"score": 5.0,
"hits": 38,
"accept_rate": 63.2
}
]
}
Zone Statuses
System Status
Public endpoint (no authentication required). Returns current engine status, version, and uptime. Use this for health checks and monitoring.
{
"status": "operational",
"engine": "v17.1",
"layers": 13,
"uptime": 99.7
}
Detection Layers
PureGuard's engine evaluates traffic through multiple independent detection layers. Each layer operates in one of three modes:
- Kill -- Instant block. A single confirmed signal is enough to reject the visitor.
- Score -- Adjusts the trust score up or down. Multiple weak signals compound.
- Observe -- Logs the signal for analysis but does not affect the verdict.
All layers are fully configurable through the dashboard. You can enable/disable individual layers and change their mode via the Guard Settings panel.
Hard Kill Layers
These layers terminate evaluation immediately when triggered. A single match means definite bot.
.0.0.0 build numbers, but older Chrome versions with .0.0.0 are spoofed bots impersonating the UA Reduction format.Trust Scoring Layers
These layers adjust the trust score (base: 5.0) up or down. Multiple signals compound. The final trust score determines the verdict: below threshold = BLOCK, above = ACCEPT.
Observation Layers
These layers collect signals for analysis and reporting but do not affect the verdict by default. Enable scoring mode on any of them to start using them in decisions.
CF-TLS-Version header. Modern browsers use TLS 1.3. Older TLS versions correlate with outdated or automated clients.Integration Guide
PureGuard integrates into any stack. Below are production-ready examples for the most common languages, plus traffic source and RTB setup instructions.
PHP Integration
Direct server-side integration. Call the API before redirecting the visitor.
<?php function checkBot($ip, $ua, $url, $headers = []) { $ch = curl_init('https://pureguard.io/api/v1/check'); curl_setopt_array($ch, [ CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => 5, CURLOPT_HTTPHEADER => [ 'X-API-Key: pg_your_api_key', 'Content-Type: application/json', ], CURLOPT_POSTFIELDS => json_encode([ 'ip' => $ip, 'ua' => $ua, 'url' => $url, 'headers' => $headers, ]), ]); $response = json_decode(curl_exec($ch), true); curl_close($ch); return $response; } // Usage in your click handler: $result = checkBot( $_SERVER['REMOTE_ADDR'], $_SERVER['HTTP_USER_AGENT'], 'https://example.com/offer' ); if ($result['verdict'] === 'BLOCK') { http_response_code(204); // Bot killed silently exit; } // Clean visitor -- redirect to offer header('Location: https://offer.example.com/lp1'); exit;
Node.js Integration
const checkBot = async (ip, ua, url) => { const res = await fetch('https://pureguard.io/api/v1/check', { method: 'POST', headers: { 'X-API-Key': process.env.PUREGUARD_KEY, 'Content-Type': 'application/json', }, body: JSON.stringify({ ip, ua, url }), }); return res.json(); }; // Express middleware example app.get('/click', async (req, res) => { const guard = await checkBot( req.ip, req.get('User-Agent'), req.originalUrl ); if (guard.verdict === 'BLOCK') { return res.status(204).end(); } res.redirect('https://offer.example.com/lp1'); });
Python Integration
import requests import os API_KEY = os.getenv("PUREGUARD_KEY") API_URL = "https://pureguard.io/api/v1/check" def check_bot(ip: str, ua: str, url: str) -> dict: resp = requests.post( API_URL, json={"ip": ip, "ua": ua, "url": url}, headers={ "X-API-Key": API_KEY, "Content-Type": "application/json", }, timeout=5, ) resp.raise_for_status() return resp.json() # Usage with Flask from flask import Flask, request, redirect, abort app = Flask(__name__) @app.route("/click") def click_handler(): result = check_bot( request.remote_addr, request.user_agent.string, request.url, ) if result["verdict"] == "BLOCK": abort(204) return redirect("https://offer.example.com/lp1")
Traffic Source Setup
For pop/push/native traffic sources, point your campaign URL through PureGuard's click handler. The engine evaluates the visitor inline and redirects clean traffic to your offer.
click.php (Guard evaluates) →
ACCEPT: 302 to offer | BLOCK: 204 No Content
Click URL Format
https://pureguard.io/click.php?s1={zone_id}&s2={click_id}&s3={source}
Source Macro Mapping
RTB / OpenRTB 2.5
PureGuard includes a built-in OpenRTB 2.5 bidder for programmatic traffic. The RTB endpoint
evaluates bid requests through a dedicated Guard::runRTB() pipeline with 36 signals
optimized for bid-time decisions (no browser headers available).
// SSP sends bid request to: POST https://pureguard.io/bid.php // PureGuard responds with: // BID (trust >= 5.5) -> 200 with bid response // NOBID (trust < 5.5) -> 204 No Content // Win notice URL (in bid response): https://pureguard.io/win.php?price=${AUCTION_PRICE}&id={bid_id}
RTB Trust Engine
The RTB pipeline starts at a base trust of 10.0 and applies 36 penalty/bonus signals. Traffic scoring at bid time does not have access to browser headers (Sec-Fetch, etc.) since the RTB request comes from the SSP server, not the end user. Instead it relies on:
- IP blocklist checks (FireHOL, CrowdSec, master blocklist)
- UA pattern matching (bot signatures, ad-fraud crawlers)
- Device type analysis (connected TV, set-top box penalties)
- Geo verification (MaxMind cross-check vs declared geo)
- Domain quality (junk domains, IP-as-domain, ad-heavy TLDs)
- Bid floor analysis (scam floors > $3, suspicious zero floors)
- Burst rate limiting (APCu in-memory, per-IP)
Rate Limits
Rate limits are enforced per API key at the Nginx level. Exceeding the limit returns
429 Too Many Requests. The response includes a Retry-After
header indicating when to retry.
Error Codes
All error responses include a JSON body with an error field describing the issue.
Error Response Format
{
"error": "Invalid or missing API key",
"code": 401
}
{
"error": "Rate limit exceeded",
"code": 429,
"retry_after": 2
}
Our team can help you set up PureGuard for your specific traffic stack.