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
| What | URL |
|---|---|
| Production base URL | https://api.pentify.io/v1 |
| OpenAPI 3.1 spec | https://api.pentify.io/openapi.json |
| Health probe | https://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.
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
- Verify target ownership (one-time per hostname). Pentify will refuse to scan unverified targets.
- Start a scan.
POST /v1/scanswithscan_type∈quick | standard | compliance. - Wait for completion. Webhooks are preferred over polling for agent integrations.
- 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/scansis not idempotent — calling it twice creates two scans (and charges twice). Track the returnedidand de-dupe before retrying. Set a deterministicidempotency_keyif you need safe retries. - Cancellation.
POST /v1/scans/{id}/cancelworks only whilestatusisqueuedorrunning. 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"}