Written by: DarkWebSonar Engineering Team
The DarkWebSonar dark web API pulls new leak-site entries into SIEMs, scripts, and dashboards over REST. Endpoints, limits, and filters are on the Dark Web Monitoring API page. API access is on Pro and Enterprise.
Create a key under Profile, then run this:
export DWS_API_KEY="your-key"
curl -s "https://api.darkwebsonar.io/v1/usage" \
-H "X-API-Key: $DWS_API_KEY"
You should see your plan and remaining credits. That call does not spend a credit. Every other call in this guide does.
Base URL is https://api.darkwebsonar.io. Every path starts with /v1. Send the key in the X-API-Key header. Parameter lists live in the API reference.
Pull leak-site entries
curl -sG "https://api.darkwebsonar.io/v1/entries/" \
-H "X-API-Key: $DWS_API_KEY" \
--data-urlencode "discovered_range=24h" \
--data-urlencode "limit=10"
The JSON is { "total", "skip", "limit", "data" }. Each item in data is one feed entry (entry_hash, title, category, threat_actors, victim fields).
Need a file instead?
curl -sG "https://api.darkwebsonar.io/v1/entries/" \
-H "X-API-Key: $DWS_API_KEY" \
--data-urlencode "format=csv" \
--data-urlencode "discovered_range=24h" \
--data-urlencode "limit=200" \
-o entries.csv
CSV still costs one credit. It just uses a separate per-minute cap.
Filter on the request
Do not download 90 days and filter in Python. The API already filters.
curl -sG "https://api.darkwebsonar.io/v1/entries/" \
-H "X-API-Key: $DWS_API_KEY" \
--data-urlencode "time_range=24h" \
--data-urlencode "category=breach" \
--data-urlencode "victim_country_code=US" \
--data-urlencode "limit=10"
Use victim_country_code for ISO codes (US, GB). Repeat a filter to OR values: category=breach&category=ransomware.
Two time fields:
| Query | Clock | Use when |
|---|---|---|
discovered_range |
When we ingested the row | A scheduled job: “what is new since last run” |
time_range |
Source publish date | A historical question: “what happened in this window” |
Windows: 2h, 24h, 7d, 30d, 90d, 180d, 365d, 730d.
A daily poller should use discovered_range. That picks up backfills whose publish date is older than the scrape.
For a chart, count instead of listing:
curl -sG "https://api.darkwebsonar.io/v1/entries/count_by_field" \
-H "X-API-Key: $DWS_API_KEY" \
--data-urlencode "group_by=victim_country" \
--data-urlencode "time_range=30d"
Actor profiles are GET /v1/threat_actor_profiles_enriched/ (there is no /threat_actor_profiles). Pass an id for one profile.
Page the results
limit max is 1000. Advance skip until a page comes back short. Set include_total=false unless you need the count; it is a separate scan.
import os
import time
import requests
URL = "https://api.darkwebsonar.io/v1/entries/"
headers = {"X-API-Key": os.environ["DWS_API_KEY"]}
skip, limit = 0, 100
while True:
r = requests.get(
URL,
headers=headers,
params={
"skip": skip,
"limit": limit,
"discovered_range": "24h",
"include_total": "false",
},
timeout=30,
)
if r.status_code == 429:
time.sleep(int(r.headers.get("Retry-After") or 2))
continue
r.raise_for_status()
rows = r.json()["data"]
for row in rows:
print(row["entry_hash"], row.get("title"))
if len(rows) < limit:
break
skip += limit
Store entry_hash and skip rows you already have. Re-pulling the same window every minute spends credits on nothing new.
Credits
One request is one credit, REST or MCP. Unused credits do not roll over.
| Plan | Credits / month | Standard | CSV |
|---|---|---|---|
| Starter, Growth | No API | n/a | n/a |
| Pro | 1,000 | 120/min | 50/min |
| Enterprise | 5,000 | 600/min | 200/min |
On 429, wait and retry. Watch credits_remaining from /v1/usage so a noisy job does not empty the month.
Skip the poller when you can
- Alerts on monitors you already set: Slack, Teams, PagerDuty, ServiceNow, webhooks.
- A question in an AI client: MCP.
- A script, SIEM load, or dashboard: this API.
Dark web API questions
What does the DarkWebSonar API return?
It returns dark web and leak-site intelligence as JSON or CSV, including a stable entry_hash, title, category, threat actor, source date, severity, and victim context where available.
Which time filter should a scheduled integration use?
Use discovered_range. It tracks when DarkWebSonar ingested an entry, so a scheduled pull also catches older posts discovered after their source publish date.
Does a CSV export use API credits?
Yes, when you request CSV from the API (format=csv). That costs one credit per request and uses the CSV rate-limit bucket. CSV downloads inside the platform do not use API credits.
Should I use REST, a webhook, or MCP?
Use REST for scheduled ingestion and dashboards, a webhook integration for monitor alerts, and MCP for questions in a compatible AI client.