Paginated, count-sorted distinct-value breakdown for a KPI tile drill-down

GET
/leaks/breakdown

Drill into a KPI tile (Total Users / Total Domains / Total Sources) with a server-paginated, count-sorted list of distinct values. Reuses the exact same tenant scoping as GET /leaks/details: results come from the tenant-routed leaks_matched_* table, restricted to the org's active domains, plus all standard DynamicFilters (dates, type, domain, not_domain, country, etc.).

Parameters:

ParameterDefaultDescription
fieldrequiredusername, domain, or source
identifier_columnrequiredroot_domain, email_domain, username, or all
page1Page number
page_size50Items per page (max 200)
search-Substring filter on the returned value
leak_modenewnew (first-seen in period) or all (any occurrence in period) -- must match the /leaks/stats KPI tile being drilled into

domain only counts round-trippable hostnames (drops base64 "email-blob" parsing garbage), matching the Insights domain pie. source emits an opaque label (Source-<md5 prefix>) -- the real channel name never leaves the API.

Response:

{
  "data": [{"value": "[email protected]", "count": 42}],
  "total": 118,
  "page": 1,
  "page_size": 50,
  "total_pages": 3
}

total is the number of distinct field values matching the filters -- the same figure as the corresponding /leaks/stats KPI (unique_usernames / unique_domains / unique_sources).

Example:

GET /leaks/breakdown?field=domain&identifier_column=root_domain&page=1&page_size=50

Authorization

ApiKeyAuth
X-API-Key<token>

API key for authentication

In: header

Query Parameters

field*Field

KPI dimension to break down

Value in"username" | "domain" | "source"
identifier_column*Identifier Column

Column to use for identifying the domain

Value in"root_domain" | "email_domain" | "username" | "all"
page?Page

Page number

Default1
Range1 <= value
page_size?Page Size

Items per page (max 200)

Default50
Range1 <= value <= 200
search?Search

Substring filter on the returned value

Lengthlength <= 200
leak_mode?Leak Mode

Leak counting mode: 'new' counts only credentials first discovered in the period, 'all' counts any credential with at least one occurrence in the period. Must match the mode used for the /leaks/stats KPI tile being drilled into.

Default"new"
Value in"new" | "all"
username?|array<string>|

Username of the leaked user (can be phone, email, ID, ...)

type?|array<string>|

Type of leak (combo, stealer)

hash?|array<string>|

Uniq identifier for the concatenation of : username, password and domain

upload_stealed?||array<|string>|

Upload date on stealed, ISO 8601, pattern YYYY-MM-DD

upload_date?||array<|string>|

Upload date on the plateform the credential was found, ISO 8601, pattern YYYY-mm-dd

log_date?||array<|string>|

Log date of the device at compromized moment (if applicable, stealer only)

start_date?||

Start date to search from leaks, format: YYYY-mm-dd (default: today - 14days at 0:00am)

end_date?||

End date to search leaks from, format YYYY-mm-dd (default: today)

host?|array<string>|

URL of the leaked data

domain?|array<string>|

FQDN of the leaked data

local_part?|array<string>|

Local part of the username section (if applicable, email only)

protocol?|array<string>|

Protocol identified (if applicable)

email_domain?|array<string>|

Email domain to filter on (if multiple email domains declared)

root_domain?|array<string>|

Root domain to filter on (if multiple root domains declared)

machine_id?|array<string>|

Machine ID (if applicable, stealer only)

computer_name?|array<string>|

Computer name (if applicable, stealer only)

hardware_id?|array<string>|

Hardware ID (if applicable, stealer only)

machine_user?|array<string>|

Machine user (if applicable, stealer only)

ip_address?|array<string>|

IP address (if applicable, stealer only)

country?|array<string>|

Country (if applicable, stealer only)

software?|array<string>|

Software (if applicable, stealer only)

stealer_name?|array<string>|

Stealer name (if applicable)

source?|array<string>|

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?|array<string>|

Keyword to filter on (only active keywords for tenant)

match_type?|array<string>|

Match type for leaks_matched table (root_domain or email_domain)

not_root_domain?|array<string>|

Root domains to exclude (NOT IN filter)

not_email_domain?|array<string>|

Email domains to exclude (NOT IN filter)

not_domain?|array<string>|

Domains to exclude (NOT IN filter)

not_type?|array<string>|

Types to exclude

not_software?|array<string>|

Software to exclude

not_stealer_name?|array<string>|

Stealer names to exclude

not_protocol?|array<string>|

Protocols to exclude

not_country?|array<string>|

Countries to exclude

first_seen_date?|

Show only hashes whose first appearance (min upload_stealed) falls on this exact date. Format: YYYY-MM-DD.

first_seen_since?|

Show only hashes whose first appearance (min upload_stealed) is on or after this date. Format: YYYY-MM-DD.

limit?|

Limit result length

min_occurrences?|

Minimum number of sources (source_count >= N)

Response Body

application/json

application/json

curl -X GET "https://api.stealed.io/leaks/breakdown?field=domain&identifier_column=root_domain"
{
  "data": [
    {
      "count": 42,
      "value": "[email protected]"
    },
    {
      "count": 17,
      "value": "[email protected]"
    }
  ],
  "page": 1,
  "page_size": 50,
  "total": 118,
  "total_pages": 3
}
{
  "detail": [
    {
      "loc": [
        "string"
      ],
      "msg": "string",
      "type": "string"
    }
  ]
}

Retrieve every occurrence (source + file) for a specific leak hash GET

Retrieve every distinct detection of a deduplicated credential — one row per `(telegram_channel, file_name)` pair — read directly from the tenant-routed `leaks_matched_*` table (no separate occurrence store, no JOIN). The row count EQUALS the `occurrences` figure shown in the `/leaks/details` list (same grain), across ALL types (Combo and Stealer). Use this after `/leaks/details` to drill into a credential and see each detection. The proprietary `telegram_channel` and `file_name` are NEVER returned: the source is replaced by a stable opaque id (`opaque_source_id`, `"Source #" + md5(channel)[:6]`) and, when the detection carried a published file, an opaque lot id (`opaque_lot_id`, `md5(file_name)[:6]`). Backfilled / historical detections have no file, hence no lot. `computer_name` is never selected nor returned. **Parameters:** - `hash` (required): The leak hash from the `/leaks/details` response - `tenant_id_override` (optional): workspace (MSSP) only — inspect a child tenant's detail; validated against the caller's portfolio (403/404 otherwise) Tenant isolation: the query is scoped `WHERE tenant_id = <server-derived> AND hash = <param>`, so a hash belonging to another tenant returns nothing. **Response:** ```json { "total_occurrences": 2, "occurrences": [ {"date": "2026-06-01T10:30:00", "source": "Source #a1b2c3", "lot": "d4e5f6", "type": "Stealer", "country": "FR", "stealer_name": "RedLine", "software": "Chrome", "ip_address": "1.2.3.4", "machine_user": "admin", "machine_id": "…", "protocol": "https"}, {"date": "2026-05-20T08:00:00", "source": "Source #99aa11", "lot": null, "type": "Combo", "country": null, "stealer_name": null, "software": null, "ip_address": null, "machine_user": null, "machine_id": null, "protocol": null} ] } ``` **Example:** ```bash GET /leaks/details/occurrences?hash=5d41402abc4b2a76b9719d911017c592 ```

Paginated list of users grouped, with leak and site counts GET

Returns a paginated list of distinct usernames found in leaks for the org's monitored scope. For each user: total leak count and number of distinct sites where leaks appear. Used by the cockpit Users drawer to provide a user-centric drill-down view.