Aiudit

External Integration API v1

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

Authentication

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.

Scopes

ScopeEndpoints
governance.readGET /api/v1/agents, GET /api/v1/agents/:id
evidence.readGET /api/v1/evidence-packages, GET /api/v1/evidence-packages/:id
audit.readGET /api/v1/audit/entries
vendors.readGET /api/v1/vendors
incidents.writePOST /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.

Rate limits

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

Classification handling

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 envelope

{
  "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.

Example — list agents (curl)

curl -s https://<your-aiudit>/api/v1/agents \
  -H "Authorization: Bearer pk_live_abc1234567_xxxxxxxxxxxxxxxxxxxxxxxx" \
  | jq

Example — TypeScript

const res = await fetch("/api/v1/evidence-packages", {
  headers: { authorization: "Bearer " + process.env.AIM_API_KEY },
});
const { data, redacted_count } = await res.json();

Example — Python

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)

GRC adapter recipe (ServiceNow GRC / RSA Archer)

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}`,
  });
}

Case management recipe (Jira / ServiceNow ITSM)

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"}'

Sovereign & air-gapped deployments

  • IP allowlists per credential (default-deny when set). IPv4 CIDRs are enforced server-side.
  • mTLS edge termination: set require_client_cert on the credential and have your reverse proxy forward X-Client-Cert-Fingerprint. Requests without it return 403.
  • Air-gapped key rotation: issue replacement credentials, switch the consumer, then revoke the old one. Revocation propagates immediately and is logged.
  • Audit anchoring: every API export emits an api.export audit event whose hash seals into the Merkle batches reachable via /api/v1/audit/entries.
  • No PII in logs: the request log records only credential id, path, status, latency, IP, and request id.

API FAQ

How does the Aiudit API authenticate requests?

Every request must include a Bearer token issued from the authenticated /integrations console. Tokens use pk_live_ or pk_test_ prefixes and are stored server-side only as SHA-256 hashes; the secret is shown to the operator exactly once at issuance.

What are the rate limits?

Default 60 requests per minute per credential, configurable up to 10000. Responses always include X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset headers; 429 responses add Retry-After.

How are webhook payloads signed?

Outbound webhooks are signed with HMAC-SHA-256 over the raw body using the per-destination signing secret and sent in the X-Aiudit-Signature header. Consumers must verify with a timing-safe compare before processing.

Are POST endpoints idempotent?

Yes. Send an Idempotency-Key request header (UUID recommended) on any state-changing call. The first successful response is cached for 24 hours and replayed on retries, so network failures are safe to retry.

What does the error envelope look like?

Errors return `{ "error": { "code", "message", "request_id" } }` with the code drawn from a stable set (invalid_request, insufficient_scope, rate_limited, classification_ceiling_exceeded, internal_error). The x-request-id response header is set on every call for support triage.

How does classification and redaction work?

Every credential carries a classification_ceiling (public, restricted, secret, top_secret). Resources above the ceiling return as { id, _redacted: true } stubs, and list endpoints report a redacted_count so integrators can reconcile totals.

Where is the API changelog and OpenAPI spec?

The current OpenAPI 3.1 spec is served at /api/v1/openapi.json. Breaking changes ship under /api/v2/...; additive changes are annotated in the spec and audit-logged so integrators can diff against pinned snapshots.