Export analytics events

Every analytics event of the workspace in [from, to), for loading into a data warehouse: conversations, messages, CSAT, tool calls, Agent Assist (copilot.*) and the rest. One row per event_id, oldest first (occurred_at, then event_id). Test and playground traffic is left out unless include_test=true.

ColumnTypeMeaning
event_iduuidStable id of the event. Upsert on it: the same event is never two rows.
occurred_atdate-timeWhen it happened, UTC, to the second.
event_typestringe.g. conversation.created, message.sent, copilot.rated.
channelstringWhere it happened: widget, whatsapp, salesforce, salesforce_agent_assist, inbox_copilot, …
conversation_iduuid or emptyThe Ayro conversation, when there is one.
agent_iduuid or emptyThe Ayro AI agent involved.
skill_iduuid or emptyThe skill involved.
valuenumber or emptyThe event's number: a CSAT score, a latency in ms, +1 / -1 / 0 for a thumb.
dimsobjectThe event's other attributes. A JSON string in CSV.

Loading it: upsert on event_id. Each event is exported once, in the window holding its first occurrence, and its occurred_at does not change between exports. Its dims can: a judged answer replaces the first version of answer.judged, so upsert rather than insert-only. Some events are written late (a backfill, a rating given days after the answer), so re-read the last few days on every run rather than only the newest day. occurred_at is to the second; within one second the order is not meaningful. Columns are only ever added, never renamed or removed; new event_type values and dims keys can appear at any time.

Authentication: a workspace API key (Bearer krns_sk_…) with the analytics:read scope, or an unscoped key. Create one per pipeline in Settings → API Keys.

Output: format=ndjson (recommended for pipelines) or csv (default), gzipped unless compression=none. Sent as an attachment with no Content-Encoding, so curl -o saves the .gz as is. The data starts streaming at once; the exact row count is in the NDJSON trailer.

Detecting an incomplete file: NDJSON ends with {"_export":"complete","rows":<n>,"from":"2026-09-01T00:00:00Z","to":"2026-10-01T00:00:00Z"} (the window, UTC), or with {"_export":"failed",…} when the export broke midway. A failing CSV download is aborted, so the client sees an error (curl -f exits non-zero) and never a short file that looks whole.

Limits: to - from at most 548 days (the retention of analytics events); one export at a time per workspace (409); 30 exports per workspace per day (429); a few exports at a time across all customers (503 when busy). Every refusal carries Retry-After; a refused or invalid request does not count toward the 30. A month of a busy workspace (millions of events) takes a few minutes; for a first load, pull one month per request, in sequence, rather than the whole range at once.

Event types

Event typeMeaningdims
conversation.createdA conversation starts.
value: 1
One row per conversation; occurred_at is its first message
—
conversation.resolvedThe conversation reaches resolved: the bot finished, the visitor closed it, a teammate closed it, or it went idle.
value: 1
One row per conversation (reopen cycle, when cycle_count is set); occurred_at is the first time
resolved_by ∈ idle, agent, operator_idle, visitor, customer, teammate (visitor and customer both mean the visitor closed it); cycle_count
conversation.escalatedThe conversation is handed to a human or another system.
value: 1
One row per conversation (reopen cycle, when cycle_count is set); occurred_at is the first hand-off, later hand-offs in the same conversation are not separate events
escalated_by: the destination, e.g. salesforce_live_chat, zendesk_ticket, tidio_live_chat, kronos_live, api; cycle_count
conversation.reopenedA visitor writes again in a resolved conversation.
value: ms from the last agent reply to the visitor coming back, or empty
One row per reopen cycle
cycle_count, reopened_by = visitor
conversation.first_responseThe agent first answers in a cycle.
value: response time in ms
One row per reopen cycle; occurred_at is the answer
cycle_count
conversation.language_detectedThe conversation language is detected or corrected.
value: 1
One row per conversation; a correction replaces the earlier verdict
language (ISO code), source ∈ auto, manual
message.sentA message is sent in a conversation.
value: message length in characters (not a count)
One row per message
sender ∈ visitor, agent, teammate, internal_note
message.classifiedA visitor message gets an intent.
value: 1
One row per message
intent (the workspace's intent slugs, or other), message_id
tool.invokedThe agent calls a tool.
value: empty
One row per tool call
tool_name, outcome ∈ ok, error, empty, tool_type ∈ custom, composio, personalized, mcp, builtin, escalation, message_id
knowledge.retrievedThe agent searches the knowledge base.
value: chunks returned (0 when nothing came back)
One row per search
outcome ∈ ok, error, empty, kb_id, top_similarity, query_length, message_id
csat.requestedA satisfaction survey is shown or sent.
value: empty
One row per conversation
reason ∈ agent_request, resolved_async, visitor_minimize, live_chat_ended
human_csatThe visitor rates the conversation. Not written for conversations a human handled.
value: score 1–5
One row per conversation
—
human_csat.commentedThe visitor adds a comment to the rating.
value: the score 1–5, or empty
One row per conversation
source ∈ widget, api, email, agent
ai_csatThe AI judge scores the conversation.
value: score 1–5
One row per conversation
prompt_version (0 = default rubric)
answer.judgedAn agent answer is checked: first from its tool trace, then replaced by the judge's verdict.
value: 1
One row per answer (the visitor turn); the verdict replaces the first version
message_id, intent, grounded ("true"/"false", a string), answer_source ∈ answered_from_knowledge, answered_from_procedure, answered_from_tool, answered_from_model, knowledge_gap, integration_gap, no_answer, problem_type, severity ∈ low, medium, high, tool_type
sentry.issue_createdA recurring problem across conversations is opened.
value: conversations affected
One row per issue
issue_id, problem_type, intent, suggested_action ∈ connect_integration, draft_article, review_escalation, none, severity, status
sentry.issue_updatedA problem's status or size changes.
value: conversations affected
One row per change
as sentry.issue_created; status ∈ open, resolved, dismissed
copilot.suggestedAgent Assist gives a human agent a suggestion (Salesforce panel or Ayro inbox).
value: 1
One row per suggestion
interaction_id, surface ∈ salesforce, inbox, action ∈ ask, suggest_reply, summarize, full_assist, … , trigger = auto_open when the panel ran it without a click, sf_org_id, sf_user_id, sf_record_id (Salesforce) or teammate_id (inbox)
copilot.ratedThe human agent sets, changes or clears a thumb.
value: 1 up, -1 down, 0 cleared
One row per thumb change; the latest per interaction_id (by occurred_at, then changed_at_ms) is the current one
as copilot.suggested, plus rating ∈ up, down, none, changed_at_ms
copilot.insertedThe human agent puts the suggestion into the reply box.
value: 1
One row per suggestion; occurred_at is the first insert
as copilot.suggested, plus inserted_into ∈ reply, note, replace
copilot.sentThe inserted suggestion is sent (Ayro inbox only).
value: 1
One row per suggestion; occurred_at is the first send
as copilot.suggested
teammate.invitedAn owner invites a teammate.
value: empty
One row per action
invited_by_user_id, invited_user_id, role, was_new_user
teammate.invite_resentAn invitation is sent again.
value: empty
One row per action
resent_by_user_id, target_user_id
teammate.role_changedA teammate's role changes.
value: empty
One row per action
changed_by_user_id, target_user_id, old_role, new_role
teammate.removedA teammate is removed or leaves.
value: empty
One row per action
removed_by_user_id, removed_user_id, was_self
curl -fSL -H "Authorization: Bearer krns_sk_…" \
  "https://api.getkronos.ai/api/analytics/export/events?from=2026-09-01T00:00:00Z&to=2026-10-01T00:00:00Z&format=ndjson" \
  -o events.ndjson.gz
Recent Requests
Log in to see full request history
TimeStatusUser Agent
Retrieving recent requests…
LoadingLoading…
Query Params
string
enum

Default gzip.

Allowed:
string
enum

Default csv; ndjson is recommended for pipelines.

Allowed:
boolean

Include test and playground traffic. Default false.

string

Comma-separated event types; all when absent.

string
required

End, exclusive. ISO 8601 instant, at most 548 days after from.

string
required

Start, inclusive. ISO 8601 instant.

Headers
string
enum
Defaults to application/x-ndjson

Generated from available response content types

Allowed:
Responses

400

A missing or invalid parameter, or a window that is too wide.

401

Missing or invalid API key.

403

The key lacks the analytics:read scope.

409

An export is already running for this workspace; retry after Retry-After seconds.

429

The daily limit of 30 exports is used up; Retry-After says when it resets (00:00 UTC).

503

Exports are busy across all workspaces; retry after Retry-After seconds.

Language
Credentials
Bearer
krns_sk_*
URL
LoadingLoading…
Response
Click Try It! to start a request and see the response here! Or choose an example:
application/x-ndjson
text/csv
application/gzip