Retest & remediation API

HTTP reference for retesting resolved findings, remediation SLAs and extra quality-gate rules that account for retest outcomes.

All paths are relative to https://api.aleex-rank.ai/api/v2 and authenticate with X-API-Key: rk_... (see REST API). A retest re-checks a resolved finding. It is not a scheduled re-run of the whole pentest, and it is not a manual reopen.

Retest one finding

POST /pentests/{id}/vulnerabilities/{vulnId}/retest

Optional auth context is used only for this run and is never returned on GET. cookies is a cookie header string, not an object. second_cookies is accepted the same way when an IDOR differential needs a second session:

{
  "cookies": "session=abc; csrf=…",
  "headers": {"Authorization": "Bearer eyJ..."}
}

The response is the run, including the queued finding rows. Ids are integers.

{
  "success": true,
  "data": {
    "id": 77,
    "pentest_id": 15,
    "requested_by": 7,
    "origin": "manual",
    "status": "queued",
    "scheduled_at": "2026-03-03 10:00:00",
    "due_at": "2026-03-06 10:00:00",
    "retest_outside_window": true,
    "findings": [
      {
        "id": 501,
        "run_id": 77,
        "vulnerability_id": 42,
        "result": "pending",
        "run_status": "queued",
        "pentest_id": 15
      }
    ]
  }
}

409 if a retest for that finding is already in flight:

{
  "success": false,
  "error": {
    "message": "A retest is already pending for this finding",
    "code": 409
  }
}

Retest all eligible findings

POST /pentests/{id}/retest

Queues a run over every eligible resolved finding on the pentest (respecting cooldown and window policy). The same optional cookies / headers body is accepted.

{
  "success": true,
  "data": {
    "id": 78,
    "pentest_id": 15,
    "origin": "manual",
    "status": "queued",
    "findings": [
      {"id": 510, "run_id": 78, "vulnerability_id": 42, "result": "pending"},
      {"id": 511, "run_id": 78, "vulnerability_id": 43, "result": "pending"}
    ]
  }
}

List and inspect runs

GET /pentests/{id}/retests
GET /pentests/{id}/retests/{runId}

The list is a compact JSON array under data (not a paginated {items} envelope). Each row has origin, status, SLA timestamps, live summary tallies and finding_count. claimed_at, error, retest_outside_window and the findings array live only on the detail GET. auth_context is never echoed.

{
  "success": true,
  "data": [
    {
      "id": 77,
      "pentest_id": 15,
      "requested_by": 7,
      "origin": "manual",
      "status": "completed",
      "scheduled_at": "2026-03-03 10:00:00",
      "due_at": "2026-03-06 10:00:00",
      "started_at": "2026-03-03 10:00:05",
      "finished_at": "2026-03-03 10:04:12",
      "retest_sla_breached_at": null,
      "created_at": "2026-03-03 09:59:50",
      "summary": {"pending": 0, "fixed": 1, "still_vulnerable": 0, "inconclusive": 0, "skipped": 0},
      "finding_count": 1
    }
  ]
}

The Python SDK wraps that array as .items. Detail:

{
  "success": true,
  "data": {
    "id": 78,
    "pentest_id": 15,
    "origin": "manual",
    "status": "completed",
    "retest_outside_window": true,
    "summary": {"pending": 0, "fixed": 1, "still_vulnerable": 1, "inconclusive": 1, "skipped": 1},
    "findings": [
      {"vulnerability_id": 42, "result": "fixed", "validation_method": "sqli-boolean/v1"},
      {"vulnerability_id": 43, "result": "still_vulnerable", "validation_method": "xss-reflected/v1"},
      {"vulnerability_id": 44, "result": "inconclusive", "skip_reason": "Target unreachable"},
      {"vulnerability_id": 45, "result": "skipped", "skip_reason": "Class is not_validatable (OOB)"}
    ]
  }
}

Results

ResultMeaning
pendingQueued or still running
fixedThe issue did not reproduce
still_vulnerableThe issue reproduced — the finding is reopened
inconclusiveThe run could not decide (target unreachable, missing cookies, budget)
skippedNo validator (OOB / not_validatable), or the run was cancelled while queued

A retest does not rewrite validation_status. still_vulnerable reopens the finding (open); the other results leave triage status alone.

Cancel

POST /pentests/{id}/retests/{runId}/cancel

Accepted only while the run is queued. A started run cannot be cancelled this way.

{
  "success": true,
  "data": {
    "id": 78,
    "status": "cancelled",
    "findings": [
      {"vulnerability_id": 42, "result": "skipped", "skip_reason": "Cancelled before the orchestrator claimed it"}
    ]
  }
}

Remediation policy

GET /remediation-policy
PUT /remediation-policy
GET /teams/{id}/remediation-policy
PUT /teams/{id}/remediation-policy

Caller default and team override share the same object. GET returns both the effective policy and system_default. PUT returns the saved policy. System defaults:

FieldDefaultNotes
sla_hours{critical: 24, high: 168, medium: 720, low: 2160, info: null}Hours to due date by severity
retest_sla_hours72Target time to complete a retest
auto_retest_on_resolvefalseQueue a retest when a finding is resolved
auto_retest_on_ticket_closetrueQueue a retest when a linked integration ticket closes
retest_cooldown_minutes15Minimum gap between retests of the same finding
retest_outside_windowtrueAllow retests outside the pentest RoE time windows
quality_gate_rules[]Default rules merged into quality-gate evaluation
{
  "sla_hours": {"critical": 24, "high": 168, "medium": 720, "low": 2160, "info": null},
  "retest_sla_hours": 72,
  "auto_retest_on_resolve": false,
  "auto_retest_on_ticket_close": true,
  "retest_cooldown_minutes": 15,
  "retest_outside_window": true,
  "quality_gate_rules": [{"severity": "critical", "max_open": 0}]
}
{
  "success": true,
  "data": {
    "policy": {
      "id": 3,
      "owner_type": "user",
      "owner_id": 7,
      "sla_hours": {"critical": 24, "high": 168, "medium": 720, "low": 2160, "info": null},
      "retest_sla_hours": 72,
      "auto_retest_on_resolve": false,
      "auto_retest_on_ticket_close": true,
      "retest_cooldown_minutes": 15,
      "retest_outside_window": true,
      "quality_gate_rules": [{"severity": "critical", "max_open": 0}]
    },
    "system_default": {
      "owner_type": "system",
      "sla_hours": {"critical": 24, "high": 168, "medium": 720, "low": 2160, "info": null},
      "retest_sla_hours": 72
    }
  }
}

Quality gate extras

POST /pentests/{id}/vulnerabilities/quality-gate
GET  /pentests/quality-gate

The per-pentest gate and the rolling gate on Pentests accept the same rule objects. In addition to severity + max_open, min_resolution_rate and max_overdue, these opt-in rules account for retests:

RuleMeaning
min_verified_resolution_rateMinimum share of resolved findings whose latest retest is fixed (0–1)
max_unverified_resolvedCeiling on resolved findings with no successful retest
max_regressedCeiling on still_vulnerable / reopened outcomes
max_pending_retestsCeiling on retests still pending
{
  "rules": [
    {"severity": "critical", "max_open": 0},
    {"min_verified_resolution_rate": 0.9},
    {"max_unverified_resolved": 0},
    {"max_regressed": 0},
    {"max_pending_retests": 2}
  ]
}

Where to go next