API Docs
Two endpoints, one API key. Assess risk from IP addresses and email addresses.
Quickstart
Get your API Key
You'll need an API key to make requests. Sign up for a free account to get one.
Make your first request
Make a GET request to either endpoint. Pass your key via header or query param.
IP Lookup
curl -s "https://api.ipasis.com/v1/lookup?ip=8.8.8.8" -H "X-API-Key: <your_api_key>"
Email Validation
curl -s "https://api.ipasis.com/v1/validate-email?email=user@mailinator.com&ip=185.220.101.4" \ -H "X-API-Key: <your_api_key>"
IP Lookup
GET /v1/lookup?ip=<ip>
Try It
Examples
fetch('https://api.ipasis.com/v1/lookup?ip=8.8.8.8', {
headers: { 'X-API-Key': '<your_api_key>' }
}).then(r => r.json()).then(console.log)import requests
r = requests.get('https://api.ipasis.com/v1/lookup', params={'ip':'8.8.8.8'}, headers={'X-API-Key':'<your_api_key>'})
print(r.json())package main
import (
"fmt"
"io"
"net/http"
"net/url"
)
func main() {
endpoint := "https://api.ipasis.com/v1/lookup"
u, _ := url.Parse(endpoint)
q := u.Query()
q.Set("ip", "8.8.8.8")
u.RawQuery = q.Encode()
req, _ := http.NewRequest("GET", u.String(), nil)
req.Header.Set("X-API-Key", "<your_api_key>")
resp, err := http.DefaultClient.Do(req)
if err != nil { panic(err) }
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
fmt.Println(string(body))
}import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
public class Main {
public static void main(String[] args) throws Exception {
String url = "https://api.ipasis.com/v1/lookup?ip=8.8.8.8";
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(url))
.header("X-API-Key", "<your_api_key>")
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
}
}Response Fields
The IP lookup API returns a JSON object with the following fields:
| Field | Type | Description |
|---|---|---|
| ip | string | The query IP address. |
| city | string | City name. |
| region | string | Region or state name. |
| country | string | Two-letter ISO 3166-1 country code (e.g., US). |
| loc | string | Latitude and Longitude (comma separated). |
| postal | string | Postal or ZIP code. |
| timezone | string | Timezone (IANA format). |
| asn.ASN | string | Autonomous System Number (e.g. AS15169). |
| asn.Name | string | Name of the ASN owner. |
| asn.Route | string | The BGP route block for this IP. |
| asn.Type | string | ASN type (isp, hosting, business, etc). |
| asn.Domain | string | Domain associated with the ASN. |
| company.Name | string | Company name associated with the IP range. |
| company.Domain | string | Company domain name. |
| company.Type | string | Company type. |
| privacy.vpn | boolean | True if the IP belongs to a commercial VPN provider. |
| privacy.proxy | boolean | True if the IP is a known public proxy. |
| privacy.tor | boolean | True if the IP is a Tor exit node. |
| privacy.relay | boolean | True if the IP is an iCloud Private Relay or similar privacy network. |
| privacy.hosting | boolean | True if the IP belongs to a hosting provider/datacenter (non-residential). |
| privacy.AI | boolean | True if the IP belongs to an AI provider like OpenAI etc. |
| privacy.abuse | boolean | True if the IP has been reported for abuse recently. |
| privacy.crawler | boolean | True if the IP is a known crawler (e.g., Googlebot, Bingbot). |
| privacy.Service | string | Specific service name if identified (e.g. "NordVPN"). |
| abuse.Address | string | Abuse contact address. |
| abuse.Country | string | Abuse contact country. |
| abuse.Email | string | Abuse contact email. |
| abuse.Name | string | Abuse contact name. |
| abuse.Network | string | Network CIDR involved in abuse reports. |
| abuse.Phone | string | Abuse contact phone. |
| domains.Total | number | Total number of domains hosted on this IP. |
| domains.Page | number | Current page number for domain pagination. |
| domains.Domains | string[] | List of domains hosted on this IP (may be null/empty). |
Email Validation
GET /v1/validate-email?email=<email>&ip=<ip>
Validate an email address and get a combined risk score. Optionally pass an IP address to include IP-based risk signals in the score.
Parameters
| Parameter | Required | Description |
|---|---|---|
| Yes | The email address to validate. | |
| ip | No | An IP address to include in the risk assessment. When provided, IP signals (VPN, Tor, proxy, etc.) are factored into the risk score. |
Try It
Examples
curl -s "https://api.ipasis.com/v1/validate-email?email=user@mailinator.com&ip=185.220.101.4" \ -H "X-API-Key: <your_api_key>"
fetch('https://api.ipasis.com/v1/validate-email?email=user@mailinator.com&ip=185.220.101.4', {
headers: { 'X-API-Key': '<your_api_key>' }
}).then(r => r.json()).then(console.log)import requests
r = requests.get(
'https://api.ipasis.com/v1/validate-email',
params={'email': 'user@mailinator.com', 'ip': '185.220.101.4'},
headers={'X-API-Key': '<your_api_key>'}
)
print(r.json())package main
import (
"fmt"
"io"
"net/http"
"net/url"
)
func main() {
endpoint := "https://api.ipasis.com/v1/validate-email"
u, _ := url.Parse(endpoint)
q := u.Query()
q.Set("email", "user@mailinator.com")
q.Set("ip", "185.220.101.4")
u.RawQuery = q.Encode()
req, _ := http.NewRequest("GET", u.String(), nil)
req.Header.Set("X-API-Key", "<your_api_key>")
resp, err := http.DefaultClient.Do(req)
if err != nil { panic(err) }
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
fmt.Println(string(body))
}Response Fields
The email validation API returns a JSON object with the following fields:
| Field | Type | Description |
|---|---|---|
| request_id | string | Unique request identifier for debugging. |
| success | boolean | Whether the request was processed successfully. |
| processed_at | string | ISO 8601 timestamp of when the request was processed. |
| risk | ||
| risk.score | number | Risk score from 0 (safe) to 100 (dangerous). |
| risk.level | string | Risk level: LOW (0-30), MEDIUM (31-60), HIGH (61-85), CRITICAL (86-100). |
| risk.recommendation | string | Suggested action: ALLOW (0-30), REVIEW (31-85), or BLOCK (86-100). |
| risk.primary_reasons | string[] | List of factors contributing to the risk score (e.g. email_disposable, ip_is_tor). |
| email.address | string | The normalized email address. |
| email.status | string | valid or invalid. |
| email.deliverability | string | deliverable, risky, or undeliverable. |
| email.type | string | personal, disposable, role, or business. |
| email.domain_age_days | number | null | Age of the email domain in days (null if unavailable). |
| email.checks | ||
| email.checks.is_valid_syntax | boolean | Whether the email has valid RFC syntax. |
| email.checks.is_disposable | boolean | True if the domain is a known disposable/temporary email provider (120k+ domains tracked). |
| email.checks.is_gibberish | boolean | True if the local part appears bot-generated (high entropy, hex patterns, excessive digits). |
| email.checks.is_newborn_domain | boolean | True if the domain was registered less than 14 days ago. |
| email.checks.is_role_account | boolean | True if the email is a role-based address (admin@, support@, info@, etc.). |
| email.checks.mx_records_found | boolean | null | Whether the domain has MX records. Null if DNS lookup timed out. |
| email.checks.is_catch_all | boolean | null | Whether the domain accepts all emails. Null if not checked. |
| email.checks.smtp_connect | boolean | null | Whether SMTP connection was successful. Null if not checked. |
| ip (included when ip parameter is provided) | ||
| ip.* | object | Full IP lookup response (same fields as the IP Lookup endpoint above). |
Risk Score Breakdown
The risk score (0-100) is calculated by combining email and IP signals:
| Signal | Points | Reason Code |
|---|---|---|
| Invalid email syntax | 100 | email_invalid_syntax |
| No MX records | 100 | email_no_mx_records |
| Disposable email domain | +40 | email_disposable |
| Newborn domain (<14 days) | +35 | email_newborn_domain |
| Gibberish/bot-like username | +25 | email_gibberish_username |
| Role account (admin@, info@) | +10 | email_role_account |
| IP is Tor exit node | +50 | ip_is_tor |
| IP is public proxy | +40 | ip_is_proxy |
| IP is VPN | +30 | ip_is_vpn |
| IP reported for abuse | +25 | ip_abuse_reported |
| IP is hosting/datacenter | +20 | ip_is_hosting |
Score is capped at 100. Tor/Proxy/VPN signals are mutually exclusive (highest value wins).
Errors
Standard HTTP status codes are used to indicate success or failure.
| Code | Meaning | Description |
|---|---|---|
| 400 | Bad Request | Missing or invalid parameters (IP address or email). |
| 401 | Unauthorized | Missing or invalid API key. |
| 403 | Forbidden | Quota exceeded or account inactive. |
| 429 | Too Many Requests | Rate limit exceeded. |
| 500 | Internal Error | Something went wrong on our end. |
Rate Limits
We limit the number of requests you can make to ensure fair usage and stability. Limits apply across both endpoints.
- Free Plan: 1,000 requests per day.
- Starter: 100,000 requests per month.
- Pro 250k: 250,000 requests per month.
- Pro 500k: 500,000 requests per month.
- Scale: 1,000,000 requests per month.
- Enterprise: 2,000,000 requests per month.
- Enterprise XL: 5,000,000 requests per month.
If you exceed the limit, you will receive a 429 Too Many Requests response. Check the X-RateLimit-Limit and X-RateLimit-Remaining response headers to track your usage.
MMDB Snapshot
We provide an ipasis.mmdb snapshot compatible with the included GeoAPI.