Skip to main content
All endpoints share one base URL — 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-readable title.
  • title / detail — a short summary and, when available, specifics.
  • status — mirrors the HTTP status code.
  • Some errors add fields: a 402 carries current_balance and action_type; a validation 400 carries an errors array of per-field messages.
The Status codes table under each endpoint lists the codes it can return.

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 as registrationStatus 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.
Either way, registration completes on its own. Poll Get app until 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.com
string
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.
Use exactly one colon per entry — DELETE:/api/v1/users/{id}, not DELETE /api/v1/users/{id}. A malformed entry is rejected when you register, which is deliberate: an unvalidated filter would otherwise fail the test itself rather than quietly skip nothing.

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:
Each entry is 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:
Raise it when the mapping is missing endpoints — large apps, deep navigation, or many nested workflows need more steps. Higher values map more thoroughly but lengthen registration. Omit it to use your organization’s configured value (150 unless you’ve changed it). Only 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.
The 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 onboarding handle (mode: "auto-signup" plus a message).
  • createTestAccounts: false — a specExtraction handle instead: no accounts are created; Perfai maps your API surface from a spec-extraction vision run, pollable via its statusUrl.
  • Re-registering a dead app — a replaced handle 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.
string
Absolute Get app URL — poll it until registrationStatus is COMPLETED.
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.
Re-registering a URL. If a URL’s previous registration through this API failed or was abandoned, re-registering it replaces that dead app automatically — no manual cleanup. A usable app for that URL — one that’s 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 — when registrationStatus 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 same tenantOneCredentials / 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.
Each entry has the same 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.
Retrying the same request will not create a second set of real accounts in your application.

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.
You can only delete apps you registered through the API. An app created in the dashboard returns 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 the appId for the service you want to test.
integer
default:"1"
Page number.
integer
default:"20"
Items per page, max 100.
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.
The body is optional — map is the default. Pass -d '{"operation":"validate-login"}' (with -H "Content-Type: application/json") to run a different operation.
The 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 — its registrationStatus (from Get app) must be COMPLETED.
string
required
App identifier returned by GET /apps.
string
required
Bearer <token>.
The security test covers all available categories for the app — there is no request body.
The 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 a taskId; 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-agentrunNumber, plus vulnerabilitiesUrl once state is COMPLETED. A FAILED or INTERRUPTED test has no trustworthy findings, so no link is offered.
  • vision-agentoperation: map, validate-login, discover-roles, or verify-rbac.
  • registrationregistrationStatus: PENDING, IN_PROGRESS, COMPLETED, FAILED, or CANCELLED.
If a registration task reports 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.
If a test is currently in progress, the endpoint returns 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).
Filters combine with AND, and apply before paging — so 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

For status: 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. Only id, 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.
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.
Reverse this with Reopen vulnerability.
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.
Takes no request body.

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.
The response is a single Vulnerability object — the same shape as an item in the 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 a downloadUrl for fetching the PDF.
Security reports are a paid feature. On the free tier this returns 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.
On success the response body is the raw PDF (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.
On success (200 OK) the response body is the raw PDF (Content-Type: application/pdf), sent as an attachment — not JSON.

Status codes