> For the complete documentation index, see [llms.txt](https://docs.bountysecurity.ai/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.bountysecurity.ai/burp-bounty-server/rest-api.md).

# REST API

Submit exchanges, control scans and retrieve results through HTTP.

REST is always available on the main listener, including when `--mcp` is enabled. Every route uses `X-BURPBOUNTY-LICENSE` in the commercial server.

## Routes

| Method and path                   | Purpose                                                            |
| --------------------------------- | ------------------------------------------------------------------ |
| `GET /health`                     | Authenticated health check; 200 with an empty body.                |
| `POST /scans`                     | Create scans using multipart uploads.                              |
| `GET /scans/:id`                  | Retrieve progress, counters, warnings and findings for a known ID. |
| `POST /scans/:id/pause`           | Pause a live scan.                                                 |
| `POST /scans/:id/resume`          | Resume a paused live scan.                                         |
| `POST /scans/:id/cancel`          | Request cancellation.                                              |
| `DELETE /history/:id`             | Delete retained history for a completed scan.                      |
| `GET /mcp/approvals`              | List pending approvals; MCP must be enabled.                       |
| `POST /mcp/approvals/:id/approve` | Operator approval; same credential as the other routes.            |
| `POST /mcp/approvals/:id/reject`  | Reject a pending request.                                          |

There is no general REST `GET /scans` listing route in this build. Use MCP `list_scans` or keep the IDs returned by creation.

## Create a scan

`POST /scans` accepts `multipart/form-data`:

| Part             | Kind          | Contents                                                                         |
| ---------------- | ------------- | -------------------------------------------------------------------------------- |
| `scans`          | Required file | ZIP of raw request entries; passive pairs use the suffixes below.                |
| `profiles`       | Required file | ZIP of `.bb` JSON arrays. Enabled profiles are loaded from the supplied archive. |
| `config`         | Optional file | JSON configuration; send as a file part, not an ordinary form string.            |
| `retain_results` | Optional text | Boolean; default `false`.                                                        |

### Request archive

For an **active** scan, use a unique extensionless ZIP entry name such as `scan_<UUID>`. Prefix the raw request with its explicit service URL on a separate line:

```
https://app.example.test:443
GET /search?q=hello HTTP/1.1
Host: app.example.test

```

Use CRLF in the actual file. The service line preserves HTTPS/port; `Host` alone is insufficient. The entry name becomes the scan ID. Avoid path separators, `..` and duplicate IDs.

For **passive** analysis, use `scan_<UUID>.request` and a matching `scan_<UUID>.response`; the ID is the shared basename. The request file still includes its service line. A request-only passive profile can omit the response; response analysis needs a captured response. A `.request` suffix is a mode selector, not the filename to use for active traffic.

The [archive builder](https://github.com/BountySecurity/burpbountypro_documentation/tree/main/examples/rest/build_scan.py) creates both ZIPs and config locally without making network calls. Run it from the documentation repository:

```bash
python3 examples/rest/build_scan.py \
  --service https://app.example.test:443 \
  --request examples/rest/request.http \
  --profiles examples/profiles/active-reflection.bb \
  --output /tmp/bounty-rest-example
```

Change the request and destination to your actual authorized input before submitting. The output directory must not already exist, which prevents an example run from overwriting a previous batch.

```bash
curl --fail-with-body --silent --show-error \
  -H "X-BURPBOUNTY-LICENSE: ${BURPBOUNTY_LICENSE_KEY}" \
  -F 'scans=@/tmp/bounty-rest-example/scans.zip;type=application/zip' \
  -F 'profiles=@/tmp/bounty-rest-example/profiles.zip;type=application/zip' \
  -F 'config=@/tmp/bounty-rest-example/config.json;type=application/json' \
  -F 'retain_results=true' \
  http://127.0.0.1:8081/scans
```

This last command **starts real work**. A successful creation returns HTTP 201 and the scan objects/IDs. A partial failure may still have started work; reconcile known IDs before resubmitting. For passive examples, add `--passive --response examples/rest/response.http` to the builder and select passive profiles.

## Configuration JSON

```json
{
  "concurrency": 5,
  "requestPerSecond": 10,
  "payloadStrategy": "all",
  "tokens": {"{ATTACKER_DOMAIN}": "callback.example.test"}
}
```

| Field                 | Meaning                                                         |
| --------------------- | --------------------------------------------------------------- |
| `concurrency`         | Positive in-flight budget, validated by the manager up to 1000. |
| `requestPerSecond`    | Positive rate override, up to 1,000,000.                        |
| `payloadStrategy`     | Use exact `only_once` or `all`.                                 |
| `tokens`              | Map of custom placeholder strings to values.                    |
| `blindHostId`         | Provider interaction identifier.                                |
| `blindHostDomain`     | Provider domain.                                                |
| `BlindHostPrivateKey` | Provider private key; this is the declared JSON field spelling. |

{% hint style="warning" %}
**REST and MCP budgets differ**

Current REST parsing differs from MCP: nonpositive concurrency/RPS overrides are ignored, and an unrecognized strategy falls back to `all`. In particular, **`requestPerSecond: 0` does not request unlimited** through this parser. Use positive values for predictable REST limits. MCP validates these fields more strictly and explicitly supports unlimited RPS.
{% endhint %}

## Retrieve and control

```bash
curl --fail-with-body --silent --show-error \
  -H "X-BURPBOUNTY-LICENSE: ${BURPBOUNTY_LICENSE_KEY}" \
  http://127.0.0.1:8081/scans/scan_REPLACE_WITH_RETURNED_ID

curl --fail-with-body --silent --show-error -X POST \
  -H "X-BURPBOUNTY-LICENSE: ${BURPBOUNTY_LICENSE_KEY}" \
  http://127.0.0.1:8081/scans/scan_REPLACE_WITH_RETURNED_ID/cancel
```

Retrieval includes `id`, `status`, `totalRequests`, `finishedRequests`, `succeedRequests`, `failedRequests`, passive analysis counters, severity counts, `issues`, `startedAt`, `finishedAt` and optional warning/history fields. Evidence includes readable requests/responses and Base64 fields for byte-preserving consumers.

Server terminal statuses are `finished`, `failed`, `cancelled`; inspect warnings even when finished. A cancellation request needs state confirmation. REST returns full issue results; use compact MCP status and paginated summaries for economical agent polling.

## Errors and interface boundaries

Typical errors include 400 for malformed input/invalid accepted budgets or marker scope, 401 for client authentication, 404 for unknown IDs and 409 for duplicate scan IDs or conflicting history operations. Result storage/read failures can return 500; expired retained evidence can return 410.

The multipart parser's 8 MiB setting is a memory-spooling threshold, not the same contract as MCP's total HTTP body limit. Apply deployment upload limits if required. REST-created work does not go through MCP approvals or install its destination guard. See [approvals and scope](/burp-bounty-server/approvals-and-scope.md).
