{"openapi":"3.1.0","info":{"title":"CheckLeaked.cc API","version":"2.1.0","description":"# CheckLeaked.cc API\n\nA comprehensive OSINT and data breach intelligence API. Search across multiple data breach databases, crack hashes, perform IP lookups, and conduct Google OSINT investigations.\n\n## Authentication\n\nAll endpoints require a **Bot Token** sent via the `api-key` header. You can obtain your token from [checkleaked.cc/botLinks](https://checkleaked.cc/botLinks).\n\n```\napi-key: YOUR_BOT_TOKEN\n```\n\n## Rate Limiting\n\n- **2 requests per second** per API key\n- **2 requests per second** per IP address\n- Hash cracking has a stricter limit of **1 request per 5ms**\n\nEvery limited response carries the IETF rate-limit headers (draft 7): `RateLimit: limit=2, remaining=1, reset=1`, `RateLimit-Policy: 2;w=1`, and `Retry-After` on a `429`. Read them to pace a client instead of retrying blind.\n\n## Webhooks\n\nTracking findings can be pushed to your own HTTPS endpoint, signed with HMAC-SHA256, or straight into Slack, Discord, Microsoft Teams or Google Chat with their native message format — see the `Webhooks` tag and the `webhooks` object at the end of this document.\n\n## Subscription Tiers\n\n| Feature | Free | Pro | Plus |\n|---------|------|-----|------|\n| LeakCheck | ✅ | ✅ | ✅ |\n| Dehashed | ❌ | ✅ | ✅ |\n| Experimental | ❌ | ✅ | ✅ |\n| Google Hunt | ❌ | ✅ | ✅ |\n| Tracking | ❌ | ❌ | ✅ |\n| Hash Cracking | ✅ | ✅ | ✅ |\n| IP Lookup | ✅ | ✅ | ✅ |","termsOfService":"https://checkleaked.cc/termsAndConditions/","contact":{"name":"CheckLeaked Support","email":"admin@checkleaked.cc","url":"https://checkleaked.cc"},"license":{"name":"Proprietary","url":"https://checkleaked.cc/termsAndConditions/"}},"servers":[{"url":"https://api.checkleaked.cc/api","description":"Production API Server"}],"tags":[{"name":"Private bots","description":"Run the CheckLeaked command set under your own Discord or Telegram bot (Pro / Plus). Pro / Plus only. The token is validated against the platform (Discord `users/@me`, Telegram `getMe`), stored encrypted (AES-256-GCM), and never returned — only its last four characters plus the validated bot id / username. The bot runs on CheckLeaked's servers with the same commands as the shared bots and answers ONLY the owner's linked account (`/auth` accepts only the owner's own bot token). One bot per platform per account; a lapsed plan stops it. Discord bots need no privileged intents (slash commands and DMs work; prefix commands inside servers cannot read message text without the Message Content intent). `invite_url` adds a Discord bot to a server with minimal permissions."},{"name":"Webhooks","description":"Signed HMAC-SHA256 webhooks for tracking findings — the fifth notification channel next to email, Discord, Telegram and push. Configure once per account; every delivery is verifiable with the secret shown at creation. Paste a Slack, Discord, Microsoft Teams or Google Chat webhook URL and the finding is rendered natively for that service (`format` auto-detected); any other URL receives the generic signed JSON event (Zapier, Make, n8n, SIEM)."},{"name":"Authentication","description":"Verify API key validity and subscription status"},{"name":"LeakCheck Search","description":"Search the LeakCheck database for breached credentials. Supports email, username, domain, phone, hash, and many more search types."},{"name":"LeakRadar Raw Search","description":"Search the raw stealer-log corpus and drill into a specific leak block. Flow: `search/raw` (find blocks) → `search/raw/parts` (list an entry's blocks) → `search/raw/part` (read/unlock one block). Requires the `api-key` bot token; consumes credits (Plus/Pro)."},{"name":"LeakRadar Search","description":"Credential-leak search by email/username or structured advanced filters, plus sync/async unlock and export. Consumes credits (Plus/Pro)."},{"name":"LeakRadar Domain","description":"Domain-level breach exposure: summary, per-bucket leak lists, exposed subdomains/URLs, and a composite report."},{"name":"LeakRadar Dark Web","description":"Search and read indexed dark-web forum/market posts. Requires Plus/Pro."},{"name":"LeakRadar Utilities","description":"LeakRadar helpers: SHA-1 password range, pwned-password check, cross-source check, unlock-by-id, search history, and async task polling."},{"name":"Dehashed Search","description":"Search the Dehashed database for breached data including emails, usernames, IP addresses, names, and more."},{"name":"Experimental Search","description":"Search across experimental / Snusbase databases for breached data."},{"name":"Hash Cracking","description":"Attempt to crack password hashes (MD5, SHA1, SHA256, etc.) using rainbow tables and known breach data."},{"name":"IP Lookup","description":"Get geolocation, ISP, and network information for any IP address."},{"name":"Domain WHOIS","description":"Get WHOIS registration data (registrar, dates, name servers, registrant, status) for any domain. Powered by Snusbase domain-whois."},{"name":"Google Hunt","description":"Perform OSINT investigation on Gmail addresses using Google Hunt. Retrieves profile information, linked services, and public data. Requires Pro or Plus subscription."},{"name":"Deep Search AI","description":"The AI layer of `/deepSearch`: a structured intelligence report over findings you already fetched (`/deep_report`, plus a PDF typesetter) and a WormGPT web investigation that gathers on its own (`/worm_report`). Pro only."},{"name":"Tracking","description":"Monitor entries for new breaches over time. Set up tracking for emails, usernames, or domains and receive alerts when new data appears."},{"name":"Tracking LeakRadar","description":"Monitor domains (LeakRadar domain audit) and free-text queries (LeakRadar raw search) for new breaches over time. Max 10 entries per user, 24h cron, fan-out via your existing Email/Discord/Telegram channels. Stored in MongoDB."},{"name":"HIBP","description":"Have I Been Pwned (HIBP) v3 integration. Public endpoints (latest breach, data classes, single breach, password k-anonymity check) require no auth. Authenticated endpoints accept either an `api-key` header or the standard dashboard access-token. The user is identified by their API key for per-user domain ownership: each user can claim domains independently and only sees results for domains they have claimed."}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","description":"Bot Token obtained from [checkleaked.cc/botLinks](https://checkleaked.cc/botLinks). Send it as the `api-key` header.","name":"api-key","in":"header"}},"schemas":{"DeepReportRequest":{"type":"object","description":"Findings the caller ALREADY fetched (and was billed for) through the search endpoints. Every array is optional: at least one non-empty array is needed by `/deep_report`, none by `/worm_report`.","required":["term"],"properties":{"term":{"type":"string","description":"The identifier the findings were gathered for.","example":"john@example.com"},"type":{"type":"string","description":"How `term` was read (`email`, `username`, `phone`, `login`, ...).","example":"email"},"engines":{"type":"array","items":{"type":"string"},"description":"Engines that ran (`leakcheck`, `hibp`, `experimental`, `dehashed`, `raw`)."},"leakcheck":{"type":"array","items":{"type":"object","additionalProperties":true},"description":"Rows from `GET /leak_check` tagged `Linked.leakCheck`."},"hibp":{"type":"array","items":{"type":"object","additionalProperties":true},"description":"Rows from `GET /leak_check` tagged `Linked.hbwPwned`."},"experimental":{"type":"array","items":{"type":"object","additionalProperties":true},"description":"Rows from `POST /experimental`."},"dehashed":{"type":"array","items":{"type":"object","additionalProperties":true},"description":"Flattened `entries[].entry` rows from `POST /dehashed`."},"raw":{"type":"array","items":{"type":"object","additionalProperties":true},"description":"Blocks from `POST /leakradar/search/raw`."},"rawCredentials":{"type":"array","description":"Credentials parsed from unlocked stealer-log blocks (`POST /leakradar/search/raw/lines`).","items":{"type":"object","properties":{"url":{"type":"string"},"username":{"type":"string"},"password":{"type":"string"},"is_hash":{"type":"boolean"},"algorithm":{"type":"string"},"recovered":{"type":"string","description":"Plaintext when the hash was cracked."},"file":{"type":"string"}}}},"pivots":{"type":"array","description":"Linked identities that were ALSO searched; their rows ride in the engine arrays.","items":{"type":"object","properties":{"term":{"type":"string"},"type":{"type":"string"},"hop":{"type":"integer"},"via":{"type":"string","description":"`engine.field` of the row that surfaced it."},"from":{"type":"string","description":"The searched term whose row surfaced it."},"records":{"type":"integer"}}}},"engine":{"type":"string","enum":["wormgpt","gemini"],"description":"Force a model. Omit to let the server pick (WormGPT first, Gemini fallback)."}}},"DeepReportData":{"type":"object","description":"The structured dossier. Figures the server can measure (identity lists, credential counts, `identity_graph`, `password_stats`) are computed from the findings, not by the model.","additionalProperties":true,"properties":{"executive_summary":{"type":"string"},"risk":{"type":"object","properties":{"score":{"type":"integer","minimum":0,"maximum":100},"level":{"type":"string","enum":["low","medium","high","critical"]},"rationale":{"type":"string"}}},"identity":{"type":"object","properties":{"emails":{"type":"array","items":{"type":"string"}},"usernames":{"type":"array","items":{"type":"string"}},"names":{"type":"array","items":{"type":"string"}},"phones":{"type":"array","items":{"type":"string"}},"addresses":{"type":"array","items":{"type":"string"}},"ip_addresses":{"type":"array","items":{"type":"string"}}}},"credentials":{"type":"object","properties":{"total_passwords":{"type":"integer"},"plaintext":{"type":"integer"},"hashed":{"type":"integer"},"cracked":{"type":"integer"},"reused_passwords":{"type":"array","items":{"type":"string"}},"weak_passwords":{"type":"array","items":{"type":"string"}},"notes":{"type":"string"}}},"password_analysis":{"type":"string"},"exposed_data_categories":{"type":"array","items":{"type":"string"}},"breaches":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"note":{"type":"string"}}}},"correlations":{"type":"array","items":{"type":"string"}},"attack_scenarios":{"type":"array","items":{"type":"string"}},"recommendations":{"type":"array","items":{"type":"string"}},"confidence":{"type":"string","enum":["low","medium","high"]},"identity_graph":{"type":"array","items":{"type":"object","properties":{"value":{"type":"string"},"kind":{"type":"string"},"sources":{"type":"array","items":{"type":"string"}},"count":{"type":"integer"}}}},"password_stats":{"type":"object","additionalProperties":true}}},"DeepReportResponse":{"type":"object","properties":{"success":{"type":"boolean","example":true},"report":{"$ref":"#/components/schemas/DeepReportData"},"meta":{"type":"object","properties":{"term":{"type":"string"},"type":{"type":"string"},"engines":{"type":"array","items":{"type":"string"}},"total_records":{"type":"integer"},"pivots":{"type":"array","items":{"type":"object","additionalProperties":true}},"generatedAt":{"type":"string","format":"date-time"}}},"error":{"type":"string","nullable":true,"description":"Stable code on failure: `report_unauthorized`, `report_pro_required`, `report_unavailable`, `report_throttled`, `report_busy`, `report_no_findings`, `report_too_large`, `report_failed`."}}},"DeepReportPdfRequest":{"type":"object","required":["report"],"properties":{"report":{"$ref":"#/components/schemas/DeepReportData"},"meta":{"type":"object","additionalProperties":true,"description":"`meta` as returned by `/deep_report`."}}},"WormReportResponse":{"type":"object","properties":{"success":{"type":"boolean","example":true},"report":{"type":"object","properties":{"markdown":{"type":"string","description":"The complete investigation, Markdown."},"sources":{"type":"array","items":{"type":"object","properties":{"title":{"type":"string"},"url":{"type":"string"}}}}}},"meta":{"type":"object","properties":{"term":{"type":"string"},"type":{"type":"string"},"engines":{"type":"array","items":{"type":"string"}},"total_records":{"type":"integer"},"generatedAt":{"type":"string","format":"date-time"}}},"error":{"type":"string","nullable":true,"description":"Stable code on failure: `worm_unauthorized`, `worm_pro_required`, `worm_disabled`, `worm_quota`, `worm_throttled`, `worm_busy`, `worm_no_subject`, `worm_unavailable`, `worm_too_large`, `worm_failed`."}}},"PrivateBot":{"type":"object","properties":{"platform":{"type":"string","enum":["discord","telegram"]},"enabled":{"type":"boolean"},"state":{"type":"string","enum":["stopped","starting","online","error"],"description":"Written by the runner; `error` comes with `last_error`."},"bot_id":{"type":["string","null"]},"bot_username":{"type":["string","null"]},"token_hint":{"type":"string","example":"…k9Qw"},"last_error":{"type":["string","null"]},"last_started":{"type":["string","null"],"format":"date-time"},"invite_url":{"type":["string","null"],"format":"uri","description":"Discord only: OAuth2 link with the `bot` + `applications.commands` scopes."}}},"PrivateBotSaveRequest":{"type":"object","required":["platform"],"properties":{"platform":{"type":"string","enum":["discord","telegram"]},"token":{"type":"string","description":"The bot token from the Discord Developer Portal (Bot → Reset Token) or from @BotFather. Omit to only toggle `enabled`."},"enabled":{"type":"boolean","default":true}},"example":{"platform":"discord","token":"MTEz…"}},"Webhook":{"type":"object","description":"The account's tracking webhook. The secret is never returned here — only its last four characters.","properties":{"format":{"type":"string","enum":["json","slack","discord","teams","google_chat"],"default":"json","description":"Delivery shape. `json` — the generic signed `tracking.finding` event (Zapier, Make, n8n, any SIEM). `slack` — Block Kit for a Slack Incoming Webhook (also Mattermost / Rocket.Chat Slack-compatible hooks). `discord` — a Discord webhook embed. `teams` — an Adaptive Card message for a Microsoft Teams Workflows webhook. `google_chat` — a Google Chat cardsV2 message. Every shape is still signed with `X-CheckLeaked-Signature`."},"url":{"type":"string","format":"uri","example":"https://siem.example.com/hooks/checkleaked"},"enabled":{"type":"boolean"},"secret_hint":{"type":"string","example":"…9f3a","description":"Last 4 characters of the stored signing secret."},"fail_count":{"type":"integer","description":"Consecutive failed notifications. Reaching 20 disables the hook."},"last_status":{"type":["integer","null"],"description":"HTTP status of the last attempt, null when the request never completed."},"last_error":{"type":["string","null"]},"last_attempt":{"type":["string","null"],"format":"date-time"},"last_success":{"type":["string","null"],"format":"date-time"},"creation_date":{"type":["string","null"],"format":"date-time"},"auto_disabled":{"type":"boolean","description":"True when the sender switched the hook off after 20 consecutive failures. Saving re-enables it."}}},"WebhookSaveRequest":{"type":"object","properties":{"url":{"type":"string","format":"uri","maxLength":2048,"description":"HTTPS only. Loopback, private (RFC 1918), link-local, CGNAT and reserved addresses, and local hostnames (`localhost`, `*.local`, `*.internal`, …) are refused; the host is re-resolved before every delivery. Required on create; on update it defaults to the stored URL."},"format":{"type":"string","enum":["json","slack","discord","teams","google_chat","auto"],"default":"auto","description":"Delivery shape. `json` — the generic signed `tracking.finding` event (Zapier, Make, n8n, any SIEM). `slack` — Block Kit for a Slack Incoming Webhook (also Mattermost / Rocket.Chat Slack-compatible hooks). `discord` — a Discord webhook embed. `teams` — an Adaptive Card message for a Microsoft Teams Workflows webhook. `google_chat` — a Google Chat cardsV2 message. Every shape is still signed with `X-CheckLeaked-Signature`. `auto` (the default when omitted) detects the service from the URL host — hooks.slack.com, discord.com/api/webhooks, *.webhook.office.com / *.logic.azure.com, chat.googleapis.com — on create and whenever the URL changes."},"enabled":{"type":"boolean","default":true},"rotate_secret":{"type":"boolean","default":false,"description":"Generate a new signing secret. The old one stops validating immediately."}},"example":{"url":"https://hooks.slack.com/services/T000/B000/XXXX","format":"auto","enabled":true}},"WebhookSaveResponse":{"type":"object","properties":{"success":{"type":"object","properties":{"webhook":{"$ref":"#/components/schemas/Webhook"},"secret":{"type":"string","description":"Present ONLY on create or when `rotate_secret` was true. Store it now; it is not shown again.","example":"whsec_3f1c…"}}},"error":{"type":["string","null"]}}},"WebhookGetResponse":{"type":"object","properties":{"success":{"type":"object","properties":{"webhook":{"oneOf":[{"$ref":"#/components/schemas/Webhook"},{"type":"null"}]}}},"error":{"type":["string","null"]}}},"WebhookTestResult":{"type":"object","description":"Outcome of one real, signed test delivery (single attempt, no retries). A failed test is reported here, not as an API error.","properties":{"success":{"type":"boolean"},"delivered":{"type":"boolean"},"status":{"type":["integer","null"]},"error":{"type":["string","null"]},"duration_ms":{"type":"integer"},"delivery_id":{"type":"string","description":"Matches the `X-CheckLeaked-Delivery` header your endpoint received."}}},"TrackingFindingEvent":{"type":"object","required":["id","event","created_at","test","data"],"properties":{"id":{"type":"string","example":"evt_5d1c0b4e-7d0a-4b6a-9c3f-2f7c1e0a9b11"},"event":{"type":"string","enum":["tracking.finding"]},"created_at":{"type":"string","format":"date-time"},"test":{"type":"boolean","description":"True for deliveries triggered by `POST /webhook/test`."},"data":{"type":"object","properties":{"source":{"type":"string","enum":["leakcheck","leakradar"],"description":"Which tracking pipeline produced the finding."},"entry":{"type":"string","description":"The tracked identifier."},"type":{"type":"string","description":"Entry kind — email, username, phone, domain, raw, …"},"severity":{"type":"string","enum":["new","exposed","clean"],"description":"`new`: new occurrences since the last check. `exposed`: known exposure, nothing new. `clean`: nothing found."},"severity_text":{"type":"string"},"found":{"type":"integer","description":"Total occurrences in the current snapshot."},"new_count":{"type":["integer","null"]},"changes":{"type":"array","items":{"type":"string"},"description":"Human-readable change lines."},"detail_link":{"type":"string","format":"uri","description":"Authenticated snapshot view on checkleaked.cc."},"record_id":{"type":["string","null"]},"rows":{"type":["object","null"],"description":"Flattened findings, capped at 200 rows; see `omitted_rows`.","properties":{"columns":{"type":"array","items":{"type":"string"}},"rows":{"type":"array","items":{"type":"object","additionalProperties":true}}}},"omitted_rows":{"type":"integer"},"domain_buckets":{"type":["array","null"],"items":{"type":"object","properties":{"label":{"type":"string"},"now":{"type":"integer"},"prior":{"type":"integer"}}}},"strength_summary":{"type":["object","null"],"additionalProperties":{"type":"integer"}}}}}},"LeakRadarError":{"type":"object","description":"Business-failure envelope returned (with HTTP 200) when a LeakRadar request cannot be fulfilled.","properties":{"success":{"type":"boolean","enum":[false],"description":"Always `false` for an error."},"error":{"type":"string","description":"Human-readable error message."}},"required":["success","error"]},"LeakRadarRawSearchRequest":{"type":"object","description":"Filters for a raw stealer-log block search. Provide `q` and/or at least one of `container_id`, `exts`, `categories`, `file_name`.","properties":{"q":{"type":"string","nullable":true,"description":"Full-text query matched inside raw blocks. When omitted/empty you must supply at least one other filter."},"container_id":{"type":"integer","nullable":true,"description":"Restrict the search to a single container id."},"exts":{"type":"array","items":{"type":"string"},"nullable":true,"description":"File extensions to include (no leading dot, case-insensitive)."},"exts_not":{"type":"array","items":{"type":"string"},"nullable":true,"description":"File extensions to exclude."},"categories":{"type":"array","items":{"type":"string"},"nullable":true,"description":"Raw file categories to include (e.g. `stealer-logs`)."},"categories_not":{"type":"array","items":{"type":"string"},"nullable":true,"description":"Raw file categories to exclude."},"file_name":{"type":"array","items":{"type":"string"},"nullable":true,"description":"Case-insensitive wildcards the entry name must match (OR by default)."},"file_name_not":{"type":"array","items":{"type":"string"},"nullable":true,"description":"Wildcards the entry name must NOT match."},"force_and":{"type":"boolean","nullable":true,"description":"Require ALL `file_name` values to match (AND instead of OR)."},"ingested_at_min":{"type":"string","format":"date-time","nullable":true,"description":"Only blocks ingested on/after this ISO datetime."},"ingested_at_max":{"type":"string","format":"date-time","nullable":true,"description":"Only blocks ingested on/before this ISO datetime."}}},"LeakRadarRawSearchItem":{"type":"object","description":"A single matched raw block. Use its `container_id` + `entry_path` (+ `seq`) to fetch the exact leak content via `GET /leakradar/search/raw/part`.","properties":{"container_id":{"type":"string","description":"Identifier of the container holding the raw entry."},"entry_path":{"type":"string","description":"Path of the entry inside the container."},"entry_name":{"type":"string","nullable":true,"description":"Base file name extracted from the path."},"ext":{"type":"string","nullable":true,"description":"Detected file extension."},"seq":{"type":"integer","nullable":true,"description":"Sequential block number within the entry."},"offset":{"type":"integer","nullable":true,"description":"Byte offset of the block within the original file."},"ingested_at":{"type":"string","nullable":true,"description":"ISO timestamp of ingestion."},"sha256_original":{"type":"string","nullable":true,"description":"SHA-256 of the original raw file, when known."},"original_file_name":{"type":"string","nullable":true,"description":"Original human-readable file name of the source drop."},"category":{"type":"string","nullable":true,"description":"Raw file category (e.g. `stealer-logs`)."},"display_name":{"type":"string","nullable":true,"description":"Friendly display name for the source file."},"snippet":{"type":"string","nullable":true,"description":"Short context snippet around the match, when available."},"already_unlocked":{"type":"boolean","description":"Whether this block (or its parent file) is already unlocked for your account."},"matching_lines":{"type":"array","items":{"type":"string"},"description":"Lines from the block that contain the query (populated on export)."}},"required":["container_id","entry_path","already_unlocked"]},"LeakRadarRawSearchResponse":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/LeakRadarRawSearchItem"},"description":"Matching raw blocks for this page."},"total":{"type":"integer","description":"Total matches. `-1` when in cursor mode (the default)."},"page":{"type":"integer","description":"Requested page index."},"page_size":{"type":"integer","description":"Items returned in this page."},"has_more":{"type":"boolean","nullable":true,"description":"True if more results exist (cursor mode)."},"next_cursor":{"type":"string","nullable":true,"description":"Opaque cursor for the next page — pass it back as `?cursor=`."},"blacklisted_value":{"type":"string","nullable":true,"description":"Set when a filter value matched a blacklist entry."}},"required":["items","total","page","page_size"]},"LeakRadarRawLineMatch":{"type":"object","description":"One matched record. For `stealer_credential` this spans several physical lines; for `netscape_cookie` and `colon_delimited` it is a single line.","properties":{"seq":{"type":"integer","description":"Block this record was found in."},"line_number":{"type":"integer","description":"1-based line index **within the block**, not the original file."},"format":{"type":"string","enum":["netscape_cookie","stealer_credential","colon_delimited","unknown"],"description":"Detected record format. Governs the shape of `parsed`."},"text":{"type":"string","description":"The verbatim record text. Always present, even when `parsed` is null."},"parsed":{"type":"object","nullable":true,"additionalProperties":true,"description":"Best-effort structured fields. `netscape_cookie` → domain, path, secure, expires, name, value. `stealer_credential` / `colon_delimited` → url, username, password, application. Null for `unknown`."},"truncated":{"type":"boolean","description":"True when the record touches a block edge and may be a byte-sliced fragment."},"context":{"type":"array","items":{"type":"string"},"description":"Surrounding lines, when `context_lines` > 0 and format is `unknown`."}},"required":["seq","line_number","format","text","truncated"]},"LeakRadarRawLinesEntry":{"type":"object","description":"One source file, with every matching record found across its blocks.","properties":{"container_id":{"type":"string"},"entry_path":{"type":"string"},"entry_name":{"type":"string","nullable":true},"ext":{"type":"string","nullable":true},"category":{"type":"string","nullable":true},"original_file_name":{"type":"string","nullable":true},"ingested_at":{"type":"string","nullable":true},"format":{"type":"string","enum":["netscape_cookie","stealer_credential","colon_delimited","unknown"]},"blocks_matched":{"type":"array","items":{"type":"integer"},"description":"Block `seq` values that contributed matches."},"matches":{"type":"array","items":{"$ref":"#/components/schemas/LeakRadarRawLineMatch"}}},"required":["container_id","entry_path","format","matches"]},"LeakRadarRawLinesResponse":{"type":"object","properties":{"query":{"type":"string","description":"The `q` that records were filtered by."},"entries":{"type":"array","items":{"$ref":"#/components/schemas/LeakRadarRawLinesEntry"}},"stats":{"type":"object","properties":{"blocks_searched":{"type":"integer"},"blocks_unlocked":{"type":"integer"},"blocks_still_censored":{"type":"integer","description":"Blocks that could not be unlocked and were skipped."},"entries":{"type":"integer"},"matches":{"type":"integer"},"degraded":{"type":"boolean","description":"True when some blocks failed to fetch or stayed censored. Results are partial, not an error."}}},"search":{"type":"object","description":"Pagination echo from the underlying raw search. Pass `next_cursor` back as `?cursor=` to page.","properties":{"total":{"type":"integer"},"page":{"type":"integer"},"page_size":{"type":"integer"},"has_more":{"type":"boolean","nullable":true},"next_cursor":{"type":"string","nullable":true}}}},"required":["query","entries","stats"]},"LeakRadarPartsItem":{"type":"object","properties":{"seq":{"type":"integer","description":"Sequential block number within the entry."},"size_bytes":{"type":"integer","nullable":true,"description":"Block size in bytes."},"offset":{"type":"integer","nullable":true,"description":"Byte offset of the block within the entry."},"ingested_at":{"type":"string","nullable":true,"description":"ISO ingestion timestamp."}},"required":["seq"]},"LeakRadarPartsResponse":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/LeakRadarPartsItem"},"description":"Blocks available for the requested entry."},"total":{"type":"integer","description":"Total number of blocks in the entry."},"page":{"type":"integer"},"page_size":{"type":"integer"},"window":{"type":"object","description":"Index window covered by this page.","properties":{"start_index":{"type":"integer"},"end_index":{"type":"integer"}}},"container_id":{"type":"string"},"entry_path":{"type":"string"}},"required":["items","total"]},"LeakRadarPartResponse":{"type":"object","description":"A single raw block. Blocks are unlocked automatically, so `text` is normally plaintext; `censored: true` with redacted (█) `text` means the block could not be opened upstream, not that you need to ask for it.","properties":{"container_id":{"type":"string"},"entry_path":{"type":"string"},"seq":{"type":"integer"},"offset":{"type":"integer"},"size_bytes":{"type":"integer","nullable":true},"ingested_at":{"type":"string","nullable":true},"trim_overlap":{"type":"boolean","description":"True if the overlapping prefix was trimmed."},"overlap_chars":{"type":"integer","description":"Characters trimmed from the start when `trim_overlap=true`."},"text":{"type":"string","description":"Block content. Redacted with █ characters when `censored` is true."},"censored":{"type":"boolean","description":"True when the content is not unlocked and was redacted."}},"required":["container_id","entry_path","seq","text","censored"]},"LeakRadarLeakDetails":{"type":"object","description":"A credential leak record. Sensitive fields are masked until the record is unlocked.","properties":{"id":{"type":"string","nullable":true,"description":"Leak id (present when unlocked / on full-access plans). Pass to `POST /leakradar/unlock`."},"url":{"type":"string","nullable":true,"description":"Source URL. Redacted for locked items on non-advanced plans."},"username":{"type":"string","nullable":true,"description":"Leaked username/email. Masked when locked."},"username_masked":{"type":"string","nullable":true,"description":"Partially masked username (e.g. `j***@example.com`)."},"password":{"type":"string","nullable":true,"description":"Leaked password. Only present when unlocked."},"password_strength":{"type":"integer","nullable":true,"description":"Raw strength score (0+). too_weak 0-2, weak 3-4, medium 5-7, strong 8+."},"unlocked":{"type":"boolean","description":"Whether this item is unlocked for your account."},"is_email":{"type":"boolean","nullable":true,"description":"True if the identifier is an email address."},"added_at":{"type":"string","nullable":true,"description":"When the leak was added to the database."},"status":{"type":"string","nullable":true,"enum":["new","in_progress","fixed","accepted_risk"],"description":"Remediation status (unlocked items only)."}},"required":["unlocked"]},"LeakRadarEmailSearchRequest":{"type":"object","properties":{"email":{"type":"string","description":"Email or username to search."},"search":{"type":"string","nullable":true,"description":"Optional free-text filter within results."},"is_email":{"type":"boolean","nullable":true,"description":"Identifier filter: true=email only, false=username only, null=both."},"max":{"type":"integer","description":"Unlock endpoints only: max records to unlock."}},"required":["email"]},"LeakRadarLeaksPage":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/LeakRadarLeakDetails"},"description":"Leak records for this page."},"total":{"type":"integer","description":"Total matching records."},"page":{"type":"integer"},"page_size":{"type":"integer"}},"required":["items","total"]},"LeakRadarSearchFilters":{"type":"object","description":"Structured filters for advanced credential search. Every field is an array (OR within a field by default; set `force_and=true` for AND).","properties":{"username":{"type":"array","items":{"type":"string"},"nullable":true,"description":"Username must contain."},"username_not":{"type":"array","items":{"type":"string"},"nullable":true,"description":"Exclude usernames containing."},"password":{"type":"array","items":{"type":"string"},"nullable":true,"description":"Password must contain."},"password_not":{"type":"array","items":{"type":"string"},"nullable":true,"description":"Exclude passwords containing."},"url":{"type":"array","items":{"type":"string"},"nullable":true,"description":"URL must contain."},"url_domain":{"type":"array","items":{"type":"string"},"nullable":true,"description":"URL domain must contain."},"url_host":{"type":"array","items":{"type":"string"},"nullable":true,"description":"URL host must contain."},"email_domain":{"type":"array","items":{"type":"string"},"nullable":true,"description":"Email domain must contain."},"email_host":{"type":"array","items":{"type":"string"},"nullable":true,"description":"Email host must contain."},"is_email":{"type":"boolean","nullable":true,"description":"true=email only, false=username only, null=both."},"password_strength":{"type":"string","nullable":true,"enum":["too_weak","weak","medium","strong"],"description":"Filter by password strength category."},"added_from":{"type":"string","format":"date-time","nullable":true,"description":"Only leaks indexed on/after this UTC datetime."},"added_to":{"type":"string","format":"date-time","nullable":true,"description":"Only leaks indexed on/before this UTC datetime."},"force_and":{"type":"boolean","nullable":true,"description":"Require all values within each field (AND within field)."},"max":{"type":"integer","description":"Unlock endpoints only: max records to unlock."}}},"LeakRadarDarkWebSearchRequest":{"type":"object","properties":{"query":{"type":"string","nullable":true,"description":"Global search term (simple mode)."},"title":{"type":"string","nullable":true,"description":"Search in title only (advanced mode)."},"content":{"type":"string","nullable":true,"description":"Search in content only (advanced mode)."},"author":{"type":"string","nullable":true,"description":"Exact author match (advanced mode)."},"source_url":{"type":"string","nullable":true,"description":"Source URL contains (advanced mode)."},"logic":{"type":"string","nullable":true,"enum":["AND","OR"],"default":"AND","description":"Logic for combining fields."}}},"LeakRadarDarkWebItem":{"type":"object","properties":{"id":{"type":"string","nullable":true,"description":"Post identifier — pass to `GET /leakradar/dark-web/post/{post_id}`."},"title":{"type":"string","nullable":true},"content":{"type":"string","nullable":true,"description":"Post content. May be truncated/censored."},"source":{"type":"string","nullable":true,"description":"Source identifier (forum/market)."},"source_name":{"type":"string","nullable":true,"description":"Human-readable source name."},"target":{"type":"string","nullable":true,"description":"Target entity mentioned."},"source_ref":{"type":"string","nullable":true,"description":"Original reference URL on the source."},"author":{"type":"string","nullable":true},"published_at":{"type":"string","nullable":true},"ingested_at":{"type":"string","nullable":true},"truncated":{"type":"boolean"},"censored":{"type":"boolean"}}},"LeakRadarDarkWebSearchResponse":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/LeakRadarDarkWebItem"}},"total":{"type":"integer"},"page":{"type":"integer"},"page_size":{"type":"integer"}},"required":["items","total"]},"LeakRadarPasswordRangeResponse":{"type":"object","description":"k-anonymity range for a SHA-1 prefix — used for pwned-password checks without sending the full hash.","properties":{"prefix":{"type":"string","description":"The queried hash prefix."},"total":{"type":"integer","description":"Number of suffixes in the range."},"hashes":{"type":"array","description":"Suffixes and their breach occurrence counts.","items":{"type":"object","properties":{"hash":{"type":"string"},"count":{"type":"integer"}},"required":["hash","count"]}}},"required":["prefix","total","hashes"]},"LeakRadarUnlockRequest":{"type":"object","properties":{"leak_ids":{"type":"array","items":{"type":"string"},"description":"Leak document ids to unlock (from search `items[].id`)."},"target_list_id":{"type":"integer","nullable":true,"description":"Optional list id to assign the newly unlocked items to."}},"required":["leak_ids"]},"LeakRadarPwnedRequest":{"type":"object","description":"Provide exactly one of `password` or `sha1`. The password is hashed server-side and never logged.","properties":{"password":{"type":"string","description":"Plaintext password to check."},"sha1":{"type":"string","description":"Uppercase 40-char SHA-1 hex of the password (alternative to `password`)."}}},"LeakRadarPwnedResponse":{"type":"object","properties":{"pwned":{"type":"boolean","description":"True if the password appears in a breach."},"count":{"type":"integer","description":"Number of times it was seen across breaches."}},"required":["pwned","count"]},"ErrorResponse":{"type":"object","properties":{"error":{"type":"string","description":"Error message describing what went wrong","example":"Unauthorized"}},"required":["error"]},"ValidationError":{"type":"object","properties":{"error":{"type":"array","items":{"type":"object","properties":{"msg":{"type":"string","example":"api-key is required"},"param":{"type":"string","example":"api-key"},"location":{"type":"string","example":"headers"}}}}}},"IpWhoisEntry":{"type":"object","description":"Whois / geolocation data for a single IP address, sourced from Snusbase `tools/ip-whois` (an ip-api.com-shaped payload). `null` when the lookup fails or the IP is invalid/reserved.","properties":{"query":{"type":"string","example":"8.8.8.8"},"continent":{"type":"string","example":"North America"},"continentCode":{"type":"string","example":"NA"},"country":{"type":"string","example":"United States"},"countryCode":{"type":"string","example":"US"},"region":{"type":"string","example":"VA"},"regionName":{"type":"string","example":"Virginia"},"city":{"type":"string","example":"Ashburn"},"zip":{"type":"string","example":"20149"},"lat":{"type":"number","example":39.03},"lon":{"type":"number","example":-77.5},"timezone":{"type":"string","example":"America/New_York"},"isp":{"type":"string","example":"Google LLC"},"org":{"type":"string","example":"Google Public DNS"},"as":{"type":"string","example":"AS15169 Google LLC"},"asname":{"type":"string","example":"GOOGLE"},"mobile":{"type":"boolean","example":false},"proxy":{"type":"boolean","example":false},"hosting":{"type":"boolean","example":true}},"additionalProperties":true},"IpLookupMap":{"type":"object","description":"Map of IP address → whois entry. Present in the response only when `enrichIps=true` is passed and the result set contains IP addresses. `null` means the lookup failed for that IP.","additionalProperties":{"oneOf":[{"$ref":"#/components/schemas/IpWhoisEntry"},{"type":"null"}]},"example":{"1.2.3.4":{"country":"Germany","isp":"Deutsche Telekom AG","as":"AS3320 Deutsche Telekom AG"},"5.6.7.8":null}},"DomainWhoisResult":{"type":"object","description":"WHOIS registration data for a single domain (sourced from Snusbase domain-whois).","properties":{"domain":{"type":"string","example":"google.com","description":"The normalized hostname that was looked up."},"found":{"type":"boolean","example":true,"description":"`false` when no WHOIS record was returned for the domain."},"whois":{"description":"WHOIS field map for the domain, or `null` when `found` is `false`. All fields are optional; the exact set varies by registrar/TLD and extra keys may appear.","oneOf":[{"type":"object","additionalProperties":true,"properties":{"domain":{"type":"string","example":"google.com"},"tld":{"type":"string","example":"com"},"date":{"type":"object","description":"Registration lifecycle timestamps (ISO 8601).","properties":{"created":{"type":"string","format":"date-time","example":"1997-09-15T04:00:00Z"},"expires":{"type":"string","format":"date-time","example":"2028-09-14T04:00:00Z"},"updated":{"type":"string","format":"date-time","example":"2019-09-09T15:39:04Z"}}},"nameserver":{"type":"array","items":{"type":"string"},"example":["ns1.google.com","ns2.google.com"]},"registrar":{"type":"object","properties":{"name":{"type":"string","example":"markmonitor inc"},"handle":{"type":"string","example":"292"}}},"status":{"type":"array","items":{"type":"string"},"example":["clientdeleteprohibited","clienttransferprohibited"]},"contact":{"type":"object","description":"Contacts keyed by role (registrant, admin, tech, abuse, …).","additionalProperties":{"type":"object","properties":{"email":{"type":"string"},"name":{"type":"string"},"organization":{"type":"string"},"phone":{"type":"string"}}},"example":{"abuse":{"email":"abusecomplaints@markmonitor.com"}}},"meta":{"type":"object","description":"Provenance metadata for the record.","properties":{"checked":{"type":"string","format":"date-time"},"updated":{"type":"string","format":"date-time"},"seen_czds":{"type":"string","format":"date-time"},"sources":{"type":"array","items":{"type":"string"},"example":["czds","rdap","dns"]}}},"dns":{"type":"object","properties":{"security":{"type":"object","properties":{"signed":{"type":"boolean","example":false}}},"records":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string","example":"A"},"name":{"type":"string","example":"google.com"},"ttl":{"type":"integer","example":300},"values":{"type":"array","description":"String values for A/AAAA/TXT records; `{ priority, server }` objects for MX.","items":{"oneOf":[{"type":"string","example":"142.250.72.14"},{"type":"object","properties":{"priority":{"type":"integer","example":10},"server":{"type":"string","example":"smtp.google.com"}}}]}}}}}}}}},{"type":"null"}]}}},"DehashedEntry":{"type":"object","required":["entry","type"],"properties":{"entry":{"type":"string","minLength":4,"maxLength":50,"example":"test12358@mail.com","description":"The value to search for (email address, username, IP, etc.)"},"type":{"type":"string","enum":["email","username","ip_address","name","address","phone","vin","free"],"example":"email","description":"The field type to search in. Use `free` for an unrestricted search across all fields."},"page":{"type":"integer","format":"int32","minimum":1,"default":1,"example":1,"description":"Page number for paginated results. Defaults to 1."}}},"ExperimentalEntry":{"type":"object","required":["entry","type"],"properties":{"entry":{"type":"string","minLength":4,"maxLength":50,"example":"test1234@mail.com","description":"The value to search for"},"type":{"type":"string","enum":["username","mass","email","lastip","password","name","hash"],"example":"email","description":"The field type to search in. `mass` searches across all fields simultaneously."}}},"CrackHashRequest":{"type":"object","required":["hash"],"properties":{"hash":{"type":"string","minLength":4,"maxLength":100,"example":"cc03e747a6afbbcbf8be7668acfebee5","description":"The hash string to crack. Supports MD5, SHA1, SHA256, and other common hash formats."}}},"TrackingNewEntry":{"type":"object","required":["entry","type"],"properties":{"entry":{"type":"string","example":"user@example.com","description":"The value to track for new breaches"},"type":{"type":"string","enum":["email","username","domain"],"example":"email","description":"The type of entry to track"}}},"TrackingDeleteEntry":{"type":"object","required":["id"],"properties":{"id":{"type":"string","description":"The tracking entry ID to delete"}}},"TrackingHistoryRequest":{"type":"object","required":["id"],"properties":{"id":{"type":"string","description":"The tracking entry ID to get history for"}}},"TrackingLeakRadarNewEntry":{"type":"object","required":["entry","type"],"properties":{"entry":{"type":"string","example":"example.com","description":"Value to track. For type=domain: a bare hostname (will be lowercased). For type=raw: email, username, or free-text query (4-256 chars)."},"type":{"type":"string","enum":["domain","raw"],"example":"domain","description":"Entry type. 'domain' uses LeakRadar domain audit; 'raw' uses LeakRadar raw search."}}},"TrackingLeakRadarDeleteEntry":{"type":"object","required":["email_unique_id"],"properties":{"email_unique_id":{"type":"string","description":"Dedup key returned by /tracking/leakradar/user. md5(entry + type + user_unique_id)."}}},"TrackingLeakRadarHistoryRequest":{"type":"object","required":["entry","type"],"properties":{"entry":{"type":"string","example":"example.com"},"type":{"type":"string","enum":["domain","raw"],"example":"domain"}}},"LeakCheckResult":{"type":"object","properties":{"success":{"type":"boolean","example":true},"found":{"type":"integer","example":5,"description":"Number of breach entries found"},"result":{"type":"array","items":{"type":"object","properties":{"email":{"type":"string","example":"user@example.com"},"username":{"type":"string","example":"user123"},"password":{"type":"string","example":"p@ssw0rd"},"hash":{"type":"string"},"source":{"type":"object","properties":{"name":{"type":"string","example":"ExampleBreach.com"},"date":{"type":"string","example":"2023-01-15"}}}}}}}},"IpLookupResult":{"type":"object","description":"Geolocation (ip2location), reverse-geocoded address (Nominatim), ASN, and whois data for a single IP address. Fields below `timeZone` come from the loaded ip2location BIN edition and are only present when that edition supports them — the current edition supports just the first 10 fields.","properties":{"ip":{"type":"string","example":"8.8.8.8"},"ipNo":{"type":"string","description":"Decimal representation of the IP address.","example":"134744072"},"countryShort":{"type":"string","example":"US"},"countryLong":{"type":"string","example":"United States of America"},"region":{"type":"string","example":"California"},"city":{"type":"string","example":"Mountain View"},"zipCode":{"type":"string","example":"94043"},"latitude":{"type":"number","example":37.405991},"longitude":{"type":"number","example":-122.078514},"timeZone":{"type":"string","description":"UTC offset.","example":"-07:00"},"isp":{"type":"string"},"domain":{"type":"string"},"netSpeed":{"type":"string"},"iddCode":{"type":"string"},"areaCode":{"type":"string"},"weatherStationCode":{"type":"string"},"weatherStationName":{"type":"string"},"mcc":{"type":"string"},"mnc":{"type":"string"},"mobileBrand":{"type":"string"},"elevation":{"type":"string"},"usageType":{"type":"string"},"addressType":{"type":"string"},"category":{"type":"string"},"district":{"type":"string"},"address":{"description":"Reverse-geocoded address (Nominatim `/reverse`). `{}` when unresolvable (e.g. lat/lon 0,0).","type":"object","additionalProperties":true,"properties":{"place_id":{"type":"integer","example":311466384},"licence":{"type":"string"},"osm_type":{"type":"string","example":"way"},"osm_id":{"type":"integer","example":227968074},"lat":{"type":"string","example":"37.405882899999995"},"lon":{"type":"string","example":"-122.07853894699258"},"class":{"type":"string","example":"building"},"type":{"type":"string","example":"yes"},"place_rank":{"type":"integer","example":30},"importance":{"type":"number"},"addresstype":{"type":"string","example":"building"},"name":{"type":"string"},"display_name":{"type":"string","example":"790, North Shoreline Boulevard, The Waters, Mountain View, Santa Clara County, California, 94043, United States"},"address":{"type":"object","description":"Address breakdown. Highly variable — the exact key set depends on the place type (e.g. `residential`/`county` vs `suburb`/`neighbourhood`).","additionalProperties":{"type":"string"},"example":{"house_number":"790","road":"North Shoreline Boulevard","residential":"The Waters","city":"Mountain View","county":"Santa Clara County","state":"California","ISO3166-2-lvl4":"US-CA","postcode":"94043","country":"United States","country_code":"us"}},"boundingbox":{"type":"array","items":{"type":"string"},"minItems":4,"maxItems":4,"example":["37.4058272","37.4060174","-122.0786263","-122.0784753"]}}},"asn":{"description":"ASN CIDR block match from the local ASN database. `null`/absent when no match is found.","type":"object","nullable":true,"properties":{"start_ip":{"type":"string","example":"8.8.250.0"},"end_ip":{"type":"string","example":"8.9.2.255"},"asn":{"type":"string","example":"AS3356"},"name":{"type":"string","example":"Level 3 Parent, LLC"},"domain":{"type":"string","example":"lumen.com"}}},"whois":{"description":"`null` when the whois lookup fails or the IP is invalid/reserved.","oneOf":[{"$ref":"#/components/schemas/IpWhoisEntry"},{"type":"null"}]}},"required":["ip","ipNo","countryShort","countryLong","region","city","zipCode","latitude","longitude","timeZone"]},"GhuntResult":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"name":{"type":"string","example":"John Doe"},"email":{"type":"string","example":"example@gmail.com"},"profile_picture":{"type":"string","format":"uri"},"last_updated":{"type":"string"},"google_maps":{"type":"object"},"google_calendar":{"type":"object"}}}}},"AuthResponse":{"type":"object","properties":{"valid":{"type":"boolean","example":true},"role":{"type":"string","example":"pro","description":"Subscription tier"},"expiration_date":{"type":"string","format":"date-time","description":"When the subscription expires"}}},"PingResponse":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"pong"}}}},"responses":{"Unauthorized":{"description":"API key is missing, invalid, or expired","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"Unauthorized"}}}},"RateLimited":{"description":"Too many requests - rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"Too many request from this api key"}}}},"ValidationFailed":{"description":"Request validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}}}},"security":[{"ApiKeyAuth":[]}],"webhooks":{"trackingFinding":{"post":{"summary":"tracking.finding — a tracked entry was checked","description":"Sent to the account's webhook after every tracking check that the tracker reports on (new exposure, unchanged exposure, or a clean result), for both the LeakCheck and the LeakRadar pipelines. Respond with any 2xx within 10 seconds; anything else is retried at 2 s and 8 s (network errors, 5xx and 429 only — a 4xx is not retried and a 3xx is never followed). After 20 consecutive failed notifications the hook is disabled until it is saved again.\n\nEvery delivery is signed. Header `X-CheckLeaked-Signature: t=<unix seconds>,v1=<hex>` where `v1 = HMAC-SHA256(secret, \"<t>.<raw request body>\")`. Verify with a constant-time comparison and reject timestamps older than your tolerance (300 s is typical). Also sent: `X-CheckLeaked-Event` (event name), `X-CheckLeaked-Delivery` (UUID, unique per attempt), `User-Agent: CheckLeaked-Webhooks/1.0`.\n\nNode.js verification:\n\n```js\nconst crypto = require(\"crypto\");\nfunction verify(secret, rawBody, header, toleranceSec = 300) {\n  const kv = Object.fromEntries(header.split(\",\").map(p => p.trim().split(\"=\")));\n  const t = Number(kv.t);\n  if (!Number.isInteger(t) || Math.abs(Date.now() / 1000 - t) > toleranceSec) return false;\n  const expected = crypto.createHmac(\"sha256\", secret).update(`${t}.${rawBody}`).digest();\n  const given = Buffer.from(kv.v1 || \"\", \"hex\");\n  return expected.length === given.length && crypto.timingSafeEqual(expected, given);\n}\n```","parameters":[{"name":"X-CheckLeaked-Signature","in":"header","required":true,"schema":{"type":"string"},"example":"t=1726300000,v1=9b2c…"},{"name":"X-CheckLeaked-Event","in":"header","required":true,"schema":{"type":"string","enum":["tracking.finding"]}},{"name":"X-CheckLeaked-Delivery","in":"header","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TrackingFindingEvent"}}}},"responses":{"200":{"description":"Any 2xx acknowledges the delivery."}}}}},"paths":{"/deep_report":{"post":{"tags":["Deep Search AI"],"summary":"AI intelligence report over your findings (Pro)","description":"Turns findings you ALREADY fetched through `/leak_check`, `/experimental`, `/dehashed` and `/leakradar/search/raw` into one structured dossier: executive summary, 0-100 risk, consolidated identity, credential statistics, password analysis, breach list, cross-engine correlations, attack scenarios and per-account recommendations. Deterministic figures (identity lists, counts, `identity_graph`, `password_stats`) are measured from the rows; the model writes the prose.\n\nRe-runs NO engine and charges NO search credit. A bounded subset of the hashes you send is cracked first (Snusbase, cache-first, at most 24 hashes / 15 s) so recovered plaintext feeds the reuse and weakness analysis.\n\n**Requires:** Pro subscription. One report per account at a time and a 15 s cooldown between reports: `report_busy` / `report_throttled` are safe to retry. Business errors are HTTP 200 `{ \"error\": \"<code>\" }` (codes listed on the response schema).","operationId":"deepReport","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeepReportRequest"}}}},"responses":{"200":{"description":"The dossier, or a `report_*` error code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeepReportResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/deep_report/pdf":{"post":{"tags":["Deep Search AI"],"summary":"Typeset a dossier as PDF (Pro)","description":"Renders a `report` returned by `/deep_report` as an A4 PDF (masthead, severity band, statistics strip, tables, numbered footer). No AI call, no engine run, no credit: it only typesets what you send. Answers `application/pdf`; failures are JSON `{ \"error\": \"<code>\" }` with 400 (`report_no_findings`), 401, 403 (`report_pro_required`) or 413 (`report_too_large`, body over 2 MB).","operationId":"deepReportPdf","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeepReportPdfRequest"}}}},"responses":{"200":{"description":"The PDF file (`Content-Disposition: attachment`).","content":{"application/pdf":{"schema":{"type":"string","format":"binary"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/worm_report":{"post":{"tags":["Deep Search AI"],"summary":"AI web investigation (Pro)","description":"Runs the WormGPT investigation agent on `term`: the model searches the web and calls the leak / OSINT tools itself (web search + fetch, LeakCheck, Dehashed, Snusbase, LeakRadar, hash cracking, GHunt, IP, WHOIS, DNS, WhatsApp, ...), pivots until the leads run dry and returns a complete Markdown dossier with its sources. Findings you already hold can be sent as grounding (same body as `/deep_report`) so the dossier cross-references them; they are optional.\n\n**Billing:** one unit of the account's WormGPT daily quota per successful answer (Pro 250 / day), separate from search credits. The agent's own tool calls spend no CheckLeaked credit.\n\n**Requires:** Pro subscription and a bot token on the account. Takes up to about 3 minutes; one investigation per account at a time and a 15 s cooldown: `worm_busy` / `worm_throttled` are safe to retry. Business errors are HTTP 200 `{ \"error\": \"<code>\" }`.","operationId":"wormReport","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeepReportRequest"}}}},"responses":{"200":{"description":"The investigation, or a `worm_*` error code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WormReportResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/private_bots":{"get":{"summary":"List Private Bots","description":"The account's private Discord / Telegram bots with their runtime state, plus `plan_ok` (Pro / Plus) and `configured` (server has the encryption key). Pro / Plus only. The token is validated against the platform (Discord `users/@me`, Telegram `getMe`), stored encrypted (AES-256-GCM), and never returned — only its last four characters plus the validated bot id / username. The bot runs on CheckLeaked's servers with the same commands as the shared bots and answers ONLY the owner's linked account (`/auth` accepts only the owner's own bot token). One bot per platform per account; a lapsed plan stops it. Discord bots need no privileged intents (slash commands and DMs work; prefix commands inside servers cannot read message text without the Message Content intent). `invite_url` adds a Discord bot to a server with minimal permissions.","operationId":"privateBotsList","tags":["Private bots"],"responses":{"200":{"description":"Bots","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"object","properties":{"bots":{"type":"array","items":{"$ref":"#/components/schemas/PrivateBot"}},"plan_ok":{"type":"boolean"},"configured":{"type":"boolean"},"max_per_platform":{"type":"integer","example":1}}},"error":{"type":["string","null"]}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}},"post":{"summary":"Create, Replace or Toggle a Private Bot","description":"With `token`: validate, encrypt and (re)store the bot; it starts within seconds. With `enabled` only: pause or resume an existing bot. Pro / Plus only. The token is validated against the platform (Discord `users/@me`, Telegram `getMe`), stored encrypted (AES-256-GCM), and never returned — only its last four characters plus the validated bot id / username. The bot runs on CheckLeaked's servers with the same commands as the shared bots and answers ONLY the owner's linked account (`/auth` accepts only the owner's own bot token). One bot per platform per account; a lapsed plan stops it. Discord bots need no privileged intents (slash commands and DMs work; prefix commands inside servers cannot read message text without the Message Content intent). `invite_url` adds a Discord bot to a server with minimal permissions.","operationId":"privateBotSave","tags":["Private bots"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PrivateBotSaveRequest"}}}},"responses":{"200":{"description":"Saved; `error` is set when the token is refused, the plan does not allow it, or the server is not configured.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"object","properties":{"bot":{"$ref":"#/components/schemas/PrivateBot"}}},"error":{"type":["string","null"]}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/private_bots/delete":{"post":{"summary":"Delete a Private Bot","description":"Stops the bot and forgets its token.","operationId":"privateBotDelete","tags":["Private bots"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["platform"],"properties":{"platform":{"type":"string","enum":["discord","telegram"]}}}}}},"responses":{"200":{"description":"Removed","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"object","properties":{"removed":{"type":"boolean"}}},"error":{"type":["string","null"]}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/webhook":{"get":{"summary":"Get Tracking Webhook","description":"The account's tracking webhook, or `null` when none is configured. The signing secret is never returned — only `secret_hint`.","operationId":"webhookGet","tags":["Webhooks"],"responses":{"200":{"description":"Current webhook","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookGetResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}},"post":{"summary":"Create or Update Tracking Webhook","description":"One webhook per account. Creating it returns the signing `secret` exactly once; later saves return the webhook without it unless `rotate_secret` is true. Any save resets the failure counter and re-enables an auto-disabled hook.\n\nEvery delivery is signed. Header `X-CheckLeaked-Signature: t=<unix seconds>,v1=<hex>` where `v1 = HMAC-SHA256(secret, \"<t>.<raw request body>\")`. Verify with a constant-time comparison and reject timestamps older than your tolerance (300 s is typical). Also sent: `X-CheckLeaked-Event` (event name), `X-CheckLeaked-Delivery` (UUID, unique per attempt), `User-Agent: CheckLeaked-Webhooks/1.0`.\n\nEvents are documented under the top-level `webhooks` object of this specification (`trackingFinding`).","operationId":"webhookSave","tags":["Webhooks"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookSaveRequest"}}}},"responses":{"200":{"description":"Saved. `error` is set (and `success` null) when the URL is refused.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookSaveResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/webhook/delete":{"post":{"summary":"Delete Tracking Webhook","description":"Remove the account's webhook. Deliveries stop with the next check cycle.","operationId":"webhookDelete","tags":["Webhooks"],"responses":{"200":{"description":"Removed","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"object","properties":{"removed":{"type":"boolean"}}},"error":{"type":["string","null"]}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/webhook/test":{"post":{"summary":"Send a Test Delivery","description":"POSTs a synthetic `tracking.finding` event (with `\"test\": true`) to the configured URL — signed exactly like a real one, single attempt, 10 s timeout. Limited to 5 calls per minute.","operationId":"webhookTest","tags":["Webhooks"],"responses":{"200":{"description":"Delivery outcome","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookTestResult"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"description":"Rate limited","content":{"application/json":{}}}}}},"/leakradar/search/raw":{"post":{"summary":"Raw stealer-log search","description":"Search the raw stealer-log corpus for text (`q`) and/or metadata filters. Each result is a **block** inside a source file, addressed by `container_id` + `entry_path` + `seq`. This is the entry point of the raw flow:\n\n1. `POST /leakradar/search/raw` → find matching blocks.\n2. `GET /leakradar/search/raw/parts` → list the blocks of one entry.\n3. `GET /leakradar/search/raw/part` → **read a specific leak block** (unlock to reveal plaintext).\n\nUse cursor pagination for deep result sets: pass the returned `next_cursor` back as `?cursor=`.\n\n**Auth & credits:** requires the `api-key` bot token. Successful calls debit credits from your CheckLeaked balance per your plan; access to LeakRadar requires a Plus or Pro subscription. Business errors (missing/invalid input, plan not entitled, upstream failure) return HTTP 200 with `{ \"success\": false, \"error\": \"<message>\" }`.","operationId":"leakRadarRawSearch","tags":["LeakRadar Raw Search"],"parameters":[{"name":"page","in":"query","required":false,"description":"1-based page index.","schema":{"type":"integer","minimum":1,"default":1}},{"name":"page_size","in":"query","required":false,"description":"Items per page. Max 100.","schema":{"type":"integer","minimum":1,"maximum":100,"default":10}},{"name":"cursor","in":"query","required":false,"description":"Opaque cursor from a previous response (`next_cursor`) for cursor-mode pagination.","schema":{"type":"string"}},{"name":"auto_unlock","in":"query","required":false,"description":"**Deprecated and ignored.** Auto-unlock is always on: results are never returned masked, so no separate unlock call is needed. A page that opens records for the first time costs a flat 1 credit whatever the row count; a page whose records were already open costs nothing. Any value sent here is discarded.","deprecated":true,"schema":{"type":"boolean","default":true}},{"name":"refresh","in":"query","required":false,"description":"Bypass the cache and force a fresh upstream lookup.","schema":{"type":"boolean","default":false}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeakRadarRawSearchRequest"},"examples":{"byText":{"summary":"Full-text query","value":{"q":"netflix.com"}},"byFilter":{"summary":"Filter by extension + category","value":{"exts":["txt"],"categories":["stealer-logs"]}},"combined":{"summary":"Text + container + date window","value":{"q":"admin@corp.com","container_id":177035,"ingested_at_min":"2026-01-01T00:00:00Z"}}}}}},"responses":{"200":{"description":"Matching raw blocks. Masked rows carry `already_unlocked: false`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeakRadarRawSearchResponse"}}}},"400":{"description":"Business error — returns `{ success: false, error }`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeakRadarError"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/leakradar/search/raw/lines":{"post":{"summary":"Raw search with unlocked matching records","description":"Run a raw stealer-log search, **unlock the matched blocks, and return the parsed leak records that match `q`** — in one call.\n\nThis collapses the 3-call raw flow (`/search/raw` → `/search/raw/parts` → `/search/raw/part`) plus client-side filtering into a single request. It exists because a locked block is redacted to █ characters, so it cannot be filtered until it is unlocked.\n\n**Records, not lines.** Each match is the whole enclosing record. Filtering a stealer-log credential block by URL would otherwise return the `URL:` line and drop the `PASS:` line below it. For cookie jars and combolists a record is a single line, so nothing is lost.\n\n`line_number` is 1-based **within the block**, not within the original file — blocks are byte-sliced and no upstream field carries a file-level line number.\n\n`parsed` is best-effort: stealer-log formats are not schema'd, so `format` is detected heuristically. `text` always holds the verbatim record, so a mis-parse can never hide data.\n\n**Auth & credits:** requires the `api-key` bot token. Charged a flat 1 credit per call that has to open a block for the first time; a call answered entirely from blocks opened earlier is free. Requires a Pro subscription. Business errors (missing/invalid input, plan not entitled, upstream failure) return HTTP 200 with `{ \"success\": false, \"error\": \"<message>\" }`.","operationId":"leakRadarRawSearchLines","tags":["LeakRadar Raw Search"],"parameters":[{"name":"max_hits","in":"query","required":false,"description":"Blocks to unlock and parse. Each costs one upstream part fetch, so large values are slow.","schema":{"type":"integer","minimum":1,"maximum":50,"default":10}},{"name":"case_sensitive","in":"query","required":false,"description":"Match `q` case-sensitively.","schema":{"type":"boolean","default":false}},{"name":"context_lines","in":"query","required":false,"description":"Extra lines of context either side of a match. Only applied to `unknown`-format blocks, where no record structure could be detected.","schema":{"type":"integer","minimum":0,"maximum":10,"default":0}},{"name":"cursor","in":"query","required":false,"description":"Opaque cursor from a previous response (`search.next_cursor`).","schema":{"type":"string"}},{"name":"refresh","in":"query","required":false,"description":"Bypass the cache and force a fresh upstream lookup.","schema":{"type":"boolean","default":false}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeakRadarRawSearchRequest"},"examples":{"byText":{"summary":"Find and unlock Netflix credentials","value":{"q":"netflix.com"}},"scoped":{"summary":"Restrict to stealer-log password dumps","value":{"q":"netflix.com","categories":["stealer-logs"],"file_name":["*password*"]}}}}}},"responses":{"200":{"description":"Matched records, grouped by source entry.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeakRadarRawLinesResponse"}}}},"400":{"description":"Business error — returns `{ success: false, error }`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeakRadarError"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/leakradar/search/raw/parts":{"get":{"summary":"List blocks of a raw entry","description":"List the sequential blocks (parts) available for a single raw entry, so you can page through a large file and pick the `seq` you want to read.\n\n**Auth & credits:** requires the `api-key` bot token. Successful calls debit credits from your CheckLeaked balance per your plan; access to LeakRadar requires a Plus or Pro subscription. Business errors (missing/invalid input, plan not entitled, upstream failure) return HTTP 200 with `{ \"success\": false, \"error\": \"<message>\" }`.","operationId":"leakRadarRawListParts","tags":["LeakRadar Raw Search"],"parameters":[{"name":"container_id","in":"query","required":true,"description":"Container id from a raw-search result.","schema":{"type":"integer"}},{"name":"entry_path","in":"query","required":true,"description":"Entry path from a raw-search result.","schema":{"type":"string"}},{"name":"page","in":"query","required":false,"description":"1-based page index.","schema":{"type":"integer","minimum":1,"default":1}},{"name":"page_size","in":"query","required":false,"description":"Items per page. Max 1000.","schema":{"type":"integer","minimum":1,"maximum":1000,"default":100}},{"name":"refresh","in":"query","required":false,"description":"Bypass the cache and force a fresh upstream lookup.","schema":{"type":"boolean","default":false}}],"responses":{"200":{"description":"Available blocks for the entry.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeakRadarPartsResponse"}}}},"400":{"description":"Business error — returns `{ success: false, error }`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeakRadarError"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/leakradar/search/raw/part":{"get":{"summary":"Read a specific leak block","description":"Fetch the content of one specific raw block by `container_id` + `entry_path` + `seq` — **this is how you see the actual leaked data for a single hit**. Blocks are unlocked automatically, so `text` is normally plaintext. This endpoint is free — the search that surfaced the block already paid for it. A redacted response (`censored: true`, █ characters) means the block could not be opened upstream; retry later.\n\n**Auth & credits:** requires the `api-key` bot token. Successful calls debit credits from your CheckLeaked balance per your plan; access to LeakRadar requires a Plus or Pro subscription. Business errors (missing/invalid input, plan not entitled, upstream failure) return HTTP 200 with `{ \"success\": false, \"error\": \"<message>\" }`.","operationId":"leakRadarRawGetPart","tags":["LeakRadar Raw Search"],"parameters":[{"name":"container_id","in":"query","required":true,"description":"Container id of the block.","schema":{"type":"integer"}},{"name":"entry_path","in":"query","required":true,"description":"Entry path of the block.","schema":{"type":"string"}},{"name":"seq","in":"query","required":true,"description":"Sequential block number to fetch.","schema":{"type":"integer","minimum":0}},{"name":"trim_overlap","in":"query","required":false,"description":"Strip the overlap prefix carried over from the previous block.","schema":{"type":"boolean","default":false}},{"name":"overlap_chars","in":"query","required":false,"description":"Overlap size in characters (0–8192).","schema":{"type":"integer","minimum":0,"maximum":8192,"default":256}},{"name":"auto_unlock","in":"query","required":false,"description":"**Deprecated and ignored.** Auto-unlock is always on: results are never returned masked, so no separate unlock call is needed. A page that opens records for the first time costs a flat 1 credit whatever the row count; a page whose records were already open costs nothing. Any value sent here is discarded.","deprecated":true,"schema":{"type":"boolean","default":true}}],"responses":{"200":{"description":"The requested block. `text` is plaintext when unlocked, otherwise redacted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeakRadarPartResponse"}}}},"400":{"description":"Business error — returns `{ success: false, error }`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeakRadarError"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/leakradar/search/raw/export":{"post":{"summary":"Export raw search results","description":"Schedule an export of a raw search. `target=rows` exports matched rows; `target=parts` exports full blocks. Returns an export job; poll `GET /leakradar/tasks/{id}` (or the exports list) for completion.\n\n**Auth & credits:** requires the `api-key` bot token. Successful calls debit credits from your CheckLeaked balance per your plan; access to LeakRadar requires a Plus or Pro subscription. Business errors (missing/invalid input, plan not entitled, upstream failure) return HTTP 200 with `{ \"success\": false, \"error\": \"<message>\" }`.","operationId":"leakRadarRawExport","tags":["LeakRadar Raw Search"],"parameters":[{"name":"target","in":"query","required":false,"description":"What to export.","schema":{"type":"string","enum":["rows","parts"],"default":"rows"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeakRadarRawSearchRequest"}}}},"responses":{"200":{"description":"Scheduled export job.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"description":"Export job descriptor (e.g. `{ status, message, export_id }`)."}}}},"400":{"description":"Business error — returns `{ success: false, error }`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeakRadarError"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/leakradar/search/raw/unlock-async":{"post":{"summary":"Async-unlock raw blocks","description":"Queue a background job that unlocks the masked blocks matching the given raw filters (up to `max`). Returns a `task_id`; poll `GET /leakradar/tasks/{id}` or `GET /leakradar/tasks/{id}/wait`. `max` credits are reserved up front and unused credits refunded on completion.\n\n**Auth & credits:** requires the `api-key` bot token. Successful calls debit credits from your CheckLeaked balance per your plan; access to LeakRadar requires a Plus or Pro subscription. Business errors (missing/invalid input, plan not entitled, upstream failure) return HTTP 200 with `{ \"success\": false, \"error\": \"<message>\" }`.","operationId":"leakRadarRawUnlockAsync","tags":["LeakRadar Raw Search"],"parameters":[{"name":"max","in":"query","required":false,"description":"Maximum blocks to unlock.","schema":{"type":"integer","minimum":1,"default":5}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeakRadarRawSearchRequest"}}}},"responses":{"200":{"description":"Queued task reference.","content":{"application/json":{"schema":{"type":"object","properties":{"task_id":{"type":"string"}},"required":["task_id"]}}}},"400":{"description":"Business error — returns `{ success: false, error }`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeakRadarError"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/leakradar/search/email":{"post":{"summary":"Search leaks by email/username","description":"Paginated listing of credential leaks for an email address or username. Rows are always returned unlocked — there is no masked mode and no separate unlock step. A page that opens records for the first time costs a flat 1 credit however many rows it opened; a page whose records were already open costs nothing.\n\n**Auth & credits:** requires the `api-key` bot token. Successful calls debit credits from your CheckLeaked balance per your plan; access to LeakRadar requires a Plus or Pro subscription. Business errors (missing/invalid input, plan not entitled, upstream failure) return HTTP 200 with `{ \"success\": false, \"error\": \"<message>\" }`.","operationId":"leakRadarEmailSearch","tags":["LeakRadar Search"],"parameters":[{"name":"page","in":"query","required":false,"description":"1-based page index.","schema":{"type":"integer","minimum":1,"default":1}},{"name":"page_size","in":"query","required":false,"description":"Items per page. Max 50.","schema":{"type":"integer","minimum":1,"maximum":50,"default":50}},{"name":"auto_unlock","in":"query","required":false,"description":"**Deprecated and ignored.** Auto-unlock is always on: results are never returned masked, so no separate unlock call is needed. A page that opens records for the first time costs a flat 1 credit whatever the row count; a page whose records were already open costs nothing. Any value sent here is discarded.","deprecated":true,"schema":{"type":"boolean","default":true}},{"name":"refresh","in":"query","required":false,"description":"Bypass the cache and force a fresh upstream lookup.","schema":{"type":"boolean","default":false}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeakRadarEmailSearchRequest"},"examples":{"email":{"summary":"By email","value":{"email":"user@example.com"}},"username":{"summary":"By username","value":{"email":"johndoe","is_email":false}}}}}},"responses":{"200":{"description":"Page of leak records.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeakRadarLeaksPage"}}}},"400":{"description":"Business error — returns `{ success: false, error }`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeakRadarError"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/leakradar/search/email/unlock":{"post":{"summary":"Unlock email leaks (sync)","description":"Synchronously unlock up to `max` leak records for an email/username and return them with plaintext credentials. Charged per record returned.\n\n**Auth & credits:** requires the `api-key` bot token. Successful calls debit credits from your CheckLeaked balance per your plan; access to LeakRadar requires a Plus or Pro subscription. Business errors (missing/invalid input, plan not entitled, upstream failure) return HTTP 200 with `{ \"success\": false, \"error\": \"<message>\" }`.","operationId":"leakRadarEmailUnlock","tags":["LeakRadar Search"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeakRadarEmailSearchRequest"},"examples":{"ex":{"summary":"Unlock up to 10","value":{"email":"user@example.com","max":10}}}}}},"responses":{"200":{"description":"Unlocked leak records.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeakRadarLeaksPage"}}}},"400":{"description":"Business error — returns `{ success: false, error }`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeakRadarError"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/leakradar/search/email/unlock-async":{"post":{"summary":"Unlock email leaks (async)","description":"Queue a background unlock for an email/username. Returns a `task_id`; `max` credits are reserved up front and slack refunded on completion. Poll `GET /leakradar/tasks/{id}`.\n\n**Auth & credits:** requires the `api-key` bot token. Successful calls debit credits from your CheckLeaked balance per your plan; access to LeakRadar requires a Plus or Pro subscription. Business errors (missing/invalid input, plan not entitled, upstream failure) return HTTP 200 with `{ \"success\": false, \"error\": \"<message>\" }`.","operationId":"leakRadarEmailUnlockAsync","tags":["LeakRadar Search"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeakRadarEmailSearchRequest"},"examples":{"ex":{"summary":"Async unlock","value":{"email":"user@example.com","max":25}}}}}},"responses":{"200":{"description":"Queued task reference.","content":{"application/json":{"schema":{"type":"object","properties":{"task_id":{"type":"string"}},"required":["task_id"]}}}},"400":{"description":"Business error — returns `{ success: false, error }`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeakRadarError"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/leakradar/search/advanced":{"post":{"summary":"Advanced credential search","description":"Search credential leaks with structured filters (username/password/url/email facets, strength, date window). Masked rows are auto-unlocked.\n\n**Auth & credits:** requires the `api-key` bot token. Successful calls debit credits from your CheckLeaked balance per your plan; access to LeakRadar requires a Plus or Pro subscription. Business errors (missing/invalid input, plan not entitled, upstream failure) return HTTP 200 with `{ \"success\": false, \"error\": \"<message>\" }`.","operationId":"leakRadarAdvancedSearch","tags":["LeakRadar Search"],"parameters":[{"name":"page","in":"query","required":false,"description":"1-based page index.","schema":{"type":"integer","minimum":1,"default":1}},{"name":"page_size","in":"query","required":false,"description":"Items per page. Max 50.","schema":{"type":"integer","minimum":1,"maximum":50,"default":50}},{"name":"refresh","in":"query","required":false,"description":"Bypass the cache and force a fresh upstream lookup.","schema":{"type":"boolean","default":false}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeakRadarSearchFilters"},"examples":{"byDomain":{"summary":"Corp email domain, strong passwords","value":{"email_domain":["corp.com"],"password_strength":"strong"}},"byUrl":{"summary":"URL host + recent","value":{"url_host":["admin.example.com"],"added_from":"2026-01-01T00:00:00Z"}}}}}},"responses":{"200":{"description":"Page of leak records.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeakRadarLeaksPage"}}}},"400":{"description":"Business error — returns `{ success: false, error }`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeakRadarError"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/leakradar/search/advanced/unlock":{"post":{"summary":"Unlock advanced results (sync)","description":"Synchronously unlock up to `max` records matching the advanced filters. Charged per record returned.\n\n**Auth & credits:** requires the `api-key` bot token. Successful calls debit credits from your CheckLeaked balance per your plan; access to LeakRadar requires a Plus or Pro subscription. Business errors (missing/invalid input, plan not entitled, upstream failure) return HTTP 200 with `{ \"success\": false, \"error\": \"<message>\" }`.","operationId":"leakRadarAdvancedUnlock","tags":["LeakRadar Search"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeakRadarSearchFilters"},"examples":{"ex":{"summary":"Unlock domain hits","value":{"email_domain":["corp.com"],"max":20}}}}}},"responses":{"200":{"description":"Unlocked leak records.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeakRadarLeaksPage"}}}},"400":{"description":"Business error — returns `{ success: false, error }`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeakRadarError"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/leakradar/search/advanced/unlock-async":{"post":{"summary":"Unlock advanced results (async)","description":"Queue a background unlock for the advanced filters. Returns a `task_id`; poll `GET /leakradar/tasks/{id}`.\n\n**Auth & credits:** requires the `api-key` bot token. Successful calls debit credits from your CheckLeaked balance per your plan; access to LeakRadar requires a Plus or Pro subscription. Business errors (missing/invalid input, plan not entitled, upstream failure) return HTTP 200 with `{ \"success\": false, \"error\": \"<message>\" }`.","operationId":"leakRadarAdvancedUnlockAsync","tags":["LeakRadar Search"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeakRadarSearchFilters"},"examples":{"ex":{"summary":"Async unlock","value":{"email_domain":["corp.com"],"max":50}}}}}},"responses":{"200":{"description":"Queued task reference.","content":{"application/json":{"schema":{"type":"object","properties":{"task_id":{"type":"string"}},"required":["task_id"]}}}},"400":{"description":"Business error — returns `{ success: false, error }`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeakRadarError"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/leakradar/search/advanced/export":{"post":{"summary":"Export advanced results","description":"Schedule a CSV/JSON export of the advanced-search results. Returns an export job descriptor.\n\n**Auth & credits:** requires the `api-key` bot token. Successful calls debit credits from your CheckLeaked balance per your plan; access to LeakRadar requires a Plus or Pro subscription. Business errors (missing/invalid input, plan not entitled, upstream failure) return HTTP 200 with `{ \"success\": false, \"error\": \"<message>\" }`.","operationId":"leakRadarAdvancedExport","tags":["LeakRadar Search"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeakRadarSearchFilters"},"examples":{"ex":{"summary":"CSV export","value":{"email_domain":["corp.com"],"format":"csv"}}}}}},"responses":{"200":{"description":"Scheduled export job.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"description":"Export job descriptor."}}}},"400":{"description":"Business error — returns `{ success: false, error }`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeakRadarError"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/leakradar/domain/summary":{"get":{"summary":"Domain breach summary","description":"Aggregate breach exposure for a domain (employees / customers / third-parties counts). Use `light=true` for just the headline counts.\n\n**Auth & credits:** requires the `api-key` bot token. Successful calls debit credits from your CheckLeaked balance per your plan; access to LeakRadar requires a Plus or Pro subscription. Business errors (missing/invalid input, plan not entitled, upstream failure) return HTTP 200 with `{ \"success\": false, \"error\": \"<message>\" }`.","operationId":"leakRadarDomainSummary","tags":["LeakRadar Domain"],"parameters":[{"name":"domain","in":"query","required":true,"description":"Domain to summarize (e.g. `example.com`).","schema":{"type":"string"}},{"name":"light","in":"query","required":false,"description":"Return only headline counts.","schema":{"type":"boolean","default":false}},{"name":"include_search_count","in":"query","required":false,"description":"Include per-bucket search counts.","schema":{"type":"boolean","default":false}},{"name":"refresh","in":"query","required":false,"description":"Bypass the cache and force a fresh upstream lookup.","schema":{"type":"boolean","default":false}}],"responses":{"200":{"description":"Domain breach summary.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"description":"Domain summary (shape depends on `light`)."}}}},"400":{"description":"Business error — returns `{ success: false, error }`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeakRadarError"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/leakradar/domain/list/{bucket}":{"get":{"summary":"List domain leaks by bucket","description":"Paginated leak records for a domain within one bucket: `employees`, `customers`, `third_parties`, or `all`.\n\n**Auth & credits:** requires the `api-key` bot token. Successful calls debit credits from your CheckLeaked balance per your plan; access to LeakRadar requires a Plus or Pro subscription. Business errors (missing/invalid input, plan not entitled, upstream failure) return HTTP 200 with `{ \"success\": false, \"error\": \"<message>\" }`.","operationId":"leakRadarDomainBucket","tags":["LeakRadar Domain"],"parameters":[{"name":"bucket","in":"path","required":true,"description":"Which population to list.","schema":{"type":"string","enum":["employees","customers","third_parties","all"]}},{"name":"domain","in":"query","required":true,"description":"Domain to list.","schema":{"type":"string"}},{"name":"page","in":"query","required":false,"description":"1-based page index.","schema":{"type":"integer","minimum":1,"default":1}},{"name":"page_size","in":"query","required":false,"description":"Items per page. Max 50.","schema":{"type":"integer","minimum":1,"maximum":50,"default":50}},{"name":"search","in":"query","required":false,"description":"Free-text filter within the bucket.","schema":{"type":"string"}},{"name":"auto_unlock","in":"query","required":false,"description":"**Deprecated and ignored.** Auto-unlock is always on: results are never returned masked, so no separate unlock call is needed. A page that opens records for the first time costs a flat 1 credit whatever the row count; a page whose records were already open costs nothing. Any value sent here is discarded.","deprecated":true,"schema":{"type":"boolean","default":true}},{"name":"refresh","in":"query","required":false,"description":"Bypass the cache and force a fresh upstream lookup.","schema":{"type":"boolean","default":false}}],"responses":{"200":{"description":"Page of leak records for the bucket.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeakRadarLeaksPage"}}}},"400":{"description":"Business error — returns `{ success: false, error }`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeakRadarError"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/leakradar/domain/{domain}/subdomains":{"get":{"summary":"List exposed subdomains","description":"Subdomains of the given domain that appear in leak data, with occurrence counts.\n\n**Auth & credits:** requires the `api-key` bot token. Successful calls debit credits from your CheckLeaked balance per your plan; access to LeakRadar requires a Plus or Pro subscription. Business errors (missing/invalid input, plan not entitled, upstream failure) return HTTP 200 with `{ \"success\": false, \"error\": \"<message>\" }`.","operationId":"leakRadarDomainSubdomains","tags":["LeakRadar Domain"],"parameters":[{"name":"domain","in":"path","required":true,"description":"Root domain.","schema":{"type":"string"}},{"name":"page","in":"query","required":false,"description":"1-based page index.","schema":{"type":"integer","minimum":1,"default":1}},{"name":"page_size","in":"query","required":false,"description":"Items per page. Max 50.","schema":{"type":"integer","minimum":1,"maximum":50,"default":50}},{"name":"search","in":"query","required":false,"description":"Filter subdomains.","schema":{"type":"string"}},{"name":"refresh","in":"query","required":false,"description":"Bypass the cache and force a fresh upstream lookup.","schema":{"type":"boolean","default":false}}],"responses":{"200":{"description":"Subdomain occurrences.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"description":"Paginated subdomain occurrences."}}}},"400":{"description":"Business error — returns `{ success: false, error }`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeakRadarError"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/leakradar/domain/{domain}/urls":{"get":{"summary":"List exposed URLs","description":"URLs under the given domain that appear in leak data, with occurrence counts.\n\n**Auth & credits:** requires the `api-key` bot token. Successful calls debit credits from your CheckLeaked balance per your plan; access to LeakRadar requires a Plus or Pro subscription. Business errors (missing/invalid input, plan not entitled, upstream failure) return HTTP 200 with `{ \"success\": false, \"error\": \"<message>\" }`.","operationId":"leakRadarDomainUrls","tags":["LeakRadar Domain"],"parameters":[{"name":"domain","in":"path","required":true,"description":"Root domain.","schema":{"type":"string"}},{"name":"page","in":"query","required":false,"description":"1-based page index.","schema":{"type":"integer","minimum":1,"default":1}},{"name":"page_size","in":"query","required":false,"description":"Items per page. Max 50.","schema":{"type":"integer","minimum":1,"maximum":50,"default":50}},{"name":"search","in":"query","required":false,"description":"Filter URLs.","schema":{"type":"string"}},{"name":"refresh","in":"query","required":false,"description":"Bypass the cache and force a fresh upstream lookup.","schema":{"type":"boolean","default":false}}],"responses":{"200":{"description":"URL occurrences.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"description":"Paginated URL occurrences."}}}},"400":{"description":"Business error — returns `{ success: false, error }`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeakRadarError"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/leakradar/domain/report":{"get":{"summary":"Composite domain report","description":"One-shot composite: summary + first page of each bucket + first page of subdomains/urls, for a single credit charge.\n\n**Auth & credits:** requires the `api-key` bot token. Successful calls debit credits from your CheckLeaked balance per your plan; access to LeakRadar requires a Plus or Pro subscription. Business errors (missing/invalid input, plan not entitled, upstream failure) return HTTP 200 with `{ \"success\": false, \"error\": \"<message>\" }`.","operationId":"leakRadarDomainReport","tags":["LeakRadar Domain"],"parameters":[{"name":"domain","in":"query","required":true,"description":"Domain to report on.","schema":{"type":"string"}},{"name":"refresh","in":"query","required":false,"description":"Bypass the cache and force a fresh upstream lookup.","schema":{"type":"boolean","default":false}}],"responses":{"200":{"description":"Composite report.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"description":"Composite domain report."}}}},"400":{"description":"Business error — returns `{ success: false, error }`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeakRadarError"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/leakradar/dark-web/search":{"post":{"summary":"Search dark-web posts","description":"Search indexed dark-web forum/market posts by simple `query` or advanced field filters. Requires Plus/Pro.\n\n**Auth & credits:** requires the `api-key` bot token. Successful calls debit credits from your CheckLeaked balance per your plan; access to LeakRadar requires a Plus or Pro subscription. Business errors (missing/invalid input, plan not entitled, upstream failure) return HTTP 200 with `{ \"success\": false, \"error\": \"<message>\" }`.","operationId":"leakRadarDarkWebSearch","tags":["LeakRadar Dark Web"],"parameters":[{"name":"page","in":"query","required":false,"description":"1-based page index.","schema":{"type":"integer","minimum":1,"default":1}},{"name":"page_size","in":"query","required":false,"description":"Items per page. Max 100.","schema":{"type":"integer","minimum":1,"maximum":100,"default":25}},{"name":"sources","in":"query","required":false,"description":"Comma-separated source ids to restrict to.","schema":{"type":"string"}},{"name":"date_from","in":"query","required":false,"description":"Only posts on/after this ISO datetime.","schema":{"type":"string","format":"date-time"}},{"name":"date_to","in":"query","required":false,"description":"Only posts on/before this ISO datetime.","schema":{"type":"string","format":"date-time"}},{"name":"sort_by","in":"query","required":false,"schema":{"type":"string","enum":["ingested_at","published_at"]}},{"name":"sort_order","in":"query","required":false,"schema":{"type":"string","enum":["asc","desc"]}},{"name":"refresh","in":"query","required":false,"description":"Bypass the cache and force a fresh upstream lookup.","schema":{"type":"boolean","default":false}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeakRadarDarkWebSearchRequest"},"examples":{"ex":{"summary":"By domain mention","value":{"query":"example.com"}}}}}},"responses":{"200":{"description":"Page of dark-web posts.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeakRadarDarkWebSearchResponse"}}}},"400":{"description":"Business error — returns `{ success: false, error }`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeakRadarError"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/leakradar/dark-web/post/{post_id}":{"get":{"summary":"Get a dark-web post","description":"Fetch the full content of one dark-web post by id.\n\n**Auth & credits:** requires the `api-key` bot token. Successful calls debit credits from your CheckLeaked balance per your plan; access to LeakRadar requires a Plus or Pro subscription. Business errors (missing/invalid input, plan not entitled, upstream failure) return HTTP 200 with `{ \"success\": false, \"error\": \"<message>\" }`.","operationId":"leakRadarDarkWebPost","tags":["LeakRadar Dark Web"],"parameters":[{"name":"post_id","in":"path","required":true,"description":"Post id from a dark-web search result.","schema":{"type":"string"}}],"responses":{"200":{"description":"The dark-web post.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeakRadarDarkWebItem"}}}},"400":{"description":"Business error — returns `{ success: false, error }`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeakRadarError"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/leakradar/dark-web/sources":{"get":{"summary":"List dark-web sources","description":"List available dark-web sources with post counts.\n\n**Auth & credits:** requires the `api-key` bot token. Successful calls debit credits from your CheckLeaked balance per your plan; access to LeakRadar requires a Plus or Pro subscription. Business errors (missing/invalid input, plan not entitled, upstream failure) return HTTP 200 with `{ \"success\": false, \"error\": \"<message>\" }`.","operationId":"leakRadarDarkWebSources","tags":["LeakRadar Dark Web"],"responses":{"200":{"description":"Available sources.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"description":"Sources with counts."}}}},"400":{"description":"Business error — returns `{ success: false, error }`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeakRadarError"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/leakradar/dark-web/stats":{"get":{"summary":"Dark-web index stats","description":"Aggregate stats for the dark-web index (total posts, sources, freshness).\n\n**Auth & credits:** requires the `api-key` bot token. Successful calls debit credits from your CheckLeaked balance per your plan; access to LeakRadar requires a Plus or Pro subscription. Business errors (missing/invalid input, plan not entitled, upstream failure) return HTTP 200 with `{ \"success\": false, \"error\": \"<message>\" }`.","operationId":"leakRadarDarkWebStats","tags":["LeakRadar Dark Web"],"responses":{"200":{"description":"Index statistics.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"description":"Index statistics."}}}},"400":{"description":"Business error — returns `{ success: false, error }`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeakRadarError"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/leakradar/password-range":{"get":{"summary":"SHA-1 password range (k-anonymity)","description":"Return the breach-occurrence range for a SHA-1 hash prefix (≥5 hex chars). Free/low-cost building block for pwned-password checks — never send the full hash.\n\n**Auth & credits:** requires the `api-key` bot token. Successful calls debit credits from your CheckLeaked balance per your plan; access to LeakRadar requires a Plus or Pro subscription. Business errors (missing/invalid input, plan not entitled, upstream failure) return HTTP 200 with `{ \"success\": false, \"error\": \"<message>\" }`.","operationId":"leakRadarPasswordRange","tags":["LeakRadar Utilities"],"parameters":[{"name":"prefix","in":"query","required":true,"description":"SHA-1 hash prefix, at least 5 hex chars.","schema":{"type":"string","minLength":5}},{"name":"limit","in":"query","required":false,"description":"Max suffixes to return.","schema":{"type":"integer","minimum":1}},{"name":"suffix_only","in":"query","required":false,"description":"Return only suffixes (omit counts).","schema":{"type":"boolean","default":false}}],"responses":{"200":{"description":"Hash range for the prefix.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeakRadarPasswordRangeResponse"}}}},"400":{"description":"Business error — returns `{ success: false, error }`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeakRadarError"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/leakradar/pwned":{"post":{"summary":"Pwned-password check","description":"Check whether a password appears in breach data. Send `password` (hashed server-side, never logged) or a precomputed `sha1`. Returns `{ pwned, count }`.\n\n**Auth & credits:** requires the `api-key` bot token. Successful calls debit credits from your CheckLeaked balance per your plan; access to LeakRadar requires a Plus or Pro subscription. Business errors (missing/invalid input, plan not entitled, upstream failure) return HTTP 200 with `{ \"success\": false, \"error\": \"<message>\" }`.","operationId":"leakRadarPwned","tags":["LeakRadar Utilities"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeakRadarPwnedRequest"},"examples":{"byPassword":{"summary":"By plaintext","value":{"password":"hunter2"}},"bySha1":{"summary":"By SHA-1 hex","value":{"sha1":"000000005AD76BD555C1D6D771DE417A4B87E4B4"}}}}}},"responses":{"200":{"description":"Pwned verdict.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeakRadarPwnedResponse"}}}},"400":{"description":"Business error — returns `{ success: false, error }`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeakRadarError"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/leakradar/cross-source-check":{"post":{"summary":"Cross-source exposure check","description":"Fan-out check across email leaks + domain summary (+ dark web for Plus/Pro) in one call. Returns each source result plus aggregated hit counts.\n\n**Auth & credits:** requires the `api-key` bot token. Successful calls debit credits from your CheckLeaked balance per your plan; access to LeakRadar requires a Plus or Pro subscription. Business errors (missing/invalid input, plan not entitled, upstream failure) return HTTP 200 with `{ \"success\": false, \"error\": \"<message>\" }`.","operationId":"leakRadarCrossSourceCheck","tags":["LeakRadar Utilities"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string","description":"Email/username to check."},"domain":{"type":"string","description":"Domain to check."}},"description":"Provide `email` and/or `domain`."},"examples":{"both":{"summary":"Email + domain","value":{"email":"user@example.com","domain":"example.com"}}}}}},"responses":{"200":{"description":"Aggregated cross-source result.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"description":"Per-source results and `totals`."}}}},"400":{"description":"Business error — returns `{ success: false, error }`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeakRadarError"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/leakradar/unlock":{"post":{"summary":"Unlock leaks by id","description":"Unlock specific leak records by their ids (from search `items[].id`). Charged per record unlocked; ids already unlocked at the shared account level are claimed for you at no charge.\n\n**Auth & credits:** requires the `api-key` bot token. Successful calls debit credits from your CheckLeaked balance per your plan; access to LeakRadar requires a Plus or Pro subscription. Business errors (missing/invalid input, plan not entitled, upstream failure) return HTTP 200 with `{ \"success\": false, \"error\": \"<message>\" }`.","operationId":"leakRadarUnlock","tags":["LeakRadar Utilities"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeakRadarUnlockRequest"},"examples":{"ex":{"summary":"Unlock two records","value":{"leak_ids":["64f0c2a1e3b1","64f0c2a1e3b2"]}}}}}},"responses":{"200":{"description":"Unlock result.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"description":"Unlocked records (or `{ already_unlocked: true, leak_ids, items: [] }`)."}}}},"400":{"description":"Business error — returns `{ success: false, error }`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeakRadarError"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/leakradar/search-history":{"get":{"summary":"Your LeakRadar search history","description":"Paginated log of your recent LeakRadar searches/actions.\n\n**Auth & credits:** requires the `api-key` bot token. Successful calls debit credits from your CheckLeaked balance per your plan; access to LeakRadar requires a Plus or Pro subscription. Business errors (missing/invalid input, plan not entitled, upstream failure) return HTTP 200 with `{ \"success\": false, \"error\": \"<message>\" }`.","operationId":"leakRadarSearchHistory","tags":["LeakRadar Utilities"],"parameters":[{"name":"page","in":"query","required":false,"description":"1-based page index.","schema":{"type":"integer","minimum":1,"default":1}},{"name":"limit","in":"query","required":false,"description":"Items per page.","schema":{"type":"integer","minimum":1,"default":20}}],"responses":{"200":{"description":"Search history.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"description":"Paginated history."}}}},"400":{"description":"Business error — returns `{ success: false, error }`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeakRadarError"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/leakradar/tasks/{id}":{"get":{"summary":"Get async task status","description":"Status of a background task (async unlock / export). Poll until `completed` / `running: false`.\n\n**Auth & credits:** requires the `api-key` bot token. Successful calls debit credits from your CheckLeaked balance per your plan; access to LeakRadar requires a Plus or Pro subscription. Business errors (missing/invalid input, plan not entitled, upstream failure) return HTTP 200 with `{ \"success\": false, \"error\": \"<message>\" }`.","operationId":"leakRadarTaskStatus","tags":["LeakRadar Utilities"],"parameters":[{"name":"id","in":"path","required":true,"description":"Task id returned by an async endpoint.","schema":{"type":"string"}}],"responses":{"200":{"description":"Task status.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"description":"Task status."}}}},"400":{"description":"Business error — returns `{ success: false, error }`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeakRadarError"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/leakradar/tasks/{id}/wait":{"get":{"summary":"Long-poll an async task","description":"Long-poll a background task (capped at ~25s) — returns as soon as it settles or the cap is hit.\n\n**Auth & credits:** requires the `api-key` bot token. Successful calls debit credits from your CheckLeaked balance per your plan; access to LeakRadar requires a Plus or Pro subscription. Business errors (missing/invalid input, plan not entitled, upstream failure) return HTTP 200 with `{ \"success\": false, \"error\": \"<message>\" }`.","operationId":"leakRadarTaskWait","tags":["LeakRadar Utilities"],"parameters":[{"name":"id","in":"path","required":true,"description":"Task id to wait on.","schema":{"type":"string"}}],"responses":{"200":{"description":"Task status.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"description":"Settled task status (or latest state at timeout)."}}}},"400":{"description":"Business error — returns `{ success: false, error }`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeakRadarError"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/auth":{"get":{"summary":"Verify API Key","description":"Validates the provided API key and returns subscription information including role and expiration date.","operationId":"verifyAuth","tags":["Authentication"],"responses":{"200":{"description":"API key is valid","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/valid":{"get":{"summary":"Ping / Health Check","description":"Simple endpoint to verify API connectivity and key validity.","operationId":"ping","tags":["Authentication"],"responses":{"200":{"description":"API is reachable and key is valid","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PingResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/leak_check":{"get":{"summary":"LeakCheck Search","description":"Search the LeakCheck database for breached credentials. Supports multiple search types including email, username, domain, phone, hash, and password.\n\n> **Note:** You must add `192.126.161.211` to your authorized IPs in LeakCheck settings if using a custom key.","operationId":"leakCheckSearch","tags":["LeakCheck Search"],"parameters":[{"name":"check","in":"query","required":true,"description":"The value to search for in breach databases","schema":{"type":"string","minLength":3},"examples":{"email":{"value":"user@example.com","summary":"Search by email"},"username":{"value":"johndoe123","summary":"Search by username"},"domain":{"value":"example.com","summary":"Search by domain"},"phone":{"value":"+1234567890","summary":"Search by phone"}}},{"name":"type","in":"query","required":true,"description":"Search type. **Primary types:** `auto`, `email`, `username`, `keyword`, `domain`, `phone`, `hash`, `password`, `origin`, `phash`. **Legacy types:** `mass`, `login`, `pass_email`, `domain_email`, `pass_login`.","schema":{"type":"string","enum":["auto","email","username","keyword","domain","phone","hash","password","origin","phash","mass","login","pass_email","domain_email","pass_login"]}},{"name":"key","in":"query","required":false,"description":"Optional custom LeakCheck API key. If not provided, the system default key is used.","schema":{"type":"string"}}],"responses":{"200":{"description":"Search results returned successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeakCheckResult"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/dehashed":{"post":{"summary":"Dehashed Search","description":"Search the Dehashed database for breached data. Supports searching by email, username, IP address, name, physical address, phone number, VIN, or free-text.\n\nResults are paginated — use the `page` parameter to navigate through large result sets.","operationId":"dehashedSearch","tags":["Dehashed Search"],"parameters":[{"name":"enrichIps","in":"query","required":false,"description":"When set to `true`, the response will include an `ipLookupMap` field containing whois/geolocation data for every unique IP address found in the result set (`ip_address` field). Lookups are batched in groups of 5 in parallel. Requires Pro/Plus subscription.","schema":{"type":"string","enum":["true","false"],"default":"false"},"example":"true"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DehashedEntry"},"examples":{"emailSearch":{"summary":"Search by email","value":{"entry":"user@example.com","type":"email","page":1}},"usernameSearch":{"summary":"Search by username","value":{"entry":"johndoe","type":"username"}},"freeSearch":{"summary":"Free text search","value":{"entry":"john doe company","type":"free"}},"emailSearchWithIpEnrich":{"summary":"Search by email + enrich IPs","value":{"entry":"user@example.com","type":"email","page":1,"enrichIps":true}}}}}},"responses":{"200":{"description":"Search results returned successfully. When `?enrichIps=true`, the response includes an additional `ipLookupMap` field — see `IpLookupMap` schema.","content":{"application/json":{"schema":{"type":"object","properties":{"ipLookupMap":{"$ref":"#/components/schemas/IpLookupMap"}},"additionalProperties":true}}}},"400":{"$ref":"#/components/responses/ValidationFailed"},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/experimental":{"post":{"summary":"Experimental / Snusbase Search","description":"Search across experimental databases (Snusbase) for breached data. Offers additional search types not available in other endpoints.\n\n### Load All (auto-expand truncated results)\n\nSome results from Snusbase are truncated and only show partial data. By adding `?loadAll=true`, the server will automatically fetch the full data for all truncated entries and merge them into the response. This requires **Pro** or **Plus** subscription.\n\nWithout `loadAll`, truncated items will have `hasMoreInfo: true` and a `moreInfo` array with `[term, type, database]` that can be used to fetch the full data separately via the `snusbase/moreInfo` endpoint.","operationId":"experimentalSearch","tags":["Experimental Search"],"parameters":[{"name":"loadAll","in":"query","required":false,"description":"When set to `true`, automatically fetches and merges full data for all truncated results in a single response. Requires Pro/Plus subscription.","schema":{"type":"string","enum":["true","false"],"default":"false"},"example":"true"},{"name":"enrichIps","in":"query","required":false,"description":"When set to `true`, the response will include an `ipLookupMap` field containing whois/geolocation data for every unique IP address found in the result set (`lastip` field). Lookups are batched in groups of 5 in parallel. Requires Pro/Plus subscription.","schema":{"type":"string","enum":["true","false"],"default":"false"},"example":"true"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExperimentalEntry"},"examples":{"emailSearch":{"summary":"Search by email","value":{"entry":"user@example.com","type":"email"}},"massSearch":{"summary":"Mass search (all fields)","value":{"entry":"johndoe","type":"mass"}},"passwordSearch":{"summary":"Search by known password","value":{"entry":"password123","type":"password"}},"emailSearchWithIpEnrich":{"summary":"Search by email + enrich IPs","value":{"entry":"user@example.com","type":"email","enrichIps":true}}}}}},"responses":{"200":{"description":"Search results returned successfully. When `?enrichIps=true`, the response includes an additional `ipLookupMap` field — see `IpLookupMap` schema.","content":{"application/json":{"schema":{"type":"object","properties":{"ipLookupMap":{"$ref":"#/components/schemas/IpLookupMap"}},"additionalProperties":true}}}},"400":{"$ref":"#/components/responses/ValidationFailed"},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/crack_hash":{"post":{"summary":"Crack a Password Hash","description":"Attempt to crack a password hash using rainbow tables and known breach data. Supports common hash formats including MD5, SHA1, SHA256, NTLM, and more.\n\n> **Rate Limit:** This endpoint has a stricter rate limit (1 request per 5ms per API key).","operationId":"crackHash","tags":["Hash Cracking"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CrackHashRequest"},"examples":{"md5":{"summary":"Crack an MD5 hash","value":{"hash":"cc03e747a6afbbcbf8be7668acfebee5"}},"sha1":{"summary":"Crack a SHA1 hash","value":{"hash":"aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d"}}}}}},"responses":{"200":{"description":"Hash cracked successfully or not found","content":{"application/json":{}}},"400":{"$ref":"#/components/responses/ValidationFailed"},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/ip":{"get":{"summary":"IP Address Lookup","description":"Returns geolocation, ISP, organization, and network information for an IP address. If no IP is provided, returns information about the requester's IP.","operationId":"ipLookup","tags":["IP Lookup"],"parameters":[{"name":"ip","in":"query","required":false,"description":"IP address to look up. If omitted, your own IP is used.","schema":{"type":"string","format":"ipv4"},"examples":{"google_dns":{"value":"8.8.8.8","summary":"Google Public DNS"},"cloudflare":{"value":"1.1.1.1","summary":"Cloudflare DNS"}}}],"responses":{"200":{"description":"IP information retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IpLookupResult"},"example":{"ip":"8.8.8.8","ipNo":"134744072","countryShort":"US","countryLong":"United States of America","region":"California","city":"Mountain View","zipCode":"94043","latitude":37.405991,"longitude":-122.078514,"timeZone":"-07:00","address":{"place_id":311466384,"osm_type":"way","osm_id":227968074,"lat":"37.405882899999995","lon":"-122.07853894699258","class":"building","type":"yes","place_rank":30,"importance":0.00000999999999995449,"addresstype":"building","name":"","display_name":"790, North Shoreline Boulevard, The Waters, Mountain View, Santa Clara County, California, 94043, United States","address":{"house_number":"790","road":"North Shoreline Boulevard","residential":"The Waters","city":"Mountain View","county":"Santa Clara County","state":"California","ISO3166-2-lvl4":"US-CA","postcode":"94043","country":"United States","country_code":"us"},"boundingbox":["37.4058272","37.4060174","-122.0786263","-122.0784753"]},"asn":{"start_ip":"8.8.250.0","end_ip":"8.9.2.255","asn":"AS3356","name":"Level 3 Parent, LLC","domain":"lumen.com"},"whois":{"query":"8.8.8.8","continent":"North America","continentCode":"NA","country":"United States","countryCode":"US","region":"VA","regionName":"Virginia","city":"Ashburn","zip":"20149","lat":39.03,"lon":-77.5,"timezone":"America/New_York","isp":"Google LLC","org":"Google Public DNS","as":"AS15169 Google LLC","asname":"GOOGLE","mobile":false,"proxy":false,"hosting":true}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/domain-whois":{"get":{"summary":"Domain WHOIS Lookup","description":"Returns WHOIS registration data (registrar, creation/expiry dates, name servers, registrant details, status) for a domain. Powered by Snusbase domain-whois. Accepts a bare hostname or a full URL — protocol, path, port and a leading `www.` are stripped automatically.","operationId":"domainWhois","tags":["Domain WHOIS"],"parameters":[{"name":"domain","in":"query","required":true,"description":"Domain to look up. A full URL is accepted and normalized to its hostname.","schema":{"type":"string","format":"hostname"},"examples":{"apex":{"value":"example.com","summary":"Apex domain"},"subdomain":{"value":"blog.example.co.uk","summary":"Subdomain"}}}],"responses":{"200":{"description":"Domain WHOIS retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainWhoisResult"}}}},"400":{"description":"Invalid domain","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"Invalid domain"}}}}}}},"/ghunt":{"get":{"summary":"Google Hunt OSINT Lookup","description":"Perform an OSINT investigation on a Gmail address using Google Hunt. Retrieves public profile information, linked Google services (Maps reviews, Calendar, etc.), and profile pictures.\n\n> **Requires:** Pro or Plus subscription.","operationId":"ghuntLookup","tags":["Google Hunt"],"parameters":[{"name":"email","in":"query","required":true,"description":"Gmail address to investigate. Must be a valid `@gmail.com` address.","schema":{"type":"string","format":"email"},"example":"example@gmail.com"}],"responses":{"200":{"description":"Google account information retrieved","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GhuntResult"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"Access denied — Pro or Plus subscription required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"Pro or Plus subscription required"}}}}}}},"/tracking/new":{"post":{"summary":"Create Tracking Entry","description":"Add a new entry to be tracked for future data breaches. You'll be notified when new breach data appears for this entry.","operationId":"trackingNew","tags":["Tracking"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TrackingNewEntry"}}}},"responses":{"200":{"description":"Tracking entry created successfully","content":{"application/json":{}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/tracking/delete":{"post":{"summary":"Delete Tracking Entry","description":"Remove a tracking entry by its ID. Stops monitoring for that entry.","operationId":"trackingDelete","tags":["Tracking"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TrackingDeleteEntry"}}}},"responses":{"200":{"description":"Tracking entry deleted successfully","content":{"application/json":{}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/tracking/limit":{"get":{"summary":"Get Tracking Limits","description":"Returns the current tracking limits for your subscription, including how many entries you can track and how many you're currently using.","operationId":"trackingLimits","tags":["Tracking"],"responses":{"200":{"description":"Tracking limits retrieved","content":{"application/json":{}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/tracking/user":{"get":{"summary":"Get Tracking Entries","description":"Returns all tracking entries for the authenticated user.","operationId":"trackingEntries","tags":["Tracking"],"responses":{"200":{"description":"Tracking entries retrieved","content":{"application/json":{}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/tracking/history":{"post":{"summary":"Get Tracking History","description":"Returns the breach history for a specific tracking entry.","operationId":"trackingHistory","tags":["Tracking"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TrackingHistoryRequest"}}}},"responses":{"200":{"description":"Tracking history retrieved","content":{"application/json":{}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/tracking/history/{id}":{"get":{"summary":"Get Tracking Result","description":"Returns the detailed result for a specific tracking history entry.","operationId":"trackingResult","tags":["Tracking"],"parameters":[{"name":"id","in":"path","required":true,"description":"Tracking history entry ID","schema":{"type":"string"}}],"responses":{"200":{"description":"Tracking result retrieved","content":{"application/json":{}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/tracking/clean_entries":{"get":{"summary":"Clean Tracking Entries","description":"Remove stale or invalid tracking entries from your account.","operationId":"trackingClean","tags":["Tracking"],"responses":{"200":{"description":"Entries cleaned successfully","content":{"application/json":{}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/tracking/leakradar/new":{"post":{"summary":"Create LeakRadar Tracking Entry","description":"Adds a domain (LeakRadar domain audit) or raw-search entry (LeakRadar raw search) to the tracking monitor. Max 10 active entries per user. A 24-hour cron worker polls LeakRadar per entry and dispatches new-leak events through your enabled channels (Email/Discord/Telegram).","operationId":"trackingLeakRadarNew","tags":["Tracking LeakRadar"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TrackingLeakRadarNewEntry"}}}},"responses":{"200":{"description":"{ success: true } or { error }","content":{"application/json":{}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/tracking/leakradar/delete":{"post":{"summary":"Delete LeakRadar Tracking Entry","description":"Soft-deletes a LeakRadar tracking entry (status=0). Scoped to the calling user via email_unique_id.","operationId":"trackingLeakRadarDelete","tags":["Tracking LeakRadar"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TrackingLeakRadarDeleteEntry"}}}},"responses":{"200":{"description":"{ success: true } or { error }","content":{"application/json":{}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/tracking/leakradar/limit":{"get":{"summary":"Get LeakRadar Tracking Limits","description":"Returns { limit, total } where limit = min(role.tracking, 10) and total is the count of active LeakRadar tracking entries for the calling user.","operationId":"trackingLeakRadarLimits","tags":["Tracking LeakRadar"],"responses":{"200":{"description":"{ limit: number, total: number }","content":{"application/json":{}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/tracking/leakradar/user":{"get":{"summary":"List My LeakRadar Tracking Entries","description":"Returns the calling user's active LeakRadar tracking entries enriched with the latest significant snapshot (changes, tsr_id, last_result_date).","operationId":"trackingLeakRadarEntries","tags":["Tracking LeakRadar"],"responses":{"200":{"description":"Array of tracking entry rows","content":{"application/json":{}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/tracking/leakradar/history":{"post":{"summary":"Get LeakRadar Tracking History","description":"Returns the snapshot history for a single LeakRadar tracking entry. Ownership-checked: the (entry, type) pair must belong to the calling user.","operationId":"trackingLeakRadarHistory","tags":["Tracking LeakRadar"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TrackingLeakRadarHistoryRequest"}}}},"responses":{"200":{"description":"Array of snapshot rows (id, creation_date, changes, found)","content":{"application/json":{}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/tracking/leakradar/history/{id}":{"get":{"summary":"Get LeakRadar Tracking Snapshot","description":"Returns a single snapshot by its Mongo _id. Ownership-checked: the snapshot's (entry, type) must belong to the calling user. The 'result' field is the JSON-parsed LeakRadar payload (DomainSearchLightResponse for domain, RawSearchResponse for raw).","operationId":"trackingLeakRadarResult","tags":["Tracking LeakRadar"],"parameters":[{"name":"id","in":"path","required":true,"description":"Snapshot Mongo _id","schema":{"type":"string"}}],"responses":{"200":{"description":"{ id, entry, type, creation_date, found, result, changes }","content":{"application/json":{}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/hibp/latest-breach":{"get":{"summary":"HIBP Latest Breach","description":"Returns the most recently added breach in the Have I Been Pwned database. Cached server-side for 1 hour. Public endpoint — no authentication required.","operationId":"hibpLatestBreach","tags":["HIBP"],"security":[],"responses":{"200":{"description":"Latest breach metadata","content":{"application/json":{"schema":{"type":"object","example":{"success":{"Name":"ExampleBreach","Title":"Example Breach","Domain":"example.com","BreachDate":"2026-04-01","PwnCount":123456,"DataClasses":["Email addresses","Passwords"]},"error":null}}}}}}}},"/hibp/data-classes":{"get":{"summary":"HIBP Data Classes","description":"Returns the alphabetically ordered array of all known HIBP data classes (e.g. 'Email addresses', 'Passwords', 'IP addresses'). Useful as the canonical filter list for UI faceted search. Cached server-side for 24 hours. Public endpoint — no authentication required.","operationId":"hibpDataClasses","tags":["HIBP"],"security":[],"responses":{"200":{"description":"Array of data class strings","content":{"application/json":{"schema":{"type":"object","example":{"success":["Email addresses","IP addresses","Passwords","Usernames"],"error":null}}}}}}}},"/hibp/password-check":{"post":{"summary":"HIBP Pwned Password Check (k-anonymity)","description":"Privacy-preserving password breach check. The plain password is SHA-1-hashed locally and ONLY the first 5 hex chars are sent to HIBP's range API. Returns whether the password appears in any known breach and how many times. Public endpoint — no authentication required.\n\nAccepts one of: `password` (plaintext), `sha1` (40-hex), `ntlm` (32-hex). Set `mode: \"ntlm\"` to query the NTLM range.","operationId":"hibpPasswordCheck","tags":["HIBP"],"security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"password":{"type":"string","description":"Plaintext password (hashed locally before transmission)","example":"P@ssw0rd"},"sha1":{"type":"string","description":"Pre-computed SHA-1 hash (40 hex chars, alternative to password)","example":"5BAA61E4C9B93F3F0682250B6CF8331B7EE68FD8"},"ntlm":{"type":"string","description":"Pre-computed NTLM hash (32 hex chars)","example":"8846F7EAEE8FB117AD06BDD830B7586C"},"mode":{"type":"string","enum":["sha1","ntlm"],"description":"Range mode (defaults to sha1)"}}}}}},"responses":{"200":{"description":"Pwned status and prevalence count","content":{"application/json":{"schema":{"type":"object","example":{"success":{"pwned":true,"count":9545824},"error":null}}}}}}}},"/hibp/breach/{name}":{"get":{"summary":"HIBP Single Breach","description":"Returns the full breach record for the given breach name (live HIBP fetch, cached 24h). Public endpoint — no authentication required.","operationId":"hibpBreachByName","tags":["HIBP"],"security":[],"parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string"},"description":"Breach name as listed in /hibp/latest-breach or HIBP /breaches","example":"Adobe"}],"responses":{"200":{"description":"Breach metadata","content":{"application/json":{}}},"404":{"description":"No breach with that name"}}}},"/hibp/account-full":{"post":{"summary":"HIBP Full Breach + Pastes for Email","description":"Returns the full set of breaches (no truncation) for an email address, optionally including unverified breaches. Pastes are NOT included here — call `/hibp/account-full` for breach data and consume the `/check` endpoint to get pastes alongside breaches. Counts toward the HIBP Pwned 2 tier of 50 RPM.\n\nThe user is identified by the `api-key` header for ownership-aware routing.","operationId":"hibpAccountFull","tags":["HIBP"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["email"],"properties":{"email":{"type":"string","format":"email","example":"test@example.com"},"includeUnverified":{"type":"boolean","default":true}}}}}},"responses":{"200":{"description":"Array of full breach objects","content":{"application/json":{}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/hibp/breached-domain":{"post":{"summary":"HIBP Breached Domain","description":"Returns the email-alias → breaches mapping for a HIBP-verified domain. **The calling user must have claimed the domain via `/hibp/domains/claim` first.** Domains claimed by other users are not accessible. Pwned 2 tier limits results to domains with ≤100 breached addresses.","operationId":"hibpBreachedDomain","tags":["HIBP"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["domain"],"properties":{"domain":{"type":"string","example":"example.com"}}}}}},"responses":{"200":{"description":"Email aliases with breach lists","content":{"application/json":{}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"Domain not claimed by the calling user"}}}},"/hibp/subscribed-domains":{"get":{"summary":"HIBP Subscribed Domains (Per-User)","description":"Returns ONLY the domains the calling user has claimed AND that the HIBP key is currently subscribed to. Domains claimed by other users are filtered out; HIBP-known domains with zero claimants are also filtered out.\n\nThe user is identified by the `api-key` header.","operationId":"hibpSubscribedDomains","tags":["HIBP"],"responses":{"200":{"description":"Filtered subscribed domains list","content":{"application/json":{}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/hibp/subscription-status":{"get":{"summary":"HIBP Subscription Status","description":"Returns the HIBP subscription tier metadata for the configured API key (subscription name, RPM ceiling, max breached accounts per domain, expiry).","operationId":"hibpSubscriptionStatus","tags":["HIBP"],"responses":{"200":{"description":"Subscription metadata","content":{"application/json":{}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/hibp/domains/claim":{"post":{"summary":"Claim Domain for User","description":"Links a domain to the calling user so subsequent `/hibp/breached-domain` and `/hibp/subscribed-domains` calls return data for it.\n\nMultiple users may claim the same domain — each gets their own row. Idempotent: re-claiming has no effect. Domain verification itself happens in the HIBP dashboard; this endpoint records local user ↔ domain ownership only.","operationId":"hibpDomainClaim","tags":["HIBP"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["domain"],"properties":{"domain":{"type":"string","example":"example.com"}}}}}},"responses":{"200":{"description":"Domain claimed","content":{"application/json":{"schema":{"type":"object","example":{"success":{"claimed":true,"domain":"example.com"},"error":null}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/hibp/domains/release":{"post":{"summary":"Release Domain Claim","description":"Removes the calling user's claim on a domain. Other users' claims on the same domain are unaffected.","operationId":"hibpDomainRelease","tags":["HIBP"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["domain"],"properties":{"domain":{"type":"string","example":"example.com"}}}}}},"responses":{"200":{"description":"Domain released","content":{"application/json":{}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/hibp/domains/mine":{"get":{"summary":"List My Claimed Domains","description":"Returns the array of domains the calling user has claimed. Identification is by `api-key` header. Other users' claims are never exposed.","operationId":"hibpDomainsMine","tags":["HIBP"],"responses":{"200":{"description":"Array of domain strings","content":{"application/json":{"schema":{"type":"object","example":{"success":["example.com","another.org"],"error":null}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}}}}