Skip to main content

Analysis

GET /api/calls/{id}/analysis

Returns the structured business analysis for a completed call.

The shape is open-ended. Every field is optional and the LLM may emit additional keys without breaking older clients. Top-level keys documented below are pinned in code; everything else passes through.

Response — 200 OK

{
"schemaVersion": 2,
"callType": "sales",
"suggestedTitle": "Pricing follow-up with Alex",
"oneLineSummary": "Discussed Q3 roadmap and follow-up demo on Friday.",
"executiveSummary": "The call covered the upcoming product launch, the customer's pricing concerns, and a follow-up demo scheduled for Friday at 11am PT.",
"executiveSummaryBullets": [
{"text": "Customer raised pricing as a blocker for procurement.", "category": "concern", "importance": "high", "sourceSegmentIds": ["seg_0012"]},
{"text": "Friday demo scheduled with procurement present.", "category": "agreement", "importance": "high", "sourceSegmentIds": ["seg_0021"]},
{"text": "Revised quote owed by Wednesday.", "category": "next_steps", "importance": "high", "sourceSegmentIds": ["seg_0015"]}
],
"conversationOutcome": "Agreed on Friday demo; revised pricing to be sent by Wednesday.",
"sections": [
{
"id": "sec_001",
"title": "Customer Pain Points",
"type": "concern",
"summary": "Pricing above $99/seat is a blocker.",
"items": [
{
"text": "Quote needs to come down at least 10% to clear procurement.",
"importance": "high",
"speaker": "Speaker 2",
"sourceSegmentIds": ["seg_0012", "seg_0014"]
}
]
}
],
"keyDiscussionPoints": [
{
"text": "Greeting and brief catch-up on the prior demo.",
"topic": "Catch-up",
"phase": "opening",
"importance": "low",
"sourceSegmentIds": ["seg_0001"]
},
{
"text": "Customer pushed back on the $99/seat tier.",
"topic": "Pricing",
"phase": "middle",
"speakerId": "spk_2",
"speakerLabel": "Speaker 2",
"speakerRole": "CONTACT",
"importance": "high",
"sourceSegmentIds": ["seg_0012", "seg_0014"]
},
{
"text": "Agreed on a Friday demo and a revised quote by Wednesday.",
"topic": "Next steps",
"phase": "closing",
"speakerId": "spk_1",
"speakerLabel": "Speaker 1",
"speakerRole": "USER",
"importance": "high",
"sourceSegmentIds": ["seg_0021", "seg_0015"]
}
],
"actionItems": [
{
"title": "Send Friday demo invite",
"description": "Calendar invite to alex@example.com with Zoom link.",
"ownerSpeaker": "Speaker 1",
"ownerSpeakerId": "spk_1",
"ownerSpeakerLabel": "Speaker 1",
"ownerDisplayName": null,
"ownerRole": "USER",
"dueDate": "2026-05-23",
"priority": "high",
"sourceSegmentIds": ["seg_0021"],
"intent": "meeting",
"intentMetadata": {
"providerHint": "zoom",
"attendees": [{"name": "Alex", "email": "alex@example.com"}],
"proposedAt": "2026-05-23T11:00:00",
"durationMinutes": 30,
"title": "Q3 roadmap demo"
}
}
],
"followUps": [],
"importantDates": [],
"decisions": [],
"commitments": [],
"openQuestions": [],
"risks": [],
"opportunities": [],
"peopleMentioned": [],
"numbersAndAmounts": [],
"sentiment": {
"overall": "positive",
"score": 0.55,
"reason": "Customer is engaged and ready to buy once pricing is resolved.",
"userSentiment": {"overall": "positive", "score": 0.5, "notes": "Confident, focused on next steps."},
"contactSentiment": {"overall": "positive", "score": 0.6, "notes": "Cooperative; pricing remains the only friction."},
"progression": [
{"phase": "opening", "overall": "neutral", "note": "Brief catch-up", "sourceSegmentIds": ["seg_0001"]},
{"phase": "middle", "overall": "mixed", "note": "Pricing pushback", "sourceSegmentIds": ["seg_0012"]},
{"phase": "closing", "overall": "positive", "note": "Agreement on demo and quote", "sourceSegmentIds": ["seg_0021"]}
],
"emotionalSignals": ["confident", "cooperative"]
},
"tone": {
"overall": "professional",
"descriptors": ["measured", "cooperative"],
"formality": "semi-formal",
"energy": "medium",
"pace": "normal",
"notes": "Both speakers stayed polite; brief escalation during pricing.",
"byParty": {
"userTone": {"overall": "supportive", "descriptors": ["calm", "explanatory"], "notes": "Stayed measured even when pushed."},
"contactTone": {"overall": "transactional", "descriptors": ["direct", "task-focused"], "notes": "Pragmatic and to the point."}
}
},
"tags": ["sales", "roadmap", "pricing"],
"qualityWarnings": [],

"shortSummary": "Discussed Q3 roadmap and follow-up demo on Friday.",
"detailedSummary": "The call covered the upcoming product launch, the customer's pricing concerns, and a follow-up demo scheduled for Friday at 11am PT.",
"keyPoints": [
"Quote needs to come down at least 10% to clear procurement."
]
}

Top-level fields

FieldTypeNotes
schemaVersionint2. v1 artifacts are still served unchanged.
callTypestringpersonal | business | sales | support | interview | finance | healthcare | legal | education | unknown | other
suggestedTitlestringHeadline.
oneLineSummarystringA single sentence. Mirrored as shortSummary for legacy clients.
executiveSummarystringMulti-paragraph prose summary. Mirrored as detailedSummary for legacy clients.
executiveSummaryBulletsSummaryBullet[]v2 — 3–7 scannable bullets paralleling executiveSummary.
conversationOutcomestringWhat was decided / resolved.
sectionsSection[]Open-ended, model-defined thematic groupings.
keyDiscussionPointsDiscussionPoint[]v2 — chronological bullet view of the call's discussion flow.
actionItemsActionItem[]Snapshot of action items at analysis time. Prefer /api/actions for editable state.
followUps / importantDates / decisions / commitments / openQuestions / risks / opportunities / peopleMentioned / numbersAndAmountstyped arraysAll optional; empty when the model has no evidence.
sentimentSentimentv2 extended — polarity, score, per-party breakdown, progression timeline, emotional signals.
toneTonev2 new — register (formality / energy / pace), descriptors, per-party tone.
tagsstring[]Short lowercase tags for search/filter.
qualityWarningsstring[]Audio / transcript issues flagged by the model.

v2 nested types

SummaryBullet

A scannable bullet inside executiveSummaryBullets. Aim for 3–7 of these.

FieldTypeNotes
textstringSentence fragment or short sentence.
categorystringcontext | outcome | next_steps | concern | agreement | decision | blocker | observation
importancestringlow | medium | high
sourceSegmentIdsstring[]Segment ids backing the bullet.

DiscussionPoint

A point on the chronological discussion timeline inside keyDiscussionPoints.

FieldTypeNotes
textstringWhat was discussed at this point.
topicstringFree-form topic label, e.g. Pricing, Delivery timeline.
phasestringopening | middle | closing | followup
speakerIdstringStable transcript id (e.g. spk_1) when one speaker drove this point; null for joint discussion.
speakerLabelstringDisplay label (Speaker 1 or refined name).
speakerDisplayNamestringRefined display name when known.
speakerRolestringUSER | CONTACT | UNKNOWN
importancestringlow | medium | high
sourceSegmentIdsstring[]Segment ids backing this point.

Sentiment (v2)

Polarity and how it evolved through the call.

FieldTypeNotes
overallstringpositive | neutral | negative | mixed | unclear
scorenumber[-1.0, 1.0]. Null when truly unclear.
reasonstringShort rationale.
userSentimentSpeakerSentimentPhone owner's polarity read.
contactSentimentSpeakerSentimentOther party's polarity read. May disagree with userSentiment.
progressionSentimentMoment[]2–4 points along the call capturing shifts.
emotionalSignalsstring[]0–6 short adjective tags, grounded in the transcript (e.g. frustrated, appreciative, relieved).

SpeakerSentiment: { overall, score, notes }.

SentimentMoment: { phase, overall, note, sourceSegmentIds } where phase ∈ {opening, middle, closing, followup}.

Tone (v2)

The register of the conversation — how it was said. Distinct from sentiment, which is polarity.

FieldTypeNotes
overallstringHeadline label, e.g. professional, friendly, tense, urgent, supportive, transactional, escalated, empathetic, terse, playful, confrontational, informational, casual, formal-business, conversational.
descriptorsstring[]1–4 short adjectives.
formalitystringformal | semi-formal | informal
energystringlow | medium | high
pacestringslow | normal | fast
notesstring1–2 sentence rationale.
byParty.userTonePartyToneTone read for the phone owner.
byParty.contactTonePartyToneTone read for the other party. They commonly differ.

PartyTone: { overall, descriptors, notes }.

ActionItem

A task extracted from the call. Also persisted to Postgres for editable state — see Action items.

FieldTypeNotes
titlestringShort action title.
descriptionstringLonger context.
ownerSpeakerstringLegacy alias for ownerSpeakerLabel.
ownerSpeakerIdstringStable spk_N from the normalised transcript.
ownerSpeakerLabelstringDisplay label at extraction time.
ownerDisplayNamestringRefined name when known.
ownerRolestringUSER | CONTACT | UNKNOWN
dueDatestringYYYY-MM-DD or null.
prioritystringlow | medium | high
sourceSegmentIdsstring[]Segment ids cited as evidence.
intentstringProvider-neutral classification: meeting | email | call | message | reminder | task | none
intentMetadataActionIntentMetadataTyped payload for deep-link construction. See Action items · Intent classification.

ActionIntentMetadata

Optional metadata the LLM extracts to help a client launch the right external app. Every field is nullable — the model is instructed never to invent values.

FieldTypeNotes
providerHintstringWhen explicit: meet | zoom | teams | phone (meetings) or whatsapp | sms | telegram (messages). A hint, not a decision.
attendees{name, email?}[]Meeting attendees. Email must appear in the transcript.
proposedAtstringISO-8601 datetime for a meeting.
durationMinutesintMeeting length when mentioned.
titlestringEvent / reminder title override.
locationstringPhysical location when explicit.
toEmailstringEmail recipient — must appear in the transcript.
toNamestringRecipient display name.
subjectstringSuggested email subject (composed draft).
bodyPreviewstring1–2 sentence draft body (composed).
phoneNumberstringOnly when a different number than the current call was named.
contactNamestringWho to call / message.
channelstringwhatsapp | sms | telegram when explicit.
handlestringChat handle when mentioned.
remindAtstringISO-8601 datetime for a reminder.
notesstringShort notes for task / reminder intents.

Legacy aliases

The endpoint always emits these alongside the v2 shape so older mobile builds keep working:

Legacy fieldSource
shortSummaryoneLineSummary
detailedSummaryexecutiveSummary
keyPointstext of all section items with importance == "high", in section + item order

actionItems and tags have the same field names in both shapes — they pass through unchanged. Aliases are added only when the new fields are present. If a stored artifact is already in a legacy shape (rare; only for pre-refactor rows), it's returned untouched.

Errors

StatusCause
404Call missing or owned by another user, or no analysis artifact exists yet.

Notes

  • For editable, server-side action item state (mark done) use PATCH /api/actions/{id}. The actionItems inside this JSON are a point-in-time snapshot from the LLM.
  • The sourceSegmentIds arrays reference normalised transcript segment ids. If the model has no evidence to cite for a claim, the array is empty rather than invented.
  • Sentiment and tone are produced by the LLM with explicit guard-rails — when speakers are brief or terse, the model is asked to prefer unclear and lower-magnitude scores rather than over-claim.