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

# Vigolium API Reference, Findings

> List, retrieve, and delete vulnerability findings with filtering, pagination, and severity-based queries.

## GET /api/findings, List Findings

Returns paginated vulnerability findings.

**Query parameters:**

| Parameter        | Type   | Default    | Description                                                                                                         |
| ---------------- | ------ | ---------- | ------------------------------------------------------------------------------------------------------------------- |
| `limit`          | int    | 50         | Number of findings to return (max 500)                                                                              |
| `offset`         | int    | 0          | Offset for pagination                                                                                               |
| `domain`         | string |            | Filter by hostname (supports `*` wildcards)                                                                         |
| `severity`       | string |            | Filter by severity (comma-separated): `critical`, `high`, `medium`, `low`, `info`                                   |
| `scan_id`        | string |            | Filter by scan UUID                                                                                                 |
| `module_name`    | string |            | Filter by module name                                                                                               |
| `module_type`    | string |            | Filter by module type: `active` or `passive`                                                                        |
| `finding_source` | string |            | Filter by finding source: `dynamic-assessment`, `known-issue-scan`, `agent`, `audit`, `oast`, `extension`, `import` |
| `search`         | string |            | Search across description, module ID, matched\_at                                                                   |
| `sort`           | string | `found_at` | Sort field: `found_at`, `created_at`, `severity`, `module_name`, `module_id`, `confidence`                          |
| `order`          | string | `desc`     | Sort order: `asc` or `desc`                                                                                         |

```bash theme={null}
# List all findings
curl -s http://localhost:9002/api/findings | jq .

# Filter by severity
curl -s 'http://localhost:9002/api/findings?severity=critical,high' | jq .

# Filter by domain and module
curl -s 'http://localhost:9002/api/findings?domain=example.com&module_name=xss' | jq .

# Filter by module type
curl -s 'http://localhost:9002/api/findings?module_type=passive' | jq .

# Filter by finding source
curl -s 'http://localhost:9002/api/findings?finding_source=dynamic-assessment' | jq .

# Search findings
curl -s 'http://localhost:9002/api/findings?search=reflected' | jq .
```

```json theme={null}
{
  "data": [
    {
      "id": 1,
      "http_record_uuids": ["abc-123"],
      "scan_uuid": "scan-456",
      "module_id": "xss-scanner",
      "module_name": "XSS Scanner",
      "module_type": "active",
      "module_short": "Detects reflected cross-site scripting via parameter injection",
      "finding_source": "dynamic-assessment",
      "description": "Reflected XSS via parameter 'q'",
      "severity": "high",
      "confidence": "firm",
      "tags": ["xss", "reflected"],
      "matched_at": ["https://example.com/search?q=test"],
      "extracted_results": ["<script>alert(1)</script>"],
      "additional_evidence": [
        "GET /search?q=%3Cimg+src%3Dx+onerror%3Dalert(1)%3E HTTP/1.1\r\nHost: example.com\r\n\r\n\n---------\nHTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n..."
      ],
      "request": "GET /search?q=%3Cscript%3Ealert(1)%3C/script%3E HTTP/1.1\r\nHost: example.com\r\n\r\n",
      "response": "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n...",
      "finding_hash": "e3b0c44298fc1c14",
      "found_at": "2026-02-16T15:05:00Z",
      "created_at": "2026-02-16T15:05:00Z"
    }
  ],
  "total": 42,
  "limit": 50,
  "offset": 0,
  "has_more": false
}
```

***

## GET /api/findings/:id, Get Finding Detail

Returns a single finding by its numeric ID.

```bash theme={null}
curl -s http://localhost:9002/api/findings/1 | jq .
```

```json theme={null}
{
  "id": 1,
  "http_record_uuids": ["abc-123"],
  "scan_uuid": "scan-456",
  "module_id": "xss-scanner",
  "module_name": "XSS Scanner",
  "module_type": "active",
  "module_short": "Detects reflected cross-site scripting via parameter injection",
  "finding_source": "dynamic-assessment",
  "description": "Reflected XSS via parameter 'q'",
  "severity": "high",
  "confidence": "firm",
  "tags": ["xss", "reflected"],
  "matched_at": ["https://example.com/search?q=test"],
  "extracted_results": ["<script>alert(1)</script>"],
  "additional_evidence": [
    "GET /search?q=%3Cimg+src%3Dx+onerror%3Dalert(1)%3E HTTP/1.1\r\nHost: example.com\r\n\r\n\n---------\nHTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n..."
  ],
  "request": "GET /search?q=%3Cscript%3Ealert(1)%3C/script%3E HTTP/1.1\r\nHost: example.com\r\n\r\n",
  "response": "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n...",
  "finding_hash": "e3b0c44298fc1c14",
  "found_at": "2026-02-16T15:05:00Z",
  "created_at": "2026-02-16T15:05:00Z"
}
```

**Error responses:**

| Code | Condition                 |
| ---- | ------------------------- |
| 400  | Invalid ID (not a number) |
| 404  | Finding not found         |
| 503  | Database unavailable      |

***

## PATCH /api/findings/:id/status, Update Finding Status

Sets the workflow status on a finding (e.g. open / triaged / closed). The status field is opaque to the server — any string is accepted.

```bash theme={null}
curl -s -X PATCH http://localhost:9002/api/findings/42/status \
  -H "Content-Type: application/json" \
  -d '{"status": "triaged"}' | jq .
```

```json theme={null}
{
  "id": 42,
  "status": "triaged"
}
```

| Status | Description             |
| ------ | ----------------------- |
| 200    | Status updated          |
| 400    | Invalid ID or body      |
| 404    | Finding not found       |
| 503    | Database not configured |

***

## DELETE /api/findings/:id, Delete Finding

Deletes a single finding by its numeric ID. Associated `finding_records` junction rows are also removed.

```bash theme={null}
curl -s -X DELETE http://localhost:9002/api/findings/42 | jq .
```

**Response:**

```json theme={null}
{
  "message": "finding deleted",
  "id": 42
}
```

| Status | Description               |
| ------ | ------------------------- |
| 200    | Finding deleted           |
| 400    | Invalid ID (not a number) |
| 404    | Finding not found         |
| 503    | Database not configured   |

***

## Finding Fields

### `additional_evidence`

**Type:** `string[]` (optional, omitted when empty)

Stores extra HTTP request/response pairs associated with a finding. Each entry is a single string containing a raw request and raw response separated by the delimiter `\n---------\n`.

This field is populated in two ways:

1. **Modules and extensions**: A module or JS extension can attach supplementary evidence when creating a finding (e.g., multiple payloads tried, confirmation requests, or baseline comparisons).
2. **Deduplication**: When duplicate findings are merged (same `module_id`, `severity`, and `matched_at` URL), the `request`/`response` pairs from the removed duplicates are automatically collected into the surviving finding's `additional_evidence`.

**Example entry format:**

```
GET /api?id=1'+OR+1=1 HTTP/1.1\r\nHost: example.com\r\n\r\n
---------
HTTP/1.1 500 Internal Server Error\r\n\r\n{"error":"syntax error"}
```

To parse an entry, split on `\n---------\n`, the first part is the request, the second is the response.
