Aiudit
Machine-to-machine REST API for connecting Aiudit to government GRC platforms (RSA Archer, ServiceNow GRC, OneTrust), case management systems (Jira, ServiceNow ITSM), and SIEMs. Designed for sovereign and air-gapped deployments.
OpenAPI spec: /api/v1/openapi.json · Issue a credential
Each request must include a Bearer token issued from API & Integrations.
Authorization: Bearer pk_live_<prefix>_<secret>
Sandbox tokens use the pk_test_ prefix and may only be issued by Pilot organizations. Secrets are stored as SHA-256 hashes and shown to the operator only once at issuance.
| Scope | Endpoints |
|---|---|
governance.read | GET /api/v1/agents, GET /api/v1/agents/:id |
evidence.read | GET /api/v1/evidence-packages, GET /api/v1/evidence-packages/:id |
audit.read | GET /api/v1/audit/entries |
vendors.read | GET /api/v1/vendors |
incidents.write | POST /api/v1/incidents |
Each credential's scopes are a strict subset of the issuer's RBAC role. A scope cannot grant access beyond what the user holds at the moment of issuance.
Per-credential, per-minute quota (default 60 req/min, configurable up to 10000). Responses always include:
X-RateLimit-Limit: 60 X-RateLimit-Remaining: 42 X-RateLimit-Reset: 2026-06-26T11:32:00.000Z Retry-After: 12 # only on 429
Every credential has a classification_ceiling (public, restricted, secret, top_secret). Resources above the ceiling return as{ id, _redacted: true } stubs. List endpoints report a redacted_count.
{
"error": {
"code": "insufficient_scope",
"message": "Required scope: evidence.read",
"request_id": "0193f1b4e8c14d52a3a..."
}
}The x-request-id response header is always set; quote it when contacting support.
curl -s https://<your-aiudit>/api/v1/agents \ -H "Authorization: Bearer pk_live_abc1234567_xxxxxxxxxxxxxxxxxxxxxxxx" \ | jq
const res = await fetch("/api/v1/evidence-packages", {
headers: { authorization: "Bearer " + process.env.AIM_API_KEY },
});
const { data, redacted_count } = await res.json();import os, requests
r = requests.get(
"https://aiudit.gov.example/api/v1/audit/entries",
headers={"Authorization": f"Bearer {os.environ['AIM_API_KEY']}"},
params={"from_seq": 0, "limit": 1000},
timeout=30,
)
r.raise_for_status()
for entry in r.json()["data"]:
sink.write(entry)Schedule a nightly job that pulls sealed evidence packages and stores the payload_hash, merkle_root, and download URL against the relevant control. See examples/grc-sync.ts in the repository.
// Nightly: pull new sealed packages and link to GRC controls
const since = lastSyncedAt(); // ISO string
const { data } = await aiudit.get("/api/v1/evidence-packages");
for (const pkg of data.filter(p => p.sealed_at > since)) {
await grc.linkEvidence({
controlId: pkg.purpose, // your mapping convention
title: pkg.title,
externalId: pkg.id,
integrityHash: pkg.payload_hash,
merkleRoot: pkg.merkle_root,
url: `https://aiudit/api/v1/evidence-packages/${pkg.id}`,
});
}On case creation, your platform's outbound webhook posts to POST /api/v1/incidents with the case key in external_ref. Aiudit creates an incident in the assigned agent's org and emits a tamper-evident audit event linking the two.
curl -X POST https://aiudit/api/v1/incidents \
-H "Authorization: Bearer $AIM_API_KEY" \
-H "Content-Type: application/json" \
-d '{"title":"Agent X breached policy","severity":"high","external_ref":"SNOW-INC012345"}'require_client_cert on the credential and have your reverse proxy forward X-Client-Cert-Fingerprint. Requests without it return 403.api.export audit event whose hash seals into the Merkle batches reachable via /api/v1/audit/entries.