Chanl

Call Logs

Every interaction captured — full transcripts with speaker turns, timestamps, audio playback, and every tool call traced

Every Interaction, Fully Captured

Call logs (called Interactions in the Chanl data model) are the complete record of every conversation your agents have — voice calls, chat sessions, SMS threads, and test simulations. Each one includes full transcripts with speaker turns and timestamps, audio playback, tool call traces, sentiment analysis, cost data, and quality metrics.

You can't improve what you can't measure. This is where you measure.

What's Inside an Interaction

Every call log captures two things: the metadata about the conversation, and the content of the conversation itself.

Metadata

  • Source provider (VAPI, Retell, Bland, etc.)
  • Phone numbers (from/to)
  • Date, time, and duration
  • Agent that handled it
  • Cost and provider metadata
  • Simulation vs. real customer call

Content and Analysis

  • Full audio recording with playback
  • Complete transcript with speaker turns and timestamps
  • Every tool call the agent made (traced with inputs/outputs)
  • Quality score (if evaluated)
  • Sentiment analysis
  • Extracted data and tags

Browsing Interactions

The call logs view gives you a searchable, filterable list of every conversation. Sort by date, score, duration, or agent to find what you're looking for.

curl https://api.chanl.ai/v1/call-logs \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d '{
    "limit": 50,
    "sortBy": "date",
    "order": "desc"
  }'
import Chanl from "@chanl/sdk";

const chanl = new Chanl({ apiKey: "YOUR_API_KEY" });

const logs = await chanl.callLogs.list({
  limit: 50,
  sortBy: "date",
  order: "desc",
});

for (const call of logs.calls) {
  console.log(`${call.date} — ${call.agent} — Score: ${call.score}`);
}
from chanl import Chanl

chanl = Chanl(api_key="YOUR_API_KEY")

logs = chanl.call_logs.list(
    limit=50,
    sort_by="date",
    order="desc"
)

for call in logs.calls:
    print(f"{call.date}{call.agent} — Score: {call.score}")
{
  "calls": [
    {
      "id": "call_abc123",
      "source": "vapi",
      "from": "+1234567890",
      "to": "+1987654321",
      "agent": "agent-v1",
      "date": "2024-01-15T14:30:00Z",
      "duration": 245,
      "score": 87,
      "analyzed": true,
      "isSimulation": false
    }
  ],
  "total": 1247,
  "page": 1
}

Transcripts

The transcript is the text representation of an interaction — auto-generated from voice via speech-to-text, or captured directly from chat messages. Each segment includes a timestamp, speaker identification, and the exact words spoken.

curl https://api.chanl.ai/v1/call-logs/call_abc123/transcript \
  -H "Authorization: Bearer YOUR_API_KEY"
const transcript = await chanl.callLogs.getTranscript("call_abc123");

for (const segment of transcript.segments) {
  console.log(`[${segment.timestamp}s] ${segment.speaker}: ${segment.text}`);
}
transcript = chanl.call_logs.get_transcript("call_abc123")

for segment in transcript.segments:
    print(f"[{segment.timestamp}s] {segment.speaker}: {segment.text}")
{
  "callId": "call_abc123",
  "transcript": [
    {
      "speaker": "agent",
      "timestamp": 0,
      "text": "Thank you for calling. How can I help you today?"
    },
    {
      "speaker": "customer",
      "timestamp": 3.2,
      "text": "I received a damaged product and need a replacement."
    },
    {
      "speaker": "agent",
      "timestamp": 6.8,
      "text": "I'm sorry to hear that. Let me help you with a replacement right away."
    }
  ],
  "duration": 245,
  "wordCount": 487
}

Reading transcripts is how teams find failure patterns. Search across thousands of conversations for specific phrases, tool failures, or escalation triggers.

Tool Call Traces

Every tool call your agent made during the conversation is recorded — what it called, what inputs it sent, what came back, and how long it took. This is how you debug agent behavior without guessing.

When your agent looks up an order, checks inventory, or creates a ticket, you'll see each step in the trace. If a tool failed or returned unexpected data, you'll see that too.

Audio Playback

Stream or download the original recording:

curl https://api.chanl.ai/v1/call-logs/call_abc123/audio \
  -H "Authorization: Bearer YOUR_API_KEY"
const audio = await chanl.callLogs.getAudio("call_abc123");

console.log(`URL: ${audio.url}`);
console.log(`Expires: ${audio.expiresAt}`);
console.log(`Duration: ${audio.duration}s`);
audio = chanl.call_logs.get_audio("call_abc123")

print(f"URL: {audio.url}")
print(f"Expires: {audio.expires_at}")
print(f"Duration: {audio.duration}s")
{
  "url": "https://chanl-audio.s3.amazonaws.com/...",
  "expiresAt": "2024-01-15T12:00:00Z",
  "format": "mp3",
  "duration": 245,
  "size": 3145728
}

Audio URLs are signed and expire after 1 hour. Request a new URL if the link has expired.

Searching Interactions

Filter by Score, Date, Agent, or Source

Find exactly the calls you're looking for:

curl "https://api.chanl.ai/v1/call-logs?minScore=0&maxScore=70" \
  -H "Authorization: Bearer YOUR_API_KEY"
curl "https://api.chanl.ai/v1/call-logs" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d '{
    "dateRange": {
      "start": "2024-01-01",
      "end": "2024-01-31"
    }
  }'
curl "https://api.chanl.ai/v1/call-logs?agent=agent-v1" \
  -H "Authorization: Bearer YOUR_API_KEY"
curl "https://api.chanl.ai/v1/call-logs?isSimulation=false" \
  -H "Authorization: Bearer YOUR_API_KEY"

Search Within Transcripts

Find conversations where specific phrases were mentioned. This is how you discover that 80% of escalations happen when customers say "refund policy" — then fix it proactively.

curl -X POST https://api.chanl.ai/v1/call-logs/search \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "query": "refund policy",
    "dateRange": "30d",
    "minScore": 0,
    "maxScore": 75
  }'
const results = await chanl.callLogs.search({
  query: "refund policy",
  dateRange: "30d",
  minScore: 0,
  maxScore: 75,
});

console.log(`Found ${results.totalResults} calls`);
for (const r of results.results) {
  console.log(`Call ${r.callId} — Score: ${r.score}`);
}
results = chanl.call_logs.search(
    query="refund policy",
    date_range="30d",
    min_score=0,
    max_score=75
)

print(f"Found {results.total_results} calls")
for r in results.results:
    print(f"Call {r.call_id} — Score: {r.score}")
{
  "results": [
    {
      "callId": "call_xyz789",
      "date": "2024-01-14T10:22:00Z",
      "score": 68,
      "matches": [
        {
          "speaker": "customer",
          "text": "What's your refund policy?",
          "timestamp": 45
        },
        {
          "speaker": "agent",
          "text": "Our refund policy allows returns within 30 days",
          "timestamp": 48
        }
      ]
    }
  ],
  "totalResults": 23
}

Analyzing Interactions

Score a Call After the Fact

Got calls that weren't evaluated when they happened? Run analysis with any scorecard:

curl -X POST https://api.chanl.ai/v1/call-logs/call_abc123/analyze \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "scorecard": "customer-service-quality"
  }'
const analysis = await chanl.callLogs.analyze("call_abc123", {
  scorecard: "customer-service-quality",
});

console.log(`Overall score: ${analysis.overallScore}`);
console.log(`Strengths: ${analysis.analysis.strengths.join(", ")}`);
console.log(`Recommendations: ${analysis.analysis.recommendations.join(", ")}`);
analysis = chanl.call_logs.analyze("call_abc123",
    scorecard="customer-service-quality"
)

print(f"Overall score: {analysis.overall_score}")
print(f"Strengths: {', '.join(analysis.analysis.strengths)}")
print(f"Recommendations: {', '.join(analysis.analysis.recommendations)}")
{
  "callId": "call_abc123",
  "overallScore": 87,
  "analysis": {
    "strengths": [
      "Showed immediate empathy for customer's issue",
      "Offered solution within first minute",
      "Confirmed customer satisfaction before ending"
    ],
    "weaknesses": [
      "Didn't verify customer identity before processing",
      "Missed opportunity to mention protection plan"
    ],
    "recommendations": [
      "Add identity verification step to prompt",
      "Include relevant product suggestions during replacement scenarios"
    ]
  },
  "categoryScores": {
    "Communication": 92,
    "Problem Resolution": 88,
    "Compliance": 79
  }
}

Batch Analysis

Score an entire week's worth of calls at once:

const results = await chanl.callLogs.batchAnalyze({
  filters: {
    dateRange: { start: "2024-01-08", end: "2024-01-15" },
    analyzed: false,
  },
  scorecard: "customer-service-quality",
});

console.log(`Analyzed ${results.count} calls`);
console.log(`Average score: ${results.avgScore}`);
results = chanl.call_logs.batch_analyze(
    filters={
        "date_range": {"start": "2024-01-08", "end": "2024-01-15"},
        "analyzed": False
    },
    scorecard="customer-service-quality"
)

print(f"Analyzed {results.count} calls")
print(f"Average score: {results.avg_score}")

Exporting Data

Pull call data into your own tools for deeper analysis or compliance records.

curl -X POST https://api.chanl.ai/v1/call-logs/export \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "format": "csv",
    "dateRange": "30d",
    "fields": ["date", "agent", "score", "duration"]
  }' > calls_export.csv
curl -X POST https://api.chanl.ai/v1/call-logs/export \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "format": "json",
    "dateRange": "30d",
    "includeTranscripts": true,
    "includeAnalysis": true
  }' > calls_export.json
curl -X POST https://api.chanl.ai/v1/call-logs/export \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "format": "zip",
    "dateRange": "7d",
    "includeAudio": true,
    "includeTranscripts": true
  }' > calls_with_audio.zip

Finding Training Data

Your best and worst calls are training data. Use them.

High-Quality Examples

Find top-scoring calls to use as fine-tuning data:

const topCalls = await chanl.callLogs.list({
  minScore: 90,
  dateRange: "90d",
  limit: 50,
  sortBy: "score",
  order: "desc",
});

const trainingData = await chanl.fineTuning.prepareDataset({
  calls: topCalls.map((c) => c.id),
  format: "conversational",
});

console.log(`Prepared ${topCalls.length} high-quality examples for training`);

Failure Pattern Detection

Find recurring problems across low-scoring calls:

const patterns = await chanl.callLogs.analyzePatterns({
  filters: { maxScore: 70, dateRange: "30d" },
  groupBy: "issue_type",
});

for (const p of patterns) {
  console.log(`${p.issue}: ${p.count} occurrences (${p.percentage}%)`);
}

// Output:
// Refund policy confusion: 23 occurrences (34%)
// Unable to verify customer: 15 occurrences (22%)
// Tool failure: 12 occurrences (18%)

Compliance and Auditing

Find calls that are missing required disclosures for regulatory review:

curl -X POST https://api.chanl.ai/v1/call-logs/compliance-search \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "dateRange": {
      "start": "2024-01-01",
      "end": "2024-01-31"
    },
    "requiredDisclosures": [
      "data_privacy_notice",
      "call_recording_notice"
    ],
    "onlyFlagged": true
  }'
{
  "flaggedCalls": [
    {
      "callId": "call_compliance123",
      "date": "2024-01-15T09:30:00Z",
      "missingDisclosures": ["call_recording_notice"],
      "severity": "high"
    }
  ],
  "totalFlagged": 3,
  "complianceRate": 98.7
}

Troubleshooting

What's Next?

Analytics

See aggregate performance trends across all interactions

Alerts

Get notified automatically when calls go wrong

Fine-Tuning

Turn your best calls into training data

Prompts

Update agent instructions based on what you find here

On this page