---
title: "Start an estimated pentest, spending the confirmed credits (organization admins only)"
method: POST
path: "/pentests/{id}/start"
tags: ["REST API - Pentests"]
---

# Start an estimated pentest, spending the confirmed credits (organization admins only)

`POST /pentests/{id}/start`

## Request

- Base URL: `https://api.hacktron.ai/v1`
- URL: `https://api.hacktron.ai/v1/pentests/{id}/start`
- Auth: API key in header `X-Api-Key`

## Path parameters

- `id` string, required

## Request body

- RestStartPentestDto
  - `expected_credits` integer, required: The total the user confirmed: the estimate's total_credits, plus triage_fee_credits when triage is required or opted in
  - `triage_enabled` boolean: Opt in to human triage of findings when it is not already required

## Response `200`

- RestPentestResponseDto
  - `scan_id` string, uuid, required: Stable pentest id; task_id changes when it starts
  - `status` 'pending' | 'running' | 'completed' | 'failed' | 'stopped' | 'cancelled' | 'skipped' | 'pending_verification' | 'pending_triage' | 'draft' | 'estimating' | 'estimated', required
  - `repos` RepoDataDto[], required
    - `include_paths` string[]: Whitebox scope: gitignore-style globs (relative to the repo root) that narrow the scan to matching paths. Empty means the whole repository.
    - `exclude_paths` string[]: Whitebox scope: gitignore-style globs removed from the scan after include_paths is applied; use `*.md` to drop a file type.
    - `source` 'connected' | 'public' | 'upload'
    - `provider` 'github' | 'gitlab' | 'bitbucket' | 'azure': Resolved by the server at scan start; ignored on input
    - `url` string: Repository URL
    - `branch` string: Branch name, tag name, or commit SHA
    - `ref_type` 'branch' | 'tag' | 'sha': How `branch` was selected (UI hint for draft re-use)
    - `archive_id` string: Scan archive ID
    - `github_installation_id` number: GitHub App installation ID (connected repos only)
  - `target_urls` string[], required
  - `login_targets` RestPentestLoginTargetDto[], required
    - `site` string, required
    - `login_check` 'unverified' | 'pending' | 'running' | 'succeeded' | 'failed' | 'cancelled' | 'expired', required: Whether Hacktron could sign in with the login the site has now. A pass lasts an hour, and changing the site or login makes it unverified.
    - `failure_reason` string, nullable, required: Why the check failed, without credentials
  - `custom_context` string, nullable, required
  - `application_id` string, uuid, nullable, required
  - `cost_estimation_id` string, uuid, nullable, required
  - `triage_enabled` boolean, nullable, required
  - `credits_used` number, nullable, required

## Other responses

- `400`: A login target has no passing login check from the last hour
- `402`: Insufficient credits
- `409`: expected_credits no longer matches the total; read the estimate again and confirm the new total

## Changes

- **2026-11-03** `48b2f95b2320`: 1 info
  - endpoint added

[Operation history](https://skmtc.dev/hacktron/apis/hacktron-rest-api/changes/pentests/:id/start/post.md)

---

[API](https://skmtc.dev/hacktron/apis/hacktron-rest-api.md) - [All operations](https://skmtc.dev/hacktron/apis/hacktron-rest-api/llms.txt) - [OpenAPI document](https://skmtc.dev/hacktron/apis/hacktron-rest-api/revisions/48b2f95b2320?raw)
