REST API Reference

All API endpoints require an API key passed as a Bearer token:

Authorization: Bearer mima_ext_...

Base URL: https://api.mima.ai

Workspace-scoped endpoints use the path prefix /api/workspaces/{workspace_id}/governance/.


Authentication

GET /api/me

Resolve workspace and user identity from the API key. Used by the SDK to auto-resolve workspace_id.

Response

1{
2 "user_id": "usr_...",
3 "workspace_id": "ws_...",
4 "org_id": "org_..."
5}

GRC Evidence

POST /api/workspaces/{workspace_id}/governance/grc/evidence

Push a single GRC evidence record.

Request body

1{
2 "record_type": "ai_risk_assessment",
3 "payload": {
4 "risk_level": "limited",
5 "risk_summary": "Customer support routing",
6 "intended_purpose": "Route customer queries to the correct team",
7 "impact_domains": ["customer_service"],
8 "art5_self_assessment": true
9 },
10 "system_name": "customer-support-ai",
11 "identity": "alice@example.com",
12 "resource": "customer-support-ai",
13 "environment": "production",
14 "occurred_at": "2026-06-28T09:00:00Z",
15 "client_sig": "abc123...",
16 "client_sig_algo": "hmac-sha256"
17}
FieldRequiredDescription
record_typeYesOne of the 11 record types
payloadYesRecord-type-specific payload (see record-types.md)
system_nameYesAI system name
identityNoActor email or identifier
resourceNoResource affected
environmentNoproduction, staging, development
occurred_atNoISO 8601 timestamp (defaults to ingest time)
client_sigNoHMAC-SHA256 signature (see Signing below)
client_sig_algoNoMust be "hmac-sha256" when client_sig is present

Dry-run mode

Append ?dry_run=true to preview which controls would be earned without writing:

POST /api/workspaces/{workspace_id}/governance/grc/evidence?dry_run=true

Response

1{
2 "record_id": "rec_...",
3 "record_type": "ai_risk_assessment",
4 "mapped_controls": ["EUAIA_ART9", "ISO42001_6_1"],
5 "detail": "ok"
6}

Dry-run response — record_id is the nil UUID:

1{
2 "record_id": "00000000-0000-0000-0000-000000000000",
3 "record_type": "ai_risk_assessment",
4 "mapped_controls": ["EUAIA_ART9", "ISO42001_6_1"],
5 "detail": "dry_run"
6}

Attestations

POST /api/workspaces/{workspace_id}/governance/attestations/external

Push a single attestation record. Used by mima.attest() / mima.wrap().

Request body

1{
2 "system_name": "my-pipeline",
3 "agent_name": "my-pipeline",
4 "tool_name": "generate_report",
5 "input_hash": "e3b0c44...",
6 "output_hash": "d4e8f23...",
7 "schema_version": 2,
8 "executed_at": "2026-06-28T09:00:00Z",
9 "model_id": "claude-opus-4-6",
10 "authorised_by": {
11 "identity": "alice@example.com",
12 "role": "ml-engineer"
13 }
14}

Response

1{
2 "attestation_id": "att_...",
3 "external_verified": true,
4 "trust_tier": "witnessed",
5 "detail": "ok"
6}

Trust tiers

TierMeaning
witnessedHMAC/Ed25519 signature verified
declaredNo signature — accepted but not cryptographically verified

Rate limits: 2000 requests/minute per workspace. Returns 429 with a Retry-After header on excess. The SDK retries once automatically.


POST /api/workspaces/{workspace_id}/governance/attestations/batch

Push multiple attestation records in a single request.

Request body

1{
2 "records": [
3 { "system_name": "...", "tool_name": "...", "input_hash": "...", "output_hash": "...", "schema_version": 2 },
4 { "system_name": "...", "tool_name": "...", "input_hash": "...", "output_hash": "...", "schema_version": 2 }
5 ]
6}

Response

1{
2 "accepted": 2,
3 "rejected": 0,
4 "results": [
5 { "status": "accepted", "attestation_id": "att_..." },
6 { "status": "accepted", "attestation_id": "att_..." }
7 ]
8}

Posture

GET /api/workspaces/{workspace_id}/governance/posture

Returns overall posture score and per-framework breakdown.

Response

1{
2 "overall_score": 74,
3 "frameworks": {
4 "EU_AI_ACT": { "score": 71, "controls_earned": 8, "controls_total": 14 },
5 "ISO_42001": { "score": 79, "controls_earned": 11, "controls_total": 16 },
6 "SOC2": { "score": 82, "controls_earned": 9, "controls_total": 12 }
7 },
8 "open_gaps": 6,
9 "gates_passing": 3,
10 "gates_total": 5
11}

Systems

GET /api/workspaces/{workspace_id}/governance/systems

List all AI systems.

Query parameters: ?name=filter

Response

1{
2 "systems": [
3 {
4 "system_id": "sys_...",
5 "system_name": "customer-support-ai",
6 "registered": true,
7 "risk_tier": "limited",
8 "last_evidence_at": "2026-06-28T09:00:00Z"
9 }
10 ]
11}

Evidence records

GET /api/workspaces/{workspace_id}/governance/evidence

List evidence records.

Query parameters

ParameterDescription
system_nameFilter by system
record_typeFilter by type
daysLookback window (default: 90)
limitMax records (default: 50, max: 200)

Response

1{
2 "records": [
3 {
4 "record_id": "rec_...",
5 "record_type": "model_evaluation",
6 "system_name": "loan-scorer",
7 "occurred_at": "2026-06-28T09:00:00Z",
8 "mapped_controls": ["EUAIA_ART9_4"],
9 "source": "sdk",
10 "signed": true
11 }
12 ]
13}

Gates

GET /api/workspaces/{workspace_id}/governance/gates

Returns gate pass/fail status.

Response

1{
2 "gates": [
3 {
4 "gate_id": "g_quarterly_eval",
5 "name": "Quarterly model evaluation",
6 "passing": true,
7 "blocking": false,
8 "exit_code": 0
9 },
10 {
11 "gate_id": "g_risk_assessment",
12 "name": "AI risk assessment",
13 "passing": false,
14 "blocking": true,
15 "exit_code": 2,
16 "reason": "No ai_risk_assessment record in the last 180 days for loan-scorer"
17 }
18 ]
19}

Exit codes: 0 = pass, 1 = soft fail, 2 = hard fail (blocking).


Controls

POST /api/workspaces/{workspace_id}/governance/derive-controls

Get recommended record types for a system description.

Request body

1{
2 "description": "A classification model that routes customer support tickets",
3 "risk_tier": "limited"
4}

Response

1{
2 "recommendations": [
3 {
4 "record_type": "ai_risk_assessment",
5 "priority": "required",
6 "controls": ["EUAIA_ART9", "ISO42001_6_1"]
7 },
8 {
9 "record_type": "model_evaluation",
10 "priority": "required",
11 "controls": ["EUAIA_ART9_4", "ISO42001_9_1"]
12 }
13 ]
14}

HMAC Signing

GRC records can include a client signature to allow auditors to verify records were created by a specific SDK instance.

Canonical message format

The canonical message is a compact JSON string with sorted keys and no spaces:

1{"occurred_at":"2026-06-28T09:00:00Z","payload":{...sorted keys...},"record_type":"ai_risk_assessment","system_name":"loan-scorer","workspace_id":"ws_..."}

The key order is always alphabetical: occurred_at < payload < record_type < system_name < workspace_id.

The payload object’s keys are also sorted recursively (matching Python’s json.dumps(sort_keys=True, separators=(',', ':'))).

Signing

1import hashlib, hmac, json
2
3canonical = json.dumps({
4 "occurred_at": occurred_at,
5 "payload": payload,
6 "record_type": record_type,
7 "system_name": system_name,
8 "workspace_id": workspace_id,
9}, sort_keys=True, separators=(",", ":"))
10
11sig = hmac.new(
12 bytes.fromhex(signing_key),
13 canonical.encode(),
14 hashlib.sha256,
15).hexdigest()

TypeScript

1import { createHmac } from 'node:crypto';
2
3// sortedStringify produces the same output as Python's json.dumps(sort_keys=True, separators=(',', ':'))
4const canonical = sortedStringify({
5 occurred_at: occurredAt,
6 payload: payload,
7 record_type: recordType,
8 system_name: systemName,
9 workspace_id: workspaceId,
10});
11
12const sig = createHmac('sha256', Buffer.from(signingKey, 'hex'))
13 .update(canonical)
14 .digest('hex');

Both SDKs use the same canonical format and produce identical signatures.


Error responses

All error responses follow this shape:

1{
2 "error": "validation_error",
3 "message": "record_type is required",
4 "field": "record_type"
5}
HTTP statusError codeMeaning
400bad_requestMissing required field or invalid value
401unauthorizedInvalid or expired API key
404not_foundWorkspace or system not found
422validation_errorField-level validation failure
429rate_limitedExceeded 2000 rpm; see Retry-After header
500server_errorUnexpected server error