diff --git a/api-reference/authentication.mdx b/api-reference/authentication.mdx new file mode 100644 index 0000000..5f86117 --- /dev/null +++ b/api-reference/authentication.mdx @@ -0,0 +1,96 @@ +--- +title: "Authentication" +description: "Create API keys and authenticate requests to the Hacktron REST API." +--- + +The Hacktron REST API authenticates every request with an organization‑scoped API key sent in the `X-Api-Key` header. + +API keys are: + +- **Organization‑scoped** — each key belongs to exactly one organization. You never need to pass an organization ID alongside the key. +- **Scoped** — each key declares one or more scopes (`read`, `write`, `delete`) that gate which endpoints it can call. + +## Creating an API key + +API keys are created from the Hacktron dashboard. You must have the **Admin** or **Owner** role in the organization you are creating a key for. + +1. Sign in to [app.hacktron.ai](https://app.hacktron.ai) and switch to the organization you want the key to belong to. +2. Open **Settings → API keys**. +3. Click **Create API key**. +4. Give the key a descriptive name (for example `ci-pipeline`, `backstage-integration`). +5. Choose the scopes the key needs — pick the minimum set your integration requires. See [Scopes](#scopes). +6. Optionally set an expiration date. +7. Click **Create**. + + + The full API key is shown **only once**, immediately after creation. Copy it and store it in a secret manager right away. If you lose it, you will need to revoke the key and create a new one. + + +Each organization can have at most **10 active API keys** at a time. Revoke unused keys before creating new ones if you hit the limit. + +### Key format + +Hacktron API keys look like this: + +``` +hacktron_3s9K1sP7m2nXvT8YhLq0ZbW4... +``` + +- They always start with the `hacktron_` prefix. +- The first 12 characters (for example `hacktron_3s9`) are stored as a non‑secret prefix so you can recognise keys in your logs and in the dashboard. The full key is never stored server‑side — only a SHA‑256 hash. + +## Making authenticated requests + +Send your API key in the `X-Api-Key` header on every request: + +```bash +curl https://api.hacktron.ai/v1/scans \ + -H "X-Api-Key: hacktron_3s9K1sP7m2nXvT8YhLq0ZbW4..." +``` + +You do **not** need to send `X-Organization-Id` or any other header — the organization is resolved from the key. + + + Never hardcode API keys in source control or client-side code. Load them from environment variables or a secret manager at runtime. + + +## Scopes + +Scopes control what an API key is allowed to do. They are declared when you create the key and cannot be changed afterwards — create a new key if you need different scopes. + +| Scope | Grants access to | +| -------- | --------------------------------------------------------------------------------------------------------------------------------- | +| `read` | All `GET` endpoints: list and read scans, findings, and cost estimations. | +| `write` | Mutating endpoints: trigger scans, create cost estimations, update findings, add comments. Implies `read` for the same resources. | +| `delete` | Reserved for future use. | + +Each endpoint in this reference states the scope it requires. Calling an endpoint with a key that is missing the required scope returns `403 Forbidden`. + +## Revoking a key + +You can revoke a key at any time from **Settings → API keys** in the dashboard. Revocation takes effect immediately — the next request with that key will fail with `401 Unauthorized`. + +Revoked keys are kept in the dashboard audit trail (with last‑used timestamps) but can never be reactivated. + +## Testing your key + +To verify a key is working, list scans: + +```bash +curl https://api.hacktron.ai/v1/scans?limit=1 \ + -H "X-Api-Key: $HACKTRON_API_KEY" +``` + +A successful response returns HTTP `200` and a JSON body containing `data`, `total`, `page`, and `limit` fields. + + + Endpoints can also be exercised interactively in the Swagger UI at [https://api.hacktron.ai/docs](https://api.hacktron.ai/docs). The "Authorize" button accepts an `X-Api-Key` value and persists it for subsequent requests. + + +Common failures: + +| Status | Meaning | +| ------ | -------------------------------------------------------------------------------------------- | +| `401` | Missing, malformed, revoked, or expired API key. | +| `403` | Key is valid but is missing the required scope. | +| `429` | You have hit the rate limit for this key. See [Rate limits](/api-reference/rate-limits). | diff --git a/api-reference/cost-estimations/create-cost-estimation.mdx b/api-reference/cost-estimations/create-cost-estimation.mdx new file mode 100644 index 0000000..2842918 --- /dev/null +++ b/api-reference/cost-estimations/create-cost-estimation.mdx @@ -0,0 +1,108 @@ +--- +title: "Create cost estimation" +api: "POST /cost-estimations" +description: "Estimate the credit cost of scanning one or more repositories before starting a scan." +--- + +A cost estimation resolves the repositories you plan to scan, detects applications within them, and returns a predicted credit cost. A completed cost estimation is required before calling [`POST /scans`](/api-reference/scans/create-scan). + +Cost estimations run asynchronously. The `POST` returns a record in `pending` or `running` state; poll [`GET /cost-estimations/{id}`](/api-reference/cost-estimations/get-cost-estimation) until `status` reaches `completed`, `partial`, or `failed`. + + + **Scope required**: `write` + + +## Request + +```bash +curl -X POST https://api.hacktron.ai/v1/cost-estimations \ + -H "X-Api-Key: $HACKTRON_API_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "name": "nightly-estimate", + "repos": [ + { + "source": "connected", + "repo_url": "https://github.com/acme/backend", + "branch": "main" + } + ] + }' +``` + +### Body + +| Field | Type | Required | Description | +| ------- | -------- | -------- | ------------------------------------------------------------------------------------------------ | +| `name` | string | No | Friendly label for this estimation. Max 255 chars. | +| `repos` | object[] | Yes | 1–20 repositories to estimate. Each entry is one of the repo shapes below, identified by `source`. | + +### Repo shapes + +Repositories use a discriminated union on the `source` field. + +#### `connected` — a repository already synced to Hacktron via GitHub, GitLab, or Bitbucket + +| Field | Type | Required | Description | +| ------------------------ | ------ | -------- | ---------------------------------------------------- | +| `source` | `"connected"` | Yes | Discriminator. | +| `repo_url` | string | Yes | Full HTTPS URL of the repository. Max 500 chars. | +| `branch` | string | Yes | Branch to estimate. Max 255 chars. | +| `github_installation_id` | int | No | Specific GitHub App installation ID to use. | + +#### `public` — a public git repository Hacktron can clone anonymously + +| Field | Type | Required | Description | +| ---------- | ------ | -------- | ----------------------------------------- | +| `source` | `"public"` | Yes | Discriminator. | +| `repo_url` | string | Yes | Full HTTPS URL. Max 500 chars. | +| `branch` | string | Yes | Branch to estimate. Max 255 chars. | + +#### `upload` — a previously uploaded archive + +| Field | Type | Required | Description | +| ------------ | ------ | -------- | ----------------------------------- | +| `source` | `"upload"` | Yes | Discriminator. | +| `archive_id` | UUID | Yes | ID of a scan archive you uploaded. | + +## Response + +`201 Created` — the estimation is queued. Poll `GET /cost-estimations/{id}` until `status` reaches a terminal value. + +```json +{ + "id": "b4f5c6a1-2d3e-4f56-9a8b-0c1d2e3f4a5b", + "organization_id": "f336d0bc-b841-465b-8045-024475c079dd", + "user_id": "e5a6d7c8-9b0a-1c2d-3e4f-5a6b7c8d9e0f", + "name": "nightly-estimate", + "task_id": "cost_est_acme-backend_1712345678", + "status": "pending", + "repos": [ + { + "source": "connected", + "repo_url": "https://github.com/acme/backend", + "branch": "main" + } + ], + "total_credits": null, + "repo_results": null, + "error": null, + "created_at": "2026-04-13T12:00:00.000Z", + "updated_at": "2026-04-13T12:00:00.000Z" +} +``` + +### Terminal statuses + +| Status | Meaning | +| ----------- | ------------------------------------------------------------------------------- | +| `completed` | All repos were estimated successfully. `total_credits` is populated. | +| `partial` | Some repos completed, others failed. Check `repo_results[].status` for details. | +| `failed` | The whole estimation failed. `error` contains a message. | + +Once in a terminal state, an estimation is immutable. Pass its `id` as `cost_estimation_id` to [`POST /scans`](/api-reference/scans/create-scan) to start the scan. + +## Errors + +- `400` — invalid or missing fields (for example, more than 20 repos, invalid `source`, or missing `repo_url`). +- `401` / `403` — authentication or scope failure. diff --git a/api-reference/cost-estimations/get-cost-estimation.mdx b/api-reference/cost-estimations/get-cost-estimation.mdx new file mode 100644 index 0000000..a50b001 --- /dev/null +++ b/api-reference/cost-estimations/get-cost-estimation.mdx @@ -0,0 +1,71 @@ +--- +title: "Get cost estimation" +api: "GET /cost-estimations/{id}" +description: "Fetch a cost estimation by ID." +--- + +Returns a single cost estimation. Poll this endpoint on a pending estimation until `status` reaches a terminal value (`completed`, `partial`, or `failed`). + + + **Scope required**: `read` + + +## Request + +```bash +curl "https://api.hacktron.ai/v1/cost-estimations/b4f5c6a1-2d3e-4f56-9a8b-0c1d2e3f4a5b" \ + -H "X-Api-Key: $HACKTRON_API_KEY" +``` + +### Path parameters + +| Parameter | Type | Description | +| --------- | ---- | --------------------------------- | +| `id` | UUID | The cost estimation UUID. | + +## Response + +`200 OK` — see [Create cost estimation](/api-reference/cost-estimations/create-cost-estimation) for the response schema. + +```json +{ + "id": "b4f5c6a1-2d3e-4f56-9a8b-0c1d2e3f4a5b", + "organization_id": "f336d0bc-b841-465b-8045-024475c079dd", + "user_id": "e5a6d7c8-9b0a-1c2d-3e4f-5a6b7c8d9e0f", + "name": "nightly-estimate", + "task_id": "cost_est_acme-backend_1712345678", + "status": "completed", + "repos": [ + { + "source": "connected", + "repo_url": "https://github.com/acme/backend", + "branch": "main", + "commit_sha": "abc123def456" + } + ], + "total_credits": 4200, + "repo_results": [ + { + "repo_url": "https://github.com/acme/backend", + "branch": "main", + "commit_sha": "abc123def456", + "status": "completed", + "from_cache": false, + "credits": 4200, + "applications": [ + { + "app_name": "backend-api", + "app_root_path": "apps/api", + "architecture": "NestJS REST API with PostgreSQL" + } + ] + } + ], + "created_at": "2026-04-13T12:00:00.000Z", + "updated_at": "2026-04-13T12:03:21.000Z" +} +``` + +## Errors + +- `404` — estimation not found or not visible to your organization. diff --git a/api-reference/cost-estimations/list-cost-estimations.mdx b/api-reference/cost-estimations/list-cost-estimations.mdx new file mode 100644 index 0000000..1d60b4b --- /dev/null +++ b/api-reference/cost-estimations/list-cost-estimations.mdx @@ -0,0 +1,86 @@ +--- +title: "List cost estimations" +api: "GET /cost-estimations" +description: "List cost estimations for your organization." +--- + +Returns cost estimations for the organization, most recent first. Use offset-based pagination to page through results. + + + **Scope required**: `read` + + + + Unlike most list endpoints, cost estimations use **offset‑based pagination** (`limit` + `offset`) instead of `page` + `limit`. See [Pagination, filtering & sorting](/api-reference/pagination-filtering) for the general conventions. + + +## Request + +```bash +curl "https://api.hacktron.ai/v1/cost-estimations?limit=20&offset=0" \ + -H "X-Api-Key: $HACKTRON_API_KEY" +``` + +### Query parameters + +| Parameter | Type | Default | Max | Description | +| --------- | ------- | ------- | --- | ------------------------------------ | +| `limit` | integer | `50` | `100` | Number of items to return. | +| `offset` | integer | `0` | — | Number of items to skip. | + +## Response + +`200 OK` + +```json +{ + "data": [ + { + "id": "b4f5c6a1-2d3e-4f56-9a8b-0c1d2e3f4a5b", + "organization_id": "f336d0bc-b841-465b-8045-024475c079dd", + "user_id": "e5a6d7c8-9b0a-1c2d-3e4f-5a6b7c8d9e0f", + "name": "nightly-estimate", + "task_id": "cost_est_acme-backend_1712345678", + "status": "completed", + "repos": [ + { + "source": "connected", + "repo_url": "https://github.com/acme/backend", + "branch": "main", + "commit_sha": "abc123def456" + } + ], + "total_credits": 4200, + "repo_results": [ + { + "repo_url": "https://github.com/acme/backend", + "branch": "main", + "commit_sha": "abc123def456", + "status": "completed", + "from_cache": false, + "credits": 4200, + "applications": [ + { + "app_name": "backend-api", + "app_root_path": "apps/api", + "architecture": "NestJS REST API with PostgreSQL" + } + ] + } + ], + "created_at": "2026-04-13T12:00:00.000Z", + "updated_at": "2026-04-13T12:03:21.000Z" + } + ], + "total": 42 +} +``` + +### Fields + +| Field | Type | Description | +| ------- | -------- | --------------------------------------------------- | +| `data` | object[] | The estimations on this page. | +| `total` | integer | Total number of estimations in the organization. | + +See [Create cost estimation](/api-reference/cost-estimations/create-cost-estimation) for the full estimation object shape. diff --git a/api-reference/errors.mdx b/api-reference/errors.mdx new file mode 100644 index 0000000..c9f7aa0 --- /dev/null +++ b/api-reference/errors.mdx @@ -0,0 +1,65 @@ +--- +title: "Errors" +description: "HTTP status codes and error response shapes." +--- + +The Hacktron REST API uses standard HTTP status codes to indicate success and failure. + +## Status codes + +| Status | Meaning | +| ------ | ---------------------------------------------------------------------------------------------------------- | +| `200` | Successful `GET` or `PATCH`. | +| `201` | Successful `POST` — a new resource was created. | +| `204` | Successful request with no response body (for example, revoking a key). | +| `400` | Bad request. Typically a validation failure; `message` identifies the field that failed validation. | +| `401` | Missing, malformed, revoked, or expired API key. | +| `402` | Payment required. Returned by `POST /scans` when the organization has insufficient pentest credits. | +| `403` | Your API key does not have the required scope. | +| `404` | The resource does not exist, or is not visible to your organization. | +| `409` | Conflict. For example, exceeding the maximum active API key count when creating a new key. | +| `429` | Rate limit exceeded. See [Rate limits](/api-reference/rate-limits). | +| `500` | Unexpected server error. Safe to retry with backoff; contact support if it persists. | + +## Error body shape + +Errors are returned as JSON with a consistent shape: + +```json +{ + "statusCode": 400, + "message": "At least one repository is required", + "error": "Bad Request" +} +``` + +Validation errors may return `message` as an array of field‑level errors: + +```json +{ + "statusCode": 400, + "message": [ + "repos must contain at least 1 elements", + "cost_estimation_id must be a UUID" + ], + "error": "Bad Request" +} +``` + +## Common failure modes + +### "This endpoint requires API key authentication" + +A REST endpoint was called with a dashboard session token instead of an API key. REST endpoints under `/v1/*` require the `X-Api-Key` header. + +### "API key missing required scope: write" + +The key was created with `read` only but the request targets a write endpoint. Create a new key that includes the `write` scope and retry. + +### "Insufficient credits to start this scan" + +The organization does not have enough pentest credits for the requested scan. Top up from **Billing** in the dashboard, or submit a smaller cost estimation. + +### "Finding not found" + +Returned when the finding does not exist, has not yet reached the approved verification state, or belongs to a different organization. Hacktron does not distinguish between these cases in the response to avoid leaking cross‑tenant information. diff --git a/api-reference/findings/add-finding-comment.mdx b/api-reference/findings/add-finding-comment.mdx new file mode 100644 index 0000000..5df6d39 --- /dev/null +++ b/api-reference/findings/add-finding-comment.mdx @@ -0,0 +1,51 @@ +--- +title: "Add finding comment" +api: "POST /findings/{id}/comments" +description: "Append a comment to a finding's triage thread." +--- + +Appends a comment to a finding's triage thread. Comments appear in the dashboard alongside comments from GitHub, Slack, and other integrations. + + + **Scope required**: `write` + + +## Request + +```bash +curl -X POST https://api.hacktron.ai/v1/findings/d1e2f3a4-b5c6-7890-1234-567890abcdef/comments \ + -H "X-Api-Key: $HACKTRON_API_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "comment": "Confirmed reproducible on staging. Opened JIRA-4821." + }' +``` + +### Path parameters + +| Parameter | Type | Description | +| --------- | ---- | ----------------- | +| `id` | UUID | Finding UUID. | + +### Body + +| Field | Type | Required | Description | +| --------- | ------ | -------- | ------------------------------------------ | +| `comment` | string | Yes | Comment text. 1–4000 characters. | + +## Response + +`201 Created` + +```json +{ + "comment_id": "c0ffee01-feed-4bad-badc-0ffee0000002" +} +``` + +The comment is tagged with `source: "api"` and attributed to the API key's creator. It then appears in the finding's [`triage_thread`](/api-reference/findings/get-finding). + +## Errors + +- `400` — comment missing or exceeds 4000 characters. +- `404` — finding not found or not visible to your organization. diff --git a/api-reference/findings/get-finding.mdx b/api-reference/findings/get-finding.mdx new file mode 100644 index 0000000..8cf592c --- /dev/null +++ b/api-reference/findings/get-finding.mdx @@ -0,0 +1,90 @@ +--- +title: "Get finding" +api: "GET /findings/{id}" +description: "Fetch a single finding with full triage context." +--- + +Returns a single finding along with its triage thread, occurrence count, repository URL, scan type, and a Mermaid diagram of the vulnerability trace when one was produced. + + + **Scope required**: `read` + + +## Request + +```bash +curl "https://api.hacktron.ai/v1/findings/d1e2f3a4-b5c6-7890-1234-567890abcdef" \ + -H "X-Api-Key: $HACKTRON_API_KEY" +``` + +### Path parameters + +| Parameter | Type | Description | +| --------- | ---- | ----------------- | +| `id` | UUID | Finding UUID. | + +## Response + +`200 OK` — all the fields from [List findings](/api-reference/findings/list-findings#finding-fields), plus: + +```json +{ + "id": "d1e2f3a4-b5c6-7890-1234-567890abcdef", + "title": "SQL injection in /api/v1/checkout", + "category": "injection", + "severity": "critical", + "state": "open", + "description": "...", + "affected_file": "apps/api/src/checkout/checkout.service.ts", + "affected_code": "...", + "proof_of_concept": "...", + "impact": "...", + "root_cause": "...", + "remediation": "...", + "tags": ["injection", "sql"], + "scan_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", + "found_at": "2026-04-13T12:15:00.000Z", + "updated_at": "2026-04-13T12:20:00.000Z", + "triage_thread": [ + { + "id": "c0ffee01-feed-4bad-badc-0ffee0000001", + "reaction": null, + "comment": "Confirmed reproducible on staging — cart_id=1' OR '1'='1 returns 200 with full row dump.", + "user_id": "e5a6d7c8-9b0a-1c2d-3e4f-5a6b7c8d9e0f", + "username": "alex", + "source": "api", + "timestamp": "2026-04-13T12:22:00.000Z" + } + ], + "mermaid_trace": "graph TD\n A[Request] --> B[checkout.service.ts]\n B --> C[(Postgres)]", + "occurrence_count": 1, + "repo_url": "https://github.com/acme/backend", + "scan_type": "full" +} +``` + +### Extra fields + +| Field | Type | Description | +| ------------------ | --------------- | --------------------------------------------------------------------------------------------- | +| `triage_thread` | object[] | Comments and reactions on the finding, aggregated across GitHub, Slack, the web app, and the API. | +| `mermaid_trace` | string\|null | Mermaid diagram source for the vulnerability trace. `null` when Hacktron did not produce one. | +| `occurrence_count` | integer | Number of scans in which this finding has appeared. Minimum `1`. | +| `repo_url` | string\|null | Primary repository URL of the parent scan. | +| `scan_type` | enum\|null | `pr` or `full`. | + +### Triage thread entry + +| Field | Type | Description | +| ----------- | ------------- | ------------------------------------------------------------------------ | +| `id` | UUID | Entry identifier. | +| `reaction` | string\|null | Triage reaction. One of the finding states (`open`, `true_positive`, `false_positive`, `accepted_risk`, `resolved`). `null` for comment-only entries. | +| `comment` | string\|null | Comment text. `null` for reaction-only entries. | +| `user_id` | UUID | Author user ID. | +| `username` | string | Author display name. | +| `source` | enum | Origin of the entry. One of `github`, `slack`, `web`, `api`, `agent`. | +| `timestamp` | string | ISO 8601 timestamp. | + +## Errors + +- `404` — finding not found, still in verification, or not visible to your organization. diff --git a/api-reference/findings/list-findings.mdx b/api-reference/findings/list-findings.mdx new file mode 100644 index 0000000..5aca470 --- /dev/null +++ b/api-reference/findings/list-findings.mdx @@ -0,0 +1,87 @@ +--- +title: "List findings" +api: "GET /findings" +description: "List findings across all scans in your organization." +--- + +Returns findings across every scan in the organization, with filtering and sorting. Only findings that have passed automated verification (`verification_status = approved`) are returned. + + + **Scope required**: `read` + + +## Request + +```bash +curl "https://api.hacktron.ai/v1/findings?severity=critical&state=open&sort_by=found_at&sort_order=DESC&page=1&limit=50" \ + -H "X-Api-Key: $HACKTRON_API_KEY" +``` + +### Query parameters + +| Parameter | Type | Default | Description | +| ------------ | ------- | ---------- | ------------------------------------------------------------------------------------------------------- | +| `page` | integer | `1` | 1‑based page number. | +| `limit` | integer | `15` | Items per page. Max `100`. | +| `severity` | enum | — | Filter by severity: `critical`, `high`, `medium`, `low`, `info`. | +| `state` | enum | — | Filter by state: `open`, `true_positive`, `false_positive`, `accepted_risk`, `resolved`. | +| `scan_id` | UUID | — | Only return findings produced by this scan. The scan must exist in the organization. | +| `sort_by` | enum | `found_at` | One of `found_at`, `updated_at`, `severity`. | +| `sort_order` | enum | `DESC` | `ASC` or `DESC`. | + +## Response + +`200 OK` + +```json +{ + "data": [ + { + "id": "d1e2f3a4-b5c6-7890-1234-567890abcdef", + "title": "SQL injection in /api/v1/checkout", + "category": "injection", + "severity": "critical", + "state": "open", + "description": "User-supplied cart ID is concatenated into a SQL query...", + "affected_file": "apps/api/src/checkout/checkout.service.ts", + "affected_code": "const rows = await conn.query(`SELECT * FROM carts WHERE id = '${cartId}'`);", + "proof_of_concept": "POST /api/v1/checkout with cart_id=1' OR '1'='1", + "impact": "Full read access to the carts table, including other customers' items.", + "root_cause": "String interpolation instead of parameterised query.", + "remediation": "Use parameterised queries via the driver's placeholder API.", + "tags": ["injection", "sql"], + "scan_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", + "found_at": "2026-04-13T12:15:00.000Z", + "updated_at": "2026-04-13T12:20:00.000Z" + } + ], + "total": 284, + "page": 1, + "limit": 50 +} +``` + +### Finding fields + +| Field | Type | Description | +| ------------------ | ------------- | --------------------------------------------------------------------------- | +| `id` | UUID | Finding identifier. | +| `title` | string | Short summary. | +| `category` | string | Vulnerability category (for example `injection`, `auth`, `xss`). | +| `severity` | enum | `critical`, `high`, `medium`, `low`, `info`. | +| `state` | enum | `open`, `true_positive`, `false_positive`, `accepted_risk`, `resolved`. | +| `description` | string | Long‑form description of the issue. | +| `affected_file` | string | Path relative to the repository root. | +| `affected_code` | string | Code snippet of the affected location. | +| `proof_of_concept` | string\|null | Reproduction steps or payload. `null` if none was captured. | +| `impact` | string\|null | Impact narrative. | +| `root_cause` | string\|null | Root-cause narrative. | +| `remediation` | string\|null | Suggested fix. | +| `tags` | string[] | Free‑form tags. | +| `scan_id` | UUID\|null | Scan that produced this finding. | +| `found_at` | string | ISO 8601 timestamp when the finding was first discovered. | +| `updated_at` | string | ISO 8601 timestamp of the most recent state or severity change. | + +## Errors + +- `404` — `scan_id` was provided but the scan does not exist or is not visible. diff --git a/api-reference/findings/update-finding.mdx b/api-reference/findings/update-finding.mdx new file mode 100644 index 0000000..c256a23 --- /dev/null +++ b/api-reference/findings/update-finding.mdx @@ -0,0 +1,65 @@ +--- +title: "Update finding" +api: "PATCH /findings/{id}" +description: "Change a finding's state and/or severity." +--- + +Updates the `state`, `severity`, or both on a single finding. Every change is recorded to the finding's audit trail and propagated to connected integrations (GitHub, Slack, Jira, Linear). + + + **Scope required**: `write` + + +## Request + +```bash +curl -X PATCH https://api.hacktron.ai/v1/findings/d1e2f3a4-b5c6-7890-1234-567890abcdef \ + -H "X-Api-Key: $HACKTRON_API_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "state": "true_positive", + "severity": "critical", + "reason": "Confirmed reproducible against staging. Raising from high to critical." + }' +``` + +### Path parameters + +| Parameter | Type | Description | +| --------- | ---- | ----------------- | +| `id` | UUID | Finding UUID. | + +### Body + +At least one of `state` or `severity` must be provided. Providing neither returns `400`. + +| Field | Type | Description | +| ----------------- | ------ | ------------------------------------------------------------------------------------------------------------ | +| `state` | enum | New state. One of `open`, `true_positive`, `false_positive`, `accepted_risk`, `resolved`. | +| `severity` | enum | New severity. One of `critical`, `high`, `medium`, `low`, `info`. | +| `state_reason` | string | Reason for the state change. Max 2000 chars. Falls back to `reason` if omitted. | +| `severity_reason` | string | Reason for the severity change. Max 2000 chars. Falls back to `reason` if omitted. | +| `reason` | string | Shorthand applied to both state and severity when their specific reason fields are omitted. Max 2000 chars. | + + + Pass `reason` alone when the same justification applies to both state and severity. Use `state_reason` and `severity_reason` only when the justifications differ. + + +## Response + +`200 OK` + +```json +{ + "id": "d1e2f3a4-b5c6-7890-1234-567890abcdef", + "state": "true_positive", + "severity": "critical" +} +``` + +The response contains only the updated state and severity. Fetch the full finding via [`GET /findings/{id}`](/api-reference/findings/get-finding) for the remaining fields. + +## Errors + +- `400` — neither `state` nor `severity` provided, or field validation failed. +- `404` — finding not found, still in verification, or not visible to your organization. diff --git a/api-reference/introduction.mdx b/api-reference/introduction.mdx new file mode 100644 index 0000000..878abf7 --- /dev/null +++ b/api-reference/introduction.mdx @@ -0,0 +1,60 @@ +--- +title: "Introduction" +description: "Programmatic access to Hacktron scans, findings, and cost estimations." +--- + +The Hacktron REST API lets you trigger pentest scans, browse and triage findings, and run cost estimations from your own tooling. + +Everything you can do in the Hacktron dashboard as a scan operator or reviewer is available through the API, scoped to a single organization per key. + +## Base URL + +``` +https://api.hacktron.ai/v1 +``` + +All endpoints in this reference are relative to this base URL. + +## Interactive API reference + +A Swagger UI rendered from the live OpenAPI spec is hosted at [https://api.hacktron.ai/docs](https://api.hacktron.ai/docs). It covers the same endpoints documented here with raw request and response schemas and a "Try it out" console, useful for verifying field names or cross-checking schemas against production. + +## What you can do + + + + Start full pentest scans against one or more repositories and track their status. + + + Generate a cost estimation for a set of repositories before committing credits. + + + List, filter, and inspect findings across scans, including their full triage context. + + + Update finding state, adjust severity, and add comments from your own systems. + + + +## Requirements + +- A Hacktron organization with an **Admin** or **Owner** role (required to create API keys). +- An API key — see [Authentication](/api-reference/authentication) for how to create one. +- An HTTP client that can set custom headers. + +## Next steps + + + + Create an API key and make your first authenticated request. + + + Understand request quotas and how to handle 429 responses. + + + Learn the shared query conventions used across list endpoints. + + + HTTP status codes and error shapes you should handle. + + diff --git a/api-reference/pagination-filtering.mdx b/api-reference/pagination-filtering.mdx new file mode 100644 index 0000000..7b2bf08 --- /dev/null +++ b/api-reference/pagination-filtering.mdx @@ -0,0 +1,104 @@ +--- +title: "Pagination, filtering & sorting" +description: "Shared query conventions used by list endpoints." +--- + +List endpoints in the Hacktron REST API share a consistent set of query parameters for pagination, sorting, and filtering. + +## Pagination + +Most list endpoints use **page‑based pagination**: + +| Parameter | Type | Default | Max | Description | +| --------- | ------- | ------- | --- | ----------------------------- | +| `page` | integer | `1` | — | 1‑based page number. | +| `limit` | integer | `15` | `100` | Number of items per page. | + +The response echoes the current `page` and `limit`, and includes `total` for building pagination controls or iterating until exhausted: + +```json +{ + "data": [/* items for this page */], + "total": 284, + "page": 2, + "limit": 50 +} +``` + +To iterate all pages: + +```bash +page=1 +while : ; do + curl -s "https://api.hacktron.ai/v1/findings?page=$page&limit=100" \ + -H "X-Api-Key: $HACKTRON_API_KEY" + # ... extract data, break when (page * limit) >= total + page=$((page + 1)) +done +``` + + + **Cost Estimations** use offset‑based pagination instead, with `limit` (default `50`, max `100`) and `offset` (default `0`). This is called out explicitly on the [List Cost Estimations](/api-reference/cost-estimations/list-cost-estimations) page. + + +## Sorting + +Endpoints that support sorting accept two parameters: + +| Parameter | Type | Description | +| ------------ | ------ | ------------------------------------------------- | +| `sort_by` | enum | Which field to sort by. Valid values vary per endpoint. | +| `sort_order` | enum | `ASC` or `DESC`. Defaults to `DESC`. | + +The allowed `sort_by` values are documented on each list endpoint. Examples: + +- **List scans**: `created_at`, `updated_at`, `status` +- **List findings**: `found_at`, `updated_at`, `severity` + +If `sort_by` is omitted, the endpoint-specific default applies (see each list page). + +## Filtering + +Filters are passed as additional query parameters. Each list endpoint documents the filters it supports. The patterns below are shared across list endpoints. + +### Enum filters + +Enum filters accept the canonical lower‑snake‑case value and return only records that match: + +```bash +# Only critical findings +GET /findings?severity=critical + +# Only scans that have finished successfully +GET /scans?status=completed +``` + +### Scoped filters + +Some filters restrict results to a related resource: + +```bash +# Findings for a specific scan +GET /findings?scan_id=123e4567-e89b-12d3-a456-426614174000 +``` + +Scoped filters validate that the target resource belongs to your organization. `404` is returned if the resource does not exist or is not visible to the key. + +### Combining filters + +Multiple filters combine with AND semantics: + +```bash +GET /findings?severity=high&state=open&scan_id=... +``` + +There is no OR operator. Call the endpoint multiple times and merge results client-side if a union is required. + +## Example + +Fetch the 25 most recently updated high‑severity findings that are still open: + +```bash +curl "https://api.hacktron.ai/v1/findings?severity=high&state=open&sort_by=updated_at&sort_order=DESC&page=1&limit=25" \ + -H "X-Api-Key: $HACKTRON_API_KEY" +``` diff --git a/api-reference/rate-limits.mdx b/api-reference/rate-limits.mdx new file mode 100644 index 0000000..1ac37c2 --- /dev/null +++ b/api-reference/rate-limits.mdx @@ -0,0 +1,52 @@ +--- +title: "Rate limits" +description: "Request quotas, 429 behaviour, and how to back off." +--- + +The Hacktron REST API rate limits requests per API key. + +## Limit + +- **100 requests per 60 seconds** per API key, across all REST endpoints. + +The window is rolling; there is no fixed start or end. After 100 requests at `t=0`, the next request is accepted at approximately `t=60s`. + +Requests authenticated with dashboard sessions (not API keys) do not count against this limit. + +## 429 responses + +When a key exceeds the limit, the API returns `429 Too Many Requests`: + +```http +HTTP/1.1 429 Too Many Requests +Content-Type: application/json + +{ + "statusCode": 429, + "message": "ThrottlerException: Too Many Requests" +} +``` + +The request body is not consumed; the request is rejected before it reaches the application. + +## Backing off + +Recommended client behaviour on a `429`: + +1. Stop issuing requests with the affected key. +2. Retry with exponential backoff (for example 1s, 2s, 4s, 8s). +3. If the limit is hit consistently, spread the workload over a longer window or contact Hacktron support about a higher quota. + +For workloads that require higher sustained throughput (for example, backfilling findings into an external system), contact [support](mailto:founders@hacktron.ai) with the use case. + +## Concurrency and long‑running scans + +`POST /scans` enqueues the scan and returns immediately; no long‑lived connection is required while the scan runs. + +The recommended pattern: + +1. `POST /scans` to start the scan and capture the returned `id`. +2. `GET /scans/{id}/status` at a 10–30 second interval to check progress. +3. Once `status` is `completed`, fetch findings with `GET /scans/{id}/findings` or `GET /scans/{id}/findings/export`. + +Polling counts toward the rate limit. Use intervals no shorter than 10 seconds. diff --git a/api-reference/scans/create-scan.mdx b/api-reference/scans/create-scan.mdx new file mode 100644 index 0000000..8f89e7c --- /dev/null +++ b/api-reference/scans/create-scan.mdx @@ -0,0 +1,87 @@ +--- +title: "Trigger a pentest scan" +api: "POST /scans" +description: "Start a pentest scan against one or more repositories." +--- + +Starts a full pentest scan against the repositories attached to a completed cost estimation. Scans run asynchronously; the endpoint returns immediately with a scan `id` for polling. + + + **Scope required**: `write` + + +## Prerequisites + +1. Create a cost estimation with [`POST /cost-estimations`](/api-reference/cost-estimations/create-cost-estimation) and wait for it to reach `completed` status. +2. Ensure your organization has enough pentest credits (visible in **Billing** in the dashboard). Insufficient credits return `402 Payment Required`. + +## Request + +```bash +curl -X POST https://api.hacktron.ai/v1/scans \ + -H "X-Api-Key: $HACKTRON_API_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "cost_estimation_id": "b4f5c6a1-2d3e-4f56-9a8b-0c1d2e3f4a5b", + "repos": [ + { + "url": "https://github.com/acme/backend", + "branch": "main", + "source": "connected" + } + ], + "target_urls": ["https://staging.acme.com"], + "auth_instructions": "Use test account test@acme.com / hunter2", + "custom_context": "Focus on the payment flow under /api/v1/checkout" + }' +``` + +### Body + +| Field | Type | Required | Description | +| ---------------------- | -------- | -------- | ----------------------------------------------------------------------------------------------------------------------- | +| `cost_estimation_id` | UUID | Yes | ID of a completed cost estimation. The first repo in `repos` must match the estimation. | +| `repos` | object[] | Yes | At least one repository. The first is the primary target; any additional entries are scanned as related repositories. | +| `target_urls` | string[] | No | Live URLs to include in the pentest (for example a staging environment). | +| `auth_instructions` | string | No | Credentials or steps the scanner should follow to authenticate. Max 2000 chars. | +| `custom_context` | string | No | Additional context: scope, areas to emphasise, exclusions. Max 2000 chars. | +| `context_document_ids` | UUID[] | No | IDs of context documents to attach to the scan. | + +### Repo object + +| Field | Type | Required | Description | +| -------- | ------ | -------- | ----------------------------------------------------------------------- | +| `url` | string | Yes | HTTPS URL of the repository. | +| `branch` | string | Yes | Branch to scan. | +| `source` | enum | No | `connected`, `public`, or `upload`. Defaults to `connected`. | + +## Response + +`201 Created` + +```json +{ + "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", + "task_id": "web_scan_1712345678", + "status": "pending", + "message": "Scan started" +} +``` + +| Field | Type | Description | +| --------- | ------ | ------------------------------------------------------------- | +| `id` | UUID | Scan UUID. Use this to fetch status, details, and findings. | +| `task_id` | string | Internal task identifier (also visible in the dashboard). | +| `status` | string | Always `pending` at creation time. | +| `message` | string | Status message suitable for display. | + +## Errors + +- `400` — missing `repos`, invalid `cost_estimation_id`, or validation failure. +- `401` / `403` — authentication or scope failure. +- `402` — insufficient pentest credits. Top up from the **Billing** page in the dashboard. + +## Next steps + +- Poll [`GET /scans/{id}/status`](/api-reference/scans/get-scan-status) until status is `completed`. +- Fetch findings with [`GET /scans/{id}/findings`](/api-reference/scans/list-scan-findings) or export them with [`GET /scans/{id}/findings/export`](/api-reference/scans/export-scan-findings). diff --git a/api-reference/scans/export-scan-findings.mdx b/api-reference/scans/export-scan-findings.mdx new file mode 100644 index 0000000..4b9c9e7 --- /dev/null +++ b/api-reference/scans/export-scan-findings.mdx @@ -0,0 +1,66 @@ +--- +title: "Export scan findings" +api: "GET /scans/{id}/findings/export" +description: "Download all findings for a scan as JSON, CSV, or SARIF." +--- + +Returns every approved finding for a scan in one of three formats. Unlike [List scan findings](/api-reference/scans/list-scan-findings), this endpoint is **not paginated**; all findings are returned in a single response. + + + **Scope required**: `read` + + +## Request + +```bash +curl "https://api.hacktron.ai/v1/scans/a1b2c3d4-e5f6-7890-abcd-ef1234567890/findings/export?format=sarif" \ + -H "X-Api-Key: $HACKTRON_API_KEY" \ + -o findings.sarif +``` + +### Path parameters + +| Parameter | Type | Description | +| --------- | ---- | ------------- | +| `id` | UUID | Scan UUID. | + +### Query parameters + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | --------------------------------------------- | +| `format` | enum | Yes | One of `json`, `csv`, `sarif`. | + +## Response + +The `Content-Type` and `Content-Disposition` headers depend on the requested format. + +### `format=json` + +```http +Content-Type: application/json; charset=utf-8 +``` + +Returns a JSON array of finding objects, each matching the schema described in [List findings](/api-reference/findings/list-findings#finding-fields). + +### `format=csv` + +```http +Content-Type: text/csv; charset=utf-8 +Content-Disposition: attachment; filename="findings-.csv" +``` + +Returns a CSV document with one row per finding and a header row. Intended for spreadsheets, BI tools, and ad‑hoc review. + +### `format=sarif` + +```http +Content-Type: application/sarif+json; charset=utf-8 +Content-Disposition: attachment; filename="findings-.sarif" +``` + +Returns a [SARIF 2.1.0](https://sarifweb.azurewebsites.net/) document. SARIF is consumed by GitHub code scanning, Azure DevOps, and most IDE security plugins; use this format to integrate Hacktron findings into existing security tooling. + +## Errors + +- `400` — missing or invalid `format` query parameter. +- `404` — scan not found or not visible to your organization. diff --git a/api-reference/scans/get-scan-status.mdx b/api-reference/scans/get-scan-status.mdx new file mode 100644 index 0000000..acd10ea --- /dev/null +++ b/api-reference/scans/get-scan-status.mdx @@ -0,0 +1,50 @@ +--- +title: "Get scan status" +api: "GET /scans/{id}/status" +description: "Lightweight endpoint for polling a scan until it completes." +--- + +Returns a minimal payload with the scan's current status. Use this for polling; the response omits the findings summary that `GET /scans/{id}` computes. + + + **Scope required**: `read` + + +## Request + +```bash +curl "https://api.hacktron.ai/v1/scans/a1b2c3d4-e5f6-7890-abcd-ef1234567890/status" \ + -H "X-Api-Key: $HACKTRON_API_KEY" +``` + +### Path parameters + +| Parameter | Type | Description | +| --------- | ---- | ------------- | +| `id` | UUID | Scan UUID. | + +## Response + +`200 OK` + +```json +{ + "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", + "task_id": "web_scan_1712345678", + "status": "running", + "created_at": "2026-04-13T12:00:00.000Z", + "updated_at": "2026-04-13T12:18:04.000Z" +} +``` + +See [List scans](/api-reference/scans/list-scans#scan-statuses) for the full list of status values. + +## Recommended polling + +A poll interval of **10–30 seconds** is sufficient. Pentest scans complete on the order of minutes; tighter polling provides no additional signal and consumes the [rate limit](/api-reference/rate-limits) quota. + +Stop polling when `status` reaches a terminal value: `completed`, `failed`, `stopped`, `cancelled`, or `skipped`. + +## Errors + +- `404` — scan not found or not visible to your organization. diff --git a/api-reference/scans/get-scan.mdx b/api-reference/scans/get-scan.mdx new file mode 100644 index 0000000..84d00a0 --- /dev/null +++ b/api-reference/scans/get-scan.mdx @@ -0,0 +1,57 @@ +--- +title: "Get scan" +api: "GET /scans/{id}" +description: "Fetch a single scan, including its findings summary." +--- + +Returns the full record for a single scan, including its findings summary. + + + **Scope required**: `read` + + +## Request + +```bash +curl "https://api.hacktron.ai/v1/scans/a1b2c3d4-e5f6-7890-abcd-ef1234567890" \ + -H "X-Api-Key: $HACKTRON_API_KEY" +``` + +### Path parameters + +| Parameter | Type | Description | +| --------- | ---- | --------------- | +| `id` | UUID | Scan UUID. | + +## Response + +`200 OK` + +```json +{ + "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", + "task_id": "web_scan_1712345678", + "scan_type": "full", + "status": "completed", + "name": "acme/backend@main", + "repo_url": "https://github.com/acme/backend", + "branch": "main", + "pr_number": null, + "target_urls": ["https://staging.acme.com"], + "findings_summary": { + "critical": 1, + "high": 3, + "medium": 7, + "low": 12, + "info": 4 + }, + "created_at": "2026-04-13T12:00:00.000Z", + "updated_at": "2026-04-13T13:42:18.000Z" +} +``` + +See [List scans](/api-reference/scans/list-scans) for a description of each field. + +## Errors + +- `404` — scan not found or not visible to your organization. diff --git a/api-reference/scans/list-scan-findings.mdx b/api-reference/scans/list-scan-findings.mdx new file mode 100644 index 0000000..d5f0f0a --- /dev/null +++ b/api-reference/scans/list-scan-findings.mdx @@ -0,0 +1,75 @@ +--- +title: "List scan findings" +api: "GET /scans/{id}/findings" +description: "Paginate through the findings produced by a scan." +--- + +Returns findings produced by a specific scan, with the same filtering and sorting controls as [List findings](/api-reference/findings/list-findings). + +Only findings that have passed automated verification (`verification_status = approved`) are returned. + + + **Scope required**: `read` + + +## Request + +```bash +curl "https://api.hacktron.ai/v1/scans/a1b2c3d4-e5f6-7890-abcd-ef1234567890/findings?severity=high&state=open&page=1&limit=50" \ + -H "X-Api-Key: $HACKTRON_API_KEY" +``` + +### Path parameters + +| Parameter | Type | Description | +| --------- | ---- | ------------- | +| `id` | UUID | Scan UUID. | + +### Query parameters + +| Parameter | Type | Default | Description | +| ------------ | ------- | ------- | ---------------------------------------------------------------------------------------- | +| `page` | integer | `1` | 1‑based page number. | +| `limit` | integer | `15` | Items per page. Max `100`. | +| `severity` | enum | — | Filter by severity: `critical`, `high`, `medium`, `low`, `info`. | +| `state` | enum | — | Filter by state: `open`, `true_positive`, `false_positive`, `accepted_risk`, `resolved`. | +| `sort_by` | enum | `found_at` | One of `found_at`, `updated_at`, `severity`. | +| `sort_order` | enum | `DESC` | `ASC` or `DESC`. | + +## Response + +`200 OK` + +```json +{ + "data": [ + { + "id": "d1e2f3a4-b5c6-7890-1234-567890abcdef", + "title": "SQL injection in /api/v1/checkout", + "category": "injection", + "severity": "critical", + "state": "open", + "description": "User-supplied cart ID is concatenated into a SQL query...", + "affected_file": "apps/api/src/checkout/checkout.service.ts", + "affected_code": "const rows = await conn.query(`SELECT * FROM carts WHERE id = '${cartId}'`);", + "proof_of_concept": "POST /api/v1/checkout with cart_id=1' OR '1'='1", + "impact": "Full read access to the carts table, including other customers' items.", + "root_cause": "String interpolation instead of parameterised query.", + "remediation": "Use parameterised queries via the driver's placeholder API.", + "tags": ["injection", "sql"], + "scan_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", + "found_at": "2026-04-13T12:15:00.000Z", + "updated_at": "2026-04-13T12:20:00.000Z" + } + ], + "total": 11, + "page": 1, + "limit": 50 +} +``` + +See [List findings](/api-reference/findings/list-findings#finding-fields) for the field reference. + +## Errors + +- `404` — scan not found or not visible to your organization. diff --git a/api-reference/scans/list-scans.mdx b/api-reference/scans/list-scans.mdx new file mode 100644 index 0000000..1454bfb --- /dev/null +++ b/api-reference/scans/list-scans.mdx @@ -0,0 +1,94 @@ +--- +title: "List scans" +api: "GET /scans" +description: "List scans with pagination, filtering, and sorting." +--- + +Returns scans in your organization, with filtering by type and status. + + + **Scope required**: `read` + + +## Request + +```bash +curl "https://api.hacktron.ai/v1/scans?status=completed&sort_by=created_at&sort_order=DESC&page=1&limit=25" \ + -H "X-Api-Key: $HACKTRON_API_KEY" +``` + +### Query parameters + +| Parameter | Type | Default | Description | +| ------------ | ------- | ------- | ------------------------------------------------------------------- | +| `page` | integer | `1` | 1‑based page number. | +| `limit` | integer | `15` | Items per page. Max `100`. | +| `scan_type` | enum | — | Filter by scan type. Values: `pr`, `full`. | +| `status` | enum | — | Filter by status. See [Scan statuses](#scan-statuses). | +| `sort_by` | enum | `created_at` | One of `created_at`, `updated_at`, `status`. | +| `sort_order` | enum | `DESC` | `ASC` or `DESC`. | + +### Scan statuses + +| Value | Meaning | +| ----------------------- | -------------------------------------------------------------- | +| `pending` | Scan queued, not yet started. | +| `running` | Scan is in progress. | +| `pending_verification` | Findings are being verified automatically. | +| `pending_triage` | Findings are ready for triage. | +| `completed` | Scan finished successfully. | +| `failed` | Scan failed. See scan detail for error context. | +| `stopped` / `cancelled` | Scan was stopped or cancelled before completion. | +| `skipped` | Scan was skipped (no applicable content). | +| `draft` | Scan was created but never started. | + +## Response + +`200 OK` + +```json +{ + "data": [ + { + "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", + "task_id": "web_scan_1712345678", + "scan_type": "full", + "status": "completed", + "name": "acme/backend@main", + "repo_url": "https://github.com/acme/backend", + "branch": "main", + "pr_number": null, + "target_urls": ["https://staging.acme.com"], + "findings_summary": { + "critical": 1, + "high": 3, + "medium": 7, + "low": 12, + "info": 4 + }, + "created_at": "2026-04-13T12:00:00.000Z", + "updated_at": "2026-04-13T13:42:18.000Z" + } + ], + "total": 142, + "page": 1, + "limit": 25 +} +``` + +### Scan object fields + +| Field | Type | Description | +| ------------------- | ------------- | ---------------------------------------------------------------- | +| `id` | UUID | Scan identifier. | +| `task_id` | string | Internal task ID for correlation with the dashboard. | +| `scan_type` | enum | `pr` or `full`. | +| `status` | enum | Current scan status. | +| `name` | string\|null | Display name. Defaults to `repo@branch`. | +| `repo_url` | string\|null | Primary repository URL. | +| `branch` | string\|null | Primary branch scanned. | +| `pr_number` | integer\|null | GitHub PR number (PR scans only). | +| `target_urls` | string[]\|null| Live targets (pentest scans). | +| `findings_summary` | object | Approved finding counts by severity. | +| `created_at` | string | ISO 8601 timestamp. | +| `updated_at` | string | ISO 8601 timestamp. | diff --git a/docs.json b/docs.json index 2d1c1ae..e915224 100644 --- a/docs.json +++ b/docs.json @@ -48,6 +48,49 @@ ] } ] + }, + { + "tab": "API Reference", + "groups": [ + { + "group": "Getting started", + "pages": [ + "api-reference/introduction", + "api-reference/authentication", + "api-reference/rate-limits", + "api-reference/pagination-filtering", + "api-reference/errors" + ] + }, + { + "group": "Cost Estimations", + "pages": [ + "api-reference/cost-estimations/create-cost-estimation", + "api-reference/cost-estimations/list-cost-estimations", + "api-reference/cost-estimations/get-cost-estimation" + ] + }, + { + "group": "Scans", + "pages": [ + "api-reference/scans/create-scan", + "api-reference/scans/list-scans", + "api-reference/scans/get-scan", + "api-reference/scans/get-scan-status", + "api-reference/scans/list-scan-findings", + "api-reference/scans/export-scan-findings" + ] + }, + { + "group": "Findings", + "pages": [ + "api-reference/findings/list-findings", + "api-reference/findings/get-finding", + "api-reference/findings/update-finding", + "api-reference/findings/add-finding-comment" + ] + } + ] } ], "global": { diff --git a/index.mdx b/index.mdx index 2b2e447..193c01c 100644 --- a/index.mdx +++ b/index.mdx @@ -45,6 +45,45 @@ Meet the next generation of AI-native tools built for developers, security engin +## REST API + +Programmatic access to scans, findings, and cost estimations. + + + + Base URL, conventions, and what you can do with the public REST API. + + + Create an API key, set the `X-Api-Key` header, and understand scopes. + + + Trigger pentest scans, poll status, and list results. + + + Browse, filter, triage, and comment on findings. + + + ## Hacktron Workbench (Deprecated)