Build with the IPBot API
Everything you need to call the API: endpoints, evidence fields, data status, and error codes. Anonymous access works out of the box, and free API keys unlock higher limits.
{
"ip": "203.0.113.1",
"stack": "ipv4",
"location": {
"country": "United States",
"country_code": "US",
"region": "California",
"city": "San Francisco",
"timezone": "-08:00"
},
"network": {
"asn": "AS15169",
"org": "Example ISP Inc.",
"category": "residential",
"operator": "Example ISP",
"operator_type": "isp",
"owner": "Example ISP Inc.",
"allocation": {
"cidr": "203.0.113.0/24",
"range": "203.0.113.0 - 203.0.113.255",
"registry": "arin",
"country": "US"
}
},
"routing": {
"origin_asn": "AS15169",
"prefix": "203.0.113.0/24",
"rpki_status": "unknown",
"confidence": "low",
"origin_conflict": false
},
"score": {
"ip_score": 60,
"risk_score": 40,
"band": "fair",
"verdict": "monitor",
"recommended_action": "rate_limit"
},
"classification": {
"usage_type": "vpn",
"is_datacenter": false,
"is_proxy": true,
"is_privacy_relay": false,
"is_known_crawler": false,
"is_verified_crawler": false,
"is_mobile": false,
"proxy_type": "vpn",
"confidence": "medium",
"traits": ["proxy", "vpn"],
"threat_level": "Low"
},
"evidence": {
"signals": [
{
"category": "privacy",
"label": "VPN",
"severity": "medium",
"confidence": "medium",
"description": "This IP is associated with VPN traffic."
}
]
}
} /v1/ip/current Auto-detect the caller IP with v1 schema. Supports fields projection and Pro RDAP include.
curl -s "https://api.ipbot.com/v1/ip/current?fields=ip,location,score" | jq /v1/ip/{ip} Lookup a specific IPv4 or IPv6 address with v1 schema. Supports fields projection and Pro RDAP include.
curl -s "https://api.ipbot.com/v1/ip/8.8.8.8?fields=ip,network,score" | jq /v1/assessment Dual-stack assessment; supports ?ipv4= and ?ipv6=.
curl -s "https://api.ipbot.com/v1/assessment?ipv4=8.8.8.8&ipv6=2001:4860:4860::8888" | jq Base URL
Canonical /v1 endpoints return JSON and include CORS headers. The two legacy lookup routes
also support an explicit plain-text representation for command-line use.
https://api.ipbot.com Plain text (legacy)
GET / and GET /{ip} return JSON by default. Request text with
?format=text or an Accept: text/plain header. The query parameter takes
precedence; otherwise text is selected only when its accepted quality is higher than JSON (or an exact
text match is more specific). Canonical /v1 routes remain JSON-only.
One-line current IP
curl -s -H "Accept: text/plain" https://api.ipbot.com/ Four-line detail
curl -s "https://api.ipbot.com/8.8.8.8?format=text&detail=1"
Lines are IP, location, ASN, and organization (plus the official operator domain when known).
Missing values render as -. Errors keep the JSON route's HTTP status and use one
error: message line.
Authentication
Anonymous access is supported with a baseline rate limit. Use an API key to raise your throughput. Pro-only fields require an authenticated Pro API key.
X-API-Key: ipb_free_REPLACE_ME V1 Lookup Parameters
GET /v1/ip/current and GET /v1/ip/{ip} support response projection.
Legacy routes and /v1/assessment keep their existing response shape.
| Parameter | Required | Description |
|---|---|---|
fields | No |
Comma-separated top-level response fields: ip, stack, location, network, routing, score, classification, evidence, decision, scores, scenarios, and explanation.
With Pro RDAP enabled, rdap becomes an additional conditional field.
|
include | No |
Optional include list. include=rdap_contacts is Pro-only and adds normalized RDAP registration/contact data.
|
Field Projection
fields trims the canonical v1 response. It does not create a new schema or rename nested fields.
Supported public values are ip, stack, location, network, routing, score, classification, evidence, decision, scores, scenarios, and explanation.
curl -s "https://api.ipbot.com/v1/ip/8.8.8.8?fields=ip,location,score" | jq {
"ip": "8.8.8.8",
"location": {
"country": "United States",
"country_code": "US",
"region": "California",
"city": "Mountain View",
"timezone": "-07:00"
},
"score": {
"ip_score": 85,
"risk_score": 15,
"band": "good",
"verdict": "allow",
"recommended_action": "allow"
}
} Pro RDAP Contacts
Free and anonymous responses never expose RDAP contact emails, phones, addresses, person records,
raw RDAP JSON, or raw WHOIS text. Pro keys can request the normalized object explicitly.
After the include is accepted, use fields=rdap to return only the RDAP object.
curl -s "https://api.ipbot.com/v1/ip/8.8.8.8?include=rdap_contacts&fields=ip,rdap" \
-H "X-API-Key: $IPBOT_PRO_API_KEY" | jq {
"ip": "8.8.8.8",
"rdap": {
"available": true,
"network": {
"handle": "NET-8-8-8-0-1",
"name": "GOGL",
"registry": "arin",
"registered_owner": "Google LLC",
"allocation": {
"cidr": "8.8.8.0/24",
"range": "8.8.8.0 - 8.8.8.255",
"registry": "arin",
"country": "US"
}
},
"contacts": [
{
"handle": "GOGL",
"roles": ["registrant"],
"name": "Google LLC",
"organization": "Google LLC",
"phones": ["+1-555-0100"]
},
{
"roles": ["abuse"],
"name": "Google Abuse",
"emails": ["abuse@example.com"]
}
]
}
}
Without a Pro key, include=rdap_contacts returns 403 PRO_REQUIRED.
Unknown include names return 400 INVALID_INCLUDE. Empty or unknown fields return
400 INVALID_FIELDS.
{
"error": "RDAP contacts require a Pro API key",
"code": "PRO_REQUIRED",
"details": {
"include": "rdap_contacts",
"allowed_includes": ["rdap_contacts"]
}
} Invalid Field Names
The server returns the current public projection set in details.allowed_fields.
When a Pro RDAP include is already accepted, rdap is appended to that list.
{
"error": "Invalid fields parameter",
"code": "INVALID_FIELDS",
"details": {
"allowed_fields": [
"ip",
"stack",
"location",
"network",
"routing",
"score",
"classification",
"evidence",
"decision",
"scores",
"scenarios",
"explanation"
],
"invalid_fields": ["bogus"]
}
} Cache Behavior
Explicit lookups such as GET /v1/ip/{ip}, legacy GET /{ip}, and
GET /v1/assessment?ipv4=...&ipv6=... default to
Cache-Control: public, max-age=86400.
Auto-detected current-IP responses (GET /v1/ip/current, legacy GET /, and auto mode on /v1/assessment),
accepted include=rdap_contacts lookups, and POST /v1/crawler/verify return
Cache-Control: no-store.
Evidence Fields
IPBot returns product-level IP intelligence: network category, classification confidence, verdict, recommended action, and structured signals. Internal source and version details are not part of the public response contract.
proxy_type, is_proxy, is_vpn, is_tor, and is_privacy_relay describe public classifications without exposing the underlying data vendor.
evidence.signals contains stable labels, categories, severities, confidence, and short explanations suitable for product UI.
When the optional ThreatFox sidecar is present, evidence.threatfox adds structured malware / first-seen / last-seen metadata without adding extra score beyond the existing ThreatFox threat-list hit.
is_known_crawler comes from official ranges, including supported search crawler feeds, and avoids generic bot-UA over-scoring. Cacheable third-party IP GETs ignore the caller User-Agent; they can verify only from caller-independent evidence such as DNS. Use the no-store POST /v1/crawler/verify surface for supported range + explicitly supplied user-agent verification.
network.routability, is_special_use, and is_bogon explain private, reserved, documentation, dynamic full-bogon, and other non-global address states without exposing raw source names.
network.category, operator_type, and service_name may include provider-declared content, network service provider, webhook, messaging, or crawler infrastructure context.
/v1/data/status reports public service and capability readiness. Detailed source readiness is reserved for internal operations.
network.owner and network.allocation come from normalized RDAP ownership data when available. Full RDAP contacts only appear in Pro responses after include=rdap_contacts.
Decision Engine
Decision Engine v1 adds four optional, additive top-level objects to v1 IP lookup responses:
decision, scores, scenarios, and explanation.
These fields are advisory only and do not change score.risk_score, score.verdict, or score.recommended_action.
| Field | What it adds |
|---|---|
decision | Top-level role/profile/action recommendation with policy version and applied guardrails. |
scores | Eight advisory component sub-scores, including base risk, abuse, anonymity, trust, infrastructure, routing risk, and evidence quality. |
scenarios | Per-surface recommendations for content, seo_crawler, login, signup, payment, and api. |
explanation | Human-readable summary, primary reason, risk drivers, guardrails, and reasoning chain. |
scenarios.*.confidence is computed per scenario from that scenario's own expected-loss margin and supporting evidence; it is not a copy of decision.confidence.
curl -s "https://api.ipbot.com/v1/ip/8.8.8.8?fields=decision,scores,scenarios,explanation" | jq {
"decision": {
"profile": "ordinary_datacenter",
"role": "datacenter",
"action": "monitor",
"risk_level": "medium",
"confidence": "high",
"policy_version": "decision-v1-2026-07.1",
"allowed_actions": ["allow", "monitor", "challenge"],
"blocked_actions": null,
"guardrails_applied": ["verified_crawler_protection"]
},
"scores": {
"risk_score": 42,
"base_risk_score": 40,
"abuse_score": 8,
"anonymity_score": 12,
"trust_score": 62,
"infrastructure_score": 74,
"routing_risk_score": 4,
"evidence_quality_score": 86
},
"scenarios": {
"content": { "action": "allow", "risk_level": "low", "confidence": "high", "reason": "Low abuse pressure" },
"seo_crawler": { "action": "allow", "risk_level": "low", "confidence": "high", "reason": "Known automation expected" },
"login": { "action": "monitor", "risk_level": "medium", "confidence": "medium", "reason": "Datacenter origin" },
"signup": { "action": "challenge", "risk_level": "medium", "confidence": "medium", "reason": "Higher fraud surface" },
"payment": { "action": "manual_review", "risk_level": "high", "confidence": "medium", "reason": "Elevated payment risk" },
"api": { "action": "monitor", "risk_level": "low", "confidence": "high", "reason": "Automation expected" }
},
"explanation": {
"summary": "Datacenter-origin traffic with moderate anonymity pressure and no strong abuse history.",
"key_reason": "datacenter_origin",
"drivers": [
{
"type": "infrastructure",
"label": "Datacenter Origin",
"impact": "+10",
"impact_score": 10,
"direction": "raises_risk",
"reason": "Traffic originates from a hosting/datacenter network."
}
],
"guardrails_applied": ["verified_crawler_protection"],
"reason_chain": ["base_risk=40", "datacenter_origin", "policy=balanced"]
}
} Crawler Verification
POST /v1/crawler/verify is a narrow verification endpoint for site-owner workflows.
It accepts an ip and optional user_agent, returns verification_status as
verified, known_unverified, or not_known, and always responds with
Cache-Control: no-store.
Request
curl -s -X POST https://api.ipbot.com/v1/crawler/verify \
-H "Content-Type: application/json" \
-d '{"ip":"66.249.66.1","user_agent":"Googlebot/2.1 (+http://www.google.com/bot.html)"}' | jq
DNS-verifiable families such as Googlebot and Bingbot can reach verified from the IP alone.
OpenAI-family crawlers require both official range membership and a matching crawler user-agent token.
Response
{
"ip": "66.249.66.1",
"user_agent": "Googlebot/2.1 (+http://www.google.com/bot.html)",
"verification_status": "verified",
"classification": {
"is_known_crawler": true,
"is_verified_crawler": true,
"crawler_provider": "Google",
"crawler_type": "googlebot",
"crawler_verified_by": "reverse_forward_dns",
"crawler_hostname": "crawl-66-249-66-1.googlebot.com."
},
"network": {
"owner": "Google LLC",
"allocation": {
"cidr": "66.249.64.0/19",
"registry": "arin",
"country": "US"
}
},
"explanation": {
"text": "Google googlebot is verified by reverse and forward DNS, and the hostname resolves back to this IP.",
"reason_code": "verified_crawler"
}
} Endpoints
| Method | Path | Description |
|---|---|---|
| GET | /v1/ip/current | Auto-detect the caller IP with v1 schema. Supports fields projection and Pro RDAP include. |
| GET | /v1/ip/{ip} | Lookup a specific IPv4 or IPv6 address with v1 schema. Supports fields projection and Pro RDAP include. |
| GET | /v1/assessment | Dual-stack assessment; supports ?ipv4= and ?ipv6=. |
| POST | /v1/crawler/verify | Crawler verification for site-owner workflows using IP and optional user-agent context. |
| GET | /v1/data/status | Public service status and high-level intelligence capabilities. |
| GET | / | Legacy auto-detect endpoint. JSON by default; supports an explicit plain-text representation. |
| GET | /{ip} | Legacy lookup endpoint. JSON by default; add ?format=text for shell-friendly output. |
| GET | /v1/asn/{asn} | Lookup ASN details with graceful local fallback, optional Radar enrichment, evidence-only threat_density, and optional ASN-DROP context. |
| GET | /health | Health check endpoint for liveness and readiness. |
| GET | /metrics | Operator-only Prometheus metrics for HTTP traffic and operational coverage counters. |
| POST | /reload | Admin-only: reloads runtime rules and intelligence data. |
| GET | /auth/github | Initiates GitHub OAuth flow for authentication. |
| GET | /auth/me | Returns current authenticated user profile. |
| GET | /auth/tiers | Returns tier limits and current tier context. |
| POST | /auth/logout | Clears the session and logs out the user. |
| GET | /auth/keys | Lists all API keys for the authenticated user. |
| POST | /auth/keys | Creates a new API key. |
| DELETE | /auth/keys/{id} | Revokes an API key immediately. |
| GET | /auth/usage | Returns request usage summary by API key. |
ASN Response
/v1/asn/{asn} is the canonical ASN route. It always returns 200 for a valid ASN,
even when Cloudflare Radar is unavailable, by falling back to IPBot's local ASN name and any evidence-only
context it can still derive. The legacy /asn/{asn} route remains as a compatibility alias.
radar is optional enrichment. threat_density and asndrop are evidence-only
ASN context and do not change per-IP risk_score.
{
"asn": "AS64500",
"name": "Example Network",
"radar": null,
"threat_density": {
"threat_network_count": 2,
"threat_ipv4_addresses": 512,
"total_ipv4_addresses": 1048576,
"ratio": 0.00048828125,
"percent": 0.048828125,
"significant": false,
"source": "threat_lists+iptoasn"
},
"asndrop": {
"asn": "AS64500",
"as_name": "EXAMPLE-NETWORK",
"rir": "arin",
"domain": "example.net",
"country_code": "US"
}
} Error Responses
All errors follow a consistent JSON format.
{
"error": "Invalid IP address format",
"code": "INVALID_IP",
"details": {
"provided": "invalid-ip"
}
} | Code | HTTP | Description |
|---|---|---|
| INVALID_IP | 400 | Malformed or invalid IP address. |
| INVALID_FIELDS | 400 | The fields projection is empty or contains unknown fields. |
| INVALID_INCLUDE | 400 | The include parameter contains an unsupported include name. |
| INVALID_ASN | 400 | Malformed or invalid ASN format. |
| NO_CLIENT_IP | 400 | Unable to determine client IP. |
| UNAUTHORIZED | 401 | Authentication required. |
| INVALID_API_KEY | 401 | The API key is invalid or revoked. |
| FORBIDDEN | 403 | Access denied for admin routes. |
| PRO_REQUIRED | 403 | The requested include, such as rdap_contacts, requires a Pro API key. |
| NOT_FOUND | 404 | Endpoint or resource does not exist. |
| RATE_LIMITED | 429 | Rate limit exceeded. |
| INTERNAL_ERROR | 500 | Unexpected server error. |
| AUTH_DISABLED | 503 | Authentication not configured. |