IP Reputation API - Risk Scoring and Threat Detection
IPBot’s risk scoring is designed to be explainable. Instead of a black box, responses include
evidence.signals[] with labels, severity, and confidence so you can build stable UI
and internal policy rules.
curl -s https://api.ipbot.com/v1/ip/8.8.8.8 | jq ‘{score, classification, signals: .evidence.signals}’Pair this with caching guidance in Rate Limits.
What Is IP Reputation?
Section titled “What Is IP Reputation?”IP reputation is a collection of network, anonymity, and threat observations associated with an IP address. Unlike geolocation, it helps answer “what evidence exists and what review action fits this policy?” It cannot prove the identity or intent of a person behind the address.
Every IP address accumulates a digital footprint over time. Mail servers that send spam get blacklisted. IPs used for DDoS attacks appear on abuse databases. VPN and proxy services operate from known IP ranges. Datacenters host both legitimate services and malicious infrastructure. IP reputation aggregates these signals into actionable intelligence.
How IPBot Calculates Risk Scores
Section titled “How IPBot Calculates Risk Scores”IPBot emits an evidence-derived 0–100 model score with a band, verdict, reasons, and a versioned Decision result. A score of 0 means that no effective scoring risk remained after evidence, trust, suppression, and rounding; it is not proof that an IP is safe. The number is not a calibrated fraud or abuse probability.
Scoring Factors
Section titled “Scoring Factors”The active model separates risk-direction and trust-direction evidence. Examples include direct threat-list matches, unsuppressed proxy/Tor evidence, stable service identity, verified crawler or public-resolver roles, routability suppression, and source confidence. Risk evidence is fused with a bounded noisy-OR and then damped by applicable trust evidence; it is not linearly added.
Exact weights, floors, suppressions, and policy behavior are versioned implementation details. Use the response’s reasons and model/policy version rather than copying an old point table into application code.
Score Granularity & Data Tiers
Section titled “Score Granularity & Data Tiers”Scores are evidence-derived, not cosmetic, but their granularity cannot exceed the underlying facts. Two IPs with different scoring evidence can get different scores. Two IPs with identical evidence — for example several public proxies on the same network sharing the same threat-list and proxy-detection signals — correctly receive the same score; IPBot does not manufacture per-IP differences the underlying data cannot support.
Fine-grained per-IP differentiation (continuous proxy fraud scores, proxy recency) depends on enhanced/commercial proxy intelligence. On base data, expect conservative risk classification and bands rather than a unique number for every individual IP.
Response Structure
Section titled “Response Structure”{ "score": { "risk_score": 65, "verdict": "challenge", "recommended_action": "captcha_challenge" }, "classification": { "threat_level": "Medium", "is_proxy": true, "is_vpn": true, "is_tor": false, "is_datacenter": true, "is_known_crawler": false, "confidence": "medium" }, "evidence": { "signals": [ { "category": "privacy", "label": "VPN", "severity": "medium", "confidence": "medium" }, { "category": "network", "label": "Datacenter", "severity": "low", "confidence": "high" } ] }}Use Cases for IP Reputation
Section titled “Use Cases for IP Reputation”Fraud Prevention in E-commerce
Section titled “Fraud Prevention in E-commerce”Online fraud costs businesses over $48 billion annually. IP reputation provides a critical first-line defense by identifying suspicious connections before transactions complete.
Implementation Pattern:
async function assessTransactionRisk(ip, orderValue) { const response = await fetch(`https://api.ipbot.com/v1/ip/${ip}`); const data = await response.json();
const { score, classification, evidence } = data; const signalLabels = evidence.signals.map((signal) => signal.label);
// High-value transactions from risky IPs require additional verification if (orderValue > 500 && score.risk_score > 50) { return { action: "REQUIRE_VERIFICATION", reasons: signalLabels, score: score.risk_score, }; }
// Block transactions from extremely high-risk IPs if (score.risk_score > 85) { return { action: "BLOCK", reasons: signalLabels, score: score.risk_score, }; }
// VPN users may need additional friction if (classification.is_vpn && orderValue > 200) { return { action: "SOFT_CHALLENGE", reasons: signalLabels, score: score.risk_score, }; }
return { action: "ALLOW", score: score.risk_score };}Key Fraud Signals:
- Mismatch between billing address country and IP geolocation
- Known proxy or VPN usage during high-value purchases
- IP associated with previous chargebacks
- Multiple accounts from same high-risk IP
Email Validation and Deliverability
Section titled “Email Validation and Deliverability”Email service providers and marketers use IP reputation to validate signups and protect deliverability. Fraudulent signups from disposable email addresses often originate from anonymized connections.
Email Signup Validation:
import requests
def validate_email_signup(ip_address, email): response = requests.get(f'https://api.ipbot.com/v1/ip/{ip_address}') data = response.json()
score = data['score'] classification = data['classification'] signal_labels = [signal['label'] for signal in data['evidence']['signals']]
# Flag signups from anonymized connections if classification['is_tor'] or classification['is_proxy']: return { 'valid': False, 'reason': 'anonymous_connection', 'action': 'require_phone_verification' }
# Datacenter IPs often indicate bots if classification['is_datacenter'] and score['risk_score'] > 40: return { 'valid': False, 'reason': 'suspected_bot', 'action': 'show_captcha' }
# Known abuse signals can block signup if 'Known Abuse' in signal_labels: return { 'valid': False, 'reason': 'known_abuse', 'action': 'block_signup' }
return {'valid': True, 'risk_score': score['risk_score']}Access Control and Authentication
Section titled “Access Control and Authentication”IP reputation enhances authentication security by identifying suspicious login attempts before they succeed.
Adaptive Authentication:
async function getAuthenticationLevel(ip, userId) { const [ipData, userHistory] = await Promise.all([ fetch(`https://api.ipbot.com/v1/ip/${ip}`).then((r) => r.json()), getUserLoginHistory(userId), ]);
const { score, classification, location, evidence } = ipData; const signalLabels = evidence.signals.map((signal) => signal.label);
// New location from high-risk IP = maximum friction const isNewLocation = !userHistory.countries.includes(location.country_code);
if (isNewLocation && score.risk_score > 60) { return "MFA_REQUIRED_WITH_EMAIL_NOTIFICATION"; }
// VPN from new location = elevated friction if (isNewLocation && classification.is_vpn) { return "MFA_REQUIRED"; }
// Known abuse signals = block and notify if (signalLabels.includes("Known Abuse")) { return "BLOCK_WITH_ADMIN_ALERT"; }
// High risk score = challenge if (score.risk_score > 70) { return "CAPTCHA_REQUIRED"; }
return "STANDARD_AUTH";}API Rate Limiting and Bot Protection
Section titled “API Rate Limiting and Bot Protection”IP reputation helps distinguish legitimate API consumers from abusive bots and scrapers.
function calculateRateLimit(ipData) { const { score, classification } = ipData;
// Datacenter IPs get stricter limits if (classification.is_datacenter) { return { requestsPerMinute: 10, burstLimit: 20 }; }
// High-risk IPs get minimal access if (score.risk_score > 70) { return { requestsPerMinute: 5, burstLimit: 10 }; }
// Proxies get reduced limits if (classification.is_proxy || classification.is_vpn) { return { requestsPerMinute: 30, burstLimit: 50 }; }
// Normal residential traffic return { requestsPerMinute: 60, burstLimit: 100 };}Public Evidence Signals
Section titled “Public Evidence Signals”IPBot exposes product-level signals instead of raw feed names or internal rule IDs. Each signal has a stable label, category, severity, and confidence so your application can explain decisions without binding to IPBot’s private data pipeline.
| Signal Label | Description | Typical Impact |
|---|---|---|
VPN | Traffic appears to come through a VPN service | Medium |
Proxy | Traffic appears to come through a proxy service | Medium |
Tor Exit Node | Traffic appears to exit through the Tor network | High |
Datacenter | IP belongs to hosting or cloud infrastructure | Low to medium |
Known Abuse | IP has abuse or threat evidence | High |
Spamhaus ASN-DROP | ASN-level Spamhaus reputation evidence | Evidence-only |
ASN Threat Density | A meaningful share of the ASN’s IPv4 space overlaps threat ranges | Evidence-only |
Recently Allocated Network | The registered allocation date is under 90 days old | Evidence-only |
Residential Proxy | Residential-looking network with proxy evidence | Medium to high |
Private Relay | Privacy relay traffic, not residential proxy | Low to medium |
Verified Crawler | Search or platform crawler verified by IPBot | Informational |
Integration Examples
Section titled “Integration Examples”# Get reputation data for any IPcurl -s https://api.ipbot.com/v1/ip/185.220.101.42 | jq '{score, classification, signals: .evidence.signals}'
# Check specific security fieldscurl -s https://api.ipbot.com/v1/ip/185.220.101.42 | jq '{ risk_score: .score.risk_score, is_vpn: .classification.is_vpn, signals: [.evidence.signals[].label]}'JavaScript / Node.js
Section titled “JavaScript / Node.js”class IPReputationClient { constructor(baseUrl = "https://api.ipbot.com") { this.baseUrl = baseUrl; this.cache = new Map(); this.cacheTTL = 3600000; // 1 hour }
async getReputation(ip) { // Check cache first const cached = this.cache.get(ip); if (cached && Date.now() - cached.timestamp < this.cacheTTL) { return cached.data; }
const response = await fetch(`${this.baseUrl}/v1/ip/${ip}`); if (!response.ok) { throw new Error(`Failed to get reputation: ${response.status}`); }
const data = await response.json();
// Cache the public reputation slice this.cache.set(ip, { data: { score: data.score, classification: data.classification, signals: data.evidence.signals, }, timestamp: Date.now(), });
return this.cache.get(ip).data; }
async isHighRisk(ip, threshold = 70) { const reputation = await this.getReputation(ip); return reputation.score.risk_score >= threshold; }
async getThreats(ip) { const reputation = await this.getReputation(ip); return { isVPN: reputation.classification.is_vpn, isProxy: reputation.classification.is_proxy, isTor: reputation.classification.is_tor, signals: reputation.signals.map((signal) => signal.label), }; }}
// Usageconst client = new IPReputationClient();
const reputation = await client.getReputation("185.220.101.42");console.log(`Risk Score: ${reputation.score.risk_score}`);console.log(`Threat Level: ${reputation.classification.threat_level}`);console.log(`Signals: ${reputation.signals.map((signal) => signal.label).join(", ")}`);Python
Section titled “Python”import requestsfrom functools import lru_cachefrom datetime import datetime, timedelta
class IPReputationClient: def __init__(self, base_url='https://api.ipbot.com'): self.base_url = base_url self._cache = {} self._cache_ttl = timedelta(hours=1)
def get_reputation(self, ip: str) -> dict: # Check cache if ip in self._cache: cached_data, cached_time = self._cache[ip] if datetime.now() - cached_time < self._cache_ttl: return cached_data
response = requests.get(f'{self.base_url}/v1/ip/{ip}') response.raise_for_status()
data = response.json() reputation = { 'score': data['score'], 'classification': data['classification'], 'signals': data['evidence']['signals'], }
# Update cache self._cache[ip] = (reputation, datetime.now())
return reputation
def is_high_risk(self, ip: str, threshold: int = 70) -> bool: reputation = self.get_reputation(ip) return reputation['score']['risk_score'] >= threshold
def get_threat_summary(self, ip: str) -> dict: reputation = self.get_reputation(ip) return { 'score': reputation['score']['risk_score'], 'level': reputation['classification']['threat_level'], 'is_anonymous': ( reputation['classification'].get('is_vpn') or reputation['classification'].get('is_proxy') or reputation['classification'].get('is_tor') ), 'signals': [signal['label'] for signal in reputation['signals']] }
# Usageclient = IPReputationClient()
# Check if IP is high riskif client.is_high_risk('185.220.101.42'): print('High risk IP detected!')
# Get detailed threat informationthreats = client.get_threat_summary('185.220.101.42')print(f"Risk Score: {threats['score']}")print(f"Anonymous: {threats['is_anonymous']}")print(f"Signals: {', '.join(threats['signals'])}")<?php
class IPReputationClient { private string $baseUrl; private array $cache = []; private int $cacheTTL = 3600;
public function __construct(string $baseUrl = 'https://api.ipbot.com') { $this->baseUrl = $baseUrl; }
public function getReputation(string $ip): array { // Check cache if (isset($this->cache[$ip])) { $cached = $this->cache[$ip]; if (time() - $cached['timestamp'] < $this->cacheTTL) { return $cached['data']; } }
$response = file_get_contents("{$this->baseUrl}/v1/ip/{$ip}"); $data = json_decode($response, true);
// Cache result $reputation = [ 'score' => $data['score'], 'classification' => $data['classification'], 'signals' => $data['evidence']['signals'] ]; $this->cache[$ip] = [ 'data' => $reputation, 'timestamp' => time() ];
return $reputation; }
public function isHighRisk(string $ip, int $threshold = 70): bool { $reputation = $this->getReputation($ip); return $reputation['score']['risk_score'] >= $threshold; }}
// Usage$client = new IPReputationClient();$reputation = $client->getReputation('185.220.101.42');
echo "Risk Score: " . $reputation['risk_score'] . "\n";echo "Action: " . $reputation['score']['recommended_action'] . "\n";Comparison: IPBot vs Competitors
Section titled “Comparison: IPBot vs Competitors”| Feature | IPBot | MaxMind minFraud | IPQS | Sift |
|---|---|---|---|---|
| Free Tier | Yes | No | Limited | No |
| API Key Required | No | Yes | Yes | Yes |
| Risk Score | 0-100 | 0-99 | 0-100 | 0-100 |
| Explainable Reasons | Yes | Limited | Yes | Limited |
| VPN Detection | Included | Separate product | Included | Included |
| Tor Detection | Included | Separate product | Included | Included |
| Abuse Signals | Yes | Yes | Yes | Yes |
| CORS Enabled | Yes | No | Yes | No |
| Published IPBot outcome benchmark | Not yet | Provider-specific | Provider-specific | Provider-specific |
| Pricing | Free tier available | Check provider | Check provider | Check provider |
This is a product-surface comparison, not an accuracy or latency benchmark. Provider packaging and prices change; verify current terms before making a purchasing decision.
Best Practices
Section titled “Best Practices”1. Prefer the Versioned Decision Contract
Section titled “1. Prefer the Versioned Decision Contract”Do not reinterpret the model score as a probability or copy a stale threshold table. Start with the API’s versioned decision and keep a fallback for unknown actions:
function applyIPDecision(ipData) { switch (ipData.decision?.action) { case "block": return denyRequest(); case "challenge": return requireAdditionalVerification(); case "monitor": return allowAndRecordReviewContext(); case "allow": return allowRequest(); default: return requireManualReview(); }}2. Combine with Other Signals
Section titled “2. Combine with Other Signals”IP reputation is one component of a broader risk system. Combine reasoned decisions and independent business signals at the policy layer; do not average unrelated 0–100 values as if they shared a probability scale:
function reviewContext(ipData, account) { return { ipAction: ipData.decision?.action ?? "manual_review", ipReasons: ipData.decision?.reason_codes ?? [], newAccount: account.ageDays < 7, recentCredentialReset: account.recentCredentialReset, };}3. Handle VPNs Thoughtfully
Section titled “3. Handle VPNs Thoughtfully”Not all VPN users are malicious. Consider context:
function assessVPNRisk(ipData, context) { if (!ipData.classification.is_vpn) return "low";
// Privacy-conscious users in sensitive contexts if (context.isPrivacySensitive) return "acceptable";
// High-value transactions from VPNs need verification if (context.transactionValue > 1000) return "high";
// Account creation from VPN is suspicious if (context.isNewAccount) return "elevated";
return "moderate";}4. Cache Appropriately
Section titled “4. Cache Appropriately”IP reputation changes slowly. Cache for at least 1 hour:
// Recommended cache TTLsconst CACHE_TTL = { HIGH_RISK: 1800000, // 30 minutes for high-risk IPs MEDIUM_RISK: 3600000, // 1 hour for medium-risk LOW_RISK: 86400000, // 24 hours for low-risk};Frequently Asked Questions
Section titled “Frequently Asked Questions”What is the difference between IP reputation and IP geolocation?
Section titled “What is the difference between IP reputation and IP geolocation?”IP geolocation estimates the location of an IP address (country, city, coordinates). IP reputation assesses the trustworthiness of an IP based on its history and characteristics. Both are useful for different purposes - geolocation for localization and compliance, reputation for security and fraud prevention.
How often is reputation data updated?
Section titled “How often is reputation data updated?”IPBot refreshes its intelligence stack on a regular operations cadence and calculates public risk scores at request time from the latest loaded data.
Can IP reputation be spoofed?
Section titled “Can IP reputation be spoofed?”The IP address itself cannot be spoofed in a TCP connection due to the three-way handshake. However, attackers can use previously unknown IPs or rotate through IP addresses. This is why IP reputation should be one component of a multi-layered security approach.
Should I block all VPN traffic?
Section titled “Should I block all VPN traffic?”Not necessarily. Many legitimate users use VPNs for privacy, especially in countries with internet restrictions. Instead of blanket blocking, consider requiring additional verification for high-risk actions from VPN IPs.
How do I handle false positives?
Section titled “How do I handle false positives?”Build an appeals process and monitor your block rates. If legitimate users are frequently flagged, adjust your thresholds or add exceptions for specific use cases. Use risk scoring as one input rather than the sole decision factor.
Get Started
Section titled “Get Started”Start using IP reputation scoring in your application:
# Quick testcurl https://api.ipbot.com/v1/ip/185.220.101.42 | jq '{score, classification, signals: .evidence.signals}'Resources:
- API Reference - Complete endpoint documentation
- Rate Limits - Caching and usage guidelines
- Code Examples - Integration samples in multiple languages
- Proxy Detection - Deep dive into VPN/proxy detection