---
title: "Get all historical chat messages."
method: GET
path: "/api/export_history"
tags: ["Admin"]
---

# Get all historical chat messages.

`GET /api/export_history`

## Request

- Base URL: `https://app.getdot.ai` (the document declares no server; this is the origin it was published from)
- URL: `https://app.getdot.ai/api/export_history`
- Auth: one of:
  - API key in header `X-API-KEY`
  - API key in cookie `Authorization`
  - OAuth 2 (password, token URL `/api/auth/token`)
  - API key in query parameter `user_id+api_token`

Export raw user_queries rows for a date range.

A row is in the range when its `start_time` (UTC) is on or after `start_date` and
before `end_date`: `start_date` is included, `end_date` is not.

Every field on each row is documented under the response schema below, in
`UserQueryRow`. Note the alias pairs: `is_scheduled` /
`created_by_schedule` (this run was scheduled) and `has_schedule` /
`has_active_schedule` (the parent chat has a schedule). Use `acc_actual`
when present, otherwise `acc_consumed`; summed by `chat_kind`, they split
what building apps cost from what questions cost.

## Query parameters

- `start_date` string: First day included (UTC), YYYY-MM-DD. Default: 14 days before today.
- `end_date` string: First day NOT included (UTC), YYYY-MM-DD: the range ends at the start of this day. Default: tomorrow, so today is included. For a single day, pass that day and the day after.
- `include_all_workspaces` boolean: Include history from all workspaces (main workspace only)
- `include_answers` boolean: Add `answer` to each row: the answer the user read for that question. Rows without a saved answer get null.

## Response `200`

Successful Response

- ExportHistoryResponse: Wrapper around the list of rows returned by `/api/export_history`.
  - `chats` UserQueryRow[], required: One entry per user query (message turn) in the requested date range, ordered by `start_time` ascending.
    - `message_id` string, nullable: Unique ID of this single user query (one message turn). Stable across the lifetime of the row. For an agentic answer it is also the answer's ID in the chat, so `<Dot URL>/?c={chat_id}&message_uuid={message_id}` opens the chat at this answer (use it to link a row, such as a thumbs-down, straight to the answer it rates).
    - `org_id` string, nullable: ID of the organization that owns this query. For workspaces, this is the workspace org ID (e.g. 'getdot.ai-w-cause').
    - `region` string, nullable: Region of the Dot deployment that processed the query and answers this export: 'US' or 'EU' on Dot's hosted service, where an organization present in both regions exports each region's queries from that region. A self-hosted deployment reports its own region setting, 'local' when it has none.
    - `user_id` string, nullable: Internal Dot user ID of the person who asked the question. For workspace users this is suffixed with `#{workspace_name}`.
    - `external_user_id` string, nullable: The original/external identifier of the user (e.g. Slack user ID, email) before Dot's internal mapping.
    - `chat_id` string, nullable: ID of the chat (conversation) this query belongs to. NOTE: chat IDs are only unique within a single workspace, not globally across workspaces.
    - `extra` string, nullable: Latest extra embed parameter on the conversation identified by chat_id. Scheduled runs without their own value fall back to their source conversation via lineage_parent_id. An opaque host-supplied string, not a per-query snapshot; null when unavailable.
    - `user_message` string, nullable: The natural-language question the user asked.
    - `answer` string, nullable: The answer to this question as the user read it: its text, with each table, chart or file it showed named in brackets (e.g. '[DATA TABLE shown to the user]'). Only filled when the export was requested with `include_answers=true`. Null when no saved answer matches this question, for example a Root (context agent) row, a scheduled delivery, or a question still running.
    - `status` string, nullable: Lifecycle status of the query. Common values: 'started' (the query began and is still in flight), 'completed' (finished successfully), 'failed' (raised an error, was interrupted before finishing, or was abandoned, with the reason in `error`), 'timeout' (agentic run hit the time limit before producing a final answer). A run that dies without reporting an outcome is reconciled to 'failed' within a few hours, so 'started' does not persist. Rows recorded before 2026-04-25 predate this column and were backfilled from `error`: 'completed' when no error was recorded, 'failed' otherwise.
    - `result_data_rows` integer, nullable: Number of rows returned by the underlying SQL query, if the query produced a tabular result.
    - `result_data_columns` string, nullable: Comma-separated list of column names returned by the SQL result.
    - `result_viz` string, nullable: Type of visualization rendered for the result (e.g. 'bar', 'line', 'table'). Empty when the answer was text-only.
    - `error` string, nullable: Error message if the query failed. Null when the query completed successfully. Two values are recorded by the platform rather than the query itself: 'Run was interrupted before it finished' (the run was cancelled or stalled mid-flight) and 'finalizer_missing' (the run stopped reporting and was reconciled afterwards). Consult `acc_actual` for the billed amount; a stalled run may have consumed billable credits before it stopped.
    - `warning` string, nullable: Non-fatal warning surfaced during the run (e.g. ambiguous column resolution, partial result). The query still completed.
    - `start_time` string, nullable: UTC timestamp when the query started, ISO 8601 format. This is the field used to filter the export by date range.
    - `end_time` string, nullable: UTC timestamp when the query finished, ISO 8601 format. Null while the query is still running.
    - `tokens_used` string, nullable: Not recorded in this export: always null. Use `acc_consumed` and `acc_actual` for what a query cost.
    - `connection_type` string, nullable: Type of the data connection used (e.g. 'snowflake', 'bigquery', 'postgres', 'duckdb'). Null for non-SQL answers.
    - `channel` string, nullable: Where the query came from. Common values: 'ui' / 'web' (Dot web app), 'slack' (Slack bot), 'teams' (Microsoft Teams bot), 'email' (email reply), 'cli' (Dot CLI), 'mcp' (MCP integration), 'context_agent' (Root agent), 'schedule' (scheduled run). New channels can appear as new integrations ship.
    - `groups` string, nullable: The asking user's group memberships at query time, copied from the user record. Used for access control. Stored as plain text. The shape depends on how the user object was configured (usually a comma-separated list of group names, but can be empty or null).
    - `role` string, nullable: Role of the asking user at query time. One of 'admin', 'modeler', 'user'.
    - `agentic` boolean, nullable: True if the query ran in agentic mode (multi-step tool-using agent). False for direct single-shot SQL generation.
    - `is_scheduled` boolean, nullable: True if THIS specific query run was triggered by the scheduler (a cron-like recurring run), not by a human. Same as `created_by_schedule`.
    - `created_by_schedule` boolean, nullable: Customer-facing alias of `is_scheduled`. True if this specific query was triggered by the scheduler. Provided so consumers don't have to disambiguate the raw column name.
    - `has_schedule` boolean, nullable: True if the PARENT CHAT has one or more active schedules attached, meaning it can run automatically in the future. Independent of whether this particular row was scheduled. Same as `has_active_schedule`.
    - `has_active_schedule` boolean, nullable: Customer-facing alias of `has_schedule`. True if the parent chat has at least one active schedule and can therefore run automatically.
    - `lineage_parent_id` string, nullable: For runs the scheduler generated, this is the `chat_id` of the source (template) chat the scheduled run came from, so you can reconcile a run back to the chat that defined it. A scheduled app delivery on the Latest numbers or Brief tier points at its schedule instead, as `scheddef-<schedule id>`: every run of one schedule shares it, though it names a chat only when the schedule has one. Null for queries that have no upstream lineage. Note: this column is generic enough that other code paths can populate it from their own metadata, so we cannot guarantee 100% that every value is a chat_id.
    - `parent_chat_id` string, nullable: The identifier the parent chat references. For chats created as a scheduled run output, or chats explicitly forked from another chat, this is normally the source `chat_id`. KNOWN ISSUE: for some scheduled-run paths (e.g. work-gate-blocked runs) this currently holds a message UUID instead of a chat_id. We are aware of this and tracking a cleanup; treat the value as 'a reference into the system' rather than strictly a chat_id.
    - `is_shared` boolean, nullable: True if the chat this query belongs to was shared with Dot's Share button, or if the query is an agentic scheduled run (`created_by_schedule` and `agentic` both true). Agentic runs are saved with an open link for their delivery, so they count even when the delivery was suppressed or sent without a link. A non-agentic scheduled run reports false: its delivery links to the source chat instead, which the scheduler shares, so that chat reports true.
    - `labels` string[], nullable: Free-form labels attached to the chat in the Dot UI. Useful for grouping (e.g. 'production', 'experiment').
    - `chat_kind` string, nullable: What the conversation this query belongs to was for: 'app' when it built or edited a Dot app, 'chat' otherwise. 'app' covers every conversation in the app editor or started by MCP `build_app`, every conversation an app was created or published from, and any other conversation in which Dot wrote an app (on the web, in Slack, Teams or email, through the API or MCP, or in a scheduled run). Set per conversation, not per query: every query of a conversation that built an app reports 'app', including questions asked in it before or after the app was built. Sum `acc_actual` (or `acc_consumed` where it is null) by this field to split what building apps cost from what questions cost. Questions asked about an app with its Ask button, Root (context agent) rows and rows of deleted conversations report 'chat'. A conversation in which Dot wrote an app outside the editor before this field was added reports 'chat', unless an app was created or published from it.
    - `acc_consumed` number, nullable: Credits (ACC) this query cost to run, including subagents and web searches. On a cancelled run this can exceed `acc_actual`.
    - `acc_actual` number, nullable: Credits (ACC) billed to the org for this query. NULL on older rows and on Root (context agent) rows; use `acc_consumed` there.
    - `web_search_credits` number, nullable: Credits within this query attributable specifically to Dot's web-search tool. This is a subset of the query's total credits and is charged at a static 0.025 ACC per search. Null for rows recorded before this breakdown was tracked.
    - `feedback` string, nullable: Thumbs-up / thumbs-down feedback the user left on the answer. Values: 'like' (thumbs up), 'dislike' (thumbs down), or null if no feedback was given.
    - `feedback_data` object, nullable: Structured feedback details: `{'description': str, 'checkboxes': list[str]}`. Populated when the user submitted the detailed feedback form.
    - `feedback_timestamp` string, nullable: UTC timestamp of when the user submitted feedback, ISO 8601 format. Null if no feedback was given.
    - `conversation_score` string, nullable: AI-judged quality score of the full conversation. Values: 'problem' (the user pushed back on an answer, had to repeat a request, hit an error, or was told the assistant could not deliver what they asked. Flagged only when the judgement is confident, so it is a short list worth working rather than every conversation with a caveat), 'good' (the user explicitly said the answer was what they needed), 'ok' (everything else, which is most conversations), 'abandoned' (the user stopped responding to Dot's clarifying question). Populated asynchronously after the chat completes, so it may be null until scoring catches up.
    - `conversation_score_reason` string, nullable: Why the conversation got its `conversation_score`. For 'problem' this is a written explanation naming what specifically went wrong (the metric, table, error or correction involved) so it can be acted on. For 'good', 'ok' and 'abandoned' it is a fixed sentence restating the verdict, not a per-conversation analysis.
    - `slack_real_name` string, nullable: Slack display name of the user who asked the question. Only populated when `channel='slack'`.
    - `slack_email` string, nullable: Email address from the Slack profile of the asking user. Only populated when `channel='slack'`.
    - `slack_title` string, nullable: Job title from the Slack profile of the asking user. Only populated when `channel='slack'`.
    - `slack_user_id` string, nullable: Slack user ID of the asking user (the workspace-scoped identifier Slack assigns to each member). Only populated when `channel='slack'`.
    - `workspace_name` string, nullable: Human-readable name of the workspace the query came from. Only populated when the export was requested with `include_all_workspaces=true`.
    - `workspace_org_id` string, nullable: Org ID of the workspace the query came from (e.g. 'getdot.ai-w-cause'). Only populated when the export was requested with `include_all_workspaces=true`.

## Other responses

- `422`: Validation Error

---

[API](https://skmtc.dev/getdot/apis/dot-api-2.md) · [All operations](https://skmtc.dev/getdot/apis/dot-api-2/llms.txt) · [OpenAPI document](https://skmtc.dev/getdot/apis/dot-api-2/revisions/d26fe7163a7f?raw)
