> ## 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.

# GitHub Leaks

> Scan a public GitHub repository for leaked secrets. 1 credit per leak found - a clean scan is free.

## Overview

GitHub Leaks scans a public repository for exposed secrets - API keys, tokens,
private keys, and other credentials committed to the code. It returns each
finding with its location, a masked preview, a severity, and a stable
fingerprint, so you can triage and track leaks over time.

Billing is outcome-based: you pay **1 credit per leak found**. A clean scan, a
refused scan, and a repeat of a repository state you already paid for are all
**free**.

Scan synchronously and read the findings in the response, or run a
[background scan](#background-scans) for large repositories and read the result
when it finishes.

## Authentication

Requires an API key in the `Authorization` header.

```bash theme={"dark"}
Authorization: Bearer YOUR_API_KEY
```

## Request

<ParamField body="repo" type="string" required>
  The repository to scan. Must be an `https` URL on an allowlisted host
  (e.g. `https://github.com/org/repo`), with no embedded credentials.
</ParamField>

<ParamField body="type" type="integer" default="0">
  Detection profile: `0` (default) runs the standard detector, `1` runs the
  alternate detector, `2` runs both in parallel and merges findings by location.
</ParamField>

<ParamField body="config" type="object">
  Optional scan tuning.

  <Expandable title="config">
    <ParamField body="deep_scan" type="boolean" default="false">
      Scan the full commit history rather than just the current tree. Forces the
      scan to run in the background.
    </ParamField>

    <ParamField body="run_at_background" type="boolean" default="false">
      Run asynchronously - the request returns `202` with `status: "processing"`
      and a `scan_id`; read the findings later from
      `GET /api/lookup/breaches/github/{id}`.
    </ParamField>

    <ParamField body="min_severity" type="string">
      Drop findings below this floor: `critical`, `high`, `medium`, or `low`.
    </ParamField>

    <ParamField body="rules" type="string[]">
      Restrict detection to specific rule ids. Empty runs every rule.
    </ParamField>

    <ParamField body="max_findings" type="integer">
      Cap the number of findings returned.
    </ParamField>

    <ParamField body="depth" type="integer">
      Bound a history scan to the most recent N commits.
    </ParamField>

    <ParamField body="baseline_fingerprints" type="string[]">
      Fingerprints to suppress - known findings you have already triaged.
    </ParamField>

    <ParamField body="include_likely_false_positives" type="boolean">
      Include findings flagged as likely false positives.
    </ParamField>

    <ParamField body="ref" type="string">
      A specific branch, tag, or commit to scan.
    </ParamField>
  </Expandable>
</ParamField>

### Example request

<CodeGroup>
  ```bash cURL (API Key) theme={"dark"}
  curl -X POST "https://developer.encrata.com/api/lookup/breaches/github" \
    -H "Authorization: Bearer YOUR_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{"repo": "https://github.com/org/repo"}'
  ```

  ```python Python theme={"dark"}
  import requests

  resp = requests.post(
      "https://developer.encrata.com/api/lookup/breaches/github",
      headers={"Authorization": "Bearer YOUR_API_KEY"},
      json={"repo": "https://github.com/org/repo"},
  )
  print(resp.json())
  ```

  ```javascript JavaScript theme={"dark"}
  const resp = await fetch("https://developer.encrata.com/api/lookup/breaches/github", {
    method: "POST",
    headers: {
      Authorization: "Bearer YOUR_API_KEY",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ repo: "https://github.com/org/repo" }),
  });
  const data = await resp.json();
  ```
</CodeGroup>

## Response

Returns the `{success, result, message}` envelope. A scan with **zero findings is
a success**, not an error.

<ResponseField name="success" type="boolean">
  Whether the scan completed.
</ResponseField>

<ResponseField name="message" type="string">
  A sentence written for your end user.
</ResponseField>

<ResponseField name="result" type="object">
  The scan outcome.

  <Expandable title="result">
    <ResponseField name="scan_id" type="string">
      The scan's id. Use it to re-read the result from
      `GET /api/lookup/breaches/github/{id}`.
    </ResponseField>

    <ResponseField name="target" type="string">
      The normalised repository URL that was scanned.
    </ResponseField>

    <ResponseField name="commit_sha" type="string">
      The repository state these findings describe.
    </ResponseField>

    <ResponseField name="status" type="string">
      `succeeded` (findings are in this response), `processing` (a background
      scan is still running), or `failed` (the scan could not be completed).
      Absent on a synchronous scan, which is always complete.
    </ResponseField>

    <ResponseField name="findings" type="object[]">
      The detected secrets. Each finding never contains the raw credential.

      <Expandable title="finding">
        <ResponseField name="fingerprint" type="string">
          Stable identifier for this finding, derived from a hash of the match.
          Use it to deduplicate and to build a baseline.
        </ResponseField>

        <ResponseField name="rule_id" type="string">
          The detection rule that matched (e.g. `aws-access-key-id`).
        </ResponseField>

        <ResponseField name="description" type="string">
          Human-readable description of what was found.
        </ResponseField>

        <ResponseField name="severity" type="string">
          `critical`, `high`, `medium`, `low`, or `unknown`.
        </ResponseField>

        <ResponseField name="file" type="string">
          Path to the file containing the secret.
        </ResponseField>

        <ResponseField name="start_line" type="integer">
          1-based line where the match starts. See also `end_line` and `column`.
        </ResponseField>

        <ResponseField name="preview" type="string">
          A masked preview of the match (e.g. `AKIA****************`). The raw
          secret is never returned.
        </ResponseField>

        <ResponseField name="commit" type="string">
          Commit the secret was found in, with `author`, `email`, and `date`
          when available.
        </ResponseField>

        <ResponseField name="likely_false_positive" type="boolean">
          Whether this finding is flagged as a likely false positive.
        </ResponseField>
      </Expandable>
    </ResponseField>

    <ResponseField name="summary" type="object">
      Roll-up of the scan: `total`, `by_severity`, `rules_requested`,
      `deep_scan`, `duration_ms`, `suppressed` (dropped by a filter or baseline),
      and `truncated`.
    </ResponseField>

    <ResponseField name="reused" type="boolean">
      An existing scan of this repository state answered the request, so no new
      scan ran.
    </ResponseField>

    <ResponseField name="charged" type="boolean">
      Whether this request debited the account. `false` on a clean scan, or when
      the account already paid for this repository state and configuration.
    </ResponseField>

    <ResponseField name="credits" type="integer">
      Credits debited: one per leak found, or `0` when the scan was clean or
      already paid for.
    </ResponseField>
  </Expandable>
</ResponseField>

## Read a stored scan

Re-read any scan by its id. Useful after a background scan, or to re-filter
findings without paying again.

```bash theme={"dark"}
curl "https://developer.encrata.com/api/lookup/breaches/github/{scan_id}?min_severity=high" \
  -H "Authorization: Bearer YOUR_API_KEY"
```

<ParamField query="min_severity" type="string">
  Filter the stored findings by minimum severity (`critical`, `high`, `medium`,
  `low`). This filters what is returned - it never re-scans and never charges
  again.
</ParamField>

## Background scans

Set `config.run_at_background: true` (or `config.deep_scan: true`, which forces
it) and the request returns `202` with `status: "processing"` and a `scan_id`,
before the scan finishes. When it completes, the findings are stored and a
realtime event is pushed - see [Webhooks & events](/webhooks). Read the finished
result from `GET /api/lookup/breaches/github/{id}`.

## Errors

| Status | Cause                                                                                     |
| ------ | ----------------------------------------------------------------------------------------- |
| `400`  | Unreadable JSON body                                                                      |
| `402`  | Insufficient credits                                                                      |
| `404`  | The repository doesn't exist or isn't public                                              |
| `422`  | `repo` missing, not `https`, carries credentials, names an IP, or its host is not allowed |
| `429`  | Too many repository scans are already running                                             |
| `502`  | The repository could not be cloned or scanned                                             |
| `504`  | The scan exceeded its time limit                                                          |

## Credits

You pay **1 credit per leak found**. A clean scan (zero leaks), a refused or
failed scan, and a repeat of a repository state and configuration you already
paid for are all free. See [Credits](/credits).

<ResponseExample>
  ```json 200 Leaks found theme={"dark"}
  {
    "success": true,
    "result": {
      "scan_id": "6f1c2e94-2b6a-4a1e-9b3a-6c9f0f2a1d77",
      "target": "https://github.com/org/repo",
      "commit_sha": "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2",
      "status": "succeeded",
      "findings": [
        {
          "fingerprint": "b9d1...e2",
          "rule_id": "aws-access-key-id",
          "description": "AWS Access Key",
          "severity": "high",
          "file": "config/prod.env",
          "start_line": 12,
          "preview": "AKIA****************",
          "commit": "a1b2c3d",
          "author": "Jane Dev",
          "email": "jane@example.com",
          "date": "2026-02-11T09:14:00Z",
          "likely_false_positive": false
        }
      ],
      "summary": {
        "total": 1,
        "by_severity": { "high": 1 },
        "deep_scan": false,
        "duration_ms": 1840,
        "suppressed": 0,
        "truncated": false
      },
      "reused": false,
      "charged": true,
      "credits": 1
    },
    "message": "Found 1 leaked secret in this repository."
  }
  ```

  ```json 200 Clean theme={"dark"}
  {
    "success": true,
    "result": {
      "scan_id": "0a7b9c11-4d22-4e88-9a10-2b3c4d5e6f70",
      "target": "https://github.com/org/repo",
      "status": "succeeded",
      "findings": [],
      "summary": { "total": 0, "by_severity": {}, "deep_scan": false, "duration_ms": 900, "suppressed": 0, "truncated": false },
      "reused": false,
      "charged": false,
      "credits": 0
    },
    "message": "No leaked secrets were found in this repository."
  }
  ```

  ```json 202 Background scan theme={"dark"}
  {
    "success": true,
    "result": {
      "scan_id": "d4e5f6a1-7b8c-4d9e-8f10-1a2b3c4d5e6f",
      "target": "https://github.com/org/repo",
      "status": "processing"
    },
    "message": "Scan started. We'll notify you when it's ready."
  }
  ```
</ResponseExample>
