Retrieve all occurrences of a specific leak by hash
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/detailsresponseidentifier_column(required):root_domain,email_domain, orusername
Response:
{
"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:
GET /leaks/details/by-hash?hash=5d41402abc4b2a76b9719d911017c592&identifier_column=root_domainAuthorization
ApiKeyAuth API key for authentication
In: header
Query Parameters
The leak hash to look up
Column to use for identifying the domain
"root_domain" | "email_domain" | "username"Response Body
application/json
application/json
curl -X GET "https://api.stealed.io/leaks/details/by-hash?hash=string&identifier_column=root_domain"null{
"detail": [
{
"loc": [
"string"
],
"msg": "string",
"type": "string"
}
]
}Retrieve paginated leak details with optional search GET
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:** ```json { "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:** ```bash # 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=200 ``` **Pagination (retrieve all results):** ```bash # 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_pages ```
Reveal one credential's password, and record that it was read GET
The password behind a hash, in clear, for a credential belonging to the calling organisation. Every other endpoint returns it masked. This one does not, which is why it is the one act in the product that writes to the access journal as `sensitive`: a client asking a year later who read his collaborators' passwords gets an answer with a name, a time and an IP. Scoped like every other read: a hash belonging to another organisation returns 404, never someone else's secret.