Developer docs
Documentation
Guides and API reference for running AntiBait analysis from the web app or from your own code.
API reference
Full AI analysis
PremiumFull analysis of one raw email: deterministic checks, an AI verdict that is reviewed again when it disagrees with the evidence, and the findings behind the result.
API endpoint
POST/api/analysis/advancedRequest body
{
"email": "string
(full raw email)"
}Max 1MB. Must include headers and body.
Response
{
"status": 200,
"success": true,
"analysisId": "uuid",
"cached": false,
"score": number,
"headerScore": number | null,
"bodyScore": number | null,
"threatType": string | null,
"type": string | null,
"confidence": number | null,
"tags": string[],
"reasoning": string | null,
"falsePositiveChecks": string[],
"error": string | null,
"data": object,
"senderInsights": {
"status": "ready" | "locked" | "off" | "unavailable",
"since": string | null,
"insights": [{ "code": string, "severity": string, ... }]
}
}Analysis features
AI-powered detection
A language model judges the message with the deterministic findings in front of it; a second pass reviews verdicts that disagree with the evidence
Comprehensive scoring
Multi-dimensional risk assessment with confidence metrics
Threat categorization
Detailed tags and threat type classification
Detailed reasoning
The model's explanation plus the evidence: sender identity, authentication, links, attachments and how the verdict was reached
Response fields
statusnumberHTTP status code (always 200 for successful requests)
successbooleanIndicates if the analysis was successful
analysisIdstring | nullUnique identifier for this analysis (UUID format)
cachedbooleanWhether the result was retrieved from cache (previously analyzed email)
scorenumberOverall risk score (0-100) combining all analysis factors
headerScorenumber | nullAlways null on this endpoint. The header heuristic score is in data.enhancedAnalysis.headerScore
bodyScorenumber | nullAlways null on this endpoint. The body heuristic score is in data.enhancedAnalysis.bodyScore
threatType / typestring | nullClassification: "phishing", "malicious", "spam", "legitimate", or null
confidencenumber | nullConfidence (0-100) in the verdict. A result resolved without a model reports 95
tagsstring[]Array of threat indicators detected (e.g., ["SUSPICIOUS_LINK", "URGENT_LANGUAGE"])
reasoningstring | nullThe model's explanation. A result resolved without a model (data.triage.gateApplied) carries a short note starting with "Resolved without AI" instead
falsePositiveChecksstring[]What a reviewer should check before trusting the verdict, including the identity check's advice when a brand/domain mismatch kept the score at 50 or above
errorstring | nullError message if analysis failed, null on success
dataobjectThe full verdict object without token counts: details (subject, from, to, date, replyTo, returnPath), llmModel ("triage-gate" when no model ran), enhancedAnalysis, triage and cache
data.enhancedAnalysisobjectDeterministic evidence gathered before the model runs: headerScore, bodyScore and deterministicScore (0-100), isHighThreat, detectedLanguage, blacklistMatches (value, indicator, severity, threatType), whitelistedUrls, urlAnalysis (urlCount, indicators), redirects (originalUrl, finalUrl, hops), domainAges (domain, ageDays, isNewDomain), attachments (filename, mimeType, size, sha256, dangerousExtension, doubleExtension, macroEnabled, blacklisted) and senderHistory (null unless the tier uses it).
data.triageobjectHow the verdict was reached. mode is off, shadow or live; in shadow, gates, reviews and floors are computed but change nothing. gate is llm, skip_malicious (critical threat-list match) or skip_legitimate (whitelisted or verified first-party sender), and gateApplied says whether it decided the result. identity, firstParty, bulk and auth summarize the evidence. escalation says whether a second, deeper pass was triggered and applied, with severity (second_opinion or must_review) and the first-pass and final verdicts. floorsApplied lists the identity floors that changed the result. Fields can be missing on results stored before they existed.
data.triage example
{
"mode": "live",
"gate": "llm",
"gateApplied": false,
"deterministicScore": 60,
"identity": {
"mismatch": true,
"lures": ["payment"],
"relayed": false,
"lookalike": null,
"brands": ["OLX"],
"senderDomain": "so-net.ne.jp"
},
"firstParty": null,
"bulk": { "isBulk": false, "network": null, "lure": true, "brand": null },
"auth": { "spf": "pass", "dkim": "pass", "dmarc": "pass", "transportHeaders": true },
"escalation": {
"triggered": true,
"applied": true,
"severity": "must_review",
"reasons": ["..."],
"firstPassType": "legitimate",
"firstPassScore": 12,
"finalType": "phishing",
"finalScore": 88
},
"floorsApplied": []
}senderInsightsobjectWhat your own history says about the sender, computed after the verdict and never part of the score. status is ready (Pro and higher), locked (your plan does not include it), off (switched off in privacy settings) or unavailable (no readable sender). since is the oldest history behind it. Not stored with the analysis.
Each insight has a code and a severity (warning, caution, info, ok): first_time (domain, domainMessages), seen_before (messages, flagged, firstSeen), lookalike_domain (domain, displayDomain, knownDomain, knownMessages, technique: punycode, homoglyph, subdomain, typo, combo or tld), known_name_new_address (displayName, knownDomain, sameDomain) and reply_to_changed (replyToDomain, usedToBeNone).
Need help integrating the API? The support team replies within 24 hours on business days.