Insights API
Retrieve the conversation insights that power your dashboard’s Insights tab: sentiment, resolution and escalation rates, top topics, tone, and per-day trends. Five endpoints are available:
GET /insights— deterministic metrics and trends for a date range. No AI cost, fast, ideal for 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 findings worth knowing about without asking: sentiment shifts, volume anomalies, 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.
Reading requires an API key with the insights:read scope; creating, updating and deleting saved queries requires insights:write. See API Keys to create one.
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"Query Parameters
Section titled “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. |
Response Format
Section titled “Response Format”{ "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 }'Request Body
Section titled “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. |
Response Format
Section titled “Response Format”{ "projectId": "proj-uuid-...", "question": "How did customer sentiment change this month?", "range": { "from": "2026-03-01", "to": "2026-03-25" }, "compareToPrevious": true, "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": []}The answer is a written summary; relevantMetrics highlights the metrics most relevant to the question. 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"Query Parameters
Section titled “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. |
refresh |
boolean | false |
Bypass the cache and recompute. |
Response Format
Section titled “Response Format”{ "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.pdfRequest Body
Section titled “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. |
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 the same parameters /insights/query accepts — from, to, compareToPrevious, deviceId, compare — 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 }, "createdAt": "2026-03-25T09:12:44.000Z", "updatedAt": "2026-03-25T09:12:44.000Z" }}Rate Limiting
Section titled “Rate Limiting”The metrics, question, highlights, export and run endpoints are rate-limited per API key. Default: 30 requests per minute. Rate limit headers are included in every response:
| Header | Description |
|---|---|
X-RateLimit-Limit |
Maximum requests per window. |
X-RateLimit-Remaining |
Remaining requests in current window. |
X-RateLimit-Reset |
Unix timestamp when the window resets. |
Retry-After |
Seconds to wait (only on 429). |
Error Responses
Section titled “Error Responses”| Status | Meaning |
|---|---|
400 |
Invalid date format, missing question, or question too long. |
401 |
Missing or invalid API key. |
403 |
Key doesn’t match the project or lacks the required scope. |
404 |
A referenced device (deviceId or compare) or saved query was not found. |
409 |
A saved query with that name already exists in the project. |
429 |
Rate limit exceeded. Check Retry-After header. |
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