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

# Monitoring

# Monitoring API: metrics, events, and cost

> Query platform-level metrics, activity event logs, API performance data, per-agent metrics and summaries, and agent cost data from the Nora Monitoring API.

The Monitoring API gives you observability into the Nora platform and the agents you can access. You can pull a high-level metrics summary, page through the activity event log, query detailed per-agent metrics with time range filters, retrieve pre-aggregated summary statistics, and fetch cost data. Session users follow normal ownership and workspace membership. A workspace API key with `monitoring:read` is restricted to agents and events in its exact bound workspace, even when the issuing user can access other workspaces.

***

## Platform metrics summary

Return aggregate health and usage metrics for the entire platform as seen by the authenticated user.

```
GET /monitoring/metrics
```

### Response

<ResponseField name="totalAgents" type="number">
  Total number of accessible agents.
</ResponseField>

<ResponseField name="activeAgents" type="number">
  Agents currently in `running` state.
</ResponseField>

<ResponseField name="deployingAgents" type="number">
  Agents currently in `deploying` state.
</ResponseField>

<ResponseField name="queuedAgents" type="number">
  Agents in `queued` state.
</ResponseField>

<ResponseField name="stoppedAgents" type="number">
  Agents in `stopped` state.
</ResponseField>

<ResponseField name="warningAgents" type="number">
  Agents in `warning` state.
</ResponseField>

<ResponseField name="errorAgents" type="number">
  Agents in `error` state.
</ResponseField>

<ResponseField name="totalDeployments" type="number">
  Total number of deployments.
</ResponseField>

<ResponseField name="queue" type="object">
  Deployment queue job counts.

  <Expandable title="properties">
    <ResponseField name="waiting" type="number">Jobs waiting to run.</ResponseField>
    <ResponseField name="active" type="number">Jobs currently running.</ResponseField>
    <ResponseField name="completed" type="number">Jobs completed.</ResponseField>
    <ResponseField name="failed" type="number">Jobs failed.</ResponseField>
  </Expandable>
</ResponseField>

<CodeGroup>
  ```bash curl theme={null} theme={null}
  curl http://localhost:8080/api/monitoring/metrics \
    -H "Authorization: Bearer $TOKEN"
  ```
</CodeGroup>

```json theme={null} theme={null}
{
  "totalAgents": 4,
  "activeAgents": 2,
  "deployingAgents": 0,
  "queuedAgents": 0,
  "stoppedAgents": 1,
  "warningAgents": 0,
  "errorAgents": 1,
  "totalDeployments": 7,
  "queue": { "waiting": 0, "active": 0, "completed": 0, "failed": 0 }
}
```

***

## Fleet needs-attention roll-up

Return only the agents that need an operator's attention right now, with the reasons why. Derived at read time from existing state — no extra configuration. Use it to drive a triage view instead of scanning every agent. Requires the `monitoring:read` scope.

Detected reasons: `error` and `budget_paused` (severity error); `warning`, `stuck_deploying` (queued/deploying over 10 minutes), `budget_warning` (a running agent crossed a budget soft threshold), and `telemetry_stalled` (a running agent reported no container telemetry for over 5 minutes).

```
GET /monitoring/fleet-status
```

### Response

<ResponseField name="generatedAt" type="string">ISO timestamp the roll-up was computed.</ResponseField>
<ResponseField name="total" type="number">Total number of accessible agents evaluated.</ResponseField>
<ResponseField name="attentionCount" type="number">Number of agents needing attention.</ResponseField>
<ResponseField name="agents" type="array">Agents needing attention, errors first. Each has `agentId`, `name`, `status`, `severity`, and a `reasons` array of `{ code, severity, label }`.</ResponseField>

<CodeGroup>
  ```bash curl theme={null} theme={null}
  curl http://localhost:8080/api/monitoring/fleet-status \
    -H "Authorization: Bearer $TOKEN"
  ```
</CodeGroup>

```json theme={null} theme={null}
{
  "generatedAt": "2026-06-12T12:00:00.000Z",
  "total": 4,
  "attentionCount": 2,
  "agents": [
    {
      "agentId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "name": "Billing bot",
      "status": "stopped",
      "severity": "error",
      "reasons": [
        { "code": "budget_paused", "severity": "error", "label": "Paused — budget cap reached" }
      ]
    },
    {
      "agentId": "b2c3d4e5-f6a7-8901-bcde-f23456789012",
      "name": "Scraper",
      "status": "deploying",
      "severity": "warning",
      "reasons": [
        { "code": "stuck_deploying", "severity": "warning", "label": "Stuck deploying for 18m" }
      ]
    }
  ]
}
```

***

## Activity event log

Return a chronological log of activity events. When you supply `agentId` the results are filtered to that agent; otherwise all events across your agents are returned.

```
GET /monitoring/events
```

### Query parameters

<ParamField query="agentId" type="string">
  Filter events to a specific agent UUID.
</ParamField>

<ParamField query="limit" type="number" default="50">
  Maximum number of events to return, ordered newest first.
</ParamField>

<ParamField query="type" type="string">
  Filter events to a specific event type slug.
</ParamField>

<ParamField query="search" type="string">
  Full-text filter across event messages.
</ParamField>

<ParamField query="from" type="string">
  Inclusive start date (`YYYY-MM-DD`) for the event window.
</ParamField>

<ParamField query="to" type="string">
  Inclusive end date (`YYYY-MM-DD`) for the event window.
</ParamField>

<ParamField query="page" type="number">
  Page number for paginated results (1-based).
</ParamField>

<Note>
  Supplying any of `page`, `search`, `type`, `from`, or `to` switches the response to a pagination
  envelope (with `limit` clamped to 10–100). Without those filters, a flat array is returned
  (`limit` 1–100, default 50).
</Note>

### Response

<ResponseField name="id" type="string">
  Event UUID.
</ResponseField>

<ResponseField name="type" type="string">
  Event type slug, e.g. `agent_deployed`, `agent_redeployed`.
</ResponseField>

<ResponseField name="message" type="string">
  Human-readable description of the event.
</ResponseField>

<ResponseField name="metadata" type="object">
  Additional context for the event.

  <Expandable title="properties">
    <ResponseField name="agentId" type="string">Related agent UUID, when applicable.</ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="created_at" type="string">
  ISO 8601 event timestamp.
</ResponseField>

<CodeGroup>
  ```bash curl (all events) theme={null} theme={null}
  curl "http://localhost:8080/api/monitoring/events?limit=20" \
    -H "Authorization: Bearer $TOKEN"
  ```

  ```bash curl (by agent) theme={null} theme={null}
  curl "http://localhost:8080/api/monitoring/events?agentId=a1b2c3d4-e5f6-7890-abcd-ef1234567890&limit=10" \
    -H "Authorization: Bearer $TOKEN"
  ```
</CodeGroup>

```json theme={null} theme={null}
[
  {
    "id": "g8h9i0j1-k2l3-4567-mnop-456789012345",
    "type": "agent_deployed",
    "message": "Agent \"My Agent\" (OpenClaw + Docker) queued for deployment",
    "metadata": { "agentId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890" },
    "created_at": "2025-03-10T09:00:05.000Z"
  }
]
```

***

## API performance data

Return raw API performance metric records. Useful for building latency dashboards or debugging slow endpoints.

```
GET /monitoring/performance
```

<Note>
  Unlike the other `/monitoring/*` endpoints, this one requires a platform-admin **session**.
  Workspace API keys are rejected with `403 session_required` even when issued by an admin; non-admin
  sessions receive `403 {"error": "Admin access required"}`.
</Note>

### Query parameters

<ParamField query="since" type="string">
  ISO 8601 start timestamp. Defaults to 24 hours ago.
</ParamField>

### Response

Each record represents a single API call that was instrumented.

<ResponseField name="value" type="number">
  Measured value (typically response time in ms).
</ResponseField>

<ResponseField name="metadata" type="object">
  Context for the measurement, such as path and method.
</ResponseField>

<ResponseField name="recorded_at" type="string">
  ISO 8601 timestamp when the metric was recorded.
</ResponseField>

<CodeGroup>
  ```bash curl theme={null} theme={null}
  curl "http://localhost:8080/api/monitoring/performance?since=2025-03-10T00:00:00Z" \
    -H "Authorization: Bearer $TOKEN"
  ```
</CodeGroup>

```json theme={null} theme={null}
[
  {
    "value": 42,
    "metadata": { "method": "GET", "path": "/agents", "status": 200 },
    "recorded_at": "2025-03-10T09:01:00.000Z"
  }
]
```

***

## Agent metrics

Return time-series metric records for a specific agent. You can filter by metric type and specify an exact time range.

```
GET /agents/:id/metrics
```

### Path parameters

<ParamField path="id" type="string" required>
  Agent UUID.
</ParamField>

### Query parameters

<ParamField query="type" type="string">
  Metric type filter, e.g. `cpu`, `memory`, `tokens`. When omitted, all types are returned.
</ParamField>

<ParamField query="since" type="string">
  ISO 8601 start of the time range. Defaults to 24 hours ago.
</ParamField>

<ParamField query="until" type="string">
  ISO 8601 end of the time range. Defaults to now.
</ParamField>

### Response

<ResponseField name="id" type="string">
  Metric record UUID.
</ResponseField>

<ResponseField name="agent_id" type="string">
  Agent UUID.
</ResponseField>

<ResponseField name="metric_type" type="string">
  Metric category slug.
</ResponseField>

<ResponseField name="value" type="number">
  Numeric metric value.
</ResponseField>

<ResponseField name="metadata" type="object">
  Additional context for the metric.
</ResponseField>

<ResponseField name="recorded_at" type="string">
  ISO 8601 timestamp.
</ResponseField>

<CodeGroup>
  ```bash curl theme={null} theme={null}
  curl "http://localhost:8080/api/agents/a1b2c3d4-e5f6-7890-abcd-ef1234567890/metrics?type=tokens&since=2025-03-10T00:00:00Z" \
    -H "Authorization: Bearer $TOKEN"
  ```
</CodeGroup>

```json theme={null} theme={null}
[
  {
    "id": "h9i0j1k2-l3m4-5678-nopq-567890123456",
    "agent_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "metric_type": "tokens",
    "value": 1240,
    "metadata": { "model": "gpt-4o", "direction": "completion" },
    "recorded_at": "2025-03-10T09:10:00.000Z"
  }
]
```

***

## Agent metrics summary

Return pre-aggregated summary statistics for an agent. Useful for dashboards that need totals without querying the full time-series.

```
GET /agents/:id/metrics/summary
```

### Path parameters

<ParamField path="id" type="string" required>
  Agent UUID.
</ParamField>

### Response

<ResponseField name="total_tokens" type="number">
  Total LLM tokens consumed by this agent.
</ResponseField>

<ResponseField name="total_requests" type="number">
  Total LLM API requests made.
</ResponseField>

<ResponseField name="avg_response_ms" type="number">
  Average LLM response latency in milliseconds.
</ResponseField>

<ResponseField name="last_active_at" type="string">
  ISO 8601 timestamp of the most recent metric record.
</ResponseField>

<CodeGroup>
  ```bash curl theme={null} theme={null}
  curl http://localhost:8080/api/agents/a1b2c3d4-e5f6-7890-abcd-ef1234567890/metrics/summary \
    -H "Authorization: Bearer $TOKEN"
  ```
</CodeGroup>

```json theme={null} theme={null}
{
  "total_tokens": 48200,
  "total_requests": 312,
  "avg_response_ms": 1840,
  "last_active_at": "2025-03-10T09:10:00.000Z"
}
```

***

## Agent cost

Return estimated token-cost data for a specific agent. Token usage is grouped by model when runtime responses include model metadata; older rows without metadata appear as `Unknown model`.

```
GET /agents/:id/cost?period_days=30
```

Use `period_start` and `period_end` instead of `period_days` for a custom UTC date window.

### Path parameters

<ParamField path="id" type="string" required>
  Agent UUID.
</ParamField>

### Response

<ResponseField name="token_cost" type="number">
  Estimated token cost in USD.
</ResponseField>

<ResponseField name="total_cost" type="number">
  Total estimated token cost in USD.
</ResponseField>

<ResponseField name="input_tokens" type="number">
  Input or prompt tokens recorded in the period.
</ResponseField>

<ResponseField name="output_tokens" type="number">
  Output or completion tokens recorded in the period.
</ResponseField>

<ResponseField name="total_tokens" type="number">
  Total tokens recorded in the period.
</ResponseField>

<ResponseField name="cost_details" type="object">
  Token pricing details.

  <Expandable title="properties">
    <ResponseField name="tokens" type="object">Fallback token rate and per-model token usage rows.</ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="periodStart" type="string">
  Start of the reporting period (ISO 8601).
</ResponseField>

<ResponseField name="periodEnd" type="string">
  End of the reporting period (ISO 8601).
</ResponseField>

<CodeGroup>
  ```bash curl theme={null} theme={null}
  curl http://localhost:8080/api/agents/a1b2c3d4-e5f6-7890-abcd-ef1234567890/cost \
    -H "Authorization: Bearer $TOKEN"
  ```
</CodeGroup>

```json theme={null} theme={null}
{
  "token_cost": 0.62,
  "total_cost": 0.62,
  "input_tokens": 120000,
  "output_tokens": 42000,
  "total_tokens": 162000,
  "cost_details": {
    "tokens": {
      "fallback_per_1k": 0.002,
      "models": [
        {
          "model": "openai/gpt-5.5",
          "provider": "openai",
          "input_tokens": 120000,
          "output_tokens": 42000,
          "total_tokens": 162000,
          "rate_source": "model",
          "token_cost": 0.62
        }
      ]
    }
  },
  "periodStart": "2025-03-01T00:00:00.000Z",
  "periodEnd": "2025-03-31T23:59:59.000Z"
}
```

| Status | Condition       |
| ------ | --------------- |
| `404`  | Agent not found |
