Skip to main content

Overview

Moda tracks your Vapi voice AI calls by processing end-of-call report webhooks. Each call is captured with full detail, including conversation turns, tool calls, squad transfers, call analysis, and cost breakdowns.

Setup

pip install moda-ai

Usage

Point your Vapi webhook URL to your server and pass the payload to Moda:
from fastapi import FastAPI, Request
import moda
from moda import process_vapi_end_of_call_report

app = FastAPI()

moda.init("YOUR_MODA_API_KEY")

@app.post("/webhooks/vapi")
async def vapi_webhook(request: Request):
    payload = await request.json()
    process_vapi_end_of_call_report(payload)
    return {"status": "ok"}

Supported Features

FeatureCaptured
Conversation turnsYes
Tool callsYes
Squad transfersYes
Call analysis / summaryYes
Structured dataYes
Cost breakdownYes
Turn latency metricsYes
Recording URLsYes

Configuration

Use ProcessVapiOptions to customize the conversation and user identifiers:
process_vapi_end_of_call_report(payload, {
    "conversation_id": "my_session_123",
    "user_id": "user_456",
})
If not provided, conversationId defaults to call.id and userId defaults to call.customer.number.

What Moda Captures

For each Vapi call, Moda captures a structured hierarchy of data:
Call
  |-- Turn 0          (first assistant turn)
  |-- Turn 1          (second assistant turn)
  |-- Tool Call        (e.g., lookupOrder)
  |-- Squad Transfer   (if applicable)

Call-Level Data

FieldDescription
Conversation IDCall ID or your custom conversation ID
User IDCustomer number or your custom user ID
DurationCall duration in seconds
Total costTotal call cost
Ended reasonReason the call ended
Assistant IDVapi assistant identifier
StatusCall status (e.g., “ended”)
Start / end timeTimestamps for the call
SummaryAI-generated call summary
Structured dataCustom structured data from Vapi
Success evaluationSuccess evaluation result
Cost breakdownSeparate costs for LLM, speech-to-text, and text-to-speech

Turn-Level Data

FieldDescription
User messageWhat the caller said
Assistant responseWhat the assistant replied
Model latencyTime for the LLM to respond (ms)
Voice latencyTime for voice synthesis (ms)
Total latencyEnd-to-end turn latency (ms)

Troubleshooting

No data appearing?
  • Ensure Moda.init() is called before processing webhooks
  • Call Moda.flush() before your process exits to ensure all data is sent
  • Verify your Vapi webhook is configured to send end-of-call-report events
Call appears with no turns?
  • Moda handles both the message-wrapped format (real Vapi webhooks) and the legacy flat format
  • If you see a call with no turns, check that your payload contains conversation data in call.artifact.messages or a transcript array
Transcript not captured?
  • Vapi uses [{role, message}] format for transcripts. Moda automatically normalizes this for display.
For full SDK documentation, see the Python SDK or Node.js SDK guides.