curl -X POST https://verification.didit.me/v3/ip/risk/ \
-H 'x-api-key: YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"ip_address": "8.8.8.8",
"claimed_country": "ESP",
"user_agent": "Mozilla/5.0",
"vendor_data": "lead-123"
}'import os, requests
resp = requests.post(
"https://verification.didit.me/v3/ip/risk/",
headers={"x-api-key": os.environ["DIDIT_API_KEY"], "Content-Type": "application/json"},
json={
"ip_address": "8.8.8.8",
"claimed_country": "ESP",
"user_agent": "Mozilla/5.0",
"vendor_data": "lead-123",
},
timeout=15,
)
resp.raise_for_status()
result = resp.json()
print(result["status"]) # Approved / In Review
print(result["ip"]["ip_country_code"], result["ip"]["country_mismatch"])const res = await fetch('https://verification.didit.me/v3/ip/risk/', {
method: 'POST',
headers: {
'x-api-key': 'YOUR_API_KEY',
'Content-Type': 'application/json',
},
body: JSON.stringify({
ip_address: '8.8.8.8',
claimed_country: 'ESP',
user_agent: 'Mozilla/5.0',
vendor_data: 'lead-123',
}),
});
const data = await res.json();
console.log(data.status, data.ip.country_mismatch);<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://verification.didit.me/v3/ip/risk/",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'ip_address' => '8.8.8.8'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"x-api-key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://verification.didit.me/v3/ip/risk/"
payload := strings.NewReader("{\n \"ip_address\": \"8.8.8.8\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("x-api-key", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://verification.didit.me/v3/ip/risk/")
.header("x-api-key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"ip_address\": \"8.8.8.8\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://verification.didit.me/v3/ip/risk/")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["x-api-key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"ip_address\": \"8.8.8.8\"\n}"
response = http.request(request)
puts response.read_body{
"request_id": "9a96ed2a-721e-4b86-8cbf-d61eda529279",
"status": "Approved",
"ip": {
"status": "Approved",
"ip_address": "192.0.2.10",
"ip_country": "Spain",
"ip_country_code": "ES",
"ip_state": "Madrid",
"ip_city": "Madrid",
"latitude": 40.4168,
"longitude": -3.7038,
"isp": "Example Telecom",
"organization": "Example Telecom SA",
"is_vpn_or_tor": false,
"is_data_center": false,
"time_zone": "Europe/Madrid",
"time_zone_offset": "+0200",
"asn_number": 3352,
"asn_organization": "EXAMPLE-TELECOM",
"connection_type": "broadband",
"carrier": "Example Telecom",
"proxy_type": null,
"claimed_country": "ESP",
"country_mismatch": false,
"threat": {}
},
"vendor_data": "lead-123",
"metadata": null,
"created_at": "2026-09-01T10:30:00.123456+00:00"
}IP Risk API
Risk-score an IP address with geolocation, ISP, VPN/Tor, datacenter, threat, and claimed-country mismatch signals.
curl -X POST https://verification.didit.me/v3/ip/risk/ \
-H 'x-api-key: YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"ip_address": "8.8.8.8",
"claimed_country": "ESP",
"user_agent": "Mozilla/5.0",
"vendor_data": "lead-123"
}'import os, requests
resp = requests.post(
"https://verification.didit.me/v3/ip/risk/",
headers={"x-api-key": os.environ["DIDIT_API_KEY"], "Content-Type": "application/json"},
json={
"ip_address": "8.8.8.8",
"claimed_country": "ESP",
"user_agent": "Mozilla/5.0",
"vendor_data": "lead-123",
},
timeout=15,
)
resp.raise_for_status()
result = resp.json()
print(result["status"]) # Approved / In Review
print(result["ip"]["ip_country_code"], result["ip"]["country_mismatch"])const res = await fetch('https://verification.didit.me/v3/ip/risk/', {
method: 'POST',
headers: {
'x-api-key': 'YOUR_API_KEY',
'Content-Type': 'application/json',
},
body: JSON.stringify({
ip_address: '8.8.8.8',
claimed_country: 'ESP',
user_agent: 'Mozilla/5.0',
vendor_data: 'lead-123',
}),
});
const data = await res.json();
console.log(data.status, data.ip.country_mismatch);<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://verification.didit.me/v3/ip/risk/",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'ip_address' => '8.8.8.8'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"x-api-key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://verification.didit.me/v3/ip/risk/"
payload := strings.NewReader("{\n \"ip_address\": \"8.8.8.8\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("x-api-key", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://verification.didit.me/v3/ip/risk/")
.header("x-api-key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"ip_address\": \"8.8.8.8\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://verification.didit.me/v3/ip/risk/")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["x-api-key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"ip_address\": \"8.8.8.8\"\n}"
response = http.request(request)
puts response.read_body{
"request_id": "9a96ed2a-721e-4b86-8cbf-d61eda529279",
"status": "Approved",
"ip": {
"status": "Approved",
"ip_address": "192.0.2.10",
"ip_country": "Spain",
"ip_country_code": "ES",
"ip_state": "Madrid",
"ip_city": "Madrid",
"latitude": 40.4168,
"longitude": -3.7038,
"isp": "Example Telecom",
"organization": "Example Telecom SA",
"is_vpn_or_tor": false,
"is_data_center": false,
"time_zone": "Europe/Madrid",
"time_zone_offset": "+0200",
"asn_number": 3352,
"asn_organization": "EXAMPLE-TELECOM",
"connection_type": "broadband",
"carrier": "Example Telecom",
"proxy_type": null,
"claimed_country": "ESP",
"country_mismatch": false,
"threat": {}
},
"vendor_data": "lead-123",
"metadata": null,
"created_at": "2026-09-01T10:30:00.123456+00:00"
}POST /v3/ip/risk/ when your backend already has an IP address and needs a server-to-server risk decision.
The response includes geolocation, network ownership, VPN/Tor and data-center flags, threat data, and country_mismatch when you send a claimed country.
Interpret the response
statusisIn Reviewwhen the resolved country conflicts withclaimed_country, or when the address is associated with VPN, Tor, or data-center infrastructure. Otherwise it isApproved.ip.ip_country_codecontains the resolved country code. Compare countries throughip.country_mismatchinstead of comparing raw country strings yourself.ip.latitudeandip.longitudeare approximate network geolocation, not a precise device location.ip.is_vpn_or_tor,ip.is_data_center,ip.proxy_type, andip.threatcarry network-risk evidence.ip.asn_number,ip.asn_organization,ip.connection_type, andip.carrierdescribe the network the address belongs to.request_idis the API session id. Store it withvendor_dataif you need to correlate the result with later webhooks or console activity.
ip.ip_address: null, ip.country_mismatch: null, and an empty ip.threat object. Individual enrichment fields can also be null when unavailable.Device intelligence
The IP Risk API is a pure server-to-server endpoint. Device fingerprinting is not, because a backend cannot observe browser or device signals by itself. For hosted-flow and SDK sessions, Didit exposes the already collected device fields on the session response, includingdevice_fingerprint, device and browser details, user_agent, raw device data, and cross-session matches.
Sandbox behavior
Sandbox keys validate the request and return deterministic approved data. They do not contact external intelligence services, consume credits, create a session, or contribute to Networks.Billing
IP Risk API calls use IP Risk API pricing. A live request is billable once the lookup starts.Authorizations
Body
IPv4 or IPv6 address to score.
"8.8.8.8"
Optional ISO 3166-1 alpha-2 or alpha-3 country claimed by the user or session. Used to calculate country_mismatch.
3"ESP"
User agent observed by your backend. Stored as request context; it does not provide device fingerprinting.
512Your stable reference for this request. Stored on the API session and echoed in the response.
Your non-sensitive JSON metadata. Stored on the API session and echoed in the response.
Response
The risk evaluation completed. Inspect status for the decision; HTTP is always 200 for completed lookups.
Id of the API session created for this request. Store it with vendor_data if you need to correlate the result with later webhooks or console activity.
Decision for this API session: In Review on network or country-mismatch risk, otherwise Approved.
Approved, In Review Timestamp of this response.
Echo of the vendor_data you sent, null when you did not send one.
Echo of the metadata you sent, null when you did not send one.
IP risk result. Individual enrichment fields can be null when the lookup returned no usable data.
Show child attributes
Show child attributes