VPN Detection API
You need to decide, in real time, whether an incoming IP is using a VPN so you can adapt authentication flows, reduce promotion abuse, or add friction where it matters. By the end of this guide you will call ipXapi’s VPN Detection API, parse security.is_vpn from the response, and integrate that check into your service with a small amount of code.
What the VPN Detection endpoint returns
The VPN Detection lookup is served from the same base endpoint used for IP intelligence. You will query the /api/ip path with an IP address and inspect the security.is_vpn flag in the JSON. Live flags can change, so treat the example as a documented fixture, not as your own IP.
Official cURL and JSON for the documented fixture IP 148.105.12.120:
curl "https://ipxapi.com/api/ip?ip=148.105.12.120" -H "Accept: application/json" -H "Authorization: Bearer YOUR_KEY"
{
"status": "success",
"country": "United States",
"countryCode": "US",
"region": "US-CA",
"regionName": "California",
"city": "Mountain View",
"zip": "94043",
"lat": 37.40599,
"lon": -122.0786,
"timezone": "America/Los_Angeles",
"isp": "MailChimp",
"org": "MailChimp",
"as": "AS14782 MailChimp",
"query": "148.105.12.120",
"inEU": false,
"continentCode": "NA",
"security": {
"is_proxy": false,
"is_vpn": false,
"is_cloud_provider": true
}
}
Fields you will actually use in a VPN check:
- security.is_vpn: boolean. The core signal for VPN usage.
- query: the IP you checked, included for correlation in logs and analytics.
- Optionally, other attributes (country, regionName, isp) can support rules or telemetry, but the decision hinge for VPN is security.is_vpn.
Quickstart: Authenticate and run a lookup
Authentication uses a Bearer token in the Authorization header. Requests should specify Accept: application/json. The path is /api/ip and you pass the target address with the ip query parameter.
Copy-paste test against the documented fixture:
Notes that save you time:
- Method: GET.
- Content negotiation: use Accept: application/json to avoid content-type issues.
- Timezone: Fields like timezone are returned as IANA strings (e.g., America/Los_Angeles). No timestamp fields are included in this response.
- Caching: IP reputation changes but not minute-by-minute for most addresses. Cache negative VPN results briefly (e.g., a few hours) and positive results conservatively if you cache them at all. Adjust to your risk tolerance.
- Live flags: Treat security flags as real-time signals. They can change for the same IP over time.
Integrate in your backend (Python example)
The example below demonstrates a minimal integration that calls the VPN Detection endpoint and makes a decision using security.is_vpn. Replace YOUR_API_KEY with your actual key in secure configuration, not in code.
import json
import sys
import time
from typing import Optional, Tuple
import requests
API_BASE = "https://ipxapi.com"
ENDPOINT = "/api/ip"
API_KEY = "YOUR_API_KEY" # configure via environment secret in production
TIMEOUT_SECONDS = 5.0
class IpXapiError(Exception):
pass
def fetch_ip_intel(ip: str) -> dict:
url = f"{API_BASE}{ENDPOINT}"
headers = {
"Accept": "application/json",
"Authorization": f"Bearer {API_KEY}",
}
params = {"ip": ip}
try:
resp = requests.get(url, headers=headers, params=params, timeout=TIMEOUT_SECONDS)
except requests.RequestException as e:
raise IpXapiError(f"network error contacting ipXapi: {e}") from e
# 2xx expected on success. Non-JSON or non-2xx should be handled.
if resp.status_code // 100 != 2:
# Provide context for observability. Avoid logging secrets.
raise IpXapiError(f"ipXapi HTTP {resp.status_code}: {resp.text[:200]}")
try:
data = resp.json()
except json.JSONDecodeError as e:
raise IpXapiError(f"invalid JSON from ipXapi: {e}") from e
# Basic structural checks. 'status' and 'security' are required for our flow.
if not isinstance(data, dict) or "status" not in data:
raise IpXapiError("unexpected schema: missing 'status'")
# Some integrations treat 'success' string as a success marker.
if data.get("status") != "success":
raise IpXapiError(f"lookup failed: status={data.get('status')}")
if "security" not in data or not isinstance(data["security"], dict):
raise IpXapiError("unexpected schema: missing 'security' object")
return data
def is_vpn_ip(ip: str) -> Tuple[bool, Optional[dict]]:
data = fetch_ip_intel(ip)
sec = data.get("security", {})
# Required decision field
is_vpn = bool(sec.get("is_vpn"))
# Optionally return additional context for logging or rules
context = {
"query": data.get("query"),
"country": data.get("country"),
"regionName": data.get("regionName"),
"isp": data.get("isp"),
"is_proxy": sec.get("is_proxy"),
"is_cloud_provider": sec.get("is_cloud_provider"),
}
return is_vpn, context
def main():
ip_to_check = "148.105.12.120" if len(sys.argv) < 2 else sys.argv[1]
try:
vpn, ctx = is_vpn_ip(ip_to_check)
except IpXapiError as e:
print(f"Lookup error: {e}", file=sys.stderr)
sys.exit(2)
# Example decision: flag session if VPN detected
if vpn:
print(f"{ip_to_check}: VPN detected")
# Example: trigger step-up auth, mark risk, etc.
sys.exit(1)
else:
print(f"{ip_to_check}: VPN not detected")
# Continue normal flow
sys.exit(0)
if __name__ == "__main__":
main()
Implementation tips:
- Timeouts: Keep a sane timeout (e.g., 5s). If the lookup is part of the request path, use a lower timeout and fall back to a default policy.
- Error handling: Treat transient network errors distinctly from non-2xx HTTP responses to simplify retries.
- Observability: Log the query IP and security.is_vpn, not the full payload. Avoid logging secrets.
- Configuration: Set YOUR_API_KEY via environment or a secret manager.
Interpreting responses and building decisions
Your primary decision input is security.is_vpn. If true, implement additional friction such as step-up authentication or transaction review. If false, proceed normally, perhaps with passive telemetry.
Related fields that can inform rules:
- security.is_proxy: A proxy may indicate similar risk characteristics as VPN. Decide if you treat it equivalently to VPN in your application.
- security.is_cloud_provider: Traffic from cloud providers might be automated or ephemeral. You may apply separate controls.
- country, regionName, isp: Useful for analytics and secondary rules (e.g., unusual geolocation for a given account). Do not use geolocation alone to infer VPN usage.
Live updates matter. An address may move between consumer networks, VPN ranges, or cloud infrastructure. Avoid long-lived caches for positive risk signals unless you have a strong reason to do so. For negative results (is_vpn=false), a short cache can reduce latency and API calls without sacrificing much accuracy.
Production design checklist
- Transport security: Always call over HTTPS.
- Authentication: Authorization: Bearer YOUR_API_KEY via header. Do not hardcode secrets; rotate them periodically.
- Latency: Consider asynchronous enrichment outside the hot path for non-critical checks. For sign-in flows, prefer synchronous checks with tight timeouts.
- Retries: Use small, bounded retries on idempotent GETs; avoid retry storms. Apply jittered backoff in shared libraries.
- Caching: Cache negative VPN results briefly to reduce load. Respect that security flags can change.
- Circuit breaking: If upstream latency spikes, fail closed or open based on your risk posture. Document the default policy.
- Logging and PII: IP addresses are personal data in many jurisdictions. Follow your data retention and minimization policies.
- Testing: Use the documented fixture IP 148.105.12.120 to validate parsing and decision logic in non-prod environments.
Where to explore and monitor:
- API reference and usage details: Documentation
- Management and control plane: MCP
Pricing, signup, and environment setup
Getting started requires an API key. There is a trial that covers 7 days or 50 requests, whichever comes first, suitable for prototyping and integration tests. The Basic plan is $29.99 per month for ongoing use.
Next steps:
- Create an account and obtain a key: Register
- Verify with the documented fixture via cURL, then wire the check into your auth or risk middleware.
- Store the key securely (environment variable or secret store), then deploy to a staging environment and exercise your flows.
Operational considerations
Throughput and quotas vary by plan; consult your account area if you anticipate bursts. If your application experiences sudden traffic spikes (e.g., during marketing campaigns), pre-warm caches with known non-risk IP ranges where appropriate and ensure your retry and timeout policies are conservative.
Error taxonomy to distinguish in your telemetry:
- Client-side errors (timeouts, DNS, TLS): treat as transient. Consider a default allow or deny based on endpoint sensitivity.
- Non-2xx HTTP: log the status code and the first couple hundred characters of the body for triage.
- Schema issues: guard your parsers. Validate the presence of security and security.is_vpn before use.
Versioning and compatibility: Use the documented fields security.is_vpn and avoid coupling to undeclared fields. If you store results, persist only what you need for decisions and audits.
End-to-end flow example
Sign-in with risk-aware friction
- Receive a login request with an IP from the edge layer.
- Lookup the IP via GET /api/ip with Authorization: Bearer YOUR_API_KEY.
- Parse security.is_vpn. If true, require an additional factor or verification step.
- If false, continue normal sign-in and record the decision outcome for analytics.
- Apply a short TTL cache entry keyed by the IP to keep latency low on repeated requests.
Promotion abuse control
- At coupon redemption, run the same lookup.
- Block or review when security.is_vpn is true to limit multi-accounting attempts.
- Log query, country, and is_vpn to a secure analytics store to tune thresholds and monitor false positives.
FAQ
Which endpoint should I call to detect VPN usage?
Use GET /api/ip with the ip query parameter and inspect security.is_vpn in the JSON response.
How do I authenticate?
Send Authorization: Bearer YOUR_API_KEY and Accept: application/json in the request headers.
Can I rely on the example fixture for production logic?
Use it only to validate parsing and integration. Live flags can change, so always evaluate security.is_vpn from real-time lookups in your environment.
What is the best way to handle timeouts?
Use a short client timeout and a clear fallback policy. For sign-in, a common pattern is to allow with increased monitoring if the lookup times out, and to challenge when is_vpn is confirmed.
Where can I manage my account or review API details?
See the Documentation and the MCP portal.
Ship a minimal VPN check today. Create an account, grab your key, and wire security.is_vpn into your sign-in or risk middleware in under an hour: Register.
