How do you read a conversation?

Send GET /api/manage/conversations/{id} with an id from the workspace list, or one you stored earlier. An id that isn’t in your workspace returns 404 with “Conversation not found.”

Request
curl 'https://app.kawlnow.com/api/manage/conversations/CONVERSATION_ID' \
  -H 'Authorization: Bearer YOUR_WORKSPACE_TOKEN'
Response 200
{
  "id": "CONVERSATION_ID",
  "channel": "support",
  "topic": "Inviting a teammate",
  "status": "ended",
  "created_at": "2026-10-08T10:02:11.000Z",
  "seconds": 96.4,
  "finalized": 1,
  "transcript": [
    {
      "role": "agent",
      "text": "Hi, I am Sam, an AI assistant for Example App. What can I help with?"
    },
    {
      "role": "customer",
      "text": "How do I invite someone from my team?"
    },
    {
      "role": "agent",
      "text": "Open Settings, choose Team and select Invite."
    }
  ],
  "summary": "How do I invite someone from my team?",
  "feedback": "Customer rating: helpful"
}

What does each field mean?

The list in the workspace response has the same fields except transcript, and adds is_test.

Conversation fields
FieldMeaning
channelsupport or sales.
topicWhat the visitor typed before the call, 1 to 1,000 characters. The agent receives it as context and treats it as untrusted.
statuspending: the ticket was issued and the call hasn’t connected. active: in progress. ended: finished normally. escalated: the caller chose Talk to a human, so the AI conversation ended and a call to your team was started, shown as Escalated in the dashboard. It doesn’t confirm that anyone answered, and it appears only if you’ve turned on human handover, an early release. incomplete: the caller’s browser asked to start, but no usage was confirmed, because the connection dropped, the free conversations were used up or the voice service refused the call. It’s shown as Interrupted in the dashboard. failed: the browser never asked to start the voice session, for example because it didn’t connect within 45 seconds.
created_atWhen the call ticket was issued, in UTC.
secondsThe call’s length in seconds, as the voice service reported it.
finalized1 when the voice service confirmed the final usage, shown as Final usage confirmed in the dashboard, otherwise 0.
transcriptThe turns in order, each with a role, customer or agent, and its text. Speech from one side in a row is joined into one turn, and a transcript longer than 180,000 characters keeps only its last 100 turns.
summaryThe first 700 characters of what the caller said, or the topic if they said nothing. It isn’t written by AI, and it’s filled in only when a call ends normally.
feedbackFeedback the agent recorded because the caller asked, such as a bug report, and “Customer rating: helpful” if they pressed That was helpful, one entry per line. Otherwise null.
is_testIn the workspace list only: 1 for a dashboard test call.

How do you collect new conversations?

There are no webhooks, paging or date filters, so poll the workspace response and remember which ids you’ve handled. Skip calls that are still pending or active, and decide whether to keep dashboard tests, which have is_test set to 1.

Fetch transcripts for new customer calls
// Node 18 or later, saved as poll.mjs. Prints finished customer calls you have not seen.
import { existsSync, readFileSync, writeFileSync } from 'node:fs';

const base = 'https://app.kawlnow.com/api/manage';
const headers = { Authorization: `Bearer ${process.env.KAWLNOW_TOKEN}` };
const seenFile = 'seen-conversations.json';
const seen = new Set(existsSync(seenFile) ? JSON.parse(readFileSync(seenFile, 'utf8')) : []);

async function get(path) {
  const response = await fetch(`${base}${path}`, { headers });
  if (!response.ok) throw new Error(`${response.status}: ${(await response.json()).error}`);
  return response.json();
}

const workspace = await get('/workspace');
for (const call of workspace.conversations) {
  const finished = !['pending', 'active'].includes(call.status);
  if (seen.has(call.id) || call.is_test || !finished) continue;
  const full = await get(`/conversations/${call.id}`);
  console.log(`${call.channel}: ${call.topic}`);
  for (const turn of full.transcript) console.log(`  ${turn.role}: ${turn.text}`);
  seen.add(call.id);
}
writeFileSync(seenFile, JSON.stringify([...seen]));

How do you read automatic insights?

GET /api/manage/insights returns the support agent’s automatic insights, and GET /api/manage/insights?channel=sales returns the sales agent’s. After calls, an OpenAI model groups recurring questions, reported issues and themes from what callers said in up to the latest 30 finished customer calls from the last 30 days, reading up to 3,000 characters from each call and 48,000 in total. Dashboard tests aren’t included, and the conversation_insights MCP tool returns the same report.

Each group has a kind, which is question, issue or theme, a label, a short summary written by the model, a count of the sampled calls behind it and its evidence: exact quotes, each with the conversationId and turnIndex of the transcript turn it comes from. Links, contact details and anything that looks like a credential are masked before analysis, so a quote can differ from the transcript there. Counts describe the sample, not every call, and there are no sentiment or satisfaction scores.

The report updates automatically, and state says where it is: ready when the latest report is done, queued or processing while a new one is made, empty when there are no calls to analyse, failed when the latest analysis didn’t succeed, with a message in error, and not-configured while insights are paused. Apart from empty, each state can still include the last finished report.

Request the support agent’s insights
curl 'https://app.kawlnow.com/api/manage/insights' \
  -H 'Authorization: Bearer YOUR_WORKSPACE_TOKEN'
Response 200, shortened to one group and one quote
{
  "channel": "support",
  "state": "ready",
  "updatedAt": "2026-10-08T11:00:00.000Z",
  "error": null,
  "report": {
    "windowStart": "2026-09-08T11:00:00.000Z",
    "windowEnd": "2026-10-08T11:00:00.000Z",
    "eligibleCalls": 12,
    "sampledCalls": 12,
    "generatedAt": "2026-10-08T11:00:00.000Z",
    "groups": [
      {
        "kind": "question",
        "label": "Inviting teammates",
        "summary": "Callers asked how to invite someone from their team.",
        "count": 3,
        "evidence": [
          {
            "conversationId": "CONVERSATION_ID",
            "turnIndex": 1,
            "excerpt": "How do I invite someone from my team?",
            "topic": "Inviting a teammate",
            "createdAt": "2026-10-08T10:02:11.000Z"
          }
        ]
      }
    ]
  }
}

What should you know before you copy transcripts?

Transcripts hold whatever callers said, which can include names, email addresses and other personal data. Copy them only into systems that need them, and protect them as you would your own support records.

Kawl Now has no retention settings or automatic deletion yet, and the API can’t delete a conversation, so transcripts are kept until you ask for them to be deleted. The dashboard’s export downloads the latest 100 conversations without transcripts, so to keep full transcripts elsewhere, fetch them from this endpoint one conversation at a time.