> ## Documentation Index
> Fetch the complete documentation index at: https://docs.encrata.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Password Breaches

> Check whether a password has appeared in known data breaches, privately, via HIBP k-anonymity.

## Overview

Password Breaches tells you whether a password has appeared in known data
breaches, and how many times, without ever transmitting or storing the
plaintext password. It's built for a **sign-up / password-reset guard**: warn a
user when the password they chose has already leaked and prompt them to pick a
different one.

It uses the **k-anonymity** model on top of Have I Been Pwned's Pwned Passwords
corpus: the password is SHA-1 hashed and only the first 5 hex characters of the
hash are ever sent to the upstream service.

There are three ways to run it:

* **Agent API** (`POST /api/agent/password-breaches`): the API-key endpoint
  documented on this page, for programmatic access (e.g. your sign-up backend).
* **In-app** (`POST /api/password/breaches`): the session-authenticated endpoint
  used by the dashboard, where the browser hashes the password first.
* **Bulk** (`POST /api/password/breaches/bulk`): check up to 1,000 passwords in
  one request.

<Note>
  The plaintext password is **never stored**. History records only a masked label
  (a dotted mask plus the 5-char hash prefix), never the password or its full hash.
</Note>

## Request

<ParamField body="password" type="string">
  The raw password to check. Hashed server-side (SHA-1) immediately and never
  stored; only the 5-char hash prefix leaves the server.
</ParamField>

<Note>
  For production, prefer sending a pre-computed hash instead of the raw password:
  pass `sha1` (upper-case hex SHA-1 of the password) in place of `password`, so the
  plaintext never leaves the caller. Provide exactly one of `password` or `sha1`.
</Note>

```bash theme={"dark"}
curl -X POST "https://encrata.com/api/agent/password-breaches" \
  -H "Authorization: Bearer $ENCRATA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"sha1": "5BAA61E4C9B93F3F0682250B6CF8331B7EE68FD8"}'
```

## Response

```json theme={"dark"}
{
  "prefix": "5BAA6",
  "found": true,
  "count": 52372427,
  "credits": 1
}
```

| Field     | Type    | Description                                                  |
| --------- | ------- | ------------------------------------------------------------ |
| `prefix`  | string  | The 5-char SHA-1 hash prefix used for the k-anonymity query. |
| `found`   | boolean | Whether the password appears in any known breach.            |
| `count`   | integer | How many times the password has been seen across breaches.   |
| `credits` | integer | Credits charged (always 1).                                  |

## Bulk

`POST /api/password/breaches/bulk` accepts `sha1s` (array of hashes) or
`passwords` (array of raw passwords), up to 1,000 entries, and charges 1 credit
per unique password:

```json theme={"dark"}
{
  "total": 3,
  "breached": 3,
  "results": [
    { "prefix": "5BAA6", "found": true, "count": 52372427 },
    { "prefix": "B1B37", "found": true, "count": 30812897 },
    { "prefix": "AAF4C", "found": true, "count": 1189270 }
  ],
  "credits": 3
}
```

## Cost

1 credit per password checked (single and per-password in bulk).

## Enterprise / async bulk (up to 1M)

For large lists (banks, enterprises), use the async job pipeline instead of the
synchronous bulk endpoint. The browser SHA-1 hashes every password first, so the
uploaded input is a list of hashes, and plaintext never reaches the server.

* `POST /api/password-jobs`: body `{ "sha1s": ["<40-hex>", ...], "file_name": "list.txt" }` (up to 1,000,000). Returns a job `{ id, status, total, ... }`.
* `GET /api/password-jobs?id=<id>`: poll live status + counts (`processed_count`, `breached_count`).
* `GET /api/password-jobs/results?id=<id>&page=&page_size=&breached=1`: paginated result rows (`{ line_no, prefix, found, count }`).
* `GET /api/password-jobs/download?id=<id>&breached=1`: stream the full results as CSV.
* `POST /api/password-jobs/cancel?id=<id>`: cancel an in-flight job.

Jobs are processed by background workers in resumable chunks, so a 1M-row job
runs reliably without a long-held HTTP request. 1 credit is charged per password.
