Жалобы по IP (REPORTS)
GET https://api.abuseipdb.ru/api/v2/reports — постраничный список жалоб по одному IP-адресу. Не путайте с REPORT: reports (во множественном числе, GET) читает жалобы, report (POST) отправляет одну жалобу.
Раздел «API v2»: Обзор · Проверка IP (CHECK) · Жалобы по IP (REPORTS) · Отправить жалобу (REPORT) · Чёрный список (BLACKLIST) · Проверка подсети (CHECK-BLOCK) · Массовые жалобы (BULK-REPORT) · Удаление жалоб (CLEAR-ADDRESS) · Лимиты · Ошибки · Fail2Ban, CSF, Suricata · FAQ
Запрос
# -G превращает -d в query-параметры: REPORTS — это GET-запрос.
curl -G https://api.abuseipdb.ru/api/v2/reports \
--data-urlencode "ipAddress=176.111.173.242" \
-d page=5 \
-d perPage=25 \
-d maxAgeInDays=30 \
-H "Key: YOUR_OWN_API_KEY" \
-H "Accept: application/json"
Параметры
| Параметр | Обязателен | По умолчанию | Допустимо | Описание |
|---|---|---|---|---|
ipAddress | да | — | IPv4 или IPv6 | адрес, по которому нужны жалобы |
maxAgeInDays | нет | 30 | 1…365 | окно: только жалобы не старше N дней |
page | нет | 1 | ≥ 1 | номер страницы, начиная с 1 |
perPage | нет | 25 | 1…100 | размер страницы |
IPv6-адрес URL-кодируйте (--data-urlencode "ipAddress=2001:db8::1"), иначе двоеточия сломают разбор query-строки.
Ответ
{
"data": {
"total": 2840,
"page": 5,
"count": 25,
"perPage": 25,
"lastPage": 114,
"nextPageUrl": "https://api.abuseipdb.ru/api/v2/reports?ipAddress=176.111.173.242&maxAgeInDays=30&perPage=25&page=6",
"previousPageUrl": "https://api.abuseipdb.ru/api/v2/reports?ipAddress=176.111.173.242&maxAgeInDays=30&perPage=25&page=4",
"results": [
{
"reportedAt": "2022-05-01T21:00:03+00:00",
"comment": "Invalid user joseph from 176.111.173.242 port 53860",
"categories": [18, 22],
"reporterId": 43121,
"reporterCountryCode": "DE",
"reporterCountryName": "Germany"
}
]
}
}
Расшифровка полей
| Поле | Тип | Что означает |
|---|---|---|
total | целое | всего жалоб по адресу внутри окна maxAgeInDays |
page | целое | номер текущей страницы |
count | целое | сколько элементов реально в results на этой странице (на последней может быть меньше perPage) |
perPage | целое | запрошенный размер страницы |
lastPage | целое | номер последней страницы: ceil(total / perPage), минимум 1 |
nextPageUrl | строка или null | готовая ссылка на следующую страницу; null на последней |
previousPageUrl | строка или null | готовая ссылка на предыдущую страницу; null на первой |
results | массив | жалобы, новые первыми |
Поля одной жалобы в results[] совпадают с массивом reports[] в CHECK: reportedAt, comment, categories (целые 1…23), reporterId, reporterCountryCode, reporterCountryName.
Пагинация
- Первая страница —
page=1; нумерация страниц начинается с 1, а не с 0. perPageмаксимум 100. Больше —422. Для больших выгрузок ставьтеperPage=100и идите по страницам.lastPageвычисляется поtotalиperPageвнутри окнаmaxAgeInDays. Если окно меняется между запросами,total(иlastPage) может измениться — это нормально для живых данных.nextPageUrlиpreviousPageUrlможно использовать как есть: они содержат все параметры, включаяipAddressиmaxAgeInDays.- Ответ содержит только опубликованные (публичные) данные жалоб: комментарий, категории, страну репортёра. Персональные данные репортёров не раскрываются —
reporterIdэто внутренний идентификатор.
Ограничения
| Ограничение | Значение |
|---|---|
perPage | 1…100 |
maxAgeInDays | 1…365 |
| Глубина пагинации | ограничена количеством жалоб в окне, а не отдельным лимитом |
| Дневной лимит запросов | по тарифу ключа, см. Лимиты |
| Кэширование | ответы по одному IP и одной странице можно кэшировать на 5–15 минут |
Пример: обойти все страницы
import math
import requests
API_KEY = "YOUR_OWN_API_KEY"
BASE = "https://api.abuseipdb.ru/api/v2"
def all_reports(ip: str, max_age_days: int = 30, per_page: int = 100) -> list[dict]:
headers = {"Key": API_KEY, "Accept": "application/json"}
first = requests.get(
f"{BASE}/reports",
params={"ipAddress": ip, "maxAgeInDays": max_age_days, "page": 1, "perPage": per_page},
headers=headers,
timeout=15,
).json()["data"]
reports = list(first["results"])
last_page = max(1, math.ceil(first["total"] / per_page))
for page in range(2, last_page + 1):
chunk = requests.get(
f"{BASE}/reports",
params={"ipAddress": ip, "maxAgeInDays": max_age_days, "page": page, "perPage": per_page},
headers=headers,
timeout=15,
).json()["data"]
reports.extend(chunk["results"])
return reports
print(len(all_reports("8.8.8.8")))
PHP — та же логика через nextPageUrl:
<?php
function all_reports(string $ip): array
{
$url = 'https://api.abuseipdb.ru/api/v2/reports?' . http_build_query([
'ipAddress' => $ip,
'maxAgeInDays' => 30,
'perPage' => 100,
'page' => 1,
]);
$headers = ['Key: ' . getenv('ABUSEIPDB_KEY'), 'Accept: application/json'];
$reports = [];
while ($url !== null) {
$ch = curl_init($url);
curl_setopt_array($ch, [CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => $headers, CURLOPT_TIMEOUT => 15]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
curl_close($ch);
if ($status !== 200) {
throw new RuntimeException("API v2 HTTP $status: $body");
}
$page = json_decode($body, true)['data'];
$reports = array_merge($reports, $page['results']);
$url = $page['nextPageUrl'];
}
return $reports;
}
Ошибки REPORTS
| Код | Причина | source.parameter |
|---|---|---|
401 | ключ отсутствует/неверен/отозван | — |
422 | не указан ipAddress | ipAddress |
422 | ipAddress не IPv4/IPv6 | ipAddress |
422 | maxAgeInDays вне 1…365 | maxAgeInDays |
422 | page меньше 1 или не целое | page |
422 | perPage вне 1…100 | perPage |
429 | дневной лимит | — |
Примеры тел — Обработка ошибок.
Дальше: Отправить жалобу (REPORT) — как эти жалобы появляются.
Версия 2.2.0 · AbuseIPDB.RU · webmaster@abuseipdb.ru · source: docs/ABUSE-API-reports.md