# Porting notes

Reference: official `AbuseIPDB/laravel` annotated tag `2.0.1`, peeled commit `554d8ef4180233cd6b0fa40f34bec3e42d900c2a`, compared with current AbuseIPDB API v2 documentation on 2026-07-31.

| Laravel 2.0.1 | Python 0.1.0 |
|---|---|
| `AbuseIPDBLaravel` | `AbuseIPDB` |
| facade | normal imported client instance |
| service provider | not applicable |
| `config()` and `.env` | constructor plus `ABUSEIPDB_API_KEY`/`ABUSEIPDB_URL` environment variables |
| Illuminate HTTP client | synchronous `httpx.Client` |
| `ENDPOINTS` | immutable `ENDPOINTS` mapping |
| `CATEGORIES` | `AbuseCategory` plus immutable `CATEGORIES` |
| response objects | frozen, slotted dataclasses |
| extra response classes | nested model dataclasses |
| PHP exceptions | `AbuseIPDBError` hierarchy |
| `DateTime` | timezone-aware `datetime.datetime` |
| camelCase methods/properties | snake_case public API |
| `AbuseIPDBExceptionReporter` | opt-in framework-neutral helper |
| Composer/Packagist | `pyproject.toml`/PyPI |
| PHPUnit/Testbench | pytest and `httpx.MockTransport` |

## Endpoint mapping

`check` GET, `reports` GET, `blacklist` GET, `report` POST, `check-block` GET, `bulk-report` POST, and `clear-address` DELETE match upstream map. Public method names are `check`, `reports`, `blacklist`, `report`, `check_block`, `bulk_report`, and `clear_address`; wire field names stay API camelCase.

## Deliberate API-correct differences

- Laravel release metadata says `2.0.1`, while `config/abuseipdb.php` still embeds `1.0.11` in `X-Request-Source`. Python has one version source, `abuseipdb.__version__`, and emits `Python_<runtime>;AbuseIPDB-Python_0.1.0;`.
- Python explicitly sends report and clear-address parameters as form data following current API examples. GET operations use query parameters.
- Laravel passes arrays for categories/countries through Illuminate. Python deterministically sends documented comma-separated values.
- Laravel README says `bulkReport('bulk-report.csv')`, but source names argument `$csvFileContents` and uploads contents. Python accepts `str | bytes` contents and avoids ambiguous path detection.
- Laravel `ReportsPaginatedResponse` declares `count` but never assigns it. Python maps documented `data.count`.
- Laravel response base requires several headers through typed properties. Python makes metadata headers optional because intermediaries can omit them; rate-limit strings become integers when present.
- Current docs say plaintext generation time is `X-Generated-At`; dedicated Python plaintext response requires it and removes blank trailing lines from address sequence.
- Current docs allow IPv4/IPv6 address and CIDR values. Like Laravel, Python leaves semantic IP/network validation to API and only URL-encodes transport parameters.
- Current docs do not define useful fixed maximum for subscriber-dependent blacklist `limit`; Python preserves Laravel's lack of client validation.

## Framework-only behavior

Laravel service discovery, facade static calls, local-environment TLS verification toggle, and automatic Symfony exception pipeline are not reproduced. Generic Python has no matching lifecycle. Core client is explicit and always uses normal `httpx` TLS verification. Reporter helper contains only meaningful upstream behavior: category 21, request-context comment, and error suppression.

Distribution identity (`abuseipdb-python-sdk`) lives only in packaging/docs. Import namespace and core classes contain no personal branding, preserving later officialization path.
