Skip to content

Use the API and a CI gate

Use the HTTP API to read existing dependency results, evaluate a CI gate, request exports, or send product feedback. For an OAuth assistant connection, see the MCP guide. API tokens and MCP connections share the same access model.

Verified against the API V1 implementation for issue #644 on October 11, 2026. You need a Pro or Team organization and an account that belongs to it, including a Viewer account. Requests use your current organization permissions.

Open Settings → API & MCP. Name the access, select its duration and permissions, and choose its scope. Copy the secret when it appears: it is shown once. Store it in your CI or client’s secret manager.

Read results and Check CI are enabled initially. Export and Send feedback are separate permissions, initially disabled. A CI-only token can have just Check CI. No token can start scans, change findings, accept risks, create remediation PRs, or provision another token.

The default duration is 90 days; available choices are 7, 30, 90, 180, and 365 days. There are no permanent tokens. Replacement preserves the access, scope, permissions and quota slot. The previous secret remains usable for at most 24 hours, or until its original expiry if sooner. You can end that transition early. Revocation invalidates all secrets of that access.

Everything available to me is dynamic. Selecting an organization includes its future applications; selecting particular applications includes only those applications. Leaving an organization or removing an application takes effect on subsequent requests.

Pro allows five authorized machine accesses per organization; Team allows 25. A slot is counted at authorization, even before the first request. Temporary blocks keep the slot. Quota refusal in one organization does not block another. After space becomes available, explicitly activate a previously refused access. An already authorized access resumes automatically after a temporary block ends.

Administrators can exclude an access locally or disable machine access for a member without changing that member’s rights in the interface. Exclusion survives replacement and renewal and only an administrator can remove it. The MCP toggle affects MCP calls and does not block the API.

A Team-to-Pro downgrade has 14 days of grace. No additional machine access is admitted once five slots are occupied. If more than five remain after the grace date, tokens that were already authorized keep calling that organization. A new token for it stays pending until fewer than five accesses are authorized. Returning from Starter does not start a new grace: calls stay blocked until the excess is resolved. Starter blocks machine calls immediately when effective, while keeping the authorizations suspended.

The following fictional example uses https://example.invalid and a token held in PERPENSA_TOKEN. Replace the host with your deployment URL.

Terminal window
curl --fail-with-body \
-H "Authorization: Bearer $PERPENSA_TOKEN" \
https://example.invalid/api/v1/orgs

Use /api/v1/orgs/{org_id}/applications and /scopes to discover the authorized application, environment and source identifiers. Read /sources, /inventory, /priorities, /coverage, /findings/{finding_id}, /updates/{update_id} or /scans/{scan_id} within that organization. There is no consolidated cross-organization read in V1. The complete endpoint and payload reference is served at /api/v1/openapi.json on your deployment.

Production is the default scope. List endpoints can use environments=non_prod or all, or a precise application_id plus environment_id. source_id requires a precise environment. Do not combine environment_id and environments. Results include their source, analysis, commit and local application/environment context; an unavailable observation is null, not a measured zero. Reading priority explanations does not start AI work. The explanation’s refinement.state matches the customer status: accepted, reviewed, in_review, or unavailable. Accepted ranks use “Perpensa AI adjusted the order within this category.” state stays unavailable both when no review decision exists and when a review failed, so clients that only read state keep working. The additive field unavailable_reason separates those cases: not_reviewed when no decision is stored (rationale “Ranked by rules.”), review_failed when the review worker stopped without a decision (rationale “Ranked by rules. Perpensa AI could not review this one.”), and null for every other state. Ignore unavailable_reason if you only read state.

Lists default to 50 items with a maximum of 100. Follow next_cursor with the same query. Cursors expire after 15 minutes and become invalid when their snapshot or authorization changes. Restart the list after CURSOR_STALE. Large scopes may return RESULT_TOO_LARGE; choose a smaller application or environment. Versioned fields can be extended; ignore unknown fields.

Terminal window
curl --fail-with-body \
-H "Authorization: Bearer $PERPENSA_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"application_id":"fictional-app"}' \
https://example.invalid/api/v1/orgs/fictional-org/ci/check

The response has one of three verdicts: compliant, non_compliant, or indeterminate. Make your pipeline proceed only for compliant. Both other verdicts block by default. A successful HTTP response is not itself a compliant CI verdict. Check the response’s verdict.

Defaults block High and Critical findings and require a complete scan less than 24 hours old. Administrators set the organization rules in API & MCP. The caller may strengthen these rules with blocking_severity or max_scan_age_seconds, but cannot relax them. A locally accepted risk is exempt only while its decision remains valid for the occurrence and episode in every selected context. Monitoring alone is not an exemption.

An application check defaults to Production. A source check specifies application_id, environment_id, and source_id. Optional expected_commits map source IDs to full 40- or 64-character commit hashes. A mismatch returns indeterminate and does not trigger a scan. Failure, incomplete or unsupported coverage, missing results, or stale scans also return indeterminate. A refresh in progress can use the last complete result while it remains valid; a failed attempt invalidates that fallback. Across sources, a blocking finding takes precedence over an indeterminate result, which takes precedence over compliance. Docker inventory is not evidence of complete vulnerability coverage.

The repository supplies scripts/machine-ci-check.mjs for Node 22 pipelines. Set PERPENSA_URL, PERPENSA_TOKEN, PERPENSA_ORG and PERPENSA_APPLICATION as CI configuration, keeping the token secret. Optional PERPENSA_EXPECTED_COMMITS is the JSON source-to-commit map. Run node scripts/machine-ci-check.mjs. Exit codes are 0 for compliant, 1 for non-compliant and 2 for indeterminate or a request error. The script does not follow redirects or print the token. HTTPS is required except on localhost.

With Export, POST /orgs/{org_id}/exports using Idempotency-Key and a body such as {"kind":"findings_csv","scope":{"application_id":"fictional-app"}}. Available kinds are sbom_cdx_json, sbom_spdx_json, findings_csv, updates_csv, and compliance_report. An accepted request is queued, not ready. Poll /exports/{id} until ready, then use /content, /chunks, or the returned authenticated interface link. Ready files last 24 hours. Rights and source attachments are rechecked before publication and each download; a previously produced file cannot bypass a later restriction. Reuse an idempotency key only for the identical request. Chunks use signed cursors and default to 32 KiB, with a maximum of 64 KiB. The default file cap is 10 MiB. A failed export with EXPORT_TOO_LARGE means its file or analysis-loading budget was exceeded; select a smaller scope and submit a new request with a new idempotency key. It does not revoke the access. A ready export has no error code, and its analyses identify the evidence used to produce the file, including available inventory from an unsupported scan.

With Send feedback, POST /feedback using Idempotency-Key, category (bug, missing_feature, or friction) and a description of at most 4,000 characters. Optional operation and related_request_id help explain the problem. The receipt confirms durable acceptance, not delivery. Poll /feedback/{id} for its status. Feedback goes to the same destination as feedback from the interface and does not automatically create an issue. Failed delivery is retried for at most 72 hours; the text is removed after successful delivery or final failure. The receipt and audit metadata last 90 days.

Default Pro Team
Requests per access per minute 60 120
Burst 20 40
Requests per organization per minute 300 1,200
Requests per organization per UTC day 50,000 200,000
Exports per organization per minute 10 30
Exports per organization per UTC day 200 1,000

At most four calls may run concurrently per access. Feedback is limited to five new submissions per access in ten minutes. Limits are shared by all secrets of an access, including replacement transitions; API and the later MCP delivery share the same counters. Operators can configure limits. On HTTP 429 respect Retry-After; read RateLimit and RateLimit-Policy for applicable budgets.

If access settings change during a request, 409 ACCESS_CHANGED discards the response. Retry the request with the current scope; an idempotent export retry must keep its original idempotency key and body.

An access has a shared version across its organizations. An administrator’s CI, member-permission or plan change in one organization may also invalidate an in-flight response (ACCESS_CHANGED) or pagination cursor (CURSOR_STALE) for that same access in another organization. Retry the request, or restart the list without its old cursor. Authorization and quota refusals remain local to the affected organization; subsequent calls to the others stay authorized.

Errors have a stable error.code and error.request_id; X-Request-Id also identifies the request. A 401 means the secret is invalid, expired or revoked. A 403 means permissions, plan, member controls or quota prevent access. A 404 also covers resources outside your scope. A 503 indicates a temporary service failure. Never include your secret when reporting an error.

The journal in API & MCP shows your access activity in the selected organization; administrators can inspect local access activity for members. Audit metadata lasts 90 days and excludes secrets and request bodies. Expiry reminders are sent seven and one days before expiry; seven-day tokens receive only the one-day reminder.

The V1 compatibility commitment is at least 90 days after announcing a replacement for an incompatible contract, except urgent security corrections. Other clients are not a verified compatibility promise for this delivery.