Conversation Export
The chatbot analytics events give you the front-end side of a chatbot session. This guide covers the other half: pulling the conversations themselves — the stored rating, topic, and where they were escalated to — into your own data warehouse, so chatbot journeys can be joined with traffic, order, and helpdesk data on your side.
Two endpoints do the work:
| Endpoint | Returns |
|---|---|
GET /api/v1/chat/conversations | Conversation-level metadata and stored signals, paginated |
GET /api/v1/chat/conversations/{id} | One conversation including the full transcript |
Both live under the management API and are documented in full in the API Reference.
Authentication
Use a chatbot API key with Basic auth, the same key used for the statistics and CSAT endpoints. The
key prefix decides the environment: a live_ key only ever returns live conversations, a test_
key only test conversations.
curl https://api.dialogintelligens.dk/api/v1/chat/conversations?chatbot_id=YOUR_CHATBOT_ID \
-u 'live_yourkey_yoursecret:'What one conversation looks like
{
"conversation_id": "conversation_42",
"chatbot_id": "shop-bot",
"environment": "live",
"visitor_id": "visitor_123",
"created_at": "2026-07-10T14:02:00.000Z",
"updated_at": "2026-07-10T14:22:00.000Z",
"message_count": 8,
"topic": "Returnering",
"tags": ["retur"],
"customer_rating": 2,
"rating_feedback": "Fik ikke svar på mit spørgsmål",
"quality_score": 4,
"fallback": true,
"lacking_info": false,
"escalation": {
"livechat": false,
"livechat_session_id": null,
"livechat_requested_at": null,
"support_ticket": true,
"support_ticket_provider": "zendesk",
"support_ticket_id": "48211",
"support_ticket_status": "completed"
},
"source": "website",
"split_test_id": null
}Signals for good and bad journeys
Every field is stored as-is — the API does not classify a conversation as good or bad, so the definition stays yours. The fields worth building on:
| Field | Meaning |
|---|---|
customer_rating | The visitor's own 1-5 rating, or null if they did not rate |
rating_feedback | Free-text the visitor left with the rating |
quality_score | The automatic 1-10 conversation score, or null if not scored |
fallback | The bot answered with its fallback response at least once |
lacking_info | The knowledge base was missing information for the question |
escalation | Whether and where the visitor was handed to a human (see below) |
topic | The automatically classified topic, matching the dashboard |
Following journeys into Zendesk or Freshdesk
When the visitor is handed over, escalation records where the journey continued:
livechatandlivechat_session_idfor conversations taken over by an agent in Diverge livechat.support_ticket_providerandsupport_ticket_idfor conversations that created a helpdesk ticket.support_ticket_idis the ticket number in Zendesk or Freshdesk, so it joins directly against your helpdesk data.
support_ticket_id is null while a ticket is still queued (support_ticket_status is pending
or processing) and for tickets created before ticket linking was introduced; support_ticket
still tells you the visitor submitted the form.
Narrow the list to escalated journeys with escalated=true, or to the ones the bot handled on its
own with escalated=false.
Incremental syncs
updated_at is the export watermark. It is the most recent of conversation creation, rating
submission, livechat session activity, and helpdesk ticket delivery — so a conversation that gets
rated two days after it started shows up again in the next sync.
Store the highest updated_at you have loaded and pass it back as updated_since:
curl -G https://api.dialogintelligens.dk/api/v1/chat/conversations \
-u 'live_yourkey_yoursecret:' \
--data-urlencode 'chatbot_id=YOUR_CHATBOT_ID' \
--data-urlencode 'updated_since=2026-07-09T00:00:00Z' \
--data-urlencode 'limit=100'When back-filling a large history, combine updated_since with a start_date/end_date window and
walk the range month by month. start_date and end_date filter on created_at and must be
supplied together.
Pagination
Results are ordered newest first and paginated with an opaque cursor. Keep requesting until
next_cursor is null:
async function fetchAll(chatbotId, updatedSince) {
const auth = Buffer.from(`${process.env.DIVERGE_API_KEY}:`).toString("base64");
const conversations = [];
let cursor = null;
do {
const url = new URL("https://api.dialogintelligens.dk/api/v1/chat/conversations");
url.searchParams.set("chatbot_id", chatbotId);
url.searchParams.set("limit", "100");
if (updatedSince) url.searchParams.set("updated_since", updatedSince);
if (cursor) url.searchParams.set("cursor", cursor);
const response = await fetch(url, { headers: { Authorization: `Basic ${auth}` } });
if (!response.ok) throw new Error(`Conversation export failed: ${response.status}`);
const page = await response.json();
conversations.push(...page.items);
cursor = page.next_cursor;
} while (cursor);
return conversations;
}Reading a transcript
Fetch a single conversation when you need the messages themselves — for example to review the low-rated conversations the list surfaced:
curl https://api.dialogintelligens.dk/api/v1/chat/conversations/conversation_42 \
-u 'live_yourkey_yoursecret:'The response is the same record plus form_data (the stored contact or support ticket form) and
history, the full message list in the same shape the chatbot API uses everywhere else.
Transcripts contain whatever visitors typed, so treat them as personal data: pull them on demand for the conversations you actually need rather than mirroring every transcript into your warehouse.
Related
- Chatbot Analytics — front-end events for Google Tag Manager.
- API Reference — every parameter and response field.