# ChartAssistant

**Summary:** Endpoints for ChartAssistant

- Role: [Developers](https://www.subrite.no/developers)
- Source: https://www.subrite.no/developers/chart-assistant
- Updated: 2026-10-13
- Markdown index: https://www.subrite.no/developers/llms.txt

<a id="post-api-v1-chart-assistant-chat"></a>
## Ask the chart assistant for a graph

`POST /api/v1/chart-assistant/chat`

Streams one turn of the conversation as an AI SDK UI message stream (server-sent events), for the `useChat` hook. The assistant reads the tenant statistics as the signed-in admin and finishes by describing a chart, which the client renders by replaying it through `run`. A tenant on the EU residency default has no model available and is refused.

**Authentication:** Bearer token (JWT)

### Request body

Content type: `application/json` · Required · `ChartAssistantChatDto`

| Name | Type | Description |
| --- | --- | --- |
| `id` (Required) | `string` | The chat id, generated by the client and stable for the conversation. Groups every model round trip of the conversation in the AI usage ledger. · `maxLength`: `128` |
| `messages` (Required) | `array of object with any values` | The conversation so far, as AI SDK UI messages. · `maxItems`: `200` |

**Example request body**

`application/json`

```json
{
  "id": "string",
  "messages": [
    {}
  ]
}
```

### Responses

#### 201

#### 400

Content type: `text/event-stream` · `ErrorResponse`

chartAssistantInvalidMessages

| Name | Type | Description |
| --- | --- | --- |
| `messageCode` (Required) | `string` | Allowed values: `"chartAssistantInvalidMessages"` |
| `message` | `string` |   |
| `errors` (Required) | `array of FieldError` |   |
| `errors[].field` (Required when parent is present) | `string` |   |
| `errors[].fieldValue` (Required when parent is present) | `string` |   |
| `errors[].identifier` (Required when parent is present) | `string` |   |
| `errors[].identifierValue` (Required when parent is present) | `string` |   |
| `errors[].messageCode` (Required when parent is present) | `string` |   |
| `errors[].message` | `string` |   |
| `errors[].errorType` (Required when parent is present) | `string` |   |

#### 401

unauthorized

#### 403

Content type: `text/event-stream` · `ErrorResponse`

aiNotAvailableForResidency

| Name | Type | Description |
| --- | --- | --- |
| `messageCode` (Required) | `string` | Allowed values: `"aiNotAvailableForResidency"` |
| `message` | `string` |   |
| `errors` (Required) | `array of FieldError` |   |
| `errors[].field` (Required when parent is present) | `string` |   |
| `errors[].fieldValue` (Required when parent is present) | `string` |   |
| `errors[].identifier` (Required when parent is present) | `string` |   |
| `errors[].identifierValue` (Required when parent is present) | `string` |   |
| `errors[].messageCode` (Required when parent is present) | `string` |   |
| `errors[].message` | `string` |   |
| `errors[].errorType` (Required when parent is present) | `string` |   |

#### 500

Content type: `application/json` · `ErrorResponse`

internalServerError

| Name | Type | Description |
| --- | --- | --- |
| `messageCode` (Required) | `string` |   |
| `message` | `string` |   |
| `errors` (Required) | `array of FieldError` |   |
| `errors[].field` (Required when parent is present) | `string` |   |
| `errors[].fieldValue` (Required when parent is present) | `string` |   |
| `errors[].identifier` (Required when parent is present) | `string` |   |
| `errors[].identifierValue` (Required when parent is present) | `string` |   |
| `errors[].messageCode` (Required when parent is present) | `string` |   |
| `errors[].message` | `string` |   |
| `errors[].errorType` (Required when parent is present) | `string` |   |

**Example response**

`application/json`

```json
{
  "messageCode": "string",
  "message": "string",
  "errors": [
    {}
  ]
}
```

#### 503

Content type: `text/event-stream` · `ErrorResponse`

aiProviderNotConfigured

| Name | Type | Description |
| --- | --- | --- |
| `messageCode` (Required) | `string` | Allowed values: `"aiProviderNotConfigured"` |
| `message` | `string` |   |
| `errors` (Required) | `array of FieldError` |   |
| `errors[].field` (Required when parent is present) | `string` |   |
| `errors[].fieldValue` (Required when parent is present) | `string` |   |
| `errors[].identifier` (Required when parent is present) | `string` |   |
| `errors[].identifierValue` (Required when parent is present) | `string` |   |
| `errors[].messageCode` (Required when parent is present) | `string` |   |
| `errors[].message` | `string` |   |
| `errors[].errorType` (Required when parent is present) | `string` |   |

### Example request

```bash
curl https://api.subrite.no/api/v1/chart-assistant/chat \
  --request POST \
  --header 'Authorization: Bearer <token>' \
  --header 'Content-Type: application/json' \
  --data '{
  "id": "string",
  "messages": [
    {}
  ]
}'
```

<a id="post-api-v1-chart-assistant-run"></a>
## Replay a saved chart's tool calls

`POST /api/v1/chart-assistant/run`

Runs each source of a chart against its Subrite stats tool as the signed-in admin and returns the payloads. No model is involved, so this needs no AI entitlement and is what a saved chart renders through on every open.

**Authentication:** Bearer token (JWT)

### Request body

Content type: `application/json` · Required · `ChartAssistantRunDto`

| Name | Type | Description |
| --- | --- | --- |
| `sources` (Required) | `array of ChartSourceRunDto` | `minItems`: `1`, `maxItems`: `4` |
| `sources[].id` (Required when parent is present) | `string` | Short id the chart refers to this source by, e.g. "ended". · `maxLength`: `40`, `pattern`: `/^[a-z0-9_]+$/` |
| `sources[].tool` (Required when parent is present) | `string` | The Subrite stats tool to call, e.g. get\_historical\_subscriptions. · `maxLength`: `100`, `pattern`: `/^[a-z0-9_]+$/` |
| `sources[].args` | `object with any values` | Arguments for the tool, checked against the tool's own schema. |

### Responses

#### 201

Content type: `application/json` · `ChartAssistantRunResponseDto`

| Name | Type | Description |
| --- | --- | --- |
| `payloads` (Required) | `array of ChartSourcePayloadDto` |   |
| `payloads[].id` (Required when parent is present) | `string` | The source id this payload answers. |
| `payloads[].payload` (Required when parent is present) | `object with any values` | The tool's JSON result as MCP returns it. Personal data is stripped, except from a list tool, whose rows are the deliverable and come back whole to an admin who may read members. |

#### 400

Content type: `application/json` · `ErrorResponse`

chartAssistantUnknownTool, chartAssistantInvalidToolArguments

| Name | Type | Description |
| --- | --- | --- |
| `messageCode` (Required) | `string` | Allowed values: `"chartAssistantUnknownTool"`, `"chartAssistantInvalidToolArguments"` |
| `message` | `string` |   |
| `errors` (Required) | `array of FieldError` |   |
| `errors[].field` (Required when parent is present) | `string` |   |
| `errors[].fieldValue` (Required when parent is present) | `string` |   |
| `errors[].identifier` (Required when parent is present) | `string` |   |
| `errors[].identifierValue` (Required when parent is present) | `string` |   |
| `errors[].messageCode` (Required when parent is present) | `string` |   |
| `errors[].message` | `string` |   |
| `errors[].errorType` (Required when parent is present) | `string` |   |

**Example response**

`application/json`

```json
{
  "messageCode": "chartAssistantUnknownTool",
  "message": "string",
  "errors": [
    {}
  ]
}
```

#### 401

unauthorized

#### 403

Content type: `application/json` · `ErrorResponse`

chartAssistantToolForbidden

| Name | Type | Description |
| --- | --- | --- |
| `messageCode` (Required) | `string` | Allowed values: `"chartAssistantToolForbidden"` |
| `message` | `string` |   |
| `errors` (Required) | `array of FieldError` |   |
| `errors[].field` (Required when parent is present) | `string` |   |
| `errors[].fieldValue` (Required when parent is present) | `string` |   |
| `errors[].identifier` (Required when parent is present) | `string` |   |
| `errors[].identifierValue` (Required when parent is present) | `string` |   |
| `errors[].messageCode` (Required when parent is present) | `string` |   |
| `errors[].message` | `string` |   |
| `errors[].errorType` (Required when parent is present) | `string` |   |

**Example response**

`application/json`

```json
{
  "messageCode": "chartAssistantToolForbidden",
  "message": "string",
  "errors": [
    {}
  ]
}
```

#### 422

Content type: `application/json` · `ErrorResponse`

chartAssistantToolFailed

| Name | Type | Description |
| --- | --- | --- |
| `messageCode` (Required) | `string` | Allowed values: `"chartAssistantToolFailed"` |
| `message` | `string` |   |
| `errors` (Required) | `array of FieldError` |   |
| `errors[].field` (Required when parent is present) | `string` |   |
| `errors[].fieldValue` (Required when parent is present) | `string` |   |
| `errors[].identifier` (Required when parent is present) | `string` |   |
| `errors[].identifierValue` (Required when parent is present) | `string` |   |
| `errors[].messageCode` (Required when parent is present) | `string` |   |
| `errors[].message` | `string` |   |
| `errors[].errorType` (Required when parent is present) | `string` |   |

**Example response**

`application/json`

```json
{
  "messageCode": "chartAssistantToolFailed",
  "message": "string",
  "errors": [
    {}
  ]
}
```

#### 500

Content type: `application/json` · `ErrorResponse`

internalServerError

Same fields as [Ask the chart assistant for a graph (500)](https://www.subrite.no/developers/chart-assistant?md=true#post-api-v1-chart-assistant-chat).

**Example response**

`application/json`

```json
{
  "messageCode": "string",
  "message": "string",
  "errors": [
    {}
  ]
}
```

### Example request

```bash
curl https://api.subrite.no/api/v1/chart-assistant/run \
  --request POST \
  --header 'Authorization: Bearer <token>' \
  --header 'Content-Type: application/json' \
  --data '{
  "sources": [
    {
      "args": {}
    }
  ]
}'
```

### Example response

201 · `application/json`

```json
{
  "payloads": [
    {
      "payload": {}
    }
  ]
}
```
