Тема
Войти Регистрация

Жалобы по 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нет301…365окно: только жалобы не старше N дней
pageнет1≥ 1номер страницы, начиная с 1
perPageнет251…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 это внутренний идентификатор.

Ограничения

ОграничениеЗначение
perPage1…100
maxAgeInDays1…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не указан ipAddressipAddress
422ipAddress не IPv4/IPv6ipAddress
422maxAgeInDays вне 1…365maxAgeInDays
422page меньше 1 или не целоеpage
422perPage вне 1…100perPage
429дневной лимит—

Примеры тел — Обработка ошибок.

Дальше: Отправить жалобу (REPORT) — как эти жалобы появляются.

Версия 2.2.0 · AbuseIPDB.RU · webmaster@abuseipdb.ru · source: docs/ABUSE-API-reports.md