Skip to content
IP IPBot
Get Started

IP Decision Engine

The Decision Engine turns IPBot’s risk score and evidence into a usable, explainable decision: a factual role, a business profile, a recommended action, per-scenario decisions (login, signup, payment, API…), the guardrails that were applied, and a human-readable explanation.

It is fully additive. The existing public fields — score.risk_score, score.verdict, and score.recommended_action — are never changed by the Decision Engine. It only annotates the response with an actionable decision view you can consume directly or ignore.

The four objects appear at the top level of every /v1/ip/* response and are projectable via ?fields=decision,scores,scenarios,explanation.

The headline recommendation.

{
"decision": {
"profile": "trusted_infrastructure",
"role": "public_dns_resolver",
"action": "allow",
"risk_level": "low",
"confidence": "high",
"policy_version": "decision-v1-2026-06.2",
"allowed_actions": ["allow", "monitor"],
"blocked_actions": ["block"],
"guardrails_applied": ["public_dns_resolver_cannot_block"]
}
}
FieldMeaning
roleBest factual classification of the IP (e.g. verified_crawler, tor_exit, datacenter, residential_proxy).
profileBusiness-facing interpretation of the role (e.g. trusted_infrastructure, anonymizing_network, ordinary_datacenter).
actionRecommended, guardrail-constrained action: allow, monitor, rate_limit, challenge, manual_review, block.
risk_levellow / medium / high.
confidenceCalculated confidence in this decision (low / medium / high), combining evidence quality, how decisively the score clears an action boundary, source authority, any trust-vs-adverse-risk contradiction, and guardrail stability. Infrastructure context is not treated as adverse by itself.
policy_versionThe decision policy that produced this result. Also surfaced at GET /health as build.decision_policy_version.
allowed_actions / blocked_actionsThe action envelope for this role (e.g. a verified crawler can never be blocked).
guardrails_appliedSafety rules that constrained the action (see below).

The expanded, bounded (0–100) score family. risk_score mirrors the public score.risk_score; the sub-scores break the basis down by group.

{
"scores": {
"risk_score": 30,
"base_risk_score": 30,
"abuse_score": 0,
"anonymity_score": 0,
"trust_score": 90,
"infrastructure_score": 0,
"routing_risk_score": 0,
"evidence_quality_score": 95
}
}

trust_score reflects official/verified signals (verified crawler, public DNS, special-use); abuse_score reflects threat-list evidence; anonymity_score reflects Tor/VPN/proxy; infrastructure_score is identity/context (cloud, CDN, datacenter) — not automatically abuse; evidence_quality_score reflects how authoritative the evidence basis is.

The same IP carries different risk depending on what it is doing. Each scenario picks its own action by expected loss — the action with the lowest combined cost of being wrong, given the IP’s evidence and that scenario’s stakes — so the friction is proportionate per surface. A clean IP gets no friction anywhere; friction rises as abuse likelihood and the scenario’s stakes (signup/payment weigh false negatives more than content) increase. The example below is a VPN:

{
"scenarios": {
"content": { "action": "monitor", "risk_level": "medium", "confidence": "medium", "reason": "VPN traffic is allowed but should be monitored in this scenario." },
"seo_crawler": { "action": "monitor", "risk_level": "medium", "confidence": "medium", "reason": "VPN traffic is allowed but should be monitored in this scenario." },
"login": { "action": "rate_limit", "risk_level": "medium", "confidence": "medium", "reason": "VPN traffic should be rate limited in this scenario." },
"signup": { "action": "challenge", "risk_level": "medium", "confidence": "high", "reason": "VPN traffic should face additional friction in this scenario." },
"payment": { "action": "rate_limit", "risk_level": "medium", "confidence": "medium", "reason": "VPN traffic should be rate limited in this scenario." },
"api": { "action": "rate_limit", "risk_level": "medium", "confidence": "medium", "reason": "VPN traffic should be rate limited in this scenario." }
}
}

Per-scenario actions then pass through the same guardrail layer as the top-level decision, so they stay consistent with the role’s allowed_actions (a verified crawler is never challenged in signup; a known abuser is never plain-allowed in content; a Tor exit floors to at least challenge).

scenarios.*.confidence is computed per scenario from that scenario’s own expected-loss margin (how decisively the chosen action beat the runner-up), combined with the shared evidence-quality / source-authority / contradiction / guardrail components — so a clear-cut scenario reads more confident than a close call. The full component breakdown for the top-level confidence is available only in the admin scoring trace at GET /v1/internal/score/{ip} as trace.decision_confidence.

A deterministic, auditable account of how the decision was reached.

{
"explanation": {
"summary": "datacenter classified as ordinary_datacenter",
"key_reason": "datacenter",
"drivers": [
{ "type": "infrastructure", "label": "infra_network", "impact": "high", "impact_score": 80, "direction": "raises_risk", "reason": "infra_network evidence (registry)" }
],
"guardrails_applied": [],
"reason_chain": [
"datacenter classified as ordinary_datacenter",
"decision action constrained to allow"
]
}
}

Guardrails are deterministic safety rules. Floors raise a too-lenient action to a minimum; caps lower a too-strict action for protected roles. Caps run last, so they are authoritative.

GuardrailEffect
verified_crawler_cannot_blockVerified crawlers are capped at monitor (never challenged/blocked).
public_dns_resolver_cannot_blockPublic DNS resolvers are capped at monitor.
special_use_must_allowSpecial-use / documentation / private ranges always allow.
routing_conflict_requires_manual_reviewRPKI/origin conflict raises non-block actions to manual_review.
strong_threat_floor_cannot_allowA known abuser can never stay allow (raised to at least monitor).
tor_exit_floorTor exits get at least challenge where they would otherwise allow.
proxy_floorVPN / residential / public proxies get at least monitor where they would otherwise allow.

Request just the decision surface with field projection:

Terminal window
curl -s "https://api.ipbot.com/v1/ip/8.8.8.8?fields=decision,scenarios"

Then branch on the scenario relevant to the request you’re handling — e.g. use scenarios.payment.action at checkout and scenarios.login.action at sign-in — or use the top-level decision.action for a single global policy.

The decision layer never changes score.risk_score / verdict / recommended_action, so you can adopt it incrementally alongside your existing score-based logic.