Skip to main content
The Perfai API gives any partner integration or automation — CI/CD pipelines, internal tooling, or custom scripts — full programmatic control of Perfai Security: register apps, trigger security tests and vision runs, poll run status, and retrieve vulnerability findings, all over a REST API secured with JWT bearer tokens.

Register app

Onboard a new app programmatically.

List apps

Resolve the app ID for your target service.

Run Vision Agent

Re-map your app or re-validate credentials with browser automation.

Run Security Agent

Schedule an asynchronous security test.

Get task status

Poll for test completion with exponential back-off.

Get vulnerabilities

Retrieve findings and gate your deployment.

Quickstart

Six calls take you from an app URL to security findings — each step feeds the next through the $TOKEN, $APP_ID, and $TASK_ID variables. You need a Perfai account with a non-Viewer role (writes are role-gated) and available credits (tests draw down your organization’s balance). Swap api.perfai.ai for your own host if you run Perfai on-premise.
Step 3 is the slow one — Perfai onboards your app (sign-up, role discovery, RBAC, mapping) before it’s testable, and the default auto sign-up path is the slowest, so poll with a generous timeout rather than assuming a fixed duration. The sections below explain each piece — base path, authentication, and the test state machine — and the complete integration example further down is a production-ready CI gate with error handling and back-off.

How it works

Perfai API lifecycle — authenticate, register a new app or reuse an existing one, Perfai onboards it without testing, poll until ready, trigger the test yourself, poll it, read findings, and re-map after a release.

The lifecycle of an app in the Perfai API: you call the magenta steps, poll the green ones, and Perfai handles the amber one on its own.

1

Authenticate

Call POST /api/v1/auth/token with your Perfai email and password (see Authentication), then send the returned id_token as Authorization: Bearer <token> on every request.
2

Register or resolve your app

For a new app, call POST /apps with just an appUrl (everything else is optional). By default Perfai runs full autonomous onboarding — creating test accounts for you (auto sign-up), discovering roles, and mapping your API surface — then drives it to a testable state. Supply tenantOneCredentials to use your own accounts, or createTestAccounts: false for an unauthenticated test. If your app has endpoints that must never be exercised — account deletion, payment capture — list them in skipEndpoints at this point; the exclusion applies to every test that follows. Poll GET /apps/{appId} until registrationStatus is COMPLETED. The default auto sign-up onboarding runs an initial security test as its final step, so first findings and a report are available as soon as registration completes; supplying your own tenantOneCredentials or createTestAccounts: false skips that initial test. Either way, call POST /apps/{appId}/security-agent to run a test on demand once the app is registered. For an existing app, call GET /apps and use the search parameter to find its appId.
3

Trigger a test

Once registrationStatus is COMPLETED, call POST /apps/{appId}/security-agent. You receive a taskId and a statusUrl immediately — the test runs asynchronously.
4

Poll for completion

Call GET /tasks/{taskId} repeatedly (with exponential back-off) until state reaches COMPLETED, FAILED, or CANCELLED.
5

Gate on findings

Call GET /apps/{appId}/vulnerabilities and parse the results. Fail the build, or trigger any downstream workflow, if unfixed Critical or High findings exist.
6

Re-run vision when your app changes

After a release that changes your UI or API surface, call POST /apps/{appId}/vision-agent to re-map the app (operation: "map") or re-validate stored credentials (operation: "validate-login"). Poll GET /tasks/{taskId} until a terminal state.
You can’t test an app until registration is ready. Every write call returns immediately with an ID (201 or 202); the real work runs in the background. After POST /apps, poll GET /apps/{appId} until registrationStatus is COMPLETED — how long that takes depends entirely on your app, and the default auto-signup path can run well beyond the test-polling window below, so use a generous timeout rather than assuming a fixed duration (see Test state machine). The default onboarding runs an initial security test itself, so findings may already be present when registration completes; to run another test call POST /apps/{appId}/security-agent, which only succeeds once registrationStatus is COMPLETED — triggering it earlier fails with 400 App is not registered yet. Tests and vision runs follow the same pattern: send the request, get an ID, then poll its statusUrl until a terminal state.

Base path

All endpoints share a common base URL:
The path is always /v1; only the host changes. On the cloud platform the host is api.perfai.ai; on-premise, use your own Perfai API address (https://<your-perfai-host>/v1). Wherever an example shows https://<host>/…, substitute that host.
Response URLs are absolute. Write endpoints return a Location response header, and the register, security-test and vision-run responses include a statusUrl — both are absolute URLs (for example https://api.perfai.ai/v1/tasks/{taskId}) that you can poll directly. On-premise, they use your own host. Add -i to curl if you want to see the response headers.

Authentication

Every endpoint requires a bearer token on the Authorization header:
The token is a standard Perfai login token tied to your user — there is no separate API key. Get one by calling POST https://api.perfai.ai/api/v1/auth/token with {"username","password"} and using the returned id_token (see the Quickstart). The token carries your organization, user identity, and role. All data is automatically scoped to your organization — cross-tenant access returns 404 (not 403) to prevent enumeration. Tokens are short-lived; on a 401, request a new one from the same endpoint.
Your token inherits your own role. Reads are open to any role; writes (register app, trigger test, run vision) require a non-Viewer role — see Roles and permissions. For automation, an org administrator can provision a service account with a role that permits writes — for example AppSec or Full-Permission-Administrator.

Rate limits

When the rate limit is exceeded, the server responds with 429 Too Many Requests. Back off and retry after the value in the Retry-After response header.

Test state machine

After you trigger a run, it moves through the following states:
COMPLETED, FAILED, CANCELLED, and INTERRUPTED are terminal states. Stop polling once you reach any of them. AWAITING_INPUT is not terminal, but polling through it will not help — nothing moves until you supply the credentials. Treat it as a prompt to act, not a state to wait out. Vision runs use the same state enum, minus AWAITING_INPUT and INTERRUPTED: QUEUED → RUNNING → COMPLETED | FAILED | CANCELLED. Only registration can reach AWAITING_INPUT, and only security tests can reach INTERRUPTED. Registration has its own field, registrationStatus, returned by POST /apps and GET /apps/{appId}: PENDING → IN_PROGRESS → COMPLETED | FAILED | CANCELLED. Unlike a test, registration time is highly app-dependent (the auto-signup path is the slowest and can run well beyond the run-polling window below) — poll GET /apps/{appId} until it’s COMPLETED with a generous timeout rather than assuming a fixed duration. Start at a 5 second interval and apply exponential back-off, capping at 60 seconds. Allow up to 30 minutes before timing out.

Roles and permissions

Reads (list apps, get app, run status, vulnerabilities, reports) are open to every authenticated role. All writes share one allow-list. Reports are a paid feature — on the free tier the report endpoints return 402 regardless of role.

Pagination

GET endpoints that return lists accept the following query parameters: page and pageSize apply to every list endpoint. search applies to List apps and Get vulnerabilities only — Get reports does not accept it and ignores it if sent. All paginated responses include top-level total, page, and pageSize fields. Check page * pageSize < total to determine whether more pages exist.

Error format

All error responses follow RFC 9457 Problem Details:

Complete integration example

The following script implements the full five-step workflow — resolve app, trigger test, poll until terminal state, fetch vulnerabilities, and fail the build on Critical findings. It’s written for a CI environment (GitHub Actions or any POSIX-compatible CI), but the same calls work from any scripting environment or internal tool.
Set PERFAI_API_TOKEN as a secret in whichever system runs this script. Never hard-code the token in a pipeline definition or commit it to version control.