Insights API
Retrieve the conversation insights that power your dashboard’s Insights page: sentiment, resolution and escalation rates, top topics, tone, per-day trends, and the findings Ragtime raises for your team. These endpoints are available:
GET /insights: deterministic metrics and trends for a date range. No AI cost and fast, which suits dashboards and scheduled reports.POST /insights/query: ask a natural-language question and get a written answer grounded in those same metrics.GET /insights/highlights: the cards worth knowing about without asking, such as sentiment shifts, volume anomalies and emerging topics. Poll this to raise your own alerts.POST /insights/export: render a report as PDF, CSV or JSON for archival and compliance./insights/saved-queries: store a named question and re-run it later.GET /insights/unanswered: what visitors asked that the assistant could not answer, grouped by meaning, for any period. Free./insights/findings: the findings from the daily check, what is going well as well as what needs attention, narrowed and compared like the dashboard’s Findings tab, with where they happened and the overview above them. Also the calls to resolve, defer, decline, dismiss or reopen them./insights/settings,/insights/purgeand/insights/test-data: data collection, purging conversations, and generated test data.
A few things remain dashboard only. See What the API does not cover.
Reading requires an API key with the insights:read scope; creating, updating and deleting saved queries requires insights:write; acting on findings and running the check requires findings:write; settings, purges and test data require insights:admin. See API Keys to create one.
Insights in the dashboard
Section titled “Insights in the dashboard”Dashboard → Insights has four tabs: Analytics, Insights, Findings and Transcripts. They share one filter bar, so a period, channel or language you pick on one tab carries over to the others.
The filter bar holds:
- Period. Presets (today, 7, 30 or 90 days, all time) and a custom range. On a narrow screen the bar shows only the short ranges.
- What the numbers show. Totals, or change from the previous period (as long as the one you picked, just before it), or change from dates you choose. Change is off for all time and for a custom range without a start date. Analytics cards then say how each figure moved, and the usage chart draws the compared period as a dashed line. On the Findings tab each finding says how its conversations moved.
- Scope. One menu for channel, comparison and language. Once you pick a channel, the menu offers a second channel (or all the others) to compare it with. Findings can compare two channels too: see Findings in the dashboard.
The choices live in the page URL (range, from, to, device, compare, lang, change, cfrom, cto), so a link shows the same view. The dashboard also remembers them for the session, per project.
Every tab ends its filter row with Export and Settings. Export gives the current tab’s data: Insights results as PDF, CSV or JSON, Transcripts as a ZIP, and Findings as CSV or JSON of the filtered list. PDFs print the dashboard as it looks, charts and map included. Settings holds data collection, the date format used in exports, and the tools to purge conversations or generate and remove test data. A purge follows the filter bar’s period and channel. Only a purge of all time on all channels also removes findings and their history; anything narrower leaves findings alone.
The Analytics tab includes a Top countries chart, taken from each visitor’s IP address.
Metrics endpoint
Section titled “Metrics endpoint”curl "https://your-ragtime-instance.com/api/v1/projects/{projectId}/insights?from=2026-03-01&to=2026-03-25" \ -H "Authorization: Bearer rt_live_YOUR_KEY_HERE"Metrics query parameters
Section titled “Metrics query parameters”| Parameter | Type | Default | Description |
|---|---|---|---|
from |
string | 30 days ago | Start date (YYYY-MM-DD), inclusive. |
to |
string | Today | End date (YYYY-MM-DD), inclusive. |
deviceId |
string | — | Limit metrics to a single device/kiosk by its slug (e.g. lobby-kiosk). |
compare |
string | — | Compare against another device slug, or __rest__ for every other device. Requires deviceId. Returns a comparison block. |
compareToPrevious |
boolean | false |
When true, also returns metrics for the immediately-preceding period as previousMetrics. Ignored when compare is set. |
previousFrom |
string | — | Compare with a period of your own instead (YYYY-MM-DD, inclusive). Needs previousTo; implies compareToPrevious. Not with compare. |
previousTo |
string | — | End of that period (YYYY-MM-DD, inclusive). Needs previousFrom. |
lang |
string | — | Only conversations in this language, as the analysis recorded it (e.g. nl). Applies to both sides of a compare. |
Metrics response
Section titled “Metrics response”{ "projectId": "proj-uuid-...", "range": { "from": "2026-03-01", "to": "2026-03-25" }, "compareToPrevious": false, "metrics": { "conversationCount": 184, "avgSentiment": 0.42, "sentimentBreakdown": { "positive": 96, "neutral": 61, "negative": 27 }, "resolutionRate": 0.78, "escalationRate": 0.09, "unansweredRate": 0.05, "topTopics": [ { "topic": "billing", "count": 45, "share": 0.245 }, { "topic": "opening hours", "count": 31, "share": 0.168 } ], "toneDistribution": { "polite": 0.71, "frustrated": 0.18, "formal": 0.4 } }, "previousMetrics": null, "trend": [ { "date": "2026-03-24", "conversationCount": 12, "avgSentiment": 0.38, "resolved": 9, "escalated": 1, "unanswered": 1 } ], "comparison": null, "compatibility": { "currentProvider": "openai", "currentModel": "text-embedding-3-small", "compatibleCount": 184, "incompatibleCount": 0, "missingCount": 0, "staleModels": [] }, "notices": []}Metric fields
Section titled “Metric fields”| Field | Description |
|---|---|
conversationCount |
Number of analyzed conversations in the period. |
avgSentiment |
Average sentiment score from -1 (negative) to 1 (positive), or null when no data. |
sentimentBreakdown |
Conversation counts grouped by sentiment label. |
resolutionRate |
Share of conversations where the user’s need was met (0–1), or null when unknown. |
escalationRate |
Share of conversations handed off to a human (0–1), or null when unknown. |
unansweredRate |
Share of conversations the assistant could not answer (0–1), or null when unknown. |
topTopics |
Up to 10 topics with their count and share (fraction of conversations). |
toneDistribution |
Average value (0–1) for each detected tone dimension. |
trend |
Per-day series (gap-filled) of counts, average sentiment, and outcome tallies. |
comparison |
When compare is set: the same metrics and trend for the comparison scope. |
compatibility |
Embedding-model coverage for analyzed conversations. See note below. |
notices |
Human-readable warnings, e.g. when some conversations were analyzed with an older embedding model. |
Question endpoint
Section titled “Question endpoint”Ask a natural-language question. The answer is generated from the same deterministic metrics above — figures are never invented.
curl -X POST "https://your-ragtime-instance.com/api/v1/projects/{projectId}/insights/query" \ -H "Authorization: Bearer rt_live_YOUR_KEY_HERE" \ -H "Content-Type: application/json" \ -d '{ "question": "How did customer sentiment change this month?", "from": "2026-03-01", "to": "2026-03-25", "compareToPrevious": true }'Question request body
Section titled “Question request body”| Field | Type | Default | Description |
|---|---|---|---|
question |
string | — | Required. The question to answer (max 500 characters). |
from |
string | 30 days ago | Start date (YYYY-MM-DD), inclusive. |
to |
string | Today | End date (YYYY-MM-DD), inclusive. |
deviceId |
string | — | Limit analysis to a single device/kiosk by its slug. |
compare |
string | — | Compare against another device slug, or __rest__ for every other device. Requires deviceId. |
compareToPrevious |
boolean | false |
Include the immediately-preceding period for comparison. Ignored when compare is set. |
previousFrom |
string | — | Compare with a period of your own (YYYY-MM-DD). Needs previousTo; not with compare. |
previousTo |
string | — | End of that period (YYYY-MM-DD). Needs previousFrom. |
lang |
string | — | Only conversations in this language. The answer and relevantConversationCount follow it. |
Question response
Section titled “Question response”{ "projectId": "proj-uuid-...", "question": "How did customer sentiment change this month?", "range": { "from": "2026-03-01", "to": "2026-03-25" }, "compareToPrevious": true, "relevantConversationCount": 42, "answer": "Sentiment improved over the period, rising from an average of 0.31 to 0.42. Resolution stayed strong at 78%, while escalations held steady around 9%.", "relevantMetrics": [ { "key": "sentiment", "phrase": "Average sentiment rose from 0.31 to 0.42." }, { "key": "outcomes", "phrase": "Resolution held at 78% with low escalation." } ], "metrics": { "...": "same shape as the metrics endpoint" }, "previousMetrics": { "...": "metrics for the preceding period, or null" }, "trend": [{ "...": "per-day series" }], "comparison": null, "compatibility": { "...": "embedding coverage" }, "notices": []}compare requires deviceId; without one the request is a 400.
The answer is a written summary; relevantMetrics highlights the metrics most relevant to the question, and relevantConversationCount is how many analyzed conversations semantically matched it. The metrics, previousMetrics, trend, comparison, compatibility, and notices fields match the metrics endpoint.
Highlights endpoint
Section titled “Highlights endpoint”The proactive cards the dashboard shows before you ask anything. Every finding is derived from SQL; the AI is used only to phrase the headline, never to produce a number.
curl "https://your-ragtime-instance.com/api/v1/projects/{projectId}/insights/highlights?from=2026-03-01" \ -H "Authorization: Bearer rt_live_YOUR_KEY_HERE"Highlights query parameters
Section titled “Highlights query parameters”| Parameter | Type | Default | Description |
|---|---|---|---|
from |
string | 30 days ago | Start date (YYYY-MM-DD), inclusive. |
to |
string | Today | End date (YYYY-MM-DD), inclusive. |
deviceId |
string | — | Limit to a single device/kiosk by its slug. |
lang |
string | — | Only conversations in this language. |
refresh |
boolean | false |
Bypass the cache and recompute. |
Highlights response
Section titled “Highlights response”{ "projectId": "proj-uuid-...", "range": { "from": "2026-03-01", "to": null }, "hasData": true, "conversationCount": 184, "cached": true, "cards": [ { "id": "sentiment_shift", "kind": "sentiment_shift", "severity": "positive", "title": "Sentiment climbing", "detail": "Average sentiment rose by 0.11 versus the preceding period.", "metricLabel": "Avg sentiment", "metricValue": "0.42", "sparkline": [{ "date": "2026-03-24", "value": 0.38 }], "baseline": 0.31, "topicBars": null, "suggestedQuestion": "What drove the improvement in sentiment?" } ]}kind is one of sentiment_shift, volume_change, volume_anomaly, emerging_topic, escalation_change or sentiment_driver. Up to six cards are returned, ranked by significance; cards is empty when the period holds no analyzed conversations (hasData: false).
Export endpoint
Section titled “Export endpoint”Render a report for archival or compliance. The question is answered server-side, so the figures in the document are the ones this API computed.
curl -X POST "https://your-ragtime-instance.com/api/v1/projects/{projectId}/insights/export" \ -H "Authorization: Bearer rt_live_YOUR_KEY_HERE" \ -H "Content-Type: application/json" \ -d '{ "question": "How did sentiment develop this month?", "format": "pdf-a4", "from": "2026-03-01" }' \ --output insights.pdfExport request body
Section titled “Export request body”| Field | Type | Default | Description |
|---|---|---|---|
question |
string | — | Required. The question the report answers (max 500 characters). |
format |
string | — | Required. One of pdf-a4, pdf-letter, csv, json. |
dateFormat |
string | iso |
How dates are rendered inside the document: iso, eu, us, long, relative. |
from |
string | 30 days ago | Start date (YYYY-MM-DD), inclusive. |
to |
string | Today | End date (YYYY-MM-DD), inclusive. |
deviceId |
string | — | Limit to a single device/kiosk by its slug. |
compare |
string | — | Compare against another device slug, or __rest__. Requires deviceId. |
compareToPrevious |
boolean | false |
Include the immediately-preceding period. Ignored when compare is set. |
previousFrom |
string | — | Compare with a period of your own (YYYY-MM-DD). Needs previousTo; not with compare. |
previousTo |
string | — | End of that period (YYYY-MM-DD). Needs previousFrom. |
lang |
string | — | Only conversations in this language. |
The response is a file attachment: application/pdf, text/csv or application/json depending on format. PDF exports include the same charts the dashboard renders.
Saved queries
Section titled “Saved queries”Store a named question with its date range and device filters, then replay it. Saved queries created through the API belong to the project, so every key bound to that project sees the same list — they are separate from the per-user queries saved in the dashboard.
# Createcurl -X POST "https://your-ragtime-instance.com/api/v1/projects/{projectId}/insights/saved-queries" \ -H "Authorization: Bearer rt_live_YOUR_KEY_HERE" \ -H "Content-Type: application/json" \ -d '{ "name": "Weekly sentiment", "question": "How did customer sentiment develop?", "defaults": { "compareToPrevious": true, "deviceId": "lobby-kiosk" } }'
# Re-run, overriding the windowcurl -X POST "https://your-ragtime-instance.com/api/v1/projects/{projectId}/insights/saved-queries/{queryId}/run?from=2026-03-01&to=2026-03-25" \ -H "Authorization: Bearer rt_live_YOUR_KEY_HERE"| Method | Path | Scope | Description |
|---|---|---|---|
GET |
/insights/saved-queries |
insights:read |
List the project’s saved queries. |
POST |
/insights/saved-queries |
insights:write |
Create one. Names are unique per project. |
GET |
/insights/saved-queries/{id} |
insights:read |
Read one. |
PATCH |
/insights/saved-queries/{id} |
insights:write |
Update name, question or defaults. |
DELETE |
/insights/saved-queries/{id} |
insights:write |
Delete one. |
POST |
/insights/saved-queries/{id}/run |
insights:read |
Replay it. Returns the same shape as /insights/query. |
defaults holds from, to, compareToPrevious, deviceId, compare and lang — the parameters /insights/query accepts, except a period of your own to compare with — and is replaced wholesale on update: a field you omit is cleared, not kept. The run endpoint accepts those same names as query parameters, each overriding the saved value.
{ "savedQuery": { "id": "query-uuid-...", "name": "Weekly sentiment", "question": "How did customer sentiment develop?", "defaults": { "from": null, "to": null, "compareToPrevious": true, "deviceId": "lobby-kiosk", "compare": null, "lang": null }, "createdAt": "2026-03-25T09:12:44.000Z", "updatedAt": "2026-03-25T09:12:44.000Z" }}Unanswered questions
Section titled “Unanswered questions”GET /api/v1/projects/{projectId}/insights/unanswered lists the questions visitors asked that the assistant could not answer, grouped by meaning, most asked first. These are the gaps in your knowledge base, in your visitors’ words.
Findings report the same gaps as missing_knowledge once they are large enough to act on. This endpoint is the signal underneath: any period, however few conversations. It reads what transcript analysis already wrote, so it spends no credits. It needs transcripts to be stored (settings).
| Parameter | Description |
|---|---|
from |
Start of the period, YYYY-MM-DD. Default: 30 days before to. |
to |
End of the period, YYYY-MM-DD, inclusive. Default: now. |
deviceId |
Only conversations at this channel, by slug. |
lang |
Only conversations in this language, as the analysis recorded it (nl). |
limit |
Groups to return, 1 to 100. Default 20. |
{ "projectId": "…", "from": "2026-09-09T10:00:00.000Z", "to": "2026-10-09T10:00:00.000Z", "questions": 42, "truncated": false, "groups": [ { "question": "Can I pay by invoice?", "examples": ["Do you accept bank transfer?", "Is invoicing possible for companies?"], "conversations": 9, "lastAskedAt": "2026-10-08T14:12:00.000Z", "languages": ["en", "nl"] } ]}questionis the phrasing closest to the group’s meaning;examplesare up to three others.conversationscounts the conversations that asked it.- Questions are anonymized and in English, whatever language they were asked in.
truncatedistruewhen the period held more than the 1,000 most recent questions grouped at once. Narrow the period to see older ones.
Findings
Section titled “Findings”Findings are what the daily check raises for your team, as the dashboard’s Findings view shows them. Each comes with its figures, a recommendation, the source it concerns and the anonymized visitor questions behind it, never conversation IDs.
There are seven kinds, in three groups. The group is the finding’s polarity.
| Polarity | Dashboard label | Kinds |
|---|---|---|
attention |
Needs attention | missing_knowledge (questions the knowledge base can’t answer), confusing_source (a source whose conversations often end badly), unused_source (a source nobody uses) |
well |
Going well | strong_source (a source whose conversations end well), improving_outcomes (conversations end well more often than before), improving_topic (a topic whose conversations now end well more often) |
know |
Worth knowing | emerging_topic (a topic that is growing) |
A fixed problem counts as going well: once Ragtime has watched an attention finding stay fixed (confirmed), its polarity is well.
| Method | Path | Scope | Description |
|---|---|---|---|
GET |
/insights/findings |
insights:read |
List findings, open first and ranked by impact; narrow and compare them. |
GET |
/insights/findings/places |
insights:read |
Where the listed findings happened, for a map. |
GET |
/insights/findings/overview |
insights:read |
The overview above the list, in a few sentences. |
POST |
/insights/findings/{findingId} |
findings:write |
Resolve, defer, decline, dismiss or reopen one finding. |
POST |
/insights/findings/check |
findings:write |
Run the daily check for this project now. |
findings:write is separate from insights:write on purpose: a key that manages saved questions can’t decline findings.
Findings in the dashboard
Section titled “Findings in the dashboard”The Findings tab opens on everything that is open, whatever its kind. Above the list, an overview says in plain figures what changed. Every number in it comes from Ragtime’s own counts, and the AI only phrases the sentences.
- Ranking. Findings are ranked by impact. A badge shows the trend (New, Rising, Stable or Fading), and open findings that came back after being resolved carry a Regressed badge.
- Filters. The Status menu (Open, Regressed, Deferred, Won’t address, Resolved, Confirmed, All) shows counts. A second control narrows by Needs attention, Going well or Worth knowing. The shared filter bar narrows by period, channel and language. A channel or language counts only that segment’s conversations. An unused source has no conversations to narrow, so it leaves a narrowed view.
- Evidence. A card shows example visitor questions, each linked to its conversation for team members, and next-step links such as adding a source to the right library. A finding about a confusing source points at the source and doesn’t offer to edit the assistant’s instructions.
- Check now runs today’s check instead of waiting for the daily one.
- Change. With the filter bar set to show change, findings group by what happened: came back, new, resolved, grew, faded, or about the same.
- Comparing channels. With a channel and a second channel picked, findings group by where they happen: mostly at one channel, mostly at the other, no clear difference, or not tied to a channel. Rates are per hundred conversations so a busy channel doesn’t win on size. A finding counts as “mostly” at a channel only when its rate there is at least three quarters of the two channels’ combined rates and a statistical test says the gap is more than chance. A line above the list compares how the two channels’ conversations end.
The List/Map toggle shows where findings happened, on OpenStreetMap. A circle is a channel and a square is a source. Each is ringed by its findings’ polarities and counts them, and places too close together merge until you zoom in. A finding sits at every channel its conversations came through that has a location, or at its source when the source has a location. With a channel or language picked, it sits only where those conversations were. Picking a place lists its findings. Picking a finding shows its places, how many of its conversations were at each, and the source its answers leaned on. Findings with no located place, and the project’s overall outcomes, are listed apart from the map. The Map button is off while nothing can be placed. A PDF made from the map view prints a still map above the list.
For the map to show anything, give your channels a location. Every channel type has a Location field (where a kiosk stands, the school a learning channel serves, the area a campaign targets), with place search. See Channels.
The daily check sends one Slack message per project to the targets you set up, listing what is new, back, regressed or rising. It carries headlines, figures and recommendations, never the visitors’ questions.
List findings
Section titled “List findings”curl "https://your-ragtime-instance.com/api/v1/projects/{projectId}/insights/findings?status=open" \ -H "Authorization: Bearer rt_live_YOUR_KEY_HERE"| Parameter | Type | Description |
|---|---|---|
status |
string | Only findings with this status: open, deferred, declined, resolved or confirmed. |
kind |
string | Only findings of this kind, one of the seven above. |
from |
string | Only findings seen in the period from this date (YYYY-MM-DD, inclusive). Without from and to: all time. |
to |
string | End of the period (YYYY-MM-DD, inclusive). |
deviceId |
string | Only the conversations at this channel, by its slug. A finding’s volume and impact count those alone. |
lang |
string | Only the conversations in this language. The response’s languages lists the ones findings were asked in. |
compare |
string | Compare deviceId with another channel’s slug (not the same one), or __rest__ for all the others. Fills comparison. |
change |
string | previous (the period just before, as long as yours) or custom. Fills changes. Needs from; not with compare. |
changeFrom |
string | With change=custom: start of the period to compare with (YYYY-MM-DD). |
changeTo |
string | With change=custom: its end (YYYY-MM-DD), before from. |
An unknown channel slug is a 404; a combination the rules above refuse is a 400.
{ "projectId": "proj-uuid-...", "findings": [ { "id": "finding-uuid-...", "kind": "missing_knowledge", "status": "open", "title": "Visitors ask: \"Can I bring my dog?\"", "volume": 14, "metrics": { "...": "figures specific to the kind" }, "questions": ["Can I bring my dog?", "Are pets allowed inside?"], "source": null, "recommendation": { "lead": "Add an answer about pets to the knowledge base.", "points": ["14 conversations asked about this and got no answer."], "next": "Once it is done, mark this resolved. Ragtime watches these questions for 14 days to confirm it." }, "deferredUntil": null, "decisionNote": null, "decidedAt": null, "resolvedAt": null, "checkUntil": null, "firstSeenAt": "2026-09-21T03:00:12.000Z", "lastSeenAt": "2026-09-30T03:00:09.000Z", "testData": false, "impact": 24.5, "trend": "rising", "delta": 6, "regressed": false, "polarity": "attention", "nearestSource": null } ], "comparison": null, "changes": null, "languages": ["en", "nl"]}| Field | Description |
|---|---|
volume |
How many conversations the finding concerns. |
metrics |
The figures behind the finding; the keys depend on kind. |
questions |
The anonymized visitor questions behind it. |
source |
{ id, name } of the Knowledge Base source a source finding is about, or null. |
recommendation |
What to do: lead (one sentence), points (why, and where to start) and optionally next. |
checkUntil |
For a resolved finding: until when Ragtime watches for it coming back. After that it becomes confirmed. |
testData |
true when raised from generated test data rather than real conversations. |
impact |
Conversations affected, weighted by how badly. The list is ranked by it. |
trend |
Against the 14 days before: new, rising, stable or fading. null until the daily check has measured it. |
delta |
Conversations in the current window minus those in the window before. null when trend is null. |
regressed |
true for an open finding that came back after it was resolved. |
polarity |
attention, well or know. See the table above. |
nearestSource |
For missing knowledge: { id, name } of the source the answers leaned on, or null. |
Comparing two channels
Section titled “Comparing two channels”With deviceId and compare, the list covers both channels, and comparison groups the listed findings by where they happen. Rates are per hundred conversations, so a busy channel doesn’t win on size, and are over the daily check’s last 14 days.
{ "comparison": { "a": "lobby-kiosk", "b": "__rest__", "groups": { "a": [{ "id": "finding-uuid-...", "a": { "conversations": 12, "per100": 8.1 }, "b": { "conversations": 3, "per100": 1.2 } }], "b": [], "both": [], "neither": [], "unsegmented": [] }, "outcomes": { "a": { "conversations": 148, "known": 140, "resolved": 102 }, "b": { "conversations": 251, "known": 238, "resolved": 190 }, "p": 0.04, "testData": false } }}a and b hold the findings mostly at one channel: at least three quarters of the two channels’ combined rate, with a statistical test saying the gap is more than chance. both has no clear difference, neither has no conversations at either, and unsegmented can’t be tied to a channel. outcomes compares how the two channels’ conversations end, with p the test’s p-value.
Change since an earlier period
Section titled “Change since an earlier period”With change, the list covers both periods, and changes groups the listed findings by what happened between them.
{ "changes": { "countedSince": "2026-08-14", "period": { "from": "2026-09-01", "to": "2026-09-30" }, "comparedWith": { "from": "2026-08-02", "to": "2026-08-31" }, "groups": { "came_back": [], "new": [{ "id": "finding-uuid-...", "now": 14, "before": 0, "movement": "up" }], "resolved": [], "grew": [], "faded": [], "same": [], "uncounted": [] } }}now and before count each finding’s conversations in the two periods. movement is up or down only when the difference is more than chance, otherwise same. Ragtime counts findings day by day from countedSince on; when the earlier period starts before that, groups is null.
Where findings happened
Section titled “Where findings happened”curl "https://your-ragtime-instance.com/api/v1/projects/{projectId}/insights/findings/places?status=open" \ -H "Authorization: Bearer rt_live_YOUR_KEY_HERE"Takes the list’s status, kind, from, to, deviceId and lang, and places what the list would list, as the dashboard’s map does. With deviceId or lang, a finding is placed only where those conversations were.
{ "projectId": "proj-uuid-...", "places": [ { "id": "device-uuid-...", "type": "channel", "slug": "lobby-kiosk", "name": "Lobby kiosk", "latitude": 52.37, "longitude": 4.89, "locationLabel": "Main entrance", "polarity": { "attention": 2, "well": 1, "know": 0 }, "findings": [{ "id": "finding-uuid-...", "conversations": 9 }] } ], "unplaced": ["finding-uuid-..."]}A place is a channel with a location (slug set) or a source with one (type: "source", slug: null). unplaced lists the findings with no located place, and the project’s outcomes as a whole. Places are not clustered: that depends on your map’s zoom.
Overview
Section titled “Overview”curl "https://your-ragtime-instance.com/api/v1/projects/{projectId}/insights/findings/overview?range=30d" \ -H "Authorization: Bearer rt_live_YOUR_KEY_HERE"| Parameter | Type | Description |
|---|---|---|
range |
string | 7d, 30d or all (the default). Kept current by Ragtime, free to read. |
from |
string | Or a period of your own (YYYY-MM-DD). Not together with range. |
to |
string | Its end (YYYY-MM-DD). |
{ "projectId": "proj-uuid-...", "overview": { "state": "ready", "sentences": [{ "text": "Visitors keep asking about parking and get no answer.", "findingIds": ["finding-uuid-..."] }], "sessions": 140, "window": { "from": "2026-09-08T00:00:00.000Z", "to": "2026-10-08T00:00:00.000Z" }, "generatedAt": "2026-10-08T03:00:12.000Z", "version": 3, "testData": false }}Every figure comes from Ragtime’s own counts; the AI only phrases the sentences. state is ready, not-enough-data (with sessions and minSessions), nothing-open or pending (not written yet). The overview covers the whole project, like the dashboard’s: it takes no channel or language.
A period of your own is written on request and kept for a day. Writing it spends your organization’s AI credits, so it also counts against the organization-wide rate limit.
Act on a finding
Section titled “Act on a finding”curl -X POST "https://your-ragtime-instance.com/api/v1/projects/{projectId}/insights/findings/{findingId}" \ -H "Authorization: Bearer rt_live_YOUR_KEY_HERE" \ -H "Content-Type: application/json" \ -d '{ "action": "defer", "deferUntil": "2026-11-01" }'| Field | Type | Description |
|---|---|---|
action |
string | Required. resolve, defer, decline, dismiss or reopen. |
deferUntil |
string | Required to defer. A future date (YYYY-MM-DD), taken as the start of that day in UTC; at most 365 days ahead. |
note |
string | Required to decline: why it won’t be addressed, so nobody raises it again (max 2000 characters). |
The rules match the dashboard. A finding that needs attention is resolved, deferred or declined, and anything else is only dismissed or reopened; using the wrong action returns 400. Resolving an already-resolved finding, dismissing a dismissed one or reopening an open one returns 409. Resolving a source finding also resolves the same finding in every other project that shares the source’s library. The finding’s history records the API key that acted.
{ "status": "deferred", "siblingsResolved": 0 }Run the check now
Section titled “Run the check now”curl -X POST "https://your-ragtime-instance.com/api/v1/projects/{projectId}/insights/findings/check" \ -H "Authorization: Bearer rt_live_YOUR_KEY_HERE"Runs the same pass the daily job runs, so repeating it is safe. Returns how many findings it opened, brought back, reopened, confirmed fixed and flagged as rising:
{ "opened": 2, "returned": 0, "reopened": 1, "confirmed": 3, "trending": 1 }Settings, purge and test data
Section titled “Settings, purge and test data”These need the insights:admin scope. Each change is recorded in the audit log with the API key that made it.
| Method | Path | Description |
|---|---|---|
GET |
/insights/settings |
{ "storeTranscripts": true }: whether conversations are kept. |
PATCH |
/insights/settings |
Turn it on or off with { "storeTranscripts": false }. |
POST |
/insights/purge |
Delete conversations. |
GET |
/insights/test-data |
Progress of a generation, and how many test conversations exist. |
POST |
/insights/test-data |
Generate test conversations. |
DELETE |
/insights/test-data |
Remove the test data. |
Purge conversations
Section titled “Purge conversations”curl -X POST "https://your-ragtime-instance.com/api/v1/projects/{projectId}/insights/purge" \ -H "Authorization: Bearer rt_live_YOUR_KEY_HERE" \ -H "Content-Type: application/json" \ -d '{ "from": "2026-01-01", "to": "2026-03-31", "deviceId": "lobby-kiosk" }'| Field | Type | Description |
|---|---|---|
from |
string | First day to purge (YYYY-MM-DD, UTC, inclusive). |
to |
string | Last day to purge (YYYY-MM-DD, UTC, inclusive). |
all |
boolean | true to purge all time. Can’t be combined with from or to. |
deviceId |
string | Only this channel, by its slug. Without it, every channel. |
A purge has no default: give a window, or "all": true. An empty body is a 400. Test conversations in the window go too. Only a purge of all time on every channel also removes the findings, their history and the overviews; anything narrower leaves findings alone.
{ "deletedConversations": 412, "findingsCleared": false, "findingsRemoved": 0 }Generate test data
Section titled “Generate test data”Fills the project with generated conversations, so you can see Insights and findings work before real traffic arrives. Findings and overviews drawn from them are marked testData.
curl -X POST "https://your-ragtime-instance.com/api/v1/projects/{projectId}/insights/test-data" \ -H "Authorization: Bearer rt_live_YOUR_KEY_HERE" \ -H "Content-Type: application/json" \ -d '{ "instruction": "Visitors of a science museum kiosk", "count": 150, "days": 28, "languages": ["nl", "en"], "deviceIds": ["lobby-kiosk"] }'| Field | Type | Default | Description |
|---|---|---|---|
instruction |
string | — | What the conversations are about (max 2,000 characters). |
change |
string | — | How things change over the period, e.g. “complaints about parking grow”. Ragtime plans phases from it. |
count |
integer | 150 |
How many conversations, 1–300. |
days |
integer | 28 |
Over how many days up to today, 1–365. |
languages |
string[] | ["en"] |
Up to six ISO language codes. |
deviceIds |
string[] | — | Up to 50 channel slugs to spread the conversations over. Without, the conversations belong to no channel. |
plan |
object | — | Phases you already planned, { "phases": [...] } (1–6), as the dashboard’s preview makes them. Skips the planning call. |
Out-of-range values are a 400, an unknown channel a 404, and a 402 means your organization’s AI credits are used up: nothing was spent. The call answers 202 once the work is queued:
{ "status": "queued", "queuedConversations": 150, "batches": 15, "phases": 1 }Poll GET /insights/test-data for progress: { generating, analyzing, ready, failed, conversations, active, workerConnected }. While a generation is still running, another POST is a 409. Generating spends your organization’s AI credits, so it also counts against the organization-wide rate limit.
DELETE /insights/test-data removes the test conversations, the findings drawn from them and the overviews they fed. Real conversations and findings stay. While a generation is still running it is a 409, because the queued batches would write test data back:
{ "deletedConversations": 150, "findingsRemoved": 3 }What the API does not cover
Section titled “What the API does not cover”- Findings export. The CSV and JSON export of the findings list is a dashboard action. The list endpoint returns the same data.
- The date format. It is a setting of your browser in the dashboard, not of the project; the export endpoint takes
dateFormatper request.
Credits and rate limits
Section titled “Credits and rate limits”Some calls spend your organization’s AI credits:
POST /insights/query,POST /insights/exportand running a saved query use embedding and LLM credits. When the credits are used up, they fall back to a computed answer without AI instead of failing.GET /insights/findings/overviewspends LLM credits only for a customfrom/towindow. Stored ranges are free.POST /insights/test-dataspends LLM credits, and returns402when they are used up.
Every endpoint is rate limited per API key. The overview for a custom window and test-data generation also count against the organization-wide limit. See Rate limits.
Error Responses
Section titled “Error Responses”Errors use the standard v1 shape, with a stable code:
{ "code": "conflict", "error": "A saved query with that name already exists.", "retryable": false, "hint": "Choose a different `name`, or PATCH the existing saved query instead."}| Status | Code | Meaning |
|---|---|---|
400 |
invalid_request |
Invalid or impossible date, missing question, question too long, a combination of parameters the endpoint refuses, or a finding action missing its deferUntil or note. |
402 |
credits_exhausted |
Your organization’s AI credits are used up (generating test data). |
404 |
not_found |
A referenced device (deviceId, compare or deviceIds), saved query or finding was not found. |
409 |
conflict |
A saved query with that name already exists, the finding is already in the requested state, or test data is still being generated. |
Authentication, scope, project and rate-limit refusals work the same on every endpoint; see Errors.
Using with N8N
Section titled “Using with N8N”Use an HTTP Request node to pull weekly insights into Slack digests, spreadsheets, or BI tools:
// N8N HTTP Request node configuration:// Method: GET// URL: https://your-ragtime-instance.com/api/v1/projects/{projectId}/insights// Authentication: Header Auth// Header Name: Authorization// Header Value: Bearer rt_live_YOUR_KEY_HERE// Query Params:// from: {{ $now.minus(7, 'days').format('yyyy-MM-dd') }}// to: {{ $now.format('yyyy-MM-dd') }}// compareToPrevious: true