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

Массовые жалобы (BULK-REPORT)

POST https://api.abuseipdb.ru/api/v2/bulk-report — отправить до 10 000 жалоб одним CSV-файлом. Удобно, когда список адресов уже есть в логах: выгрузите IP,Categories,ReportDate,Comment и отправьте файл целиком.

Раздел «API v2»: Обзор · Проверка IP (CHECK) · Жалобы по IP (REPORTS) · Отправить жалобу (REPORT) · Чёрный список (BLACKLIST) · Проверка подсети (CHECK-BLOCK) · Массовые жалобы (BULK-REPORT) · Удаление жалоб (CLEAR-ADDRESS) · Лимиты · Ошибки · Fail2Ban, CSF, Suricata · FAQ

Формат CSV

Первая строка — заголовок, затем по одной жалобе в строке:

IP,Categories,ReportDate,Comment
41.188.138.68,18,2023-10-18T11:25:11-04:00,"SSH login attempts with user root"
189.87.146.50,18,2023-10-18T11:26:02-04:00,"Failed password for admin"
203.0.113.7,14,2023-10-18T11:30:00-04:00,"Port scan on 22,80,443"
КолонкаОбязательнаЧто содержит
IPдаадрес нарушителя, IPv4 или IPv6
Categoriesдаидентификаторы категорий 1…23 через запятую; несколько значений — в кавычках: "18,22", потому что запятая разделяет колонки CSV
ReportDateнетвремя инцидента ISO 8601; пусто — текущее время
Commentнеттекст жалобы; в кавычках, если содержит запятую; до 1024 символов

Правила: регистр имён колонок не важен (IP, ip, Ip), лишние колонки игнорируются, порядок колонок произволен. Файл — UTF-8. Пустые строки пропускаются. Заголовок обязателен и должен содержать колонку IP (без этого — 422 с source.parameter=csv).

IP,Categories,ReportDate,Comment
41.188.138.68,18,2023-10-18T11:25:11-04:00,"SSH login attempts with user root"
189.87.146.50,"18,22",2023-10-18T11:26:02-04:00,"Failed password for admin"
203.0.113.7,14,,Port scan

Отправка

# POST multipart/form-data: файл в поле csv
curl https://api.abuseipdb.ru/api/v2/bulk-report \
  -F csv=@report.csv \
  -H "Key: YOUR_OWN_API_KEY" \
  -H "Accept: application/json"

Кроме multipart принимаются ещё два варианта тела (расширение AbuseIPDB.RU). Метод GET тоже принимается как отладочный алиас POST.

# application/json: содержимое CSV строкой
curl https://api.abuseipdb.ru/api/v2/bulk-report \
  -H "Content-Type: application/json" \
  -H "Key: YOUR_OWN_API_KEY" \
  -H "Accept: application/json" \
  --data '{"csv":"IP,Categories,ReportDate,Comment\n89.205.125.160,18,2026-11-07T02:00:00+00:00,SSH brute-force"}'

# application/x-www-form-urlencoded: поле csv
curl https://api.abuseipdb.ru/api/v2/bulk-report \
  -H "Key: YOUR_OWN_API_KEY" \
  -H "Accept: application/json" \
  --data-urlencode "csv@report.csv"

Ограничения

ОграничениеЗначение
Строк в CSVдо 10 000 (без учёта заголовка)
Размер тела запроса8 МБ — платформенный предел; при превышении 413/422
Дедупликацията же, что у одиночной жалобы: один репортёр + один IP не чаще раза в 15 минут; дубли внутри файла отбрасываются
Дневной лимитсчитается как один запрос на ключ, но лимит строк — 10 000 за запрос
Валидациякаждая строка проверяется отдельно; невалидные попадают в invalidReports, остальные сохраняются

Ответ

{
  "data": {
    "savedReports": 60,
    "invalidReports": [
      {
        "error": "Duplicate IP",
        "input": "41.188.138.68",
        "rowNumber": 5
      },
      {
        "error": "Invalid IP",
        "input": "127.0.foo.bar",
        "rowNumber": 6
      },
      {
        "error": "Invalid Category",
        "input": "189.87.146.50",
        "rowNumber": 8
      }
    ],
    "errors": [
      {
        "row": 5,
        "error": "Duplicate IP",
        "input": "41.188.138.68"
      }
    ]
  }
}
ПолеЧто означает
savedReportsсколько жалоб успешно сохранено
invalidReportsмассив отклонённых строк в формате AbuseIPDB: error, input, rowNumber
invalidReports[].errorпричина: Invalid IP, Invalid Category, Duplicate IP, Invalid Date, Missing IP
invalidReports[].inputзначение, которое не удалось принять (обычно адрес)
invalidReports[].rowNumberномер строки в CSV, начиная с 1; строка с заголовком — первая
errorsрасширение AbuseIPDB.RU: тот же список отклонённых строк плоским массивом с полем row вместо rowNumber (удобно для скриптов)

Если какие-то строки отклонены, запрос всё равно отвечает 200: частичный успех — это успех. Проверяйте savedReports и invalidReports.

Как избежать отказов

  • Проверьте CSV локально: адрес разбирается как IPv4/IPv6 (filter_var($ip, FILTER_VALIDATE_IP) в PHP, ipaddress.ip_address() в Python), категории — целые 1…23.
  • Не отправляйте один и тот же адрес от одного репортёра дважды за 15 минут: второй раз придёт Duplicate IP.
  • Локальные, приватные и служебные адреса в CSV отбрасываются построчно в invalidReports с ошибкой Invalid IP: жаловаться можно только на публичные адреса. Повторная строка с тем же IP от одного репортёра попадает туда же как Duplicate IP.
  • Даты в ReportDate — ISO 8601 или пусто. Строка «вчера» даст Invalid Date.
  • Разбивайте файл на части по 5 000 строк: так проще отлаживать и видеть, какая часть отклонена.
  • Комментарии должны быть без персональных данных (см. REPORT), иначе жалоба может быть удалена по takedown-запросу.

Пример генерации и отправки

Python:

import csv
import requests

API_KEY = "YOUR_OWN_API_KEY"
BASE = "https://api.abuseipdb.ru/api/v2"

rows = [
    {"IP": "89.205.125.160", "Categories": "18,22", "ReportDate": "2026-11-07T02:00:00+00:00", "Comment": "SSH brute-force"},
    {"IP": "197.156.104.113", "Categories": "14", "ReportDate": "2026-11-07T02:01:00+00:00", "Comment": "Port scan"},
]

with open("report.csv", "w", encoding="utf-8", newline="") as handle:
    writer = csv.DictWriter(handle, fieldnames=["IP", "Categories", "ReportDate", "Comment"])
    writer.writeheader()
    writer.writerows(rows)

with open("report.csv", "rb") as handle:
    response = requests.post(
        f"{BASE}/bulk-report",
        files={"csv": ("report.csv", handle, "text/csv")},
        headers={"Key": API_KEY, "Accept": "application/json"},
        timeout=120,
    )

response.raise_for_status()
data = response.json()["data"]
print("сохранено:", data["savedReports"])
for row in data.get("invalidReports", []):
    print(f'строка {row["rowNumber"]}: {row["error"]} — {row["input"]}')

PHP:

<?php
$file = new CURLFile('report.csv', 'text/csv', 'report.csv');
$ch = curl_init('https://api.abuseipdb.ru/api/v2/bulk-report');
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_POSTFIELDS => ['csv' => $file],
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => ['Key: ' . getenv('ABUSEIPDB_KEY'), 'Accept: application/json'],
    CURLOPT_TIMEOUT => 120,
]);
$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");
}
$data = json_decode($body, true)['data'];
printf("сохранено: %d\n", $data['savedReports']);
foreach ($data['invalidReports'] ?? [] as $row) {
    printf("строка %d: %s — %s\n", $row['rowNumber'], $row['error'], $row['input']);
}

Ошибки BULK-REPORT

КодПричинаТело/параметр
401ключ отсутствует/неверен/отозван—
422не передан файл/поле csv{"errors":[{"detail":"The csv field is required.","status":422,"source":{"parameter":"csv"}}]}
422в заголовке нет колонки IP{"errors":[{"detail":"The csv must have a header row containing IP,Categories,ReportDate,Comment.","status":422,"source":{"parameter":"csv"}}]}
422больше 10 000 строк{"errors":[{"detail":"The csv must not contain more than 10000 rows.","status":422,"source":{"parameter":"csv"}}]}
413/422тело больше 8 МБ—
429дневной лимит—

Обратите внимание: ошибки отдельных строк не меняют HTTP-код ответа — смотрите invalidReports. Полный список конвертов — Обработка ошибок.

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