Use
Public API
The Akesis API gives your own tools and your security operations platform (SOAR or SIEM) read access to findings, remediation status, risk narratives, repositories and the audit log. It also offers a few actions: ask for a fix, revert one, ask for less autonomy, and attach your case ID. Akesis's autonomy policy still decides what happens. Akesis can also push lifecycle events to you as webhooks (below).
Authentication
Create a personal access token under Settings → API tokens and send it as a bearer token:
curl -H "Authorization: Bearer akp_…" https://akesis.app/api/public/v1/findings
Each token carries scopes:
findings:readcovers findings, remediation status, narratives and repositories.audit:readcovers the audit log.
A token can never do more than its user's current role allows, and it stops working when the user is disabled or removed. Tokens expire after at most a year and can be revoked at any time. Their creation and revocation are in the audit log.
Endpoints
| Endpoint | Scope | Returns |
|---|---|---|
GET /api/public/v1/findings |
findings:read |
Findings, active by default, in update order |
GET /api/public/v1/findings/{id} |
findings:read |
One finding |
GET /api/public/v1/findings/{id}/remediation |
findings:read |
Fix pull requests with Akesis's decision, CI and provenance; Akesis's own fix; tickets; accepted risk; fixes your team rejected |
GET /api/public/v1/findings/{id}/narrative |
findings:read |
The latest AI-written risk narrative, labelled as AI-generated |
GET /api/public/v1/repositories |
findings:read |
Connected repositories |
GET /api/public/v1/audit |
audit:read |
Audit entries, oldest first |
GET /api/public/v1/audit/verify |
audit:read |
Whether the audit log's hash chain is intact |
The full description, ready for API tools and SOAR platforms, is at https://akesis.app/api/public/v1/openapi.json.
Actions
Actions change something, so each has its own scope. Give a tool only the ones it needs. Every action also needs an Idempotency-Key header: any unique string, such as your playbook run ID. If a call is repeated with the same key, Akesis returns the first answer and does nothing twice. The same key used for a different request is refused (422 idempotency_key_reused).
| Action | Scope | Role | What happens |
|---|---|---|---|
POST /findings/{id}/actions/generate-fix |
fixes:generate |
engineer | For npm findings in repositories with fix generation on: Akesis's generator takes it first on its next run, usually within 15 minutes. It answers 202 {"state": "queued"}, or 200 with the pull request if a fix is already open or merged. Watch for fix_pr.opened, or poll /remediation. It refuses with a reason if the fix can't be generated, including when your team rejected the same fix before. |
POST /findings/{id}/actions/revert |
fixes:revert |
engineering lead | Opens a revert pull request for the finding's merged automatic fix, for a person to merge. A repeat returns the same revert. |
POST /findings/{id}/actions/request-tier {"tier": "t1"} |
autonomy:request |
engineer | Asks Akesis to act no further than that tier on this finding's fixes. If the repository's policy already allows less, the request is refused with 409 escalation_rejected and the attempt is recorded in the audit log: a caller can ask for less, never more. {"tier": null} clears it. |
PUT /findings/{id}/case {"case_ref": "INC-123"} |
findings:case |
engineer | Attaches your case or incident ID. Every later webhook event about the finding carries it as case_ref. null clears it. |
Actions are recorded in the audit log as coming from the API, with the token. A token's actions can never exceed its user's role; for example, an engineer's token can't revert. AI assistants connected over MCP never get action scopes.
Keeping in sync
Findings come in the order they last changed. To keep another system in step:
- Ask for findings changed since your last sync:
?updated_since=2026-10-30T09:00:00Z&state=all. - Follow
next_cursor(?cursor=…) until it'snull. - Next time, start from the latest
updated_atyou saw.
Paging this way never skips or repeats a finding, even if findings change while you page. Filters: state (active or all), status, severity, repository (e.g. acme/api), kev and limit (up to 200).
OCSF
Add ?format=ocsf to GET /findings or GET /findings/{id} to get findings as OCSF 1.3 Vulnerability Finding events (class 2002). OCSF is the open schema many SIEMs, SOAR platforms and security data lakes read natively, so they need no Akesis-specific mapping:
- Severity and status:
severity_idandstatus_iduse OCSF's codes (New, In Progress, Suppressed for accepted risks and false positives, Resolved). - Finding details:
finding_infolinks back to the finding in Akesis. - Vulnerability:
vulnerabilities[0]has the CVE with CVSS and EPSS, the weakness (CWE), the affected package with its fixed version, whether a fix exists, and whether it's known to be exploited (CISA KEV). - Resource: the repository is the resource, with its owners from CODEOWNERS.
- Akesis-specific fields: the re-scored priority and its rationale, reachability, and the fix pull request with Akesis's decision are under
akesis. That's an extension declared inmetadata.extensions, never mixed into OCSF's own fields.
Webhook endpoints can receive OCSF too: choose OCSF as the format when you add one. Each event then arrives as a Vulnerability Finding event:
activity_idis 1 (Create) forfinding.ingested, and 2 (Update) for the rest.metadata.uidis the event ID,metadata.event_codethe Akesis event type, andmetadata.correlation_uidthe correlation ID.- The event's own details (such as the pull request) are under
akesis.event.
Test events keep the Akesis format.
Webhooks
Instead of polling, an admin can have Akesis post events to your HTTPS endpoint as remediation happens: Integrations → Security operations → Webhooks. Choose the events, or leave them all ticked off to get everything:
| Event | When |
|---|---|
finding.ingested |
A scanner reported a new finding |
finding.rescored |
A finding's severity changed (previous_severity says from what) |
fix_pr.opened |
A fix pull request was linked to a finding |
fix_pr.ci_changed |
A fix pull request's CI result changed (previous_ci, ci) |
fix_pr.auto_merged |
Akesis merged a fix automatically |
fix_pr.regression_suspected |
CI failed after an automatic merge, and Akesis stopped autonomy for the repository |
risk_acceptance.expired |
An accepted risk expired and the finding came back for review |
Each request is a JSON POST; this is the Akesis format (for OCSF, see above):
{
"id": "6f1c…",
"type": "fix_pr.auto_merged",
"api_version": "1",
"created_at": "2026-10-30T12:00:00.000Z",
"correlation_id": "akesis:finding:3f2a…",
"data": { "finding": { "id": "3f2a…", "severity": "high", "…": "…" }, "pr": { "number": 101, "url": "…" } }
}
data.findinghas the same shape asGET /findings/{id}.- Deduplicate on
id. Delivery is at least once, so the same event may arrive twice. correlation_idis the same for every event about a finding. A SOAR can file later events under the case it opened for the first one.case_refcarries your own case ID once you've set it withPUT /findings/{id}/case.- Retries: answer with any
2xxstatus within 10 seconds. Anything else is retried after 1 minute, 5 minutes, 30 minutes, 2 hours, 6 hours and 15 hours, then given up. If nothing has been delivered to an endpoint for a day, Akesis turns it off and says why. Turn it back on once it's fixed. Send test event checks an endpoint at any time. - Verify the signature before trusting a request. Each request has an
Akesis-Signature: t=<unix seconds>,v1=<hex>header, wherev1is the HMAC-SHA256 of<t>.<raw body>keyed with the endpoint's signing secret. The secret is shown once, when you add the endpoint. Reject requests whosetis more than five minutes old. In Node.js:
const [t, v1] = header.split(',').map((p) => p.split('=')[1]);
const expected = crypto.createHmac('sha256', secret).update(`${t}.${rawBody}`).digest('hex');
const ok = crypto.timingSafeEqual(Buffer.from(v1), Buffer.from(expected)) && Date.now() / 1000 - Number(t) < 300;
Akesis only posts to public HTTPS addresses. It never follows redirects and never posts to private or internal networks.
Limits and errors
Each token can make 60 calls a minute. Over that, the API answers 429 with a Retry-After header. Errors look like {"error": {"code": "...", "message": "..."}}:
400:invalid_parameterorinvalid_cursor;401:unauthorized;403:insufficient_scope;404:not_found(orno_narrative);429:rate_limited.
Stability
Every response carries Akesis-API-Version: 1. Within version 1, fields are only ever added, never renamed or removed, so a client written today keeps working. A change that would break that comes as version 2, alongside version 1.