Retrieve paginated leak details with optional search
Retrieve paginated, deduplicated leak details for the current organization.
Results are deduplicated by hash: each unique credential (username + password + domain) appears once, with aggregated metadata from all occurrences.
Specific Parameters:
| Parameter | Default | Description |
|---|---|---|
identifier_column | required | root_domain, email_domain, or username |
page | 1 | Page number |
page_size | 50 | Items per page (max: 200) |
search | - | Full-text search across username, host, domain, email_domain, root_domain, ip_address, computer_name, machine_user |
sort_by | source_count | Sort order: source_count (most seen first) or last_seen (most recent first) |
min_occurrences | - | Only return credentials seen in N+ distinct sources |
Plus all standard filters (see API description above).
Response Fields:
| Field | Type | Description |
|---|---|---|
username | string | Username or email. The local part (before the @) is not returned separately, derive it client-side if needed |
password | string | Masked password: first and last character, one * per character in between (starred whole under 6 characters). See unmask for the clear value |
types | string[] | All distinct leak types for this credential, e.g. ["Combo", "Stealer"]. A credential found in both Combo dumps and Stealer logs will have both values. |
type | string | Deprecated (flagged in the schema). Single type value, the most recent ingestion's. Use types. |
last_seen | datetime | Most recent detection date (aggregated max(upload_stealed) across all occurrences) |
upload_date | datetime | Deprecated (flagged in the schema). Source file publication date. Duplicates last_seen on the default per-hash read; use last_seen |
log_date | datetime | Infostealer log creation date, as declared by the malware: sparse and partly bogus (see the note below). Representative value |
first_seen | datetime | Earliest detection date (min(first_seen), the credential's global first discovery, NOT min(upload_stealed): it can predate this tenant's earliest occurrence) |
source_count | int | Deprecated (flagged in the schema). Legacy proxy metric uniq(file_name, stealer_name, country). Prefer sources/occurrences/files. |
sources | int | Number of distinct sources reporting this credential (uniqExactIf(telegram_channel), floored by the backfill HLL snapshot and by 1), from leaks_matched |
occurrences | int | Number of distinct (source, file) detections all-time (uniqExact((telegram_channel, file_name))) for this credential |
files | int | Number of distinct named files (uniqExactIf(file_name, going-forward)) this credential was found in |
domain | string | Associated domain |
host | string | Full URL or host |
email_domain | string | Email domain part |
root_domain | string | Root domain |
country | string | ISO 2-letter country code. Representative value (see note below) |
stealer_name | string | Stealer family (RedLine, Raccoon, etc.). Representative value |
software | string | Browser/app. Representative value |
protocol | string | Protocol (https, android, ...). Representative value |
ip_address | string | Victim IP address. Representative value |
computer_name | string | Machine name. Representative value |
machine_id | string | Machine id. Representative value |
machine_user | string | Machine user account. Representative value |
hardware_id | string | Hardware id. Representative value |
log_date | datetime | Date of the infostealer log. Representative value |
countries | string[] | EVERY country this credential was seen from |
stealers | string[] | EVERY stealer family |
softwares | string[] | EVERY browser/app |
protocols | string[] | EVERY protocol |
hosts | string[] | EVERY host, normalised to a bare hostname |
ip_addresses | string[] | EVERY victim IP |
machine_users | string[] | EVERY machine user account |
computer_names | string[] | EVERY machine name |
machine_ids | string[] | EVERY machine id |
hardware_ids | string[] | EVERY hardware id |
hash | string | Unique deduplication hash |
Note: Results are deduplicated by hash. The raw upload_stealed column is not returned directly.
Instead, first_seen and last_seen are computed as min(upload_stealed) and max(upload_stealed) across all occurrences of each credential.
About log_date. It is written by the malware inside the stealer log, not
by us: only ~0.2% of raw occurrences carry one (~44% of credentials once
aggregated), and a few are dated in the future. Treat it as indicative.
Representative values vs sets. One credential (hash) is typically seen in
several infostealer logs, and the machine-level values can differ between them.
Each such field is returned twice: the singular field (software, country,
ip_address, ...) carries ONE representative value, the most recent occurrence's,
and the plural field (softwares, countries, ip_addresses, ...) carries the
deduplicated set of EVERY value seen across all occurrences. Empty values are
dropped, so a Combo-only credential returns [] and never [""]. A credential
seen in three logs from three countries returns "country": "FR" and
"countries": ["FR", "MX", "ID"].
These sets are materialised per credential in the read model, so they cost
nothing extra to return. What they do NOT give is the pairing between values
(which IP went with which browser, on which date): for that, call
GET /leaks/details/occurrences?hash=..., which returns every (source, file)
detection with its own machine metadata.
Response Format:
{
"data": [
{
"username": "user@example.com",
"password": "p****d",
"types": ["Stealer"],
"type": "Stealer",
"first_seen": "2025-01-15T08:30:00",
"last_seen": "2025-03-01T12:00:00",
"host": "login.example.com",
"domain": "login.example.com",
"protocol": "https",
"email_domain": "example.com",
"root_domain": "example.com",
"upload_date": "2025-02-28T10:00:00",
"log_date": "2025-02-27T14:00:00",
"machine_id": "DESKTOP-ABC1234",
"computer_name": "LAPTOP-XYZ",
"hardware_id": "hwid-1234-5678",
"machine_user": "john.doe",
"ip_address": "192.168.1.10",
"country": "FR",
"software": "chrome, profile: 0",
"stealer_name": "RedLine",
"countries": ["FR", "BE"],
"stealers": ["RedLine", "Lumma"],
"softwares": ["chrome, profile: 0", "Opera GX, Profile: 0"],
"protocols": ["https"],
"hosts": ["login.example.com"],
"ip_addresses": ["192.168.1.10", "10.0.0.4"],
"machine_users": ["john.doe"],
"computer_names": ["LAPTOP-XYZ"],
"machine_ids": ["DESKTOP-ABC1234"],
"hardware_ids": ["hwid-1234-5678"],
"hash": "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4",
"source_count": 3,
"sources": 2,
"occurrences": 3,
"files": 3
}
],
"total": 12345,
"page": 1,
"page_size": 50,
"total_pages": 247
}Examples:
# Basic paginated request
GET /leaks/details?identifier_column=root_domain&page=1&page_size=50
# Sort by most recent
GET /leaks/details?identifier_column=root_domain&sort_by=last_seen
# Sort by number of distinct sources (leaks_matched-derived)
GET /leaks/details?identifier_column=root_domain&sort_by=sources
# Only credentials seen 3+ times
GET /leaks/details?identifier_column=root_domain&min_occurrences=3
# Full-text search with filters
GET /leaks/details?identifier_column=root_domain&search=john&type=Stealer&country=FR
# Custom date range
GET /leaks/details?identifier_column=root_domain&start_date=2024-01-01&end_date=2024-12-31&page_size=200Pagination (retrieve all results):
# Page 1
GET /leaks/details?identifier_column=root_domain&page=1&page_size=200
# Page 2
GET /leaks/details?identifier_column=root_domain&page=2&page_size=200
# ... continue until page >= total_pagesAuthorization
ApiKeyAuth API key for authentication
In: header
Query Parameters
Column to use for identifying the domain. Use 'all' for the cockpit cross-scope view (External + Internal union, dedup by hash).
"root_domain" | "email_domain" | "username" | "all"Page number
11 <= valueItems per page (max 200)
501 <= value <= 200Search term for full-text filtering
length <= 200Column to sort on. source_count is the legacy default (most-seen first). Other supported columns: last_seen, first_seen, username, host, sources (distinct sources from leaks_matched), occurrences (distinct source+file detections).
"source_count""source_count" | "last_seen" | "first_seen" | "username" | "host" | "sources" | "occurrences"Sort direction: desc (default) or asc.
"desc""asc" | "desc"Multi-select scope filter (repeat the query param for several values). external/internal filter on match_type (root_domain / email_domain) and only apply to the leaks_matched_* tables — raw leaks ignores them. stealer/combo filter on type. Within each pair, selecting both is treated as no filter (the union is the full set). An empty list means no scope filter.
Leak counting mode: 'new' counts only credentials first discovered in the period, 'all' counts any credential with at least one occurrence in the period.
"new""new" | "all"Workspace-only: when set together with tenant_id_override, force the redacted preview path (querying leaks_history) scoped to a single domain. Used to preview a pending domain BEFORE running the backfill.
length <= 253Return passwords in CLEAR instead of masked. Three conditions, all required: an API key must carry the leaks:secrets scope (a JWT caller must hold the org ADMIN role instead -- a member reads what happens, he does not walk out with his colleagues' credentials), and each credential's own domain must have proved its DNS ownership or been granted access by Stealed. Rows whose domain did neither stay masked in the same response — this is decided per row, not per request. Every call that actually returns cleartext is written to the access journal as a sensitive read.
When the answer comes back fully masked anyway, the response carries password_lock_reason saying which condition was not met: domain_not_open (no domain here proved its DNS or was granted access), caller_not_admin (reading a password in clear is an admin act; an API key counts as one), client_consent_missing, partner_not_admin or tenant_referenced.
falseUsername of the leaked user (can be phone, email, ID, ...)
Type of leak (combo, stealer)
Uniq identifier for the concatenation of : username, password and domain
Upload date on stealed, ISO 8601, pattern YYYY-MM-DD
Upload date on the plateform the credential was found, ISO 8601, pattern YYYY-mm-dd
Log date of the device at compromized moment (if applicable, stealer only)
Start date to search from leaks, format: YYYY-mm-dd (default: today - 14days at 0:00am)
End date to search leaks from, format YYYY-mm-dd (default: today)
URL of the leaked data
FQDN of the leaked data
Local part of the username section (if applicable, email only)
Protocol identified (if applicable)
Email domain to filter on (if multiple email domains declared)
Root domain to filter on (if multiple root domains declared)
Machine ID (if applicable, stealer only)
Computer name (if applicable, stealer only)
Hardware ID (if applicable, stealer only)
Machine user (if applicable, stealer only)
IP address (if applicable, stealer only)
Country (if applicable, stealer only)
Software (if applicable, stealer only)
Stealer name (if applicable)
Opaque source label(s) to filter on, of the form Source-<6 hex> (as returned by the sources breakdown). The raw telegram_channel is never exposed: the label is matched back against the same MD5-prefix expression server-side.
Keyword to filter on (only active keywords for tenant)
Match type for leaks_matched table (root_domain or email_domain)
Root domains to exclude (NOT IN filter)
Email domains to exclude (NOT IN filter)
Domains to exclude (NOT IN filter)
Types to exclude
Software to exclude
Stealer names to exclude
Protocols to exclude
Countries to exclude
Show only hashes whose first appearance (min upload_stealed) falls on this exact date. Format: YYYY-MM-DD.
Show only hashes whose first appearance (min upload_stealed) is on or after this date. Format: YYYY-MM-DD.
Limit result length
Minimum number of sources (source_count >= N)
Response Body
application/json
application/json
curl -X GET "https://api.stealed.io/leaks/details?identifier_column=root_domain"{
"data": [
{
"username": "string",
"password": "string",
"hash": "string",
"password_locked": true,
"domain": "string",
"root_domain": "string",
"email_domain": "string",
"first_seen": "2019-08-24T14:15:22Z",
"last_seen": "2019-08-24T14:15:22Z",
"upload_date": "2019-08-24T14:15:22Z",
"log_date": "2019-08-24T14:15:22Z",
"types": [
"string"
],
"type": "string",
"scope": "string",
"host": "string",
"country": "string",
"stealer_name": "string",
"software": "string",
"protocol": "string",
"ip_address": "string",
"computer_name": "string",
"machine_id": "string",
"machine_user": "string",
"hardware_id": "string",
"hosts": [
"string"
],
"countries": [
"string"
],
"stealers": [
"string"
],
"softwares": [
"string"
],
"protocols": [
"string"
],
"ip_addresses": [
"string"
],
"computer_names": [
"string"
],
"machine_ids": [
"string"
],
"machine_users": [
"string"
],
"hardware_ids": [
"string"
],
"sources": 0,
"occurrences": 0,
"files": 0,
"source_count": 0,
"tenant_id": "string",
"tenant_name": "string"
}
],
"total": 0,
"page": 0,
"page_size": 0,
"total_pages": 0,
"preview": true,
"redacted": true
}{
"detail": [
{
"loc": [
"string"
],
"msg": "string",
"type": "string"
}
]
}Retrieve all leak statistics in a single request GET
Retrieve all leak statistics for the current organization in a single request. This endpoint fetches all leak data once and calculates multiple statistics server-side, reducing the number of queries needed. If `start_date` and `end_date` are not provided, defaults to **the last 14 days**. Includes trend data comparing the current period to the previous period of the same length (e.g. if querying 30 days, trends compare to the 30 days before that). **Returns a dictionary with the following statistics:** - `total_leaks`: Total number of leaks - `unique_usernames`: Number of unique usernames - `unique_domains`: Number of unique domains - `unique_passwords`: Number of unique passwords - `unique_leaks`: Number of unique leak hashes - `leaks_by_type`: Number of leaks grouped by type (combo/stealer) - `leaks_by_day`: Number of leaks grouped by day and identifier (limited globally to 10 top identifiers + other) - `leaks_by_domain`: Number of leaks grouped by domain (limited globally to 10 top domains + other) - `leaks_by_domain_all`: Number of leaks grouped by domain (all domains, no limit) - `leaks_by_inverse_identifier`: Number of leaks grouped by the inverse identifier (email_domain if root_domain, or vice-versa) (limited globally to 10 top + other) - `top_domains`: Top domains with most leaks (limited globally to 10) - `top_users`: Top users with most leaks (all users, no limit) - `password_strength`: Average password length - `password_reuse`: Number of reused passwords - `password_length_distribution`: Distribution of passwords by length - `external_accounts`: Detailed list of external accounts (username, masked password, type, domain, upload_stealed; capped at 50, most recent first) - `external_accounts_count`: Total count of external accounts - `admin_accounts`: Detailed list of admin/privileged accounts (same shape as `external_accounts`; capped at 50, most recent first) - `admin_accounts_count`: Total count of admin accounts - `unique_sources`: Total number of unique sources (opaque count, channel identity not exposed) - `sources`: List of sources with leak counts (all sources, no limit) - `latest_leak_date`: Date of the latest leak - `leak_details`: All leak details (same as org_leaks_detail_per_identifier, limited to 20000) - `leaks_by_country`: Top 50 countries by leak count (non-empty only) - `leaks_by_stealer_name`: Top 50 stealer families by leak count (non-empty only) - `leaks_by_software`: Top 50 software/browsers by leak count (non-empty only) - `leaks_by_computer_name`: Top 30 computer names by leak count (non-empty only) **Trend Fields** (percentage change vs previous period of same length): - `total_leaks_trend`, `unique_usernames_trend`, `unique_domains_trend` - `unique_sources_trend`, `admin_accounts_count_trend`, `external_accounts_count_trend` **Examples:** ```bash # All stats for the last 14 days (default) GET /leaks/stats?identifier_column=root_domain # With custom date range GET /leaks/stats?identifier_column=root_domain&start_date=2024-01-01&end_date=2024-12-31 # With filters GET /leaks/stats?identifier_column=root_domain&type=Stealer&country=FR ```
Retrieve all occurrences of a specific leak by hash GET
Retrieve all individual occurrences (raw records) for a specific leak hash. Use this after `/leaks/details` to drill down into a deduplicated leak and see every source where the credential was found. **Parameters:** - `hash` (required): The leak hash from the `/leaks/details` response - `identifier_column` (required): `root_domain`, `email_domain`, or `username` **Response:** ```json { "data": [ { "type": "Stealer", "username": "user@example.com", "password": "p****d", "domain": "example.com", "upload_stealed": "2025-01-15T10:30:00", "upload_date": "2025-01-14T08:00:00", "stealer_name": "RedLine", "country": "FR", "ip_address": "1.2.3.4", "computer_name": "DESKTOP-ABC", "software": "Chrome" }, ... ] } ``` **Example:** ```bash GET /leaks/details/by-hash?hash=5d41402abc4b2a76b9719d911017c592&identifier_column=root_domain ```