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

# Model Activity

> Read model usage, spend, latency, outcomes, and routing transitions from the CLI or Platform API.

```bash theme={null}
dari activity models \
  --from 2026-07-01T00:00:00Z \
  --to 2026-07-08T00:00:00Z
```

Model Activity returns the statistics shown under **Activity → Models & Routing** in the [Dari dashboard](https://app.dari.dev) as JSON.

## Authorization

Sign in with `dari auth login`, or set `DARI_API_KEY` to a [Management key](/api-keys#create-a-management-key). The authorizing user must have the owner or admin role in the organization.

* A per-user CLI key authorizes as the user it was created for. A manually created Management key authorizes as its creator.
* Routing keys cannot read activity data.

## Filter Activity

`--from` is inclusive and `--to` is exclusive. Both are required RFC3339 timestamps with a timezone offset, and the range cannot exceed 366 days.

```bash theme={null}
dari activity models \
  --from 2026-07-01T00:00:00Z \
  --to 2026-07-08T00:00:00Z \
  --router-id rtr_123 \
  --model openai/gpt-5.5 \
  --status completed
```

| Flag           | Accepts                                                       | Find values with     |
| -------------- | ------------------------------------------------------------- | -------------------- |
| `--router-id`  | One router ID                                                 | `dari router list`   |
| `--api-key-id` | Repeatable API-key IDs                                        | `dari api-keys list` |
| `--user-id`    | Repeatable user IDs                                           | `dari org members`   |
| `--model`      | Repeatable model IDs                                          | `dari router list`   |
| `--provider`   | One lowercase slug such as `openai` or `anthropic`            | —                    |
| `--status`     | `completed`, `provider_error`, `selector_error`, or `aborted` | —                    |

Repeated flags combine with OR inside their dimension, and a row matches either the user set or the API-key set. The other dimensions combine with AND.

For transitions, the identity filters (router, API key, user) constrain each conversation before adjacent requests are compared. Model, provider, and status apply to the destination request afterward, so filtering never invents transitions.

## Call The API

The CLI wraps this Platform API endpoint. Pass the same filters as the query parameters `router_id`, `api_key_id`, `user_id`, `model`, `provider`, and `status`:

```bash theme={null}
curl --get \
  "https://api.dari.dev/v1/organizations/current/routing/activity/models" \
  -H "Authorization: Bearer $DARI_API_KEY" \
  --data-urlencode "from=2026-07-01T00:00:00Z" \
  --data-urlencode "to=2026-07-08T00:00:00Z" \
  --data-urlencode "model=openai/gpt-5.5"
```

Management keys must use the `current` route; the server derives the organization from the key. Dashboard clients authenticated with a user session can replace `current` with an explicit organization ID.

## Example Response

```json theme={null}
{
  "from_at": "2026-07-01T00:00:00Z",
  "to_at": "2026-07-08T00:00:00Z",
  "summary": {
    "model_steps": 40,
    "observed_conversations": 12,
    "switched_conversations": 3,
    "model_switches": 5,
    "cross_provider_switches": 2,
    "switched_conversation_rate": 0.25,
    "cross_provider_switch_rate": 0.4
  },
  "models": [
    {
      "model": "openai/gpt-5.5",
      "provider": "openai",
      "model_steps": 25,
      "provider_input_tokens": 12000,
      "provider_cache_read_tokens": 8000,
      "provider_cache_write_tokens": 1000,
      "provider_output_tokens": 4000,
      "provider_total_tokens": 25000,
      "provider_spend_usd": "0.125",
      "priced_model_steps": 25,
      "unpriced_model_steps": 0,
      "provider_latency_p95_ms": 1800,
      "non_completed_steps": 1,
      "provider_cost_per_step_usd": "0.005",
      "non_completion_rate": 0.04
    }
  ],
  "transitions": [
    {
      "from_model": "openai/gpt-5.5",
      "from_provider": "openai",
      "to_model": "anthropic/claude-opus-4-6",
      "to_provider": "anthropic",
      "occurrences": 2,
      "conversations": 2,
      "tool_continuations": 1,
      "switch_share": 0.4
    }
  ],
  "transitions_truncated": false
}
```

### Summary

A model step is one persisted downstream model inference; a tool-result continuation is a new step. An observed conversation is a distinct combination of router, API key, attributed user, and a nonempty conversation identifier.

| Field                        | Meaning                                                     |
| ---------------------------- | ----------------------------------------------------------- |
| `model_steps`                | Persisted routing requests in the range.                    |
| `observed_conversations`     | Conversations with a protocol-visible selected route.       |
| `switched_conversations`     | Conversations containing at least one route change.         |
| `model_switches`             | Adjacent requests whose selected model or provider changed. |
| `cross_provider_switches`    | The subset of switches that changed providers.              |
| `switched_conversation_rate` | `switched_conversations / observed_conversations`.          |
| `cross_provider_switch_rate` | `cross_provider_switches / model_switches`.                 |

### Models

One row per exact model and provider pair.

| Field                                        | Meaning                                                                                              |
| -------------------------------------------- | ---------------------------------------------------------------------------------------------------- |
| `provider_*_tokens`                          | Fresh input, cache-read, cache-write, output, and total tokens.                                      |
| `provider_spend_usd`                         | Spend across steps with known pricing, as a decimal string.                                          |
| `provider_cost_per_step_usd`                 | Known spend divided by all model steps, including unpriced ones.                                     |
| `priced_model_steps`, `unpriced_model_steps` | Pricing coverage for the row.                                                                        |
| `provider_latency_p95_ms`                    | Discrete 95th percentile of persisted provider durations, or `null` when none are positive.          |
| `non_completed_steps`, `non_completion_rate` | Steps whose persisted status was not `completed`. An execution outcome, not an output-quality score. |

### Transitions

One row per exact route change, ordered by volume. Requests are ordered by receipt time and then request ID; retries and provider attempts within one routing request do not become separate transitions.

| Field                | Meaning                                                                        |
| -------------------- | ------------------------------------------------------------------------------ |
| `occurrences`        | Times this exact route change happened, including repeats in one conversation. |
| `conversations`      | Distinct conversations containing it.                                          |
| `tool_continuations` | Occurrences whose destination inference continued after a tool result.         |
| `switch_share`       | This row's occurrences divided by all model switches.                          |

## Semantics And Limits

* Money values are decimal strings with no fixed precision; parse them numerically before comparing or sorting. Spend is computed from Dari's configured model catalog rates.
* Unknown pricing is never reported as free usage: both money fields are `null` when no step has known pricing. Check the priced and unpriced step counts before comparing partially priced rows.
* Rates are numbers from `0` to `1` and return `0` when the denominator is zero.
* The response is not paginated. Transitions are limited to the highest-volume pairs; `transitions_truncated` is `true` when those rows omit switches that summary counts still include.
* The endpoint reads persisted Chat Completions routing telemetry and never returns prompts, responses, tool arguments, or credentials. Rows without a conversation identifier count toward model totals but not conversation or transition statistics.
* Telemetry is reported separately from the client response, so very recent or failed telemetry deliveries may not appear immediately.

## Errors

| Status | Cause                                                                        |
| ------ | ---------------------------------------------------------------------------- |
| `400`  | Reversed range, range over 366 days, or timestamp without a timezone offset. |
| `422`  | Unparseable timestamp or unsupported status value.                           |
| `401`  | Missing, invalid, or wrong-type credentials.                                 |
| `403`  | The authenticated user lacks owner or admin access.                          |

The CLI validates timestamps, range order, and status values before sending a request, so it reports those mistakes locally.
