Skip to main content

Overview

Structured filters are the shared language for searches that need more than simple exact-match query parameters. They power breach search, stealer search, victim search, investigation fanout, AI-generated filters, and saved query_config values for exports, bulk search, and scanners. Use this guide to understand what filter, filter_id, operators, merge order, and validation errors mean. Use the OpenAPI reference when you need the exact request schema for one API operation.

Start Here

Use the simplest option that fits your case:
  1. If you only need simple exact filters like email, domain, country, or db name, use normal query params.
  2. If you need or, in, not_in, contains, starts_with, ends_with, wildcard, range filters, or exists, use a structured filter.
  3. If you want to type plain English like “US gmail users older than 18”, use the AI filter endpoint and then search with filter_id.
  4. If you are saving a search for scanners, bulk search, or exports, use query_config.
Recommended client pattern:
  • keep simple exact rules as normal flat params
  • switch to a structured filter when flat params are no longer enough
  • keep filter_id only when there is no real filter to send yet

1. Simple Search: Use Normal Query Params

This is the easiest option. Use it when every condition is a simple exact match.
Common flat params:
  • breach: email[], email_domain[], username[], name[], full_name[], first_name[], last_name[], country[], city[], state[], postal_code[], address[], dbname[], phone[], ip[], discord[], discord_id[], social[], financial[], gaming[], iban[], ssn[], date_birth_from, date_birth_to
  • stealer credentials: domain[], subdomain[], path[], username[], password[], email[], email_domain[], ip[], hwid[], discord_id[], log_id, has_log_id, source_type[], password_hash[], archive_hash[], canonical_credential_id[]
  • victims: username[], email[], email_domain[], ip[], hwid[], discord_id[], country[], city[], os[], service[], steam_id[], steam_name[], phone[], domain[], subdomain[], identity_state[], victim_ip[], antivirus[], infection_path[], total_docs_min, total_docs_max, service_count_min, service_count_max, view=enriched
  • investigation evidence: property_type, service, identity_kind, account_id, username, display_name, value, domain, active, source_type, confidence, confidence_min, include_cookie_evidence, exclude_cookie_evidence
  • investigation files: name, folder, kind, ext, size_min, size_max
If you need any kind of nested logic, partial text match, range, or existence check, move to the next option.

2. Complex Search: Use filter

Use a structured filter when normal query params are not enough. Good examples:
  • country is US OR CA
  • email ends with @gmail.com
  • age is at least 18
  • instagram exists
  • (country is US AND dbname is linkedin.com) OR password contains hunter
You can send filter in two ways.

Option A: GET with filter in the query string

Pass filter as a JSON-encoded string:

Option B: POST to the same search route with a JSON body

Use this form for complex filters. The response shape is the same as GET /search.
The body only needs:
  • filter
  • filter_id
Things like page_size, cursor, sort, from, to, and date_field can stay in the query string.

Investigation Section Filters

Investigation search accepts section-specific filters so one request can return a combined investigation workspace.
Use links in the response to explain why records from different sections are related.

Step 1: Ask the AI filter endpoint to build the filter

Example response:

Step 2: Search with the returned filter_id

Step 3: Optional: edit the filter and send your own filter

If you want to change the AI result before searching, send a real filter instead of relying only on the stored context.

4. Saved Jobs: Use query_config

query_config is the JSON version of a search. It is used by:
  • scanners
  • bulk search
  • exports
It may also carry client-side organization helpers such as extra_params, which are flattened into the eventual request when supported.

Simple query_config

For JSON query_config objects, prefer canonical keys such as domain, email_domain, and dbname. Bracketed variants such as domain[] are still accepted for parity with query-string filters.

Complex query_config

When the logic is too complex for simple flat keys, put a real structured filter inside query_config.filter.

Filter Grammar

Every filter is built from just three shapes:
  • a leaf rule with field
  • an and group
  • an or group

Leaf node

AND group

OR group

Nested example

Merge Order

Requests support this merge order:
  1. filter_id loads a stored transient filter context when it still exists.
  2. An explicit filter replaces that stored filter.
  3. Flat filters such as email[], domain[], dbname[], or log_id are merged on top.
  4. Pagination and sort settings such as cursor, page_size, fields[], from, to, and sort still apply normally.
In simple terms:
  • start from a saved or AI-generated filter_id
  • send your own filter if you want to take control
  • still add normal query params if needed

Operator Guide In Plain Language

Quick examples

Common Cases

Pattern searches

  • contains, ends_with, and wildcard require at least 2 non-wildcard characters
  • patterns like "*", "*a*", or "?" are rejected with 400
  • starts_with uses prefix semantics

Exists / missing checks

Numeric and date ranges

Use string values that match the public field format:
  • numeric-style fields such as age should use numeric strings like "18"
  • date-style fields such as date_birth should use ISO-style dates like "1990-01-01"
  • datetime fields such as indexed_at should use RFC3339 timestamps like "2026-04-18T00:00:00Z"

in and not_in

Use arrays when you already know multiple values:

Domain-only email filters

When you already know the mail domain, prefer the dedicated public field:

Step-By-Step Examples

Example: exact filters only

Example: one structured rule

Example: AND two rules together

Example: OR two rules together

Example: nested logic

Example: send the filter with POST

Example: filter_id plus your own exact params

This is valid:

Example: filter_id plus a replacement filter

This is also valid:

Choosing Fields

Field availability is endpoint-specific. A field accepted by breach search is not automatically valid for stealer or victims.
  • breach search commonly uses fields such as email, email_domain, username, country, city, dbname, date_birth, and age
  • stealer search commonly uses fields such as domain, subdomain, path, username, password, email, ip, hwid, discord_id, and log_id
  • victims search commonly uses fields such as username, email, ip, hwid, discord_id, log_id, and total_docs
Use the workflow guides to understand each search surface, then use the OpenAPI reference for exact fields, parameters, schemas, and playground requests. The breach autocomplete endpoints help discover db names and field/value coverage. query_config reuses the same filter system, with a few extra rules:
  • filter can be a JSON object or a JSON string
  • flat filters can be sent with canonical JSON keys such as domain, email_domain, or dbname
  • bracketed keys such as domain[] are also accepted
  • scanners reject runtime-only keys such as from, to, cursor, page_size, format, debug, and search_id
  • scanners always monitor on indexed_at
  • exports and bulk search allow from, to, date_field, and sort because those jobs serialize full searches
In practice:
  • start flat when the saved search is simple
  • switch to query_config.filter when the saved search becomes complex

Limits

  • filter_id must be a 24-character hex string
  • maximum nesting depth is 2
  • maximum leaf conditions is 50
  • value is required for every operator except exists
  • in and not_in require arrays

Common 400 Errors

Typical structured-filter validation failures include:
  • malformed JSON in filter
  • a node that mixes field with and or or
  • invalid operator names
  • disallowed fields for the selected endpoint
  • contains, ends_with, or wildcard patterns that are too short
  • using pattern operators on date or IP fields
  • nesting deeper than two levels
  • more than fifty leaf rules
Use three practical rules when building an API client:
  1. If a filter can be represented as normal exact-match params, keep it simple and send flat params.
  2. If the filter needs nested logic or advanced operators, send a real structured filter.
  3. If both filter_id and a real filter are available for a saved config, prefer the real filter as the canonical version.

Breach Search

Search breach data with structured filters

Stealer Search

Search stealer records with flat or structured filters

Victim Workflows

Search victim summaries using the same filter grammar

API Reference

Use OpenAPI for exact filter request fields and playground examples