Tutorial · Threat API · Free key
Sync a blocklist to DNS or your firewall
Keep a local copy of every active confirmed-abuse domain for a DNS resolver, firewall, proxy or Pi-hole.
1Simple: download the feed
The text feed has one active domain per line. A free key may download feeds 24 times a day, so hourly is fine.
# /etc/cron.hourly/fraudpol-feed
curl -fsS "https://ugapgzpffrykyglevlhz.supabase.co/functions/v1/threat-api/v1/feed.txt" -H "X-API-Key: $FP_KEY" \
-o /etc/blocklists/fraudpol.txt.new \
&& mv /etc/blocklists/fraudpol.txt.new /etc/blocklists/fraudpol.txtUse /v1/feed.json for a JSON array instead.
2Advanced: incremental sync
For large deployments, fetch only what changed. Keep since fixed while following next_cursor until it is null, then remember the newest updated_at for the next run. A change with listed: false removes a domain.
import os, requests
BASE = "https://ugapgzpffrykyglevlhz.supabase.co/functions/v1/threat-api"
H = {"X-API-Key": os.environ["FP_KEY"]}
def sync(since, blocklist):
cursor, newest = "", since
while True:
r = requests.get(BASE + "/v1/domains", headers=H, timeout=30,
params={"since": since, "cursor": cursor, "limit": 1000})
r.raise_for_status()
page = r.json()
for c in page["changes"]:
if c.get("listed") and c.get("status") == "active":
blocklist.add(c["domain"])
else:
blocklist.discard(c["domain"])
newest = max(newest, c.get("updated_at", newest))
cursor = page["next_cursor"]
if not cursor:
return newest # store and pass as since next timeAttribution: free use requires showing Data: Fraudpol where the data is presented to people.
