API Documentation
Comprehensive guide to using the PhishStats API for accessing phishing data
API use is subject to tier quotas and our Terms of Service (including acceptable use limits).
Base URL
https://api.phishstats.info/api/phishing
Authentication & API keys
Read-only endpoints on api.phishstats.info are public, but
daily quotas depend on how you authenticate. Anonymous traffic (no key) is
limited to 50 requests/day per IP. Registered and paid tiers require a psk_* API key
sent on every request.
- Sign in and create an API key (free accounts get 1 key; Premium 2; Enterprise 3).
- Copy the full key when shown. It is displayed only once.
- Send the key as a header on every programmatic call (see example below).
curl -H 'X-API-Key: psk_YOUR_KEY' \
'https://api.phishstats.info/api/phishing?_sort=-id&_p=0&_size=100'
Alternative: Authorization: Bearer psk_… or query
?apikey=psk_… (header preferred).
Subscribing to Premium or Enterprise does not upgrade anonymous IP traffic. You
must send your key. Do not use _apikey=; that prefix is xmysql filter syntax.
Parameters
Filtering
_where=(field,operator,value) Filter results based on field conditions
Operators
eq equals
ne not equals
gt greater than
lt less than
like contains
and logical AND
or logical OR
Sorting
_sort=field Sort by field (use -field for descending order)
Pagination
_p=page_number _size=records_per_page Examples
Basic Queries
By ID
/api/phishing?_where=(id,eq,3296584)
Get specific record by ID
By ASN
/api/phishing?_where=(asn,eq,AS14061)
Get records from specific ASN
By IP Address
/api/phishing?_where=(ip,eq,148.228.16.3)
Get records from specific IP
By Country
/api/phishing?_where=(countrycode,eq,US)
Get records from specific country
By TLD
/api/phishing?_where=(tld,eq,BR)
Get records with specific top-level domain
Advanced Queries
Latest by Date
/api/phishing?_sort=-date
Get most recent records
Title Contains "apple"
/api/phishing?_where=(title,like,apple)&_sort=-id
Search for records with "apple" in title
URL Contains "login"
/api/phishing?_where=(url,like,login)&_sort=-id
Search for records with "login" in URL
Title OR URL Contains "bank"
/api/phishing?_where=(title,like,bank)~or(url,like,bank)&_sort=-id
Search for "bank" in either title or URL
Score > 5 and Country ≠ BR
/api/phishing?_where=(score,gt,5)~and(countrycode,ne,BR)&_sort=-id
High score records not from Brazil
High Score with .com TLD
/api/phishing?_where=(score,gt,8)~and(tld,eq,com)&_sort=-date
High confidence .com domains
Complex Query
/api/phishing?_where=(countrycode,eq,BR)~and(url,like,login)~and(score,gt,4)&_sort=-date
Brazilian login pages with score > 4
Pagination Examples
Page 1, 50 Results
/api/phishing?_p=1&_size=50
Get first 50 records
Page 2, 100 Results
/api/phishing?_p=2&_size=100
Get next 100 records
Recent .xyz Domains
/api/phishing?_where=(tld,eq,xyz)&_sort=-date&_p=1&_size=100
Latest 100 .xyz domain records
Rate Limits
Limits depend on your plan. Anonymous API access is capped at 50 requests per day per IP. Registered free users get 150 API requests per day with an API key, plus per-minute burst limits. Premium and Enterprise plans offer higher daily quotas. See our Pricing page for details. All daily quotas reset at UTC midnight.
PhishStats has offered free API access since 2018. Tiered limits fund infrastructure while keeping research access free. Register for a key before upgrading if you need more than 50 requests/day.
| Tier | API requests / day | Burst (approx.) |
|---|---|---|
| Anonymous (no API key) | 50 / IP | 20 / min |
| Free (registered + API key) | 150 | 120 / min |
| Premium | 1,000 | Higher burst |
| Enterprise | 10,000 | Higher burst |
Authenticate with X-API-Key: psk_… or
Authorization: Bearer psk_….
Create keys at Settings → API keys
after signing in. Prefer webhook monitoring over polling. See
Monitoring alerts.
Query-string auth is supported as ?apikey=psk_… (no underscore).
Do not use _apikey=. That prefix is
xmysql filter syntax, not API authentication. Premium and paid tiers only apply when a valid
psk_* key is sent; unauthenticated requests stay on the anonymous 50/day IP limit.
Handling HTTP 429
When you exceed burst or daily limits, the API returns HTTP 429 Too Many Requests.
Responses include a human-readable error field and structured
metadata to help clients back off or upgrade.
Limit types
burst: too many requests per minute; spread traffic or retry afterRetry-After.anonymous_daily: 50/day without an API key; register for 150/day free.daily: API-key daily quota exhausted; upgrade or wait until UTC midnight.
Example: anonymous daily limit
HTTP/1.1 429 Too Many Requests
Content-Type: application/json
{
"error": "Anonymous daily limit reached (50/day). Register free at phishstats.info for 150 API requests/day with an API key. Quota resets at UTC midnight.",
"limit_type": "anonymous_daily",
"limit": 50,
"register_url": "https://phishstats.info/settings/api-keys",
"upgrade_url": "https://phishstats.info/pricing",
"monitoring_url": "https://phishstats.info/settings/monitoring",
"docs_url": "https://phishstats.info/api-docs",
"quota_resets_at": "2026-06-19T00:00:00.000Z"
} Example: burst rate limit
HTTP/1.1 429 Too Many Requests
Content-Type: application/json
{
"message": "API rate limit exceeded (20/min). Spread requests across time, or upgrade at https://phishstats.info/pricing."
}
Kong burst responses use the message field; daily quota responses use error plus the fields above.
Example: daily quota (API key)
HTTP/1.1 429 Too Many Requests
Content-Type: application/json
{
"error": "Daily API quota reached (150/day). Quota resets at UTC midnight. Upgrade at https://phishstats.info/pricing for higher limits, or use webhook monitoring at https://phishstats.info/settings/monitoring instead of polling.",
"limit_type": "daily",
"limit": 150,
"register_url": "https://phishstats.info/settings/api-keys",
"upgrade_url": "https://phishstats.info/pricing",
"monitoring_url": "https://phishstats.info/settings/monitoring",
"docs_url": "https://phishstats.info/api-docs",
"quota_resets_at": "2026-06-19T00:00:00.000Z"
}
Client recommendation: honor Retry-After, cache results,
avoid polling more often than our 90-minute data refresh cycle, and use
monitoring webhooks
for term-based alerts instead of repeated API queries.
Support
For any questions or support regarding the API, please send an email to [email protected]