Массовые жалобы (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