PureGuard API Documentation
PureGuard is a server-side bot detection engine built for performance media buyers. It analyzes every click through 18 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/v7/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": "high",
"reason": "",
"ms": 2.3
}
Authentication
All API requests (except GET /api/v7/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/v7/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/v7. 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/v7/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",
"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",
"source": "POPADS"
}
{
"api_version": "v7",
"verdict": "ACCEPT",
"action": "pass",
"trust": 7.3,
"trust_threshold": 7.0,
"confidence": "high",
"reason": "",
"scores": {
"device": 1.2,
"browser": 1.5,
"headers": 1.0,
"network": 1.3,
"behavior": 0.8,
"reputation": 0.5
},
"signals": { /* detection flags — see Signal Reference */ },
"detection_layers": {
"total": 18,
"triggered": [
{ "layer": "device", "impact": 1.2 },
{ "layer": "browser", "impact": 1.5 }
]
},
"geo": {
"country": "TH",
"asn": "45758",
"isp": "Triple T Broadband"
},
"zone": {
"id": "zone_1234",
"allowed": true,
"status": "known",
"accept_rate": 87.3,
"hits": 4521
},
"redirect": {
"action": "pass_to_l3",
"l3_required": true
},
"ms": 2.3,
"request_id": "a1b2c3d4e5f6g7h8"
}
Response Fields
{"verdict":"BLOCK","trust":0.0,"confidence":"high","reason":"threat_intel","ms":0.8}
Traffic Quality Tiers
Every check returns a quality tier classification:
- Gold — Trust score 7.0+. High confidence human visitor with clean signals across all detection layers.
- Silver — Trust score 5.0-6.9. Passed detection but with borderline or missing signals.
- Filtered — Bot signals detected or zone blocked. Non-human or fraudulent traffic.
- Unknown — Insufficient data to classify (rare).
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. Supports pagination, filtering by status and source, and sorting.
Query Parameters
{
"api_version": "v7",
"total": 9501,
"returned": 3,
"offset": 0,
"limit": 100,
"summary": { "block": 9501, "neutral": 52046, "trusted": 25 },
"zones": [
{
"id": "5149124",
"status": "block",
"rule": "BOTH_CONFIRM",
"source": "POPADS",
"hits": 31058,
"accepts": 30492,
"blocks": 566,
"accept_rate": 98.2,
"avg_trust": 0
},
{
"id": "3212677",
"status": "neutral",
"rule": "CONVERSION_PROTECTED",
"source": "POPADS",
"hits": 26399,
"accepts": 16091,
"blocks": 10095,
"accept_rate": 61.0,
"avg_trust": 3.2
}
]
}
Zone Statuses
Zone Response Fields
The summary object in the zones response includes a tier_counts field with aggregate counts:
"tier_counts": { "gold": 142, "silver": 3891, "filtered": 9501, "unknown": 48038 }
UQC v4 Block Rules
The Zone Quality Engine (UQC v4) evaluates zones against 14 blocking rules every 10 minutes.
When a zone is blocked, the rule field tells you exactly why.
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.25",
"layers": 18,
"uptime": 99.7
}
Beacon
Client-side engagement and browser integrity data from the PureGuard WordPress plugin or custom integration. Beacons are sent via navigator.sendBeacon and are non-blocking.
Request Body
Authentication
API key passed as query parameter: ?key=YOUR_API_KEY
Response
Returns 204 No Content on success. Beacons are fire-and-forget.
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 (proprietary base) 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.L3 Client-Side Detection
Layer 3 (L3) is a client-side JavaScript probe that runs in the visitor's browser after server-side Guard analysis. It collects hardware and software signals that cannot be obtained from HTTP headers alone. L3 detects headless browsers, emulators, and sophisticated bot frameworks.
L3 results feed back into the zone quality engine and the Quality Tiers system. Zones with high L3 failure rates receive penalties that trigger zone blocking and tier downgrades. The combination of server-side Guard analysis and client-side L3 probing creates a detection system that is extremely difficult for bot operators to bypass.
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/v7/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/v7/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/v7/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 your offer URL | BLOCK: 302 to dump URL
Click URL Format
https://pureguard.io/click.php?wk={workspace_key}&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 RTB pipeline with dozens of 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 (above threshold) -> 200 with bid response // NOBID (below threshold) -> 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 score and applies multiple 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 (multiple threat intelligence feeds)
- UA pattern matching (bot signatures, ad-fraud crawlers)
- Device type analysis (connected TV, set-top box penalties)
- Geo verification (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 (in-memory, per-IP)
Bid Request Format (OpenRTB 2.5)
Send a POST request with a JSON body conforming to OpenRTB 2.5:
{
"id": "request-123",
"imp": [{
"id": "1",
"instl": 1,
"bidfloor": 0.50,
"banner": { "topframe": 1 },
"ext": { "type": "pop" }
}],
"site": {
"domain": "example.com",
"id": "site_456",
"page": "https://example.com/page"
},
"device": {
"ua": "Mozilla/5.0 (Linux; Android 14; ...) Chrome/131.0...",
"ip": "203.0.113.42",
"devicetype": 2,
"os": "Android",
"geo": { "country": "US" }
},
"at": 1,
"cur": ["USD"]
}
Bid Response Format (200 OK)
When Guard accepts the traffic (above acceptance threshold), PureGuard returns a bid:
{
"id": "request-123",
"seatbid": [{
"bid": [{
"id": "bid-abc123",
"impid": "1",
"price": 0.501,
"adm": "https://pureguard.io/click.php?s1={zone}&s3=SSP&...",
"nurl": "https://pureguard.io/win.php?bid=bid-abc123&price=${AUCTION_PRICE}&req=request-123&zone={zone}&ssp=SSP",
"adomain": ["pureguard.io"],
"crid": "pop-1"
}]
}],
"cur": "USD"
}
No-Bid Response (204 No Content)
A 204 response means PureGuard declined to bid. Common reasons:
Win Notice
The nurl field in the bid response contains the win notification URL. The SSP must
call this URL when the auction is won, replacing ${AUCTION_PRICE} with the actual
clearing price (CPM). PureGuard uses this to track daily spend and per-zone win caps.
GET https://pureguard.io/win.php?bid={bid_id}&price={clearing_price_cpm}&req={request_id}&zone={zone}&ssp={ssp_name}
Testing Your Integration
curl -X POST https://pureguard.io/bid.php \
-H "Content-Type: application/json" \
-d '{
"id":"test-1",
"imp":[{"id":"1","instl":1,"bidfloor":0.50,"ext":{"type":"pop"}}],
"site":{"domain":"test.com"},
"device":{"ua":"Mozilla/5.0 Chrome/131.0","geo":{"country":"US"},
"ip":"1.2.3.4","devicetype":2},
"at":1,"cur":["USD"]
}'
# 200 = bid accepted (check response JSON)
# 204 = no bid (check RTB dashboard for reason)
Current SSP Status
Conversion Tracking (Postback)
PureGuard tracks conversions via server-to-server postback URLs. When a user converts on your offer, the smartlink or offer network fires a postback to PureGuard with the conversion details. This lets PureGuard attribute revenue to specific zones and power the zone quality engine.
How It Works
click.php filters and redirects clean traffic to your offer
https://pureguard.io/postback.php?...
Postback URL Parameters
Example Postback URL
https://pureguard.io/postback.php?s2={click_id}&value={payout}&s1={zone}&network=HILLTOPADS&wk=YOUR_WK
Network-Specific Macros
Each ad network uses different macro names. Use the correct macros for your network:
Duplicate Protection
PureGuard automatically deduplicates conversions. If the same click ID (s2) fires a postback
within 5 minutes, the duplicate is rejected. This prevents double-counting from network retries.
Response Format
OK: Fired to HILLTOPADS | HILLTOPADS: HTTP 200. Sentinel Updated.
DUPLICATE: Conversion for token already recorded within 5 minutes.
Shadow Mode
Shadow mode lets you see exactly what PureGuard would do with your traffic -- without blocking anything. Every click is analyzed, scored, and logged, but all traffic passes through to your destination. Use it to prove the value before committing.
What Shadow Mode Does
Setting Up Shadow Mode
- Go to Connectors and create (or edit) your traffic source connector
- Set the Mode dropdown to Shadow
- Copy your campaign URL and paste it into your traffic source
- Launch your campaign -- traffic flows through PureGuard immediately
Reading Your Shadow Results
After running shadow mode, your dashboard shows:
Shadow → Protect
When you are ready to start blocking bots, switch the connector mode from Shadow to Protect. That is it -- one toggle, instant protection. All your shadow data and zone intelligence carries over.
Rate Limits
Rate limits are enforced per API key using in-memory counters. Exceeding the limit returns
429 Too Many Requests. The response includes X-RateLimit-Remaining
and X-RateLimit-Reset headers.
API Rate Limits (per API key)
Endpoint Rate Limits (per IP, Nginx level)
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.