https://api.perfai.ai/v1 on the cloud platform (on-premise, swap in your own host). Every request needs a bearer token on the Authorization header.
Machine-readable spec. The full OpenAPI 3.1.1 contract is served at https://api.perfai.ai/v1/openapi.yaml — import it into Postman, an SDK generator, or any API tooling.
New here? Start with the Quickstart — it shows how to get a token and run your first test end to end. The API overview also covers authentication, rate limits, the run state machines, and a complete integration example. The examples below use the cloud host api.perfai.ai; replace it with your own host if you run Perfai on-premise.
Errors
Every error response uses one RFC 7807 problem+json shape (Content-Type: application/problem+json) — the endpoints’ own errors and framework errors (auth, validation) alike:
type— a stable URI identifying the error kind; branch on this, not the human-readabletitle.title/detail— a short summary and, when available, specifics.status— mirrors the HTTP status code.- Some errors add fields: a
402carriescurrent_balanceandaction_type; a validation400carries anerrorsarray of per-field messages.
Register app
Registers a target app and drives it to a testable state. On the default auto sign-up path, Perfai runs one initial security test as the final onboarding step, so first findings are available as soon asregistrationStatus is COMPLETED. Supplying your own tenantOneCredentials or createTestAccounts: false skips that initial test. Either way, run further tests on demand with Run Security Agent.
Perfai onboards the app for you — entirely from your inputs, with sensible defaults:
- URL only — the default. Perfai runs the full autonomous onboarding: it maps your API surface, creates test accounts for you (auto sign-up), validates the logins, discovers roles, provisions role-based (RBAC) accounts, and completes registration. This is what lets a URL-only registration run authenticated, RBAC and cross-tenant (BOLA) tests — not just a shallow unauthenticated test.
- You provide credentials (
tenantOneCredentials/tenantTwoCredentials) — Perfai maps your API surface and uses your accounts instead of signing up, then runs role/RBAC mapping. createTestAccounts: false— Perfai maps your API surface by exploring the app but does not create accounts: an unauthenticated (public-endpoint-only) test.
registrationStatus is COMPLETED, then trigger a test.
Registration time depends heavily on your app — its size, structure, number of roles, sign-up flow, and how quickly it responds — so there’s no fixed duration. It ranges from a few minutes to considerably longer, and the auto-signup path is the slowest (account creation, login validation, role discovery, RBAC provisioning, and full app mapping all run first). Poll Get app until
registrationStatus is COMPLETED (or FAILED/CANCELLED) rather than assuming a fixed time — use a generous timeout, and don’t treat a still-IN_PROGRESS app as stalled just because it’s taking a while.If Perfai can’t sign up — no public sign-up page, a CAPTCHA, an SSO wall, or an unreachable URL — it pauses and emails you to add credentials, rather than silently continuing unauthenticated. The app stays
IN_PROGRESS; re-register with tenantOneCredentials to continue.string
required
Bearer <token>.string
required
Base URL of the application under test (
http/https). Example: https://api.payments.example.comstring
default:"host of appUrl"
App name (max 150 chars). Defaults to the host of
appUrl (e.g. api.payments.example.com) when omitted.RoleCredential[]
Credentials for the primary tenant, one entry per role (max 20). Omit to have Perfai auto-create accounts (default), or for unauthenticated APIs (with
createTestAccounts: false).RoleCredential[]
Credentials for a second tenant, used for cross-tenant (BOLA) testing (max 20). Same
RoleCredential shape as tenantOneCredentials.boolean
default:"true"
Whether Perfai autonomously creates test accounts (auto sign-up) when no credentials are supplied. Only applies when no credentials are supplied. Set
false to register for an unauthenticated (public-endpoint-only) test — no accounts, so authenticated/RBAC/BOLA tests won’t run.string[]
Endpoints to exclude from every test of this app, as
method:path entries (max 200). Use it to keep destructive operations out of scope — see Excluding endpoints.string[]
Extra HTTP headers sent to your app on every request, as
Name: value entries (max 50). Use it for a gateway API key, a tenant selector, or a feature flag your app requires.integer
default:"150"
How many exploration steps Perfai may take while mapping your API surface (1–1000). Defaults to your organization’s configured value, which itself defaults to 150.
Terms used here. A tenant is a customer or account boundary inside your application (for example two separate customer accounts). Supplying a second tenant’s logins in
tenantTwoCredentials lets Perfai test whether one tenant can reach another tenant’s data — BOLA (Broken Object Level Authorization). A role is the permission level a login has (e.g. Admin vs User); giving several roles drives role-based access control (RBAC) testing.Credentials are optional — unauthenticated or public APIs register and test without them. When you supply them, Perfai logs in as each role to run authenticated and role-based access testing. Passwords are sent over TLS, stored encrypted, and never logged or returned. The API style (REST or GraphQL) is detected automatically — you don’t declare it.
Excluding endpoints from tests
skipEndpoints keeps chosen endpoints out of every test of the app. Reach for it before you point Perfai at anything you can’t freely mutate — account deletion, logout, payment capture, bulk imports.
Each entry is method:path:
- Method is an HTTP verb, or
*for any. - Path may use
**as a glob —*:/internal/**excludes everything under/internal.
Sending extra headers
headers adds HTTP headers to every request Perfai makes against your app — on top of anything the credentials supply. Use it when your app needs a gateway key, a tenant selector, or a feature flag to answer at all:
Name: value. Values are sent as supplied and are never returned by the API.
Controlling mapping depth
Perfai explores your app to map its API surface.maxSteps caps that exploration:
appUrl is required — the Minimal form runs full autonomous onboarding, defaulting the label to the host and creating test accounts for you. The Full form shows every field.
Location header contains the app URL to poll. Every 201 also returns a top-level taskId of the form task_reg_<appId> — poll it via Get task status for the same registration progress. The onboarding handle in the body depends on the path taken:
- Default (auto-signup) — an
onboardinghandle (mode: "auto-signup"plus a message). createTestAccounts: false— aspecExtractionhandle instead: no accounts are created; Perfai maps your API surface from a spec-extraction vision run, pollable via itsstatusUrl.- Re-registering a dead app — a
replacedhandle alongside the usual fields.
Response
string
The registered app’s identifier.
string
Registration task of the form
task_reg_<appId> — poll it via Get task status.string
Always
IN_PROGRESS immediately after registering.ISO 8601 string
When the app was registered.
object
Present on the default (URL-only) path. Carries
mode: "auto-signup" and a human-readable message.object
Present instead of
onboarding when createTestAccounts: false. Carries visionRunId, state, and a pollable Get task status statusUrl for the mapping run.object
Present only when re-registering a URL whose previous API registration had failed or been abandoned. Carries
previousAppId and previousStatus.COMPLETED or still onboarding — is never replaced; you get 409 with its existing appId to reuse instead (see Status codes). An app first registered outside this API is also never touched — you get 409 app-registered-outside-api; remove that app, then retry. In every case the signal that the app is ready to test is registrationStatus: COMPLETED from Get app — not the onboarding handle alone.
Status codes
Get app
Returns a single app, including its registration state. Use it to poll onboarding progress after registering — whenregistrationStatus is COMPLETED, the app is fully onboarded and ready to test.
string
required
Identifier of the app to fetch.
string
required
Bearer <token>.Response
string
App identifier.
string
Human-readable app name.
string
Base URL of the app under test.
string
API base path (e.g.
/api/v2).string
Registration state. Moves
PENDING → IN_PROGRESS → COMPLETED | FAILED | CANCELLED; the last three are terminal — stop polling once you reach one.ISO 8601 string
When the app was registered.
string
How often Perfai re-tests this app on its own. Apps inherit your organization’s setting when they are registered and fall back to
nightly, so an app may be on a schedule you did not ask for here — each run uses credits. Change it in the dashboard under Edit app.Status codes
Run Account Setup
Supplies test-account credentials for an app that cannot sign itself up. Perfai creates its own test accounts wherever it can. Some applications make that impossible — no public sign-up page, a CAPTCHA, an SSO wall, or invite-only registration. In those cases onboarding pauses and waits for you rather than quietly falling back to an unauthenticated test, which would report far less than a real one. Submit your credentials here and onboarding resumes from where it stopped. This takes the sametenantOneCredentials / tenantTwoCredentials shape as Register app, so if you already have credentials you can supply them either at registration or here afterwards.
string
required
The app awaiting credentials.
RoleCredential[]
required
Accounts for your primary tenant, one per role (max 20). At least one is required — without a working account Perfai cannot test anything behind your login.
RoleCredential[]
Accounts for a second tenant (max 20). Supply these to enable cross-tenant (BOLA) testing — checks that one customer cannot reach another customer’s data. Without a second tenant those checks cannot run.
RoleCredential fields as at registration: role, username, password, and an optional loginUrl.
Response
string
The app the accounts were saved against.
string
Registration task — poll Get task status to watch onboarding continue.
integer
How many credential sets were stored.
boolean
true when onboarding was waiting for these credentials and has now resumed. false means they are saved but nothing was waiting — either onboarding had not reached that point yet, or it stopped for another reason.string
Absolute URL to poll.
Status codes
Delete app
Permanently deletes an app you registered through the API, along with all of its data — test runs, findings, mappings, and stored credentials. This can’t be undone.409 — delete it from the dashboard instead.
string
required
The app to delete. Must be one you registered through the API.
Response
string
The deleted app’s identifier.
string
Always
DELETED on success.string
The app’s registration state at the moment it was deleted.
Status codes
List apps
Returns all apps registered to your organization, sorted by creation date (newest first). Use this endpoint to resolve theappId for the service you want to test.
integer
default:"1"
Page number.
integer
default:"20"
Items per page, max 100.
string
Case-insensitive filter on app label or API name.
Response
App[]
Paginated apps — newest first.
integer
Total apps across all pages.
integer
Current page.
integer
Page size used for this response.
Status codes
Run Vision Agent
Launches a vision run — Perfai’s browser automation that explores your application like a real user to map the API surface, validate credentials, and discover roles. Vision runs automatically during onboarding; use this endpoint to re-run it on demand — for example after a release that changes your UI or API surface. Vision runs triggered through the API always execute browserless in the background. Credentials are resolved server-side from the app’s stored authentication — nothing travels in the request.When to use this. Vision runs on their own during onboarding and before each scheduled test, so it is not a required step in the basic register → test → results flow. Call this endpoint only to re-map on demand after your app’s UI or API changes, or to re-validate stored credentials.
string
required
App identifier returned by
GET /apps.string
required
Bearer <token>.enum
default:"map"
map — explore the app and map or refresh your API surface. validate-login — verify stored credentials still work. discover-roles — discover RBAC roles. verify-rbac — re-verify role capabilities.map is the default. Pass -d '{"operation":"validate-login"}' (with -H "Content-Type: application/json") to run a different operation.
Location header contains the status URL to poll.
Response
string
Task handle — poll it via Get task status.
string
App the run belongs to.
string
The operation that was triggered.
string
Always
QUEUED immediately after triggering.ISO 8601 string
When the run was created.
ISO 8601 string | null
When the state last changed.
string
Absolute URL to poll for status.
Status codes
Run Security Agent
Schedules an asynchronous security test for the specified app. The app must be onboarded first — itsregistrationStatus (from Get app) must be COMPLETED.
string
required
App identifier returned by
GET /apps.string
required
Bearer <token>.Location response header also contains the statusUrl value. Use either to poll for run completion.
Response
string
Task handle — poll it via Get task status.
string
App the run belongs to.
SecurityRunState
Always
QUEUED immediately after triggering.ISO 8601 string
When the run was created.
ISO 8601 string | null
When the state last changed.
string
Absolute URL to poll for status.
Status codes
Get task status
Returns the current state of any task on this API — a registration, a security test, or a Vision Agent run. Every action that starts work returns ataskId; poll this endpoint until state is terminal.
string
required
Task identifier returned by register, run security test, or run Vision Agent. Treat it as opaque — pass it back exactly as given.
Response
string
Echoes the requested id.
string
security-agent, vision-agent, or registration.string
App the task belongs to.
TaskState
Current state — see Test state machine.
ISO 8601 string
When the task was created.
ISO 8601 string | null
When it last changed;
null if unchanged since creation.object
Type-specific detail:
security-agent—runNumber, plusvulnerabilitiesUrloncestateisCOMPLETED. AFAILEDorINTERRUPTEDtest has no trustworthy findings, so no link is offered.vision-agent—operation:map,validate-login,discover-roles, orverify-rbac.registration—registrationStatus:PENDING,IN_PROGRESS,COMPLETED,FAILED, orCANCELLED.
state: AWAITING_INPUT, Perfai could not create test accounts on its own and is waiting for yours — send them to Run Account Setup. The task returns to RUNNING once they are accepted.
Status codes
Get vulnerabilities
Returns security vulnerability findings for the specified app.status: "RUN_IN_PROGRESS" rather than findings. Wait for the run to reach COMPLETED before fetching results.
string
required
App identifier returned by
GET /apps.integer
default:"1"
Page number.
integer
default:"20"
Items per page, max 100.
string
Free-text filter across the finding’s text fields.
string
Only return findings of this severity (case-insensitive):
Critical, High, Medium, or Low.boolean
Only return findings Perfai has confirmed fixed (
true) or not yet fixed (false).boolean
Only return dismissed findings (
true) or not-dismissed findings (false).total reflects the filtered set.
An app registered with your own
tenantOneCredentials or with createTestAccounts: false returns NO_RUNS until you trigger a test — those paths don’t run one automatically. On the default auto sign-up path, the initial onboarding test usually means findings are already present. Treat NO_RUNS as “not tested yet” and call Run Security Agent; don’t read it as “no vulnerabilities found.”Response
Forstatus: COMPLETED or NO_RUNS:
"COMPLETED" | "NO_RUNS"
Result availability.
Vulnerability[]
Paginated vulnerability findings — see the Vulnerability object below.
integer
Total findings across all pages.
integer
Current page.
integer
Page size used for this response.
string | null
ID of the most recent completed run.
ISO 8601 string | null
When the last run completed.
Vulnerability object
The vulnerability object carries the same finding detail the Perfai dashboard shows. Onlyid, label, and severity appear on every finding. Every other field is conditional — it is included only when the scan produced a value for it, and usually omitted otherwise (absent from the JSON rather than returned as null), so write your integration to treat them as optional. path and method are present for endpoint-specific findings and may be null or omitted for app-level findings (for example a missing rate-limit header or an unauthenticated-exposure finding not tied to one route). How often a field appears depends heavily on the finding type: a request reproducer accompanies most findings, response bodies and schemas a subset, and explainer/remediation and the compliance flags only a small fraction. The object is flat on the wire — the groups below are for reading only.
Security categories — the values `label` can take
Security categories — the values `label` can take
Every finding’s
label is one of Perfai’s security categories, aligned to the OWASP API Security Top 10. The current set:API Governance / Inventory, BOLA – Cross-Role Access, BOLA – Cross-Tenant Role Access, BOLA – Same-Tenant Ownership Bypass, BOLA – Same-Tenant Write Without Read Access, Broken Access Control (BAC) - Inconsistent Permissions, Broken Authentication (Expired Token), Broken Authentication (Invalid Credentials), Broken Authentication (Invalid Token), Broken Authentication (No Token), Broken CORS Policy, Broken Data Access (BDA) - Inconsistent Permissions, Broken Date Range Limit, Broken Function Level Authorization, Broken Logout, Broken Object Level Authorization (BOLA), Broken Pagination Limit, Broken Project-Level Authorization (BPLA), Broken Resource-Level Authorization (BRLA), Broken Tenant-Level Authorization (BTLA), Broken Token Claim Manipulation, Broken Token Revocation, Broken Token Signature Verification, Client Side Request Forgery, Cost Evasion / Audit Data Tampering, Credential Exposure via URL Parameters, Cross-Application Token Acceptance, Cross-Environment Token Acceptance, Cross-Site Scripting (XSS), Cross-Tenant Data Contamination, Cross-Tenant Takeover, Cross-User Data Contamination, Data Access Authorization Anomaly, Data Access Breaking Change, Debug Endpoint Exposed, Enumerable Resource ID, Excessive Token Data Exposure, Exposed Credentials, Hidden Sensitive Data in Authorized Responses, Input Validation, JNDI Injection, Malicious File Acceptance, Missing HSTS Header, Missing Token Audience Claim, Missing Token Issuer Claim, Missing Token Revocation, Nested Sensitive Data Exposure, NoSQL Injection, Non-JWT Token Format, Open HTTP Redirection, Pagination Missing, Privilege Escalation, Prompt Injection, RBAC Matrix Validation, SBAC Matrix Validation, SQL Injection, SSL Certificate Expiration (<15 days), Search Data Leak, Search Data Leak (Authorized), Security Configuration Missing, Self-Signed SSL Certificate, Sensitive Business Flows / Rate Limiting, Sensitive Data Exposure, Sensitive Data in Error & Metadata Responses, Server Side Request Forgery (SSRF), Session Hijacking, Shadow Data, TLS Version Below 1.2, Token & Data Security (Read Operations), Token & Data Security (Write Operations), Token Data Tampering, Token Signing-Key Leak, UI Workflow Permission Anomalies, Unauthorized Token Generation, Unrestricted Access to Sensitive Business Flows, Unsafe HTTP Method for Authentication Operations, Unsecured Observability Endpoints, Valid Authentication Baseline, Weak AuthorizationNew categories are added as Perfai’s detection coverage grows, so treat label as an open set of strings rather than a fixed enum.Identity & location
string
required
Finding identifier — pass it to the dismiss/fix/reopen and Get vulnerability endpoints. Always present.
string
required
Finding name / security category. Always present.
string
Specific finding title, when the scan set one distinct from the category.
string
API path where the issue was found. Present for endpoint-specific findings;
null or omitted for app-level findings.string
HTTP method of the affected endpoint. Present for endpoint-specific findings;
null or omitted for app-level findings.string
UI route the finding was reproduced through, when it was discovered via the app UI.
Classification & scoring
"Critical" | "High" | "Medium" | "Low"
required
Risk severity. Always present.
string
Severity after a manual override, when one was applied.
string
Short business- and security-impact summary.
string
security or privacy.string
Action classification the scanner assigned.
string
The intended request behaviour the test exercised.
string
OWASP API Security Top 10 reference.
string
CWE identifier.
number
CVSS v3 base score (0.0–10.0).
string
CVSS v3 vector string.
Compliance flags
Present on the fraction of findings the platform classified against a compliance regime;true when the finding involves that data class.
boolean
Finding involves Personally Identifiable Information.
boolean
Finding involves Payment Card Industry data.
boolean
Finding involves HIPAA-regulated data.
Explanation & remediation
string
Technical explanation of the vulnerability. Populated on a small fraction of findings.
string
Recommended fix. Populated on a small fraction of findings.
object
Deep-dive analysis, when available. Common keys:
description, StepsToReproduce, impact_analysis, mitigation, long_solution, references, conclusion, copilot_prompt, workingExamples. Which keys are present varies by finding.Evidence
string
cURL reproducer for the authenticated request. Present on most findings.
object | string
Response body observed for the authenticated request.
string
cURL reproducer for the same call made without authentication — present on findings that reproduce unauthenticated.
object | string
Response body observed for the unauthenticated request.
object
JSON Schema of the request body, when one was derived.
object
JSON Schema of the response body, when one was derived.
array
Affected or sensitive fields attached to the finding, each with a name, data type, and location.
Triage & fix state
boolean
Finding has been dismissed as accepted risk. See Dismiss vulnerability.
boolean
Set by Perfai once a previously-reported finding stops being detected by a later test. You cannot set this.
boolean
Someone asserted the finding is fixed — a claim pending verification, distinct from
isFixed. See Mark vulnerability fixed.ISO 8601 string | null
When the fix was claimed.
string | null
Who claimed the fix.
string | null
Comment supplied with the fix claim.
boolean
true for a manually created finding rather than one the scanner detected.Timestamps
ISO 8601 string | null
When the finding was first recorded.
ISO 8601 string | null
When the finding was last updated.
Response — test in progress
When a test is active, the response is a small envelope instead of findings (status: RUN_IN_PROGRESS):
"RUN_IN_PROGRESS"
Indicates a test is currently active.
string
Human-readable description.
string
ID of the in-progress run.
"QUEUED" | "RUNNING"
Current state of the active run.
Status codes
Dismiss vulnerability
Marks a finding as accepted risk so it stops appearing in your open findings. Later tests do not re-raise it.string
required
The
id of a finding from Get vulnerabilities.string
Why you dismissed it. Max 1000 characters.
Response
"DISMISSED"
State of the finding after the action.
object
The updated finding — the full Vulnerability object reflecting its new state (the sample response is abbreviated to the state fields).
Status codes
Mark vulnerability fixed
Records that you have fixed a finding.This records a claim pending verification, not a verified result. If the next security test still detects the finding, the claim is dropped and the finding stays open. It is reported separately from
isFixed, which Perfai sets on its own once a finding stops being detected — so fixClaimed is what you asserted, and isFixed is what Perfai observed.string
required
The
id of a finding from Get vulnerabilities.string
Notes about the fix. Max 1000 characters.
Response
"FIX_CLAIMED"
State of the finding after the action.
object
The updated finding — the full Vulnerability object, carrying the
fixClaimed* fields (the sample response is abbreviated to the state fields).Status codes
Reopen vulnerability
Returns a finding to your open findings. Undoes a dismissal or a fix claim — whichever state the finding is in.string
required
The
id of a finding from Get vulnerabilities.Response
"OPEN"
State of the finding after the action.
object
The updated finding — the full Vulnerability object reflecting its new state (the sample response is abbreviated to the state fields).
Status codes
Get vulnerability
Returns a single finding by id, scoped to your organization. Use it to re-read one finding after acting on it, without paging the whole list.string
required
The
id of a finding from Get vulnerabilities.data array.
Full finding detail is a paid feature. On the free tier this returns
402 — upgrade to fetch a finding by id.Status codes
Get reports
Lists the security reports generated for an app, newest first. Each item includes adownloadUrl for fetching the PDF.
402 — upgrade to list and download reports.
string
required
App identifier returned by
GET /apps.integer
default:"1"
Page number.
integer
default:"20"
Items per page, max 100.
Response
Report[]
Security reports — newest first. An app with no reports returns an empty array.
integer
Total reports across all pages.
integer
Current page.
integer
Page size used for this response.
Status codes
Download report
Downloads a security report as a PDF. Store the bytes wherever you like.Content-Type: application/pdf), not JSON. Security reports are a paid feature. On the free tier this returns 402 — upgrade to download reports.
string
required
Report identifier from Get reports.
200 OK) the response body is the raw PDF (Content-Type: application/pdf), sent as an attachment — not JSON.

