> ## Documentation Index
> Fetch the complete documentation index at: https://docs.gominerva.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Risk Assessment Agents API

> How to create, run, review, and collaborate on beta agent risk assessments through the Minerva API.

The Risk Assessment Agents API lets approved applications create and manage beta agent-driven risk assessments programmatically.

<Warning>
  <strong>Beta API:</strong> Risk assessment agent endpoints require beta
  enablement and application access. Contact your Minerva representative or
  [support@gominerva.com](mailto:support@gominerva.com) before building against these endpoints.
</Warning>

## Base URL

Use the central Minerva API domain:

```text theme={null}
https://api.gominerva.com/risk-assessments/v2
```

Your Minerva contact will confirm when this public base URL is enabled for your application and environment. Internally, these endpoints route to Minerva's risk assessment service customer API.

## Authentication

Use a Minerva application API key.

```bash theme={null}
Authorization: Api-Key YOUR_API_KEY
```

The legacy `X-Api-Key` header is also accepted by the service, but new integrations should use the `Authorization: Api-Key ...` header.

The application key determines the tenant, workspace, and actor context. Do not send tenant or workspace identifiers in the request body unless Minerva has explicitly documented a field for that endpoint.

For method-level endpoint reference, use <strong>Agent Risk Assessments - Endpoints</strong> in the API Reference sidebar.

## API Usage Guide

The most common integration flow is:

1. fetch available workflows
2. create a draft assessment
3. start the agent run
4. poll the assessment summary until it is ready for review, blocked, or terminal
5. add user input or steering when the agent needs more context
6. read tasks and risks
7. conclude the assessment after reviewer validation

Minerva responses use the standard envelope:

```json theme={null}
{
  "status": 200,
  "msg": "OK",
  "result": {
    "assessment": {},
    "summary": {},
    "tasks": []
  }
}
```

Read response data from `result.assessment`, `result.summary`, `result.tasks`, and similar result fields.

## Create An Assessment

The exact workflow, scorecard, and subject fields available to your application depend on your beta configuration. Fetch workflows and scorecards first, then create an assessment using the selected IDs.

```bash theme={null}
curl -sS -X POST \
  https://api.gominerva.com/risk-assessments/v2/assessments \
  -H "Authorization: Api-Key YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Northstar Holdings KYB onboarding review",
    "workflow_id": "workflow_kyb_onboarding",
    "context": {
      "purpose": "KYB onboarding",
      "description": "Review registration, ownership, screening exposure, and adverse media before onboarding."
    },
    "subjects": [
      {
        "type": "organization",
        "name": "Northstar Holdings Inc.",
        "registration_id": "123456789",
        "jurisdiction": {
          "country": "CA",
          "state": "ON"
        }
      }
    ]
  }'
```

The response includes the `assessment_id`. Save it for subsequent lifecycle, upload, run, review, and report steps.

### Create And Start In JavaScript

```javascript theme={null}
const API_BASE = "https://api.gominerva.com/risk-assessments/v2";

async function minerva(path, { method = "GET", body } = {}) {
  const response = await fetch(`${API_BASE}${path}`, {
    method,
    headers: {
      Authorization: `Api-Key ${process.env.MINERVA_API_KEY}`,
      "Content-Type": "application/json",
    },
    body: body ? JSON.stringify(body) : undefined,
  });

  const payload = await response.json();
  if (!response.ok) {
    throw new Error(payload?.msg || `Minerva API error ${response.status}`);
  }
  return payload.result;
}

const { assessment } = await minerva("/assessments", {
  method: "POST",
  body: {
    title: "Northstar Holdings KYB onboarding review",
    purpose: "KYB onboarding",
    workflow_id: "workflow_kyb_onboarding",
    context: {
      description:
        "Review registration, ownership, screening exposure, and adverse media before onboarding.",
    },
    subjects: [
      {
        type: "organization",
        name: "Northstar Holdings Inc.",
        locations: [{ type: "headquarters", country: "CA", state: "ON" }],
        registrations: [
          {
            registration_id: "123456789",
            registry_name: "Ontario Business Registry",
            jurisdiction: { level: "state", country: "CA", state: "ON" },
          },
        ],
      },
    ],
  },
});

await minerva(`/assessments/${assessment.assessment_id}/start`, {
  method: "POST",
  body: {
    reason: "Start automated KYB review from onboarding case CASE-12345.",
  },
});
```

## Start The Agent Run

```bash theme={null}
curl -sS -X POST \
  https://api.gominerva.com/risk-assessments/v2/assessments/ASSESSMENT_ID/start \
  -H "Authorization: Api-Key YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "reason": "Start automated EDD investigation from case CASE-12345."
  }'
```

Starting an assessment creates an agent run owned by the risk assessment service. Use the run and trajectory endpoints to inspect progress.

## Poll Status And Completion

Use `GET /assessments/{assessmentId}/summary` for polling. It returns compact state, task status counts, client risk rating counts, timestamps, and the latest run reference.

```bash theme={null}
curl -sS \
  https://api.gominerva.com/risk-assessments/v2/assessments/ASSESSMENT_ID/summary \
  -H "Authorization: Api-Key YOUR_API_KEY" \
  | jq '.result.summary | {
      assessment_id,
      status,
      task_status_counts,
      latest_run,
      updated_at,
      ready_at,
      concluded_at
    }'
```

Interpret assessment status as:

| Status             | Meaning                                                       | Integration behavior                                                        |
| ------------------ | ------------------------------------------------------------- | --------------------------------------------------------------------------- |
| `draft`            | Assessment exists but has not started.                        | Start it when required input is present.                                    |
| `running`          | The agent is actively working.                                | Keep polling summary or trajectory.                                         |
| `waiting_for_user` | The agent needs human/application input.                      | Read trajectory, questions, confirmations, or commands, then call `/input`. |
| `interrupted`      | Work was paused or interrupted.                               | Inspect trajectory and call `/resume` when ready.                           |
| `ready_for_review` | Agent work is complete and ready for human/API review.        | Read tasks, risks, evidence, and CRR before concluding.                     |
| `reopened`         | A previously reviewed or terminal assessment needs more work. | Review comments/tasks and resume or add input as needed.                    |
| `concluded`        | Final reviewer/API conclusion has been recorded.              | Treat as final for downstream systems.                                      |
| `cancelled`        | Assessment was cancelled.                                     | Stop polling and record cancellation.                                       |
| `failed`           | Run or assessment failed.                                     | Stop polling, capture context, and contact Minerva if repeatable.           |

<Tip>
  `ready_for_review` means the agent work is complete. It is not the same as a
  final compliance decision. Use `concluded` only after your reviewer or
  integration has validated tasks, risks, evidence, and comments.
</Tip>

### Polling Example

```javascript theme={null}
const REVIEW_READY = new Set(["ready_for_review"]);
const TERMINAL = new Set(["concluded", "cancelled", "failed"]);
const ATTENTION_REQUIRED = new Set(["waiting_for_user", "interrupted"]);

async function waitForAssessmentReview(assessmentId, options = {}) {
  const timeoutMs = options.timeoutMs ?? 30 * 60 * 1000;
  const intervalMs = options.intervalMs ?? 10_000;
  const startedAt = Date.now();

  while (Date.now() - startedAt < timeoutMs) {
    const { summary } = await minerva(`/assessments/${assessmentId}/summary`);

    if (REVIEW_READY.has(summary.status) || TERMINAL.has(summary.status)) {
      return summary;
    }

    if (ATTENTION_REQUIRED.has(summary.status)) {
      return summary;
    }

    await new Promise((resolve) => setTimeout(resolve, intervalMs));
  }

  throw new Error(`Timed out waiting for assessment ${assessmentId}`);
}
```

Use a polling interval appropriate to your workflow. For most integrations, `10` to `30` seconds is enough. Avoid tight polling loops.

## Track Run Progress

Use the trajectory endpoint when you need a detailed activity stream, tool calls, intermediate messages, or evidence of why the agent is waiting.

```bash theme={null}
curl -sS \
  "https://api.gominerva.com/risk-assessments/v2/assessments/ASSESSMENT_ID/trajectory?after_sequence=0&limit=100&sort_direction=asc" \
  -H "Authorization: Api-Key YOUR_API_KEY"
```

For incremental polling, store the highest returned sequence and pass it as `after_sequence` on the next call.

```javascript theme={null}
let afterSequence = 0;

async function readNewTrajectoryEvents(assessmentId) {
  const params = new URLSearchParams({
    after_sequence: String(afterSequence),
    limit: "100",
    sort_direction: "asc",
  });

  const result = await minerva(
    `/assessments/${assessmentId}/trajectory?${params}`,
  );

  const events = result.trajectory || result.events || [];
  for (const event of events) {
    afterSequence = Math.max(afterSequence, event.sequence || 0);
  }

  return events;
}
```

## Check Task Completion

Use `GET /assessments/{assessmentId}/tasks` to inspect task status, notes, questions, confirmations, and client risk rating state.

```bash theme={null}
curl -sS \
  https://api.gominerva.com/risk-assessments/v2/assessments/ASSESSMENT_ID/tasks \
  -H "Authorization: Api-Key YOUR_API_KEY" \
  | jq '.result | {
      task_status_counts,
      tasks: [
        .tasks[] | {
          task_id,
          title,
          required,
          status,
          tags,
          evidence_ids,
          risk_ids,
          completed_at,
          incomplete_at,
          requires_review_at
        }
      ],
      questions,
      confirmations,
      client_risk_ratings
    }'
```

Task statuses are:

| Status            | Meaning                                                  |
| ----------------- | -------------------------------------------------------- |
| `pending`         | Task has not started.                                    |
| `in_progress`     | Task is being worked.                                    |
| `complete`        | Task is complete according to workflow requirements.     |
| `incomplete`      | Task could not be completed with available evidence.     |
| `requires_review` | Task has output or risk that needs human/API validation. |

Use `task_status_counts` for queue and completion checks, but read individual tasks before concluding.

```javascript theme={null}
function taskCompletionSummary(tasks) {
  const required = tasks.filter((task) => task.required);
  return {
    required_count: required.length,
    complete: required.filter((task) => task.status === "complete").length,
    requires_review: required.filter(
      (task) => task.status === "requires_review",
    ).length,
    incomplete: required.filter((task) => task.status === "incomplete").length,
    open: required.filter((task) =>
      ["pending", "in_progress"].includes(task.status),
    ).length,
  };
}

const { tasks } = await minerva(`/assessments/${assessmentId}/tasks`);
const completion = taskCompletionSummary(tasks);
```

To find work needing review across many assessments, use the list endpoint filters:

```bash theme={null}
curl -sS \
  "https://api.gominerva.com/risk-assessments/v2/assessments?status=ready_for_review,reopened&task_status=requires_review,incomplete&sort_by=updated_at&sort_direction=desc&limit=25" \
  -H "Authorization: Api-Key YOUR_API_KEY"
```

## Get Risks

Use `GET /assessments/{assessmentId}` to read the full assessment document. Risk findings are returned on `result.assessment.risks`.

```bash theme={null}
curl -sS \
  https://api.gominerva.com/risk-assessments/v2/assessments/ASSESSMENT_ID \
  -H "Authorization: Api-Key YOUR_API_KEY" \
  | jq '.result.assessment.risks // []'
```

Each risk finding can include:

| Field          | Use                                                                 |
| -------------- | ------------------------------------------------------------------- |
| `risk_id`      | Stable risk finding identifier.                                     |
| `title`        | Short risk title.                                                   |
| `summary`      | Human-readable finding summary.                                     |
| `severity`     | `low`, `medium`, `high`, or `critical`.                             |
| `category`     | Broad category such as screening, ownership, adverse media, or CRR. |
| `tags`         | Workflow-specific topic labels for more precise filtering.          |
| `status`       | `active`, `resolved`, `false_positive`, or `accepted`.              |
| `subject_ids`  | Subjects implicated by the finding.                                 |
| `task_ids`     | Workflow tasks associated with the finding.                         |
| `evidence_ids` | Evidence supporting the finding.                                    |
| `source_urls`  | Source URLs supporting the finding, when available.                 |

There is not currently a separate customer endpoint that lists risks independently from the assessment document. Filter risks client-side from the assessment payload.

## Filter Risks By Topic, Tag, Status, Or Severity

Risk tags are configured by the workflow and generated during the assessment. Do not assume every tenant uses the same tag vocabulary. Use your workflow's task tags and returned risk tags as the source of truth.

Common topic groups might include:

| Topic group                | Example categories or tags                                                   |
| -------------------------- | ---------------------------------------------------------------------------- |
| Screening                  | `screening`, `sanctions`, `pep`, `watchlist`, `criminal`                     |
| Adverse media and legal    | `adverse_media`, `legal`, `litigation`, `fraud`, `corruption`, `enforcement` |
| Ownership and control      | `ownership`, `control`, `ubo`, `nominee`, `corporate_structure`              |
| Geography and jurisdiction | `geography`, `jurisdiction`, `high_risk_jurisdiction`                        |
| Source of funds or wealth  | `source_of_funds`, `source_of_wealth`, `sof`, `sow`                          |
| Client risk rating         | `crr`, `client_risk_rating`, `risk_rating`                                   |

### Filter With `jq`

```bash theme={null}
TOPIC="ownership"

curl -sS \
  https://api.gominerva.com/risk-assessments/v2/assessments/ASSESSMENT_ID \
  -H "Authorization: Api-Key YOUR_API_KEY" \
  | jq --arg topic "$TOPIC" '
      .result.assessment.risks // []
      | map(select((.status // "active") == "active"))
      | map(select(
          (.category == $topic)
          or ((.tags // []) | index($topic))
        ))
    '
```

To filter by several related tags:

```bash theme={null}
curl -sS \
  https://api.gominerva.com/risk-assessments/v2/assessments/ASSESSMENT_ID \
  -H "Authorization: Api-Key YOUR_API_KEY" \
  | jq '
      ["sanctions", "pep", "watchlist"] as $topics
      | .result.assessment.risks // []
      | map(select((.status // "active") == "active"))
      | map(select(
          (.category as $category | $topics | index($category))
          or ((.tags // []) as $tags | any($topics[]; $tags | index(.)))
        ))
    '
```

### Filter In JavaScript

```javascript theme={null}
const severityRank = {
  low: 1,
  medium: 2,
  high: 3,
  critical: 4,
};

function riskMatchesTopic(risk, topics) {
  const normalizedTopics = new Set(topics.map((topic) => topic.toLowerCase()));
  const category = String(risk.category || "").toLowerCase();
  const tags = (risk.tags || []).map((tag) => String(tag).toLowerCase());

  return (
    normalizedTopics.has(category) ||
    tags.some((tag) => normalizedTopics.has(tag))
  );
}

function filterRisks(
  risks,
  {
    topics = [],
    statuses = ["active"],
    minSeverity = "low",
    subjectIds = [],
    taskIds = [],
  } = {},
) {
  const allowedStatuses = new Set(statuses);
  const subjectFilter = new Set(subjectIds);
  const taskFilter = new Set(taskIds);
  const minRank = severityRank[minSeverity] || severityRank.low;

  return (risks || []).filter((risk) => {
    const status = risk.status || "active";
    if (!allowedStatuses.has(status)) return false;
    if ((severityRank[risk.severity] || 0) < minRank) return false;
    if (topics.length > 0 && !riskMatchesTopic(risk, topics)) return false;
    if (
      subjectFilter.size > 0 &&
      !(risk.subject_ids || []).some((id) => subjectFilter.has(id))
    ) {
      return false;
    }
    if (
      taskFilter.size > 0 &&
      !(risk.task_ids || []).some((id) => taskFilter.has(id))
    ) {
      return false;
    }
    return true;
  });
}

const { assessment } = await minerva(`/assessments/${assessmentId}`);

const sanctionsOrPepRisks = filterRisks(assessment.risks, {
  topics: ["sanctions", "pep", "watchlist"],
  minSeverity: "medium",
});

const ownershipRisks = filterRisks(assessment.risks, {
  topics: ["ownership", "control", "ubo", "nominee"],
  statuses: ["active", "accepted"],
});
```

### Filter Risks By Task Tags

Task tags and risk tags should align with your workflow taxonomy. When you want "risks related to tasks tagged ownership," read tasks and risks together:

```javascript theme={null}
const [{ assessment }, { tasks }] = await Promise.all([
  minerva(`/assessments/${assessmentId}`),
  minerva(`/assessments/${assessmentId}/tasks`),
]);

const ownershipTaskIds = new Set(
  tasks
    .filter((task) => (task.tags || []).includes("ownership"))
    .map((task) => task.task_id),
);

const ownershipTaskRiskIds = new Set(
  tasks
    .filter((task) => ownershipTaskIds.has(task.task_id))
    .flatMap((task) => task.risk_ids || []),
);

const risksForOwnershipTasks = (assessment.risks || []).filter((risk) => {
  return (
    ownershipTaskRiskIds.has(risk.risk_id) ||
    (risk.task_ids || []).some((taskId) => ownershipTaskIds.has(taskId))
  );
});
```

## Provide Steering

Use steering when the run should adjust direction without creating a new assessment.

```bash theme={null}
curl -sS -X POST \
  https://api.gominerva.com/risk-assessments/v2/assessments/ASSESSMENT_ID/steer \
  -H "Authorization: Api-Key YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "Prioritize official registry evidence before adverse media. Add any parent entities discovered during ownership review as related subjects."
  }'
```

Good steering is specific, short, and tied to the current assessment. Do not use steering to bypass required review or evidence requirements.

Use `/steer` when you want to change how the agent proceeds. Use `/input` when you are answering a question, providing missing facts, or adding more instructions as user-provided context.

```bash theme={null}
curl -sS -X POST \
  https://api.gominerva.com/risk-assessments/v2/assessments/ASSESSMENT_ID/input \
  -H "Authorization: Api-Key YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "Additional instruction from the onboarding case: treat the newly uploaded ownership chart as the customer-supplied version, but corroborate beneficial owners against official registry or reliable public sources before marking the ownership task complete.",
    "reason": "Customer supplied a revised ownership chart after the run started."
  }'
```

Both `/steer` and `/input` accept:

| Field           | Use                                                                |
| --------------- | ------------------------------------------------------------------ |
| `prompt`        | Plain-text instruction or answer.                                  |
| `message`       | Alternate plain-text instruction field. `prompt` is preferred.     |
| `reason`        | Short audit reason for the command.                                |
| `payload`       | Structured JSON context for integration-specific instructions.     |
| `artifact_refs` | References to artifacts already known to the runtime, when needed. |
| `run_id`        | Optional explicit run id when using the latest-run endpoint.       |

## Update Task Status

```bash theme={null}
curl -sS -X PATCH \
  https://api.gominerva.com/risk-assessments/v2/assessments/ASSESSMENT_ID/tasks/TASK_ID/status \
  -H "Authorization: Api-Key YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "status": "requires_review",
    "comment_markdown": "Ownership task needs analyst review because the registry extract and ownership chart disagree."
  }'
```

Use status changes to reflect actual review state. Include comments when the reason will matter for audit or handoff.

## Add A Comment

```bash theme={null}
curl -sS -X POST \
  https://api.gominerva.com/risk-assessments/v2/assessments/ASSESSMENT_ID/comments \
  -H "Authorization: Api-Key YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "subject_kind": "assessment",
    "subject_id": "ASSESSMENT_ID",
    "markdown": "Please confirm whether the uploaded ownership chart is the current signed version before concluding."
  }'
```

Comments should name the review question, the evidence or task involved, and the action needed.

## Conclude An Assessment

```bash theme={null}
curl -sS -X POST \
  https://api.gominerva.com/risk-assessments/v2/assessments/ASSESSMENT_ID/conclude \
  -H "Authorization: Api-Key YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "decision": "approved_with_conditions",
    "summary": "KYB review is complete. Ownership is understood, sanctions/PEP screening did not identify confirmed matches, and the remaining medium-risk ownership factor is documented in the CRR scorecard."
  }'
```

Conclude only after required tasks, evidence, risk findings, comments, and client risk rating criteria have been reviewed according to your policy.

## Operational Guidance

* Create separate application keys for test and Live use.
* Confirm beta enablement before using the public route.
* Fetch workflows and scorecards instead of hard-coding IDs where possible.
* Store assessment IDs in your internal case system.
* Use descriptive assessment titles so dashboard users can identify API-created cases.
* Upload or register source documents before starting the run when they are material to the task.
* Review trajectory and evidence IDs before concluding assessments.
* Retry idempotent reads safely, but avoid repeated start or conclude calls without checking current status.
* Contact Minerva if the same endpoint returns repeated failures for one tenant, workspace, or workflow.

## Related Guides

* [Agent Risk Assessments Guide](/agent-risk-assessments-guide)
* [API Introduction](/api-reference/introduction)
* [API Keys](/api-reference/api-keys)
