Pentify
Guides

Integrate an autonomous agent

A one-page brief for any LLM/agent that will consume the Pentify API. Read it end-to-end before writing code.

What Pentify is

AI-powered penetration-testing API. Submit a target, get a full pentest report (findings + evidence + PDF) back. The service runs autonomous AI agents that perform reconnaissance, vulnerability scanning, and exploitation attempts inside a sandboxed runtime, then writes a structured report.

Think of it as OpenAI for pentesting — but instead of LLM tokens you pay for scan tokens, and instead of completions you get vulnerability findings.

Endpoints

WhatURL
Production base URLhttps://api.pentify.io/v1
OpenAPI 3.1 spechttps://api.pentify.io/openapi.json
Health probehttps://api.pentify.io/v1/healthz
Token-pack catalog (no auth)https://api.pentify.io/token-packs

Authentication

Authorization: Bearer pk_live_<26 chars> on every request. For autonomous agents, use a workspace key — owned by the tenant, shared between admins, survives an individual user’s departure. Mint one at app.pentify.io/settings/api-keys → Create key → choose workspace scope. The full key is shown exactly once.

Tokens (the meter)

Every API call consumes scan tokens from the workspace balance. Pricing is deterministic. Read operations cost 1 token; scans cost 1k / 5k / 25k depending on type. See Tokens & pricing for the full table.

Insufficient tokens
When the workspace lacks tokens for the requested operation, the API returns 402 insufficient_tokens with a top_up_url in the error details. The agent should report this to the human and stop — do not retry blindly.

Core workflow

  1. Verify target ownership (one-time per hostname). Pentify will refuse to scan unverified targets.
  2. Start a scan. POST /v1/scans with scan_typequick | standard | compliance.
  3. Wait for completion. Webhooks are preferred over polling for agent integrations.
  4. Read the report. JSON, PDF (302 to signed R2 URL), and a per-finding feed.

A complete TypeScript recipe

import { Pentify, PentifyInsufficientTokensError } from "@pentify/sdk";

const p = new Pentify({ apiKey: process.env.PENTIFY_API_KEY! });

async function pentestTarget(hostname: string) {
  // 1. Ensure the target is verified.
  const targets = await p.targets.list();
  let target = targets.data.find((t) => t.hostname === hostname);
  if (!target) {
    target = await p.targets.create({ hostname, method: "dns_txt" });
    console.log(`Add DNS TXT _pentify-verify.${hostname} = "${target.token}"`);
    console.log("Then run pentestTarget() again.");
    return;
  }
  if (target.status !== "verified") {
    const updated = await p.targets.verify(target.id);
    if (updated.status !== "verified") {
      throw new Error(`Target ${hostname} could not be verified: ${updated.failure_reason}`);
    }
  }

  // 2. Start the scan.
  let scan;
  try {
    scan = await p.scans.create({ target: hostname, scan_type: "standard" });
  } catch (e) {
    if (e instanceof PentifyInsufficientTokensError) {
      throw new Error(`Out of tokens. Need ${e.required}, have ${e.balance}. Top up at ${e.topUpUrl}`);
    }
    throw e;
  }

  // 3. Poll until done. (Or use webhooks — preferred for production.)
  while (scan.status === "queued" || scan.status === "running") {
    await new Promise((r) => setTimeout(r, 30_000));
    scan = await p.scans.get(scan.id);
  }
  if (scan.status !== "completed") {
    throw new Error(`Scan ${scan.status}: ${scan.error_message}`);
  }

  // 4. Fetch findings.
  const { data: findings } = await p.reports.findings(scan.id);
  return findings;
}

Operational notes

  • Idempotency. POST /v1/scans is not idempotent — calling it twice creates two scans (and charges twice). Track the returned id and de-dupe before retrying. Set a deterministic idempotency_key if you need safe retries.
  • Cancellation. POST /v1/scans/{id}/cancel works only while status is queued or running. The unspent portion of the hold is refunded.
  • Webhook reliability. Pentify retries failed deliveries with exponential backoff up to 24h. Your handler must be idempotent on event.id, and you must verify the HMAC signature before acting — see Webhooks.
  • Long-lived workflows.A typical compliance scan takes 30–90 minutes. Don’t keep an HTTP connection open — use webhooks, or poll on a 60-second cadence. The scan continues running even if your client disconnects.
  • Reading the report. report.pdfis a 302 redirect to a signed R2 URL with ~30-minute TTL. Follow the redirect immediately; don’t cache the URL.
  • Multi-tenant safety. A workspace key only sees data inside its own workspace. Two different organizations cannot leak data through your agent even if both keys are configured.
  • Test mode. Use a pk_test_* key for development. Same endpoints, no real charges, scans run against safe test targets only.

Quick reference card

BASE   https://api.pentify.io/v1
AUTH   Authorization: Bearer pk_live_<26 chars>

POST   /scans                         scan_type ∈ {quick, standard, compliance}
GET    /scans                         list, filterable by status
GET    /scans/{id}                    poll
POST   /scans/{id}/cancel             stop running scan
GET    /scans/{id}/report             JSON report
GET    /scans/{id}/report.pdf         PDF (302 redirect)
GET    /scans/{id}/findings           per-finding details

POST   /targets                       method ∈ {dns_txt, http_file}
GET    /targets                       list verifications
GET    /targets/{id}
POST   /targets/{id}/verify           trigger check

GET    /usage                         {balance, breakdown}

POST   /webhooks                      {url, events[]}
GET    /webhooks
DELETE /webhooks/{id}

GET    /openapi.json                  full OpenAPI 3.1 spec (no auth)
GET    /healthz                       {status:"ok"}
Note
Account / billing / portal access: app.pentify.io. Support: support@pentify.io.