Response Object
Every field Checkpoint returns for a request: the verdict, the evidence behind it, and the engine that produced it
Every Checkpoint integration runs the same detection engine, and every verdict it produces is a single object, the VerifyResult.
This page documents that object in full: every field, when it is present, and what its values mean.
What your integration receives from the object depends on the surface you installed and on whether full response delivery is enabled for your project.
Full response delivery
By default, each integration returns a projection of this object: headers from the SDKs and the
DNS gateway, the result of /api/v1/detect, and the stored record through the read-back API.
With full response delivery enabled, Checkpoint sends the complete object documented here,
including every signal, reason code and captured attribute. Vouched enables full response delivery
per project or per organization. Contact your account team to turn it on.
The response object, fully expanded
The example below is a GPTBot crawler request from an OpenAI IP address, evaluated in observe mode against a policy that allows it. Values are illustrative. Comments give each field's type and when it appears.
{
"decision": { "kind": "Permit", "policyId": "allow-search-and-ai-crawlers" }, // Permit | Block | Challenge | Redirect | Instruct (tag = kind)
"detectionDetail": {
"isAgent": false, // boolean, always. true only for the AiAgent class; route on detectionClass instead
"isBot": true, // boolean, optional. Omitted when the class is IncompleteData
"isAiCrawler": true, // boolean, optional. Omitted when the class is IncompleteData
"confidence": 99.0, // number 0-100, always. How strongly the evidence indicates automation; see Reading the object
"detectionClass": {
// tagged by type: Human | AiAgent | Bot | IncompleteData
"type": "Bot",
"botType": "Scraper", // Bot only: Scraper | SearchEngine | HeadlessBrowser | Tool | HighVelocity
"legitimacy": "Suspicious", // Bot only: Suspicious | Legitimate
},
"confidenceLevel": "very_high", // low | medium | high | very_high; bands at /docs/detect#confidence-scores
"reasons": [
// string[], always. Human-readable, one per piece of classifying evidence
"User-Agent matched known agent pattern: GPTBot",
"Vendor IP + User-Agent cross-match: OpenAI GPTBot (training crawler)",
],
"signals": [
// array, always (may be empty). The evidence behind the verdict
{
"signalType": "pattern", // signature | pattern | behavioral | network | fingerprint
"confidence": 90.0, // number 0-100. Strength of this piece of evidence
"weight": 0.5, // number 0-1. How much this evidence counts toward confidence; 0 for recorded context
"source": "user_agent_pattern", // which detector produced it (see Signal sources)
"explanation": "User-Agent matched known agent pattern: GPTBot",
},
{
"signalType": "network",
"confidence": 90.0,
"weight": 0.5,
"source": "vendor_ip_feed",
"explanation": "Vendor IP + User-Agent cross-match: OpenAI GPTBot (training crawler)",
"metadata": { "vendor_id": "openai_gptbot" }, // object, optional. Omitted when empty
},
],
"detectedAgent": { "type": "bot", "name": "GPTBot" }, // optional. type: ai_agent | bot; vendor set on verified vendor signatures
"botType": "ai_crawler", // optional. ai_crawler | search_engine | headless_browser | tool | high_velocity | ai_agent
"agentType": "GPTBot", // optional. Matched agent name, vendor id, KYA-OS proof issuer, or "kya-os"
"verificationMethod": "pattern", // optional. none | pattern | signature | kya-http | kya-http-delegated | a2a | mcp_i_handshake | tier1_rfc9421 | error
"assurance": "anonymous", // always. anonymous | attested-bearer | key-bound | delegated
"riskLevel": "high", // low | medium | high
"forgeabilityRisk": "medium", // low (cryptographically verified) | medium (pattern) | high (engine error)
"timestamp": 1789500000, // integer, always. Unix seconds
// "metadata": { ... } object, optional. Path-specific keys (see Metadata keys)
// "requestId": "..." string, optional. Added by some integrations; never set by the engine
// "engine": { ... } object, optional. Copy of engineInfo on signature-verified paths
// "grantedScopes": [ ... ] string[], optional. Present when a delegation was verified
},
"enforcementMode": "observe", // enforce | observe. In observe mode your integration records the decision without acting on it
"engineInfo": {
"name": "checkpoint-engine-wasm", // checkpoint-engine-wasm | checkpoint-engine-wasi | checkpoint-engine-native
"version": "0.2.0",
"rulesetHash": "sha256:…", // identifies the bundled detection rules
"rulesetVersion": "0.2.0",
// "buildSha": "..." string, optional
},
"trace": [
// array, always. One entry per engine stage that ran
{
"name": "detection",
"verdict": "pass",
"latencyMicros": 4,
"reason": "AiCrawler (99% confidence)",
},
{ "name": "reputation", "verdict": "pass", "latencyMicros": 0 },
{ "name": "policy", "verdict": "pass", "latencyMicros": 0 },
],
// "network": { "trueIp", "asn", "isp", "routingType", "proxy" } object, optional. Present when network context was available
}Route on detectionClass, not isAgent
isAgent is true only for the AiAgent class. Crawlers such as GPTBot are Bot, so isAgent
is false for them. Other surfaces use a broader meaning: the /api/v1/detect result and stored
detection records treat any non-human class as an agent. Use detectionClass and botType to
decide what to do with a request.
Reading the object
confidencemeasures how strongly the evidence indicates automation. It runs from 0 to 100 and weighs many independent signals together: network and TLS characteristics, HTTP and header consistency, browser and runtime integrity, behavior, and known-agent intelligence. Verified cryptographic identity takes precedence over heuristic evidence and scores at the top of the range.confidenceis a score of the evidence, not a measured probability, a measure of certainty in the class, or a fraud-risk score.confidenceLevelgives its band, andriskScoreis a separate, uncalibrated score.- No evidence is not proof of a human.
Humanwith an emptysignalslist means nothing indicated automation, not that a person was confirmed. Weigh low-evidenceHumanverdicts accordingly in your own risk logic. - Identity and heuristics are separate axes.
verificationMethodandassurancesay what was cryptographically proven.signalssay what heuristics observed. A GPTBot User-Agent from an OpenAI IP address is strong heuristic evidence, but itsassuranceis stillanonymous. - Scales differ by surface.
confidenceis 0 to 100 in this object, in/api/v1/enforceand in the extended read-back. The legacy detections list and webhook payloads use 0 to 1. - Expect additions. New signal sources, metadata keys and reason codes are added over time. Ignore values you don't recognize rather than rejecting the response.
Top-level fields
Decision
decision is tagged by kind. Each kind carries its own payload.
// Permit: the request may proceed. policyId names the deciding policy when there is one
{ "kind": "Permit", "policyId": "allow-search-and-ai-crawlers" }
// Block: the request is refused. reason is tagged by kind (see the table below)
{ "kind": "Block", "reason": { "kind": "PolicyDenied", "detail": "Automated traffic is not allowed on /checkout", "policyId": "block-automation-on-checkout" } }
// Challenge: the client must step up before retrying
{
"kind": "Challenge",
"params": {
"nonce": "c2f1…",
"audience": "https://app.example.com",
"expiresAt": 1789500300,
"algorithmsAccepted": ["EdDSA", "ES256"],
"minAssurance": "delegated", // optional
"policyId": "require-delegation", // optional
"challengeType": "human_step_up", // optional. Omitted for delegation; browser_integrity | human_step_up
},
}
// Redirect: send the client elsewhere
{ "kind": "Redirect", "target": { "url": "https://app.example.com/verify", "reason": "…", "state": "…", "policyId": "…" } }
// Instruct: tell an agent how to make an acceptable request
{
"kind": "Instruct",
"payload": {
"problem": "…",
"title": "…",
"suggestedActions": [{ "kind": "UseDifferentScope", "scope": "read:documents" }],
"policyId": "…", // optional
},
}suggestedActions[].kind is one of UseDifferentScope (scope), UpdateRequestField (field, acceptedValues), UpgradeProtocolVersion (version) or Other (code, detail).
Block reasons
Block reason fields are written in snake_case, unlike the rest of the object.
The table is in order of severity. When more than one outcome applies, Redirect wins, then Challenge, then Instruct, then the most severe Block reason.
Detection detail
Classes
AiAgent may also carry vendor and model. Bot carries botType (Scraper, SearchEngine, HeadlessBrowser, Tool, HighVelocity) and legitimacy (Suspicious, Legitimate).
Signals
Each entry in detectionDetail.signals is one piece of evidence.
Signal sources
Signal metadata keys not listed here are diagnostic and may change.
/api/v1/detect returns this same list on result.signals, unconditionally, on every response. /api/v1/enforce returns it only when you set options.includeDetectionResult.
Metadata keys
Keys not listed here are diagnostic and may change.
Reason codes
Reason codes are the machine-readable form of reasons: an ordered list of detection/* codes, most significant evidence first and never empty.
They appear in /api/v1/enforce (detection.reasonCodes), in the extended read-back (reasonCodes), and in the DNS gateway's KYA-Reason-Codes header (up to five).
Risk score
riskScore is an uncalibrated score of the same evidence, from 0 to 1. It is never derived from confidence and never feeds into it, and the two are on different scales, so they can differ widely. Don't convert one into the other.
They appear in the /api/v1/detect result, in /api/v1/enforce detection when you set options.includeDetectionResult, and in the .NET (RiskScore, RiskScoreSource) and Java (riskScore(), riskScoreSource()) SDK detection results. The engine object on this page, the Next.js and Express SDKs, and response headers do not carry them.
Captured context
Alongside the verdict, Checkpoint stores the context it observed for the request: TLS details from the DNS gateway, device and browser attributes from the Beacon or pixel, interaction counters, and IP intelligence. It is part of the stored detection record and of full response delivery.
{
"transport": {
// DNS gateway only
"tlsJa4": "t13d1516h2_8daaf6152771_02713d6af862",
"tlsVersion": "TLSv1.3",
"cfBotScore": 2, // when Cloudflare Bot Management is available
"cfVerifiedBot": false,
"asn": 16509,
"asOrganization": "Amazon.com, Inc.",
},
"client": {
// Beacon, pixel and native collectors. Each attribute is { "value": "<string>" }
"attributes": {
"device.platform": { "value": "MacIntel" },
"browser.timezone": { "value": "America/Chicago" },
"screen.resolution": { "value": "1512x982" },
"browser.language": { "value": "en-US" },
"platform.hardwareConcurrency": { "value": "10" },
},
},
"behavioural": {
"mouseMovements": 42,
"clickCount": 3,
"scrollDepthPercent": 60,
"timeOnPageMs": 18450,
},
"network": {
"trueIp": "3.19.44.10",
"asn": 16509,
"isp": "Amazon.com, Inc.",
"routingType": "hosting", // residential | mobile | datacenter | hosting | unknown
"proxy": { "isProxy": true, "proxyType": "datacenter", "confidence": 95 }, // vpn | tor | datacenter | residential_proxy | unknown
},
}A missing network field means no data was available for that address, not that the address is clean.
Examples by evidence path
Each example shows only the fields that differ from the fully expanded object. Values are illustrative.
"confidence": 1.0,
"detectionClass": { "type": "Human" },
"confidenceLevel": "low",
"reasons": ["No known agent indicators matched"],
"signals": [],
"verificationMethod": "none",
"riskLevel": "low"What each integration returns
Enumerations
Values that contain mcp_i or mcp-i, such as mcp_i_handshake and detection/mcp-i-verified, keep the former name of KYA-OS, MCP-I.
