Pentests API

HTTP reference for pentest CRUD, assets, agents, phases, lifecycle, comments, and the run/report operations on the streaming backend.

All paths are relative to https://api.aleex-rank.ai/api/v2 and authenticate with X-API-Key: rk_... (see REST API). Run, stream, report and cancel operations live on the streaming backend at https://aleex.aleex-rank.ai and are flagged as such below.

Pentest model

A pentest has a fixed type (web, api, server) and mode (guided, automatic), a status from its lifecycle, one or more assets, and agents assigned across phases 1 Reconnaissance, 2 Enumeration, 3 Analysis. See Pentests, assets & phases.

List pentests

GET /pentests

Query parameters: page (default 1), per_page (default 20), status, type.

{
  "success": true,
  "data": {
    "items": [
      {
        "id": 15,
        "name": "Acme web assessment",
        "type": "web",
        "mode": "guided",
        "status": "configured",
        "progress_percentage": 0,
        "created_at": "2026-01-29 14:30:00"
      }
    ],
    "pagination": {"total": 1, "count": 1, "per_page": 20, "current_page": 1, "total_pages": 1}
  }
}

Create a pentest

POST /pentests
Content-Type: application/json
FieldTypeRequiredNotes
namestringYesDisplay name
descriptionstringNoFree text
typestringYesweb, api or server
modestringYesguided or automatic
urlstringNoPrimary URL convenience field
methodology_idintConditionalRequired in guided mode; forced to 1 in automatic
team_idintConditionalRequired if you belong to any team
assetsarrayYesAt least one; exactly one is_primary: true
{
  "name": "Acme web assessment",
  "description": "Security review of the customer portal",
  "type": "web",
  "mode": "guided",
  "methodology_id": 1,
  "team_id": 4,
  "assets": [
    {"asset_type": "domain", "asset_value": "acme.example.com", "is_primary": true},
    {"asset_type": "ip", "asset_value": "192.0.2.10"},
    {"asset_type": "url", "asset_value": "https://acme.example.com/api"}
  ]
}

Response 201:

{
  "success": true,
  "data": {
    "id": 15,
    "name": "Acme web assessment",
    "type": "web",
    "mode": "guided",
    "status": "draft",
    "methodology_id": 1,
    "methodology_name": "OWASP Top 10",
    "team": {"id": 4, "name": "Security Team"},
    "assets": [
      {"id": 1, "type": "domain", "value": "acme.example.com", "is_primary": true},
      {"id": 2, "type": "ip", "value": "192.0.2.10", "is_primary": false},
      {"id": 3, "type": "url", "value": "https://acme.example.com/api", "is_primary": false}
    ],
    "created_at": "2026-01-29 14:30:00"
  }
}

Activate a Rules of Engagement before you launch. Creating a pentest does not start it. POST /chat is fail-closed: without an active RoE the run is refused (409 / no_active_roe). Set and activate the RoE with the Engagement & RoE API, then assign agents and stream.

Retrieve, update, delete

GET    /pentests/{id}
PATCH  /pentests/{id}
DELETE /pentests/{id}

GET returns the pentest with its assets and agents. PATCH (or PUT) updates mutable fields such as name and description. DELETE soft-deletes the pentest.

Limits and quality gate

GET /pentests/limits
GET /pentests/quality-gate

limits reports how many pentests you may still create this period for your tier. quality-gate evaluates a rolling quality check over your last 7 pentests.

{
  "success": true,
  "data": {
    "max_pentests_per_month": 50,
    "used_this_month": 12,
    "remaining": 38
  }
}

Response fields above are representative; consult the live response for exact keys.

Methodologies

GET /methodologies

Lists the methodologies you can attach to a guided pentest.

{
  "success": true,
  "data": [
    {"id": 1, "name": "OWASP Top 10", "description": "Web application security testing"},
    {"id": 2, "name": "PTES", "description": "Penetration Testing Execution Standard"}
  ]
}

Assets

GET    /pentests/{id}/assets
POST   /pentests/{id}/assets
DELETE /pentests/{id}/assets/{assetId}

Add an asset:

{"asset_type": "url", "asset_value": "https://acme.example.com/admin", "is_primary": false}

asset_type is one of url, domain, ip, api. A pentest must always keep at least one asset.

Agents

Agents are assigned per phase, 3 to 4 per phase, in order. You cannot assign phase N+1 until phase N has at least 3 agents.

GET    /pentests/{id}/agents
POST   /pentests/{id}/agents
DELETE /pentests/{id}/agents/{agentId}
POST   /pentests/{id}/agents/deactivate
GET    /pentests/{id}/default-agents

Assign agents to a phase:

{
  "agents": [
    {"agent_id": 101, "phase_id": 1, "execution_order": 1},
    {"agent_id": 102, "phase_id": 1, "execution_order": 2},
    {"agent_id": 103, "phase_id": 1, "execution_order": 3}
  ]
}

Response 201 — note that agents which can’t be assigned (duplicates, or a phase already at its max of 4) are reported rather than silently dropped:

{
  "success": true,
  "data": {
    "pentest_id": 15,
    "assigned_count": 2,
    "assigned_ids": [1, 2],
    "skipped_count": 1,
    "skipped": [
      {"agent_id": 103, "phase_id": 1, "reason": "already_assigned"}
    ]
  }
}

GET /pentests/{id}/default-agents returns the default agents grouped by phase. For an automatic pentest that is still configured with no agents yet, this call also auto-assigns those defaults and reports auto_assigned: true. DELETE …/agents/{agentId} unassigns one agent (refused if it would drop a phase below 3); POST …/agents/deactivate clears all assignments.

Phases and lifecycle

A pentest moves draft → configured → running → phase_completed → processing → completed, with paused, cancelled, archived and failed as off-ramps. Only valid transitions are accepted.

Mark a phase complete (user-facing):

POST /pentests/{id}/phases/{phaseId}/complete

Finish the pentest:

POST /pentests/{id}/finish

The pentest must be in phase_completed or processing — you cannot finish a running pentest. A guided pentest must also have at least one processed vulnerability first; automatic pentests are finished for you by the streaming backend.

{
  "success": true,
  "data": {
    "id": 15,
    "status": "completed",
    "progress_percentage": 100,
    "total_vulnerabilities": 12,
    "end_time": "2026-01-29 16:45:00"
  }
}

Error when finished too early:

{
  "success": false,
  "error": {
    "message": "Pentest must be in 'phase_completed' or 'processing' state to finish (current: running).",
    "code": 400
  }
}

Comments and evidences

GET    /pentests/{id}/comments
POST   /pentests/{id}/comments
DELETE /pentests/{id}/comments/{commentId}
GET    /pentests/{id}/evidences

Add a comment:

{"comment": "Re-scoped to include the staging environment"}

GET /pentests/{id}/evidences returns the agent operations that produced findings, i.e. the original discovery evidence across the pentest.

Run, process and report (streaming backend)

These operations are served by the streaming backend at https://aleex.aleex-rank.ai, not the REST base. They authenticate with the same credentials.

POST https://aleex.aleex-rank.ai/chat
POST https://aleex.aleex-rank.ai/handle_vulnerability
GET  https://aleex.aleex-rank.ai/handle_vulnerability/status
POST https://aleex.aleex-rank.ai/generate_report
GET  https://aleex.aleex-rank.ai/pentest/{id}/stream
POST https://aleex.aleex-rank.ai/pentest/{id}/cancel
  • POST /chat launches execution and streams agent activity over Server-Sent Events. The pentest must have an active RoE or the call is refused (409 / no_active_roe).
  • POST /handle_vulnerability enqueues asynchronous processing of a guided pentest’s findings into stored vulnerabilities. It returns as soon as the job is created — poll the status endpoint for the result.
  • GET /handle_vulnerability/status reports the state of that job and, once finished, the severity summary.
  • POST /generate_report seals a report for a completed pentest and emails it. Body fields below.
  • GET /pentest/{id}/stream reconnects to an in-progress run’s event stream.
  • POST /pentest/{id}/cancel asks the orchestrator to stop the stream (cooperative cancel). This is not the kill switch.
  • Kill is REST on this API, not the streaming host: POST /pentests/{id}/kill — a terminal emergency stop that preserves evidence. See Engagement & RoE. Use cancel to drop a stream; use kill when the engagement must not continue.

Launch body:

{
  "agent_type": "pentest",
  "pentest_id": 15,
  "phase_id": 1,
  "mode": "guided",
  "user_prompt": "Start reconnaissance of the target"
}

The full request body, dispatch rules and event contract for /chat are documented in Chat & pentest execution; the event payloads are detailed in Streaming.

Generate a report

POST https://aleex.aleex-rank.ai/generate_report
Content-Type: application/json
{
  "pentest_id": 15,
  "recipient_email": "ciso@example.com",
  "recipient_name": "Alex Rivera",
  "subject": "Acme web assessment — sealed report",
  "cc_emails": ["security@example.com"],
  "extended": 1,
  "formats": ["pdf", "json"],
  "audience": "technical"
}
FieldRequiredNotes
pentest_idYesThe completed pentest
recipient_emailYesWhere the PDF is sent
recipient_nameNoDisplay name
subjectNoEmail subject
cc_emailsNoCC list
extendedNo0 summary, 1 full report with evidence details
formatsNoOverride the profile: pdf, html, markdown, docx, json
audienceNoOne-off audience: executive, technical, attestation

Sealed files are then listed under the Reports API. Branding (logos and colours) is the visual layer — Branding.

Process vulnerabilities (asynchronous)

Once a guided pentest’s phases are done (status phase_completed), turn the agents’ raw output into stored vulnerabilities with POST /handle_vulnerability. Processing runs in the background: the call enqueues a job and returns immediately — it does not wait for or return the findings.

POST https://aleex.aleex-rank.ai/handle_vulnerability
Content-Type: application/json
{
  "pentest_id": 15,
  "model_alias": "gemini-2.5-flash"
}

Both fields are required. The response is 202 Accepted:

{
  "status": "processing",
  "message": "Procesamiento de vulnerabilidades iniciado"
}

Common errors: 400 if a field is missing or the pentest is not in phase_completed; 403 if you lack access to the model, the pentest or the operation; 409 if the pentest already has processed vulnerabilities or a job is already running; 503 if the processing lock is momentarily unavailable.

Automatic pentests do not call this endpoint. The streaming backend processes their findings inside the run and emits processing_vulnerabilities and vulnerabilities_complete events over SSE — see Chat & pentest execution.

Poll the processing status

Poll GET /handle_vulnerability/status until the job reaches a terminal state. status is one of processing, completed, failed or idle (idle means no job has run for this pentest).

GET https://aleex.aleex-rank.ai/handle_vulnerability/status?pentest_id=15

While the job runs:

{
  "status": "processing",
  "pentest_id": 15,
  "summary": {"critical": 0, "high": 0, "medium": 0, "low": 0, "info": 0}
}

When it finishes, the response carries the counts, the severity summary and references to the created findings:

{
  "status": "completed",
  "pentest_id": 15,
  "total_responses": 12,
  "total_detected": 8,
  "total_created": 7,
  "summary": {"critical": 1, "high": 2, "medium": 3, "low": 1, "info": 0},
  "vulnerabilities_created": [
    {"vulnerability_id": 501, "operation_id": 1203}
  ],
  "started_at": 1700000000.0,
  "finished_at": 1700000060.0
}

A failed status carries an error message instead of a summary. After a completed job, finish the pentest with POST /pentests/{id}/finish and triage the findings through the Vulnerabilities API.

Vulnerabilities on a pentest

Triage endpoints live under /pentests/{id}/vulnerabilities/... and have their own page: Vulnerabilities API. Prefer tenant webhooks (GET/POST /webhooks) so every pentest of the owner inherits the subscription; per-pentest hooks still exist as a legacy path. See Webhooks.