Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.mavera.io/llms.txt

Use this file to discover all available pages before exploring further.

Scenario

Call recordings from sales calls, support calls, and consultations contain the richest customer language — tone, objections, questions, and commitments. This job fetches recordings, transcribes them (via Twilio’s built-in transcription or an external service), then runs the transcript through Mave for meeting-style analysis: key topics, action items, sentiment flow, and follow-up recommendations. Flow: Twilio GET /Recordings → Fetch transcription → Mavera POST /mave/chat → Meeting-style analysis report

Code

import os, requests, time

TW_SID = os.environ["TWILIO_ACCOUNT_SID"]
TW_TOKEN = os.environ["TWILIO_AUTH_TOKEN"]
TW_AUTH = (TW_SID, TW_TOKEN)
TW_BASE = f"https://api.twilio.com/2010-04-01/Accounts/{TW_SID}"
MV = os.environ["MAVERA_API_KEY"]
MV_BASE = "https://app.mavera.io/api/v1"
MV_H = {"Authorization": f"Bearer {MV}", "Content-Type": "application/json"}

# 1. List recent recordings
r = requests.get(f"{TW_BASE}/Recordings.json", auth=TW_AUTH,
    params={"PageSize": 10})
r.raise_for_status()
recordings = r.json().get("recordings", [])
print(f"Found {len(recordings)} recordings")

# 2. Fetch transcriptions
analyzed = []
for rec in recordings[:5]:
    rec_sid = rec.get("sid", "")
    duration = int(rec.get("duration", 0))
    date = rec.get("date_created", "")[:10]

    tr = requests.get(f"{TW_BASE}/Recordings/{rec_sid}/Transcriptions.json", auth=TW_AUTH)
    if not tr.ok or not tr.json().get("transcriptions"):
        print(f"  {rec_sid}: No transcription available (duration: {duration}s)")
        continue

    transcriptions = tr.json()["transcriptions"]
    transcript_text = ""
    for t in transcriptions:
        t_sid = t.get("sid", "")
        t_detail = requests.get(f"{TW_BASE}/Transcriptions/{t_sid}.json", auth=TW_AUTH)
        if t_detail.ok:
            transcript_text += t_detail.json().get("transcription_text", "")
    
    if transcript_text:
        analyzed.append({
            "sid": rec_sid, "duration": duration, "date": date,
            "transcript": transcript_text[:3000],
        })
        print(f"  {rec_sid}: {duration}s, {len(transcript_text):,} chars transcribed")
    time.sleep(0.5)

if not analyzed:
    print("No transcriptions found. Ensure recording transcription is enabled in Twilio.")

# 3. Analyze each call via Mave
for call in analyzed:
    analysis = requests.post(f"{MV_BASE}/mave/chat", headers=MV_H, json={
        "message": f"Meeting analyst. Analyze this {call['duration']}s call recording transcript from {call['date']}.\n\n"
            f"TRANSCRIPT:\n{call['transcript']}\n\n"
            "Produce a CALL ANALYSIS REPORT:\n\n"
            "1. **Call Summary** — 2-3 sentence overview\n"
            "2. **Key Topics Discussed** — Bulleted list with time estimates\n"
            "3. **Customer Sentiment Flow** — How did sentiment change through the call?\n"
            "4. **Questions Asked** — By the customer (signals interest/concern areas)\n"
            "5. **Objections Raised** — With how they were handled\n"
            "6. **Commitments Made** — By both parties\n"
            "7. **Action Items** — What needs to happen next\n"
            "8. **Call Score** — Rate the call quality (1-10) with reasoning\n"
            "9. **Coaching Notes** — 2-3 suggestions for the rep\n\n"
            "Be specific. Reference transcript content."
    }).json()

    print(f"\n{'='*60}\nCALL ANALYSIS: {call['sid']} ({call['duration']}s, {call['date']})\n{'='*60}")
    print(analysis.get("content", "")[:2500])

Example Output

Found 10 recordings
  RE_abc123: 347s, 4,231 chars transcribed
  RE_def456: 892s, 11,456 chars transcribed

CALL ANALYSIS: RE_abc123 (347s, 2026-03-12)
============================================================

1. SUMMARY: Sales discovery call with mid-market prospect. Customer
   is evaluating 3 vendors. Main concerns: pricing transparency and
   implementation timeline. Call ended with agreement to schedule demo.

2. KEY TOPICS:
   • Current pain points with existing tool (0:00-2:30)
   • Feature comparison vs Competitor X (2:30-4:00)
   • Pricing discussion (4:00-5:00) — customer pushed back on per-seat
   • Implementation timeline (5:00-5:30)

3. SENTIMENT FLOW:
   Opened positive (curious) → Dipped at pricing ("that's more than
   we expected") → Recovered after ROI framing → Ended cautiously positive

5. OBJECTIONS:
   a) "Per-seat pricing doesn't work for us — we have seasonal staff"
      → Rep offered annual plan with flexible seats. Partially resolved.
   b) "Your competitor does this for free"
      → Rep: "Free tier doesn't include SSO or audit logs." Effective.

8. CALL SCORE: 7/10
   Strong discovery questions. Pricing objection handling was adequate
   but could be sharper — missed opportunity to quantify ROI.

9. COACHING:
   • Prepare ROI calculator before pricing discussions
   • Ask "What does your budget process look like?" before quoting
   • Mirror customer's exact language when restating pain points

Error Handling

Twilio’s built-in transcription is English-only and may not be enabled by default. Enable via TwiML <Record transcribe="true">. For higher quality, use AssemblyAI or Deepgram on the recording audio URL.
Recordings are stored for the retention period configured in your Twilio Console (default: indefinitely). Access the audio at https://api.twilio.com/2010-04-01/Accounts/{sid}/Recordings/{RecordingSid}.mp3.
Calls over 15 minutes produce large transcripts. The code limits to 3,000 chars. For full analysis of long calls, split the transcript into segments and analyze each separately, then summarize.
Twilio transcription doesn’t separate speakers. For speaker-attributed analysis, use a service like AssemblyAI with speaker labels, then format as Agent: ... / Customer: ... before sending to Mave.