Вступление

Этот API создан для разработчиков, которым необходимы высокая производительность, низкая задержка и надёжность.
Наша платформа работает на собственной Anycast-сети с глобально распределённой, отказоустойчивой и саммасштабируемой инфраструктурой, обеспечивающей низкую задержку по всему миру. Ядро построено на высокооптимизированном стеке OpenResty и Rust, разработанном для максимальной пропускной способности и минимальных накладных расходов.
Базы данных IP-геолокации хранятся в компактном двоичном формате и загружаются непосредственно в высокоскоростную память, что позволяет выполнять поиск за постоянное время без обращения к диску. Такая архитектура, работающая в оперативной памяти, позволяет API обрабатывать более 1 миллиарда запросов в день с неизменно стабильной производительностью.
Наша база данных обновляется несколько раз в день и дополнительно совершенствуется с использованием AI-алгоритмов агрегации и валидации данных, повышая точность за счёт непрерывного анализа сигналов из множества надёжных источников.
Благодаря чистому и удобному для разработчиков интерфейсу, гибким возможностям интеграции и предсказуемой производительности при высокой нагрузке, API легко интегрируется в современные production-среды.


Конечные точки

Одиночная геолокация

Вы можете вызвать API, отправив GET запрос http://ipwho.is/[IP address]

[IP address] может быть IPv4 или IPv6 адресом, оставьте параметр пустым чтобы использовать текущий IP-адрес.

# Получить подробности для 8.8.4.4
$ curl "http://ipwho.is/8.8.4.4"

# Получите подробную информацию о вашем собственном IP-адресе
$ curl "http://ipwho.is/"

Наш API доступен через защищенное соединение HTTPS. Просто добавьте https:// к URL-адресам запросов.


Лимиты

Эта конечная точка не устанавливает ежемесячного лимита запросов. API-ключ не требуется.
В целях обеспечения добросовестного использования запросы ограничены до 1 запроса в секунду (~2.5 млн. запросов/месяц) с одного IP-адреса.
Допускаются кратковременные всплески запросов; однако в пределах любого 60-секундного окна разрешено не более 60 запросов.

CORS (JavaScript-запросы с вашего сайта) не поддерживается в данной конечной точке. Доступ к этой конечной точке должен осуществляться с вашего backend (server-to-server), а не напрямую из браузера.

При превышении лимита запросы будут ограничены и вернут HTTP 429 (Too Many Requests).
Ваш IP-адрес будет временно заблокирован на 5 минут. Если в течение периода блокировки превышение лимита запросов продолжится, дополнительные 5-минутные блокировки будут применяться последовательно после окончания каждой предыдущей до тех пор, пока чрезмерная активность не прекратится.

В ответе сервера возвращается HTTP-заголовок Retry-After, который содержит количество секунд до сброса лимита.

Коммерческое использование данной конечной точки запрещено.

Откройте полный потенциал нашей платформы с помощью Premium-сервиса — включая доступ к массовой геолокации, подробной аналитике использования, расширенным функциям и коммерческой поддержке.

Premium-сервис также включает валютные данные, данные по безопасности, поддержку CORS, результаты с повышенной точностью и 99,9% SLA, соответствующие требованиям production-среды.


Живой пример

Вы можете отредактировать этот запрос и поэкспериментировать с параметрами:

GET
Actual response
{
    "ip": "8.8.4.4",
    "success": true,
    "type": "IPv4",
    "continent": "North America",
    "continent_code": "NA",
    "country": "United States",
    "country_code": "US",
    "region": "California",
    "region_code": "CA",
    "city": "Mountain View",
    "latitude": 37.3860517,
    "longitude": -122.0838511,
    "is_eu": false,
    "postal": "94039",
    "calling_code": "1",
    "capital": "Washington D.C.",
    "borders": "CA,MX",
    flag {
        "img": "https://cdn.ipwhois.io/flags/us.svg",
        "emoji": "🇺🇸",
        "emoji_unicode": "U+1F1FA U+1F1F8"
    },
    connection {
        "asn": 15169,
        "org": "Google LLC",
        "isp": "Google LLC",
        "domain": "google.com"
    },
    timezone {
        "id": "America/Los_Angeles",
        "abbr": "PDT",
        "is_dst": true,
        "offset": -25200,
        "utc": "-07:00",
        "current_time": "2022-04-22T14:31:48-07:00"
    },
    currency {
        "name": "US Dollar",
        "code": "USD",
        "symbol": "$",
        "plural": "US dollars",
        "exchange_rate": 1
    },
    security {
        "anonymous": false,
        "proxy": false,
        "vpn": false,
        "tor": false,
        "hosting": false
    },
    rate {
        "limit": 250000,
        "remaining": 50155
    }
}

Обратите внимание: для наглядности мы включили все доступные поля в приведенный выше ответ API. В зависимости от вашего плана подписки ответ API может отличаться.


Возвращаемые данные

В зависимости от вашего плана подписки и параметров, выбранных вами для запроса API, ответ будет содержать несколько разных полей. Ниже приведен список всех доступных полей ответа API:

название описание
ip Запрашиваемый IP адрес (например 8.8.4.4)
success В случае успешного выполнения запроса будет возвращено значение true, а в случае неудачи — значение false.
message Включается только в том случае, если success равен false
Может быть одним из следующих: Смотри коды ошибок
type Тип IP адреса (IPv4 или IPv6)
continent Название континента (например North America)
continent_code Двухбуквенный (ISO 3166-1) код континента (например NA)
country Название страны (например United States)
country_code Двухбуквенный (ISO 3166-1) код страны (например US)
region Название региона/штата (например California)
region_code Код штата/региона (ISO 3166-2), если он доступен (например CA)
city Название города (например Mountain View)
latitude Приблизительная (WGS84) широта местоположения, связанного с IP (например 37.3860517)
longitude Приблизительная (WGS84) долгота местоположения, связанного с IP (например -122.0838511)
is_eu Возвращает true или false в зависимости от того, находится ли страна, связанная с IP, в Европейском союзе.
postal Почтовый индекс, связанный с местоположением.
calling_code Телефонный код страны (например 1)
capital Столица страны (например Washington)
borders Двухбуквенный (ISO 3166-1) код стран, граничащих со страной, связанной с этим IP (например CA,MX)
flag > img Возвращает URL-адрес, ведущий к SVG изображению флага страны.
flag > emoji Эмодзи-версия флага страны (например 🇺🇸)
flag > emoji_unicode Юникод значение значка эмодзи для флага.
connection > asn Номер автономной системы (AS) (например 15169)
connection > org Название организации, владеющей AS для анализируемого IP-адреса (например Google LLC)
connection > isp Имя провайдера, связанного с IP (например Google LLC)
connection > domain Доменное имя, связанное с организацией, которой принадлежит IP-адрес (например google.com)
timezone > id Идентификатор часового пояса, связанного с местоположением (например America/Los_Angeles)
timezone > abbr Аббревиатура часового пояса (например PDT)
timezone > is_dst true или false в зависимости от того, учитывался ли переход на летнее время.
timezone > offset Смещение от UTC (в секундах) для данного местоположения (например -25200)
timezone > utc Смещение часового пояса UTC (например -07:00)
timezone > current_time Точная текущая дата и время (в формате ISO 8601), связанные с местоположением (например 2022-04-22T14:31:48-07:00)
currency > name Название валюты (например US Dollar)
currency > code Трехбуквенный (ISO 4217) код валюты (например USD)
currency > symbol Родной (местный) символ данной валюты (например $)
currency > plural Множественная версия названия валюты (например US dollars)
currency > exchange_rate Текущий курс по отношению к доллару США.
security > anonymous Логическое значение со значением true, если proxy, vpn или tor равны true.
security > proxy true или false в зависимости от того, является ли IP-адрес известным прокси-сервером или любым другим типом.
security > vpn Возвращает true, если искомый IP-адрес используется VPN, и false в противном случае.
security > tor true или false в зависимости от того, является ли IP-адрес известным выходным узлом или принадлежит сети Tor.
security > hosting true или false в зависимости от того, используется ли IP-адрес для хостинга.
rate > limit Общее количество запросов к API, которым ограничена ваша учетная запись за указанный период времени (месяц).
rate > remaining Количество запросов к API, оставшихся за указанный период времени (месяц).

Указать формат вывода

Используя параметр GET output, вы можете переключать формат результатов API между JSON (по умолчанию), XML и CSV. Если вы используете JSON, этот параметр можно не указывать.

Например:
output=xml
output=csv
output=json

Указать поля ответа

Вы можете ограничить результаты API определенными полями данных, если вам не нужно отслеживать все данные. В этом случае вам нужно добавить параметр GET fields к URL-адресу API-запроса и указать определенное поле или список полей через запятую.

Например:
fields=country,city,flag.emoji
fields=city,timezone
fields=ip,timezone.current_time

Локализация

Локализацию city, region, country, capital и continent можно запросить, установив для GET параметра lang одно из следующих значений:

язык описание демо
en English (по умолчанию)
ru Русский (Russian)
de Deutsch (German)
es Español (Spanish)
pt-BR Português - Brasil (Portuguese)
fr Français (French)
zh-CN 中国 (Chinese)
ja 日本語 (Japanese)

Включить обнаружение угроз

Доступно в планах: Бизнес и Премиум

Включение полей данных безопасности (proxy, vpn, tor, hosting) для обнаружения угроз. Это позволит защитить ваш сайт или приложение от злоупотреблений в виде обхода бана, сокрытия реального IP-адреса, парсинга сайта и т.д. Для того, чтобы использовать эту возможность, добавьте GET-параметр security к URL-адресу запроса API и установите для него значение 1.

{
    [...],
    security {
        "anonymous": true,
        "proxy": false,
        "vpn": true,
        "tor": false,
        "hosting": false,
    }
}
Например:
security=1

Статистика запросов в ответе API

Доступно в планах: Базовый, Бизнес и Премиум

Чтобы использовать эту возможность, добавьте параметр GET rate к URL-адресу запроса API и установите для него значение 1.
Вот пример (в формате JSON) информации в теле ответа API:

{
    [...],
    rate {
        "limit": "250000",
        "remaining": 50155
    }
}
Например:
rate=1

Коды ошибок

API может возвращать следующие стандартные клиентские ошибки HTTP 4xx:

КодПричинаОтвет
400Неверный запрос{"success":false,"message":"Bad Request"}
400CORS не разрешен{"success":false,"message":"CORS is not supported on the Free plan"}
403Доступ запрещён{"success":false,"message":"The current subscription plan does not support this API endpoint"}
404URL не найден{"success":false,"message":"404 not found"}
405Метод HTTP не разрешен{"success":false,"message":"HTTP method is not allowed"}
414Слишком длинный URI запроса{"success":false,"message":"URI Too Long"}
429Превышен лимит{"success":false,"message":"Rate limit exceeded"}

В общем случае статус-код HTTP 2xx означает, что запрос был успешно обработан.

Однако в некоторых случаях API может вернуть ответ 200 OK, указывая при этом на ошибку на уровне приложения в теле ответа. В таких случаях запрос был технически корректным, но операция не могла быть выполнена.

Такие ответы содержат JSON-объект с "success":false и поясняющим полем "message", например:

HTTP статус-кодПричинаОтвет
200Некорректный IP-адрес{"success":false,"message":"Invalid IP address"}
200Зарезервированный IP-адрес{"success":false,"message":"Reserved range"}

Примеры кода

Ниже приведены простые примеры кода на популярных языках:

  • PHP
  • Node.js
  • Go
  • Python
  • Java (11+)
  • Ruby
  • Swift
  • Rust
$ip = '8.8.8.8';
$ch = curl_init('https://ipwho.is/' . $ip);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HEADER, false);
$ipwhois = json_decode(curl_exec($ch), true);
curl_close($ch);
echo $ipwhois['country'] . ' ' . $ipwhois['flag']['emoji']; // Output: United States 🇺🇸
const ip = '8.8.8.8';
const url = `https://ipwho.is/${ip}`;

fetch(url)
  .then(res => res.json())
  .then(data => {
    console.log(`${data.country} ${data.flag.emoji}`); // Output: United States 🇺🇸
  });
package main

import (
  "encoding/json"
  "fmt"
  "net/http"
)

func main() {
  url := "https://ipwho.is/8.8.8.8"
  resp, _ := http.Get(url)
  defer resp.Body.Close()

  data := map[string]any{}
  json.NewDecoder(resp.Body).Decode(&data)

  fmt.Println(data["country"], data["flag"].(map[string]any)["emoji"]) // Output: United States 🇺🇸
}
import requests

ip = '8.8.8.8'
url = 'https://ipwho.is/' + ip
response = requests.get(url)
data = response.json()

print(data['country'], data['flag']['emoji']) # Output: United States 🇺🇸
import java.net.URI;
import java.net.http.*;

public class Main {
  public static void main(String[] args) throws Exception {
    var client = HttpClient.newHttpClient();
    var url = "https://ipwho.is/8.8.8.8";

    var request = HttpRequest.newBuilder()
      .uri(URI.create(url))
      .build();

    var response = client.send(request, HttpResponse.BodyHandlers.ofString());
    System.out.println(response.body()); // Output: JSON response
  }
}
require 'net/http'
require 'json'
require 'uri'

ip = '8.8.8.8'
url = 'https://ipwho.is/' + ip
response = Net::HTTP.get(URI(url))
data = JSON.parse(response)

puts data['country'] + ' ' + data['flag']['emoji'] # Output: United States 🇺🇸
import Foundation

let ip = "8.8.8.8"
let url = "https://ipwho.is/\(ip)"

let sem = DispatchSemaphore(value: 0)

URLSession.shared.dataTask(with: URL(string: url)!) { data, _, _ in
  guard let data = data else { sem.signal(); return }
  let json = try? JSONSerialization.jsonObject(with: data) as? [String: Any]
  let country = json?["country"] as? String ?? ""
  let flag = (json?["flag"] as? [String: Any])?["emoji"] as? String ?? ""
  print(country, flag) // Output: United States 🇺🇸
  sem.signal()
}.resume()

sem.wait()
use reqwest;
use serde_json::Value;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
  let ip = "8.8.8.8";
  let url = format!("https://ipwho.is/{ip}");

  let data: Value = reqwest::get(url).await?.json().await?;

  let country = data["country"].as_str().unwrap_or("");
  let flag = data["flag"]["emoji"].as_str().unwrap_or("");

  println!("{country} {flag}"); // Output: United States 🇺🇸
  Ok(())
}
  • PHP
  • Node.js
  • Go
  • Python
  • Java (11+)
  • Ruby
  • Swift
  • Rust
$ips = ['8.8.8.8', '1.1.1.1', '208.67.222.222'];
$ch = curl_init('https://ipwho.is/bulk');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HEADER, false);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($ips));
$data = json_decode(curl_exec($ch), true);
curl_close($ch);
echo $data[0]['ip'] . ': ' . $data[0]['country'] . ' ' . $data[0]['flag']['emoji']; // Example output: 8.8.8.8: United States 🇺🇸
const ips = ['8.8.8.8', '1.1.1.1', '208.67.222.222'];
const url = `https://ipwho.is/bulk`;

fetch(url, {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify(ips)
})
  .then(res => res.json())
  .then(data => {
    console.log(`${data[0].ip}: ${data[0].country} ${data[0].flag.emoji}`); // Example output: 8.8.8.8: United States 🇺🇸
  });
package main

import (
  "bytes"
  "encoding/json"
  "fmt"
  "io"
  "net/http"
)

func main() {
  ips := []string{"8.8.8.8", "1.1.1.1", "208.67.222.222"}
  body, _ := json.Marshal(ips)

  url := "https://ipwho.is/bulk"
  req, _ := http.NewRequest("POST", url, bytes.NewReader(body))
  req.Header.Set("Content-Type", "application/json")

  client := &http.Client{}
  resp, _ := client.Do(req)
  defer resp.Body.Close()

  b, _ := io.ReadAll(resp.Body)
  data := []map[string]any{}
  json.Unmarshal(b, &data)

  fmt.Println(data[0]["ip"], data[0]["country"]) // Example output: 8.8.8.8 United States
}
import requests

ips = ['8.8.8.8', '1.1.1.1', '208.67.222.222']
url = 'https://ipwho.is/bulk'

response = requests.post(url, json=ips)
data = response.json()

print(data[0]['ip'], data[0]['country'], data[0]['flag']['emoji']) # Example output: 8.8.8.8 United States 🇺🇸
import java.net.URI;
import java.net.http.*;

public class Main {
  public static void main(String[] args) throws Exception {
    var client = HttpClient.newHttpClient();
    var url = "https://ipwho.is/bulk";

    var body = "[\"8.8.8.8\",\"1.1.1.1\",\"208.67.222.222\"]";

    var request = HttpRequest.newBuilder()
      .uri(URI.create(url))
      .header("Content-Type", "application/json")
      .POST(HttpRequest.BodyPublishers.ofString(body))
      .build();

    var response = client.send(request, HttpResponse.BodyHandlers.ofString());
    System.out.println(response.body()); // Output: JSON array
  }
}
require 'net/http'
require 'json'
require 'uri'

ips = ['8.8.8.8', '1.1.1.1', '208.67.222.222']
url = 'https://ipwho.is/bulk'

uri = URI(url)
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

req = Net::HTTP::Post.new(uri)
req['Content-Type'] = 'application/json'
req.body = ips.to_json

res = http.request(req)
data = JSON.parse(res.body)

puts data[0]['ip'] + ': ' + data[0]['country'] + ' ' + data[0]['flag']['emoji'] # Example output: 8.8.8.8: United States 🇺🇸
import Foundation

let url = "https://ipwho.is/bulk"
let ips = ["8.8.8.8", "1.1.1.1", "208.67.222.222"]

var request = URLRequest(url: URL(string: url)!)
request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.httpBody = try? JSONSerialization.data(withJSONObject: ips)

let sem = DispatchSemaphore(value: 0)

URLSession.shared.dataTask(with: request) { data, _, _ in
  guard let data = data else { sem.signal(); return }
  let json = try? JSONSerialization.jsonObject(with: data) as? [[String: Any]]
  let first = json?.first
  let ip = first?["ip"] as? String ?? ""
  let country = first?["country"] as? String ?? ""
  let flag = (first?["flag"] as? [String: Any])?["emoji"] as? String ?? ""
  print(ip, country, flag) // Example output: 8.8.8.8 United States 🇺🇸
  sem.signal()
}.resume()

sem.wait()
use reqwest;
use serde_json::Value;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
  let url = format!("https://ipwho.is/bulk");
  let ips = vec!["8.8.8.8", "1.1.1.1", "208.67.222.222"];

  let data: Value = reqwest::Client::new()
    .post(url)
    .json(&ips)
    .send().await?
    .json().await?;

  println!("{}: {}", data[0]["ip"], data[0]["country"]); // Example output: 8.8.8.8: United States
  Ok(())
}