API documentation
IPzentra is a JSON API over HTTPS. Send an IP address, get back its country, network and risk signals.
Authentication
Create an API key in your dashboard and send it in the X-Api-Key header with every request. Keep keys secret: call the API from your server, never from code that runs in the browser.
Endpoints
Base URL: https://api.ipzentra.com
Look up an IP address
GET /v1/{ip}Works with IPv4 and IPv6.
Check an IP against expected countries
GET /v1/check?ip={ip}&country=IN,SGPass one or more two-letter country codes. The response adds expected and country_match.
Look up the caller
GET /v1/Returns the lookup for the address the request came from. Handy for testing your setup.
Response fields
| Field | Type | Description |
|---|---|---|
ip | string | The IP address, normalised. |
version | integer | 4 or 6. |
country_code | string or null | ISO 3166-1 alpha-2 code, for example IN. |
country_name | string or null | Country name in English. |
asn | integer or null | Autonomous system number of the network. |
org | string or null | Owner of the network. |
is_vpn | boolean | True when the IP belongs to a known commercial VPN network. |
is_proxy | boolean | True when the IP is a known open proxy. |
is_tor | boolean | True when the IP is a current Tor exit node. |
is_hosting | boolean | True for hosting, cloud and datacenter networks. |
hosting_provider | string or null | Provider when is_hosting is true, for example aws. |
risk | string | low; medium for VPN and hosting networks; high for Tor and open proxies. |
The check endpoint also returns:
| Field | Type | Description |
|---|---|---|
expected | array | The country codes you passed. |
country_match | boolean | True when country_code is one of the expected countries. |
Example response for GET /v1/5.9.0.1:
{
"ip": "5.9.0.1",
"version": 4,
"country_code": "DE",
"country_name": "Germany",
"asn": 24940,
"org": "HETZNER-AS",
"is_vpn": false,
"is_proxy": false,
"is_tor": false,
"is_hosting": true,
"hosting_provider": "hetzner",
"risk": "medium"
}We may add new fields over time. New fields never change or remove existing ones.
Errors
Errors return JSON in the form {"error": "code", "message": "explanation"} with these HTTP statuses:
| Status | Error code | Meaning |
|---|---|---|
400 | bad_ip | Not a valid IPv4 or IPv6 address. |
400 | bad_country | country is not a list of two-letter codes. |
401 | invalid_key | The API key is missing, wrong or revoked. |
402 | subscription_required | The trial has ended or the subscription has lapsed. |
404 | not_found | The path does not exist. |
429 | rate_limited | Per-second or daily limit reached. |
500 | server_error | A problem on our side. Retry after a short wait. |
Limits
Limits apply per account across all its keys. Daily limits reset at 00:00 UTC, and each response carries an X-RateLimit-Remaining-Day header.
- Free trial: 100 lookups per day, 2 requests per second, for 20 days.
- Pro: 20,000 lookups per day, 10 requests per second.
Code examples
cURL
curl -H "X-Api-Key: YOUR_API_KEY" https://api.ipzentra.com/v1/5.9.0.1
curl -H "X-Api-Key: YOUR_API_KEY" \
"https://api.ipzentra.com/v1/check?ip=49.207.48.1&country=IN,SG"PHP
<?php
$ip = $_SERVER['REMOTE_ADDR'];
$ch = curl_init('https://api.ipzentra.com/v1/check?ip=' . urlencode($ip) . '&country=IN');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 3,
CURLOPT_HTTPHEADER => ['X-Api-Key: ' . getenv('IPZENTRA_KEY')],
]);
$res = json_decode((string)curl_exec($ch), true);
if (!empty($res['country_match']) && empty($res['is_hosting']) && empty($res['is_tor'])) {
// allow the visitor
}Python
import os, requests
r = requests.get(
"https://api.ipzentra.com/v1/check",
params={"ip": "49.207.48.1", "country": "IN"},
headers={"X-Api-Key": os.environ["IPZENTRA_KEY"]},
timeout=3,
)
data = r.json()
if r.ok and data["country_match"] and not data["is_hosting"] and not data["is_tor"]:
print("allow")Node.js
const res = await fetch(
"https://api.ipzentra.com/v1/check?ip=49.207.48.1&country=IN",
{ headers: { "X-Api-Key": process.env.IPZENTRA_KEY } }
);
const data = await res.json();
if (res.ok && data.country_match && !data.is_hosting && !data.is_tor) {
console.log("allow");
}Data sources and freshness
- Country: IP geolocation data by IPLocate.io, licensed CC BY-SA 4.0, refreshed daily.
- Network (ASN): refreshed daily.
- Hosting and datacenter ranges: published cloud ranges and hosting networks, refreshed daily.
- Tor exit nodes: the Tor Project exit list, refreshed hourly.
- VPN networks: known VPN provider networks, refreshed daily.
- Open proxies: verified open proxy lists, refreshed every 30 minutes.