Calls API
Get Call Details
Retrieve detailed information about a specific call including transcript, summary, and LiveKit status
Get Call Details
Retrieve comprehensive information about a specific call, including full transcript, summary, duration, LiveKit room status, and metadata.
Endpoint
GET /api/v1/calls/{callId}Authentication
Requires API key in request headers:
x-api-key: YOUR_API_KEYPath Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
callId | string | Yes | Unique call identifier |
Response
Returns detailed call information including transcript and LiveKit status.
Response Schema
{
"data": {
"id": "string",
"status": "string",
"direction": "inbound|outbound",
"phoneNumber": "string",
"duration": "integer|null",
"startedAt": "string|null",
"endedAt": "string|null",
"failureReason": "string|null",
"agent": {
"id": "string",
"name": "string",
"type": "voice"
},
"summary": "string|null",
"transcript": "array|null",
"metadata": "object",
"roomId": "string|null",
"jobId": "string|null",
"sipParticipantId": "string|null",
"liveRoomStatus": {
"roomExists": "boolean",
"numParticipants": "integer",
"participants": "array"
},
"createdAt": "string",
"updatedAt": "string"
}
}Field Descriptions
id: Unique call identifierstatus: Current call status (initiated, connecting, ringing, active, completed, failed, cancelled, no_answer, busy)direction: Call direction (inbound/outbound)phoneNumber: Phone number involved in the callduration: Call duration in seconds (null if not completed)startedAt: When the call started (ISO 8601)endedAt: When the call ended (ISO 8601)failureReason: Reason for failure (if applicable)agent: Agent information objectsummary: AI-generated call summarytranscript: Array of conversation messagesmetadata: Additional call metadataroomId: LiveKit room IDjobId: LiveKit job IDsipParticipantId: SIP participant identifierliveRoomStatus: Real-time LiveKit room status (only for active calls)createdAt: Call creation timestampupdatedAt: Last update timestamp
Examples
Basic Request
curl -X GET "https://v2.heppu.ai/api/v1/calls/call_abc123" \
-H "x-api-key: YOUR_API_KEY"const callId = 'call_abc123';
const response = await fetch(`https://v2.heppu.ai/api/v1/calls/${callId}`, {
method: 'GET',
headers: {
'x-api-key': 'YOUR_API_KEY'
}
});
const data = await response.json();
console.log('Call details:', data.data);import requests
call_id = 'call_abc123'
response = requests.get(
f'https://v2.heppu.ai/api/v1/calls/{call_id}',
headers={'x-api-key': 'YOUR_API_KEY'}
)
data = response.json()
print(f"Call details: {data['data']}")Get Transcript
curl -X GET "https://v2.heppu.ai/api/v1/calls/call_abc123" \
-H "x-api-key: YOUR_API_KEY" \
| jq '.data.transcript'async function getCallTranscript(callId) {
const response = await fetch(`https://v2.heppu.ai/api/v1/calls/${callId}`, {
headers: { 'x-api-key': 'YOUR_API_KEY' }
});
const data = await response.json();
return data.data.transcript;
}
const transcript = await getCallTranscript('call_abc123');
transcript?.forEach((message, index) => {
console.log(`[${message.role}]: ${message.content}`);
});def get_call_transcript(call_id):
response = requests.get(
f'https://v2.heppu.ai/api/v1/calls/{call_id}',
headers={'x-api-key': 'YOUR_API_KEY'}
)
data = response.json()
return data['data'].get('transcript', [])
transcript = get_call_transcript('call_abc123')
for message in transcript:
print(f"[{message['role']}]: {message['content']}")Check Live Call Status
curl -X GET "https://v2.heppu.ai/api/v1/calls/call_abc123" \
-H "x-api-key: YOUR_API_KEY" \
| jq '.data.liveRoomStatus'async function checkLiveCallStatus(callId) {
const response = await fetch(`https://v2.heppu.ai/api/v1/calls/${callId}`, {
headers: { 'x-api-key': 'YOUR_API_KEY' }
});
const data = await response.json();
const call = data.data;
if (call.liveRoomStatus && call.liveRoomStatus.roomExists) {
console.log(`Call is active with ${call.liveRoomStatus.numParticipants} participants`);
return {
isActive: true,
participants: call.liveRoomStatus.numParticipants
};
}
return {
isActive: false,
status: call.status
};
}def check_live_call_status(call_id):
response = requests.get(
f'https://v2.heppu.ai/api/v1/calls/{call_id}',
headers={'x-api-key': 'YOUR_API_KEY'}
)
data = response.json()
call = data['data']
if call.get('liveRoomStatus') and call['liveRoomStatus'].get('roomExists'):
print(f"Call is active with {call['liveRoomStatus']['numParticipants']} participants")
return {
'is_active': True,
'participants': call['liveRoomStatus']['numParticipants']
}
return {
'is_active': False,
'status': call['status']
}Response Examples
Completed Call with Transcript
{
"data": {
"id": "call_abc123",
"status": "completed",
"direction": "outbound",
"phoneNumber": "+14155552671",
"duration": 245,
"startedAt": "2025-12-01T14:00:00Z",
"endedAt": "2025-12-01T14:04:05Z",
"failureReason": null,
"agent": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "Customer Support Agent",
"type": "voice"
},
"summary": "Customer called to inquire about order status. Provided tracking information and estimated delivery date of December 5th. Customer satisfied with response.",
"transcript": [
{
"role": "assistant",
"content": "Hello! This is the Customer Support Agent. How can I help you today?",
"timestamp": "2025-12-01T14:00:05Z"
},
{
"role": "user",
"content": "Hi, I wanted to check on my order status. My order number is 12345.",
"timestamp": "2025-12-01T14:00:15Z"
},
{
"role": "assistant",
"content": "Let me look that up for you. One moment please.",
"timestamp": "2025-12-01T14:00:20Z"
},
{
"role": "assistant",
"content": "I found your order. It's currently in transit and scheduled to arrive on December 5th. Your tracking number is 1Z999AA10123456784.",
"timestamp": "2025-12-01T14:00:35Z"
},
{
"role": "user",
"content": "Great, thank you so much!",
"timestamp": "2025-12-01T14:00:42Z"
},
{
"role": "assistant",
"content": "You're welcome! Is there anything else I can help you with?",
"timestamp": "2025-12-01T14:00:45Z"
},
{
"role": "user",
"content": "No, that's all. Thanks!",
"timestamp": "2025-12-01T14:00:50Z"
}
],
"metadata": {
"caller_id": "+14155551234",
"from_phone_number": "+14155551234",
"priority": 5,
"source": "api",
"contact": {
"firstName": "John",
"lastName": "Doe",
"company": "Acme Corp"
}
},
"roomId": "room_xyz789",
"jobId": "job_123",
"sipParticipantId": "sip_456",
"liveRoomStatus": null,
"createdAt": "2025-12-01T13:59:55Z",
"updatedAt": "2025-12-01T14:04:05Z"
}
}Active Call with LiveKit Status
{
"data": {
"id": "call_def456",
"status": "active",
"direction": "outbound",
"phoneNumber": "+14155552672",
"duration": null,
"startedAt": "2025-12-01T15:30:00Z",
"endedAt": null,
"failureReason": null,
"agent": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "Sales Agent",
"type": "voice"
},
"summary": null,
"transcript": [
{
"role": "assistant",
"content": "Hello! This is the Sales Agent calling from Acme Corp. May I speak with Jane Smith?",
"timestamp": "2025-12-01T15:30:05Z"
},
{
"role": "user",
"content": "Yes, this is Jane.",
"timestamp": "2025-12-01T15:30:10Z"
}
],
"metadata": {
"caller_id": "+14155551234",
"priority": 8,
"source": "api_batch",
"campaignId": "holiday-2025"
},
"roomId": "room_live123",
"jobId": "job_live456",
"sipParticipantId": "sip_live789",
"liveRoomStatus": {
"roomExists": true,
"numParticipants": 2,
"participants": [
{
"identity": "agent",
"name": "Sales Agent"
},
{
"identity": "caller",
"name": "+14155552672"
}
]
},
"createdAt": "2025-12-01T15:29:50Z",
"updatedAt": "2025-12-01T15:30:10Z"
}
}Failed Call
{
"data": {
"id": "call_ghi789",
"status": "failed",
"direction": "outbound",
"phoneNumber": "+14155552673",
"duration": null,
"startedAt": "2025-12-01T16:00:00Z",
"endedAt": "2025-12-01T16:00:15Z",
"failureReason": "no_answer",
"agent": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "Support Agent",
"type": "voice"
},
"summary": null,
"transcript": null,
"metadata": {
"caller_id": "+14155551234",
"priority": 5,
"retryConfig": {
"maxRetries": 3,
"retryOnNoAnswer": true
}
},
"roomId": null,
"jobId": null,
"sipParticipantId": null,
"liveRoomStatus": null,
"createdAt": "2025-12-01T15:59:55Z",
"updatedAt": "2025-12-01T16:00:15Z"
}
}Error Responses
Call Not Found
{
"error": {
"message": "Call not found",
"code": 404
}
}Unauthorized
{
"error": {
"message": "Unauthorized",
"code": 401
}
}Access Denied
{
"error": {
"message": "Access denied - call belongs to different organization",
"code": 403
}
}Use Cases
Call Analytics and Reporting
async function analyzeCall(callId) {
const response = await fetch(`https://v2.heppu.ai/api/v1/calls/${callId}`, {
headers: { 'x-api-key': 'YOUR_API_KEY' }
});
const { data: call } = await response.json();
return {
duration: call.duration,
outcome: call.status,
summary: call.summary,
messageCount: call.transcript?.length || 0,
avgResponseTime: calculateAvgResponseTime(call.transcript),
sentiment: analyzeSentiment(call.transcript)
};
}
function calculateAvgResponseTime(transcript) {
if (!transcript || transcript.length < 2) return 0;
let responseTimes = [];
for (let i = 1; i < transcript.length; i++) {
const current = new Date(transcript[i].timestamp);
const previous = new Date(transcript[i-1].timestamp);
responseTimes.push((current - previous) / 1000); // in seconds
}
return responseTimes.reduce((a, b) => a + b, 0) / responseTimes.length;
}Monitor Active Calls
import time
def monitor_active_call(call_id, interval=5):
"""Poll call status every interval seconds until call completes"""
while True:
response = requests.get(
f'https://v2.heppu.ai/api/v1/calls/{call_id}',
headers={'x-api-key': 'YOUR_API_KEY'}
)
data = response.json()
call = data['data']
print(f"Status: {call['status']}")
if call.get('liveRoomStatus') and call['liveRoomStatus'].get('roomExists'):
print(f"Active participants: {call['liveRoomStatus']['numParticipants']}")
# Check if call is complete
if call['status'] in ['completed', 'failed', 'cancelled', 'no_answer']:
print(f"Call ended. Duration: {call.get('duration')} seconds")
print(f"Summary: {call.get('summary')}")
break
time.sleep(interval)Extract Transcript for Training
def extract_transcript_for_training(call_id):
"""Extract and format transcript for AI training"""
response = requests.get(
f'https://v2.heppu.ai/api/v1/calls/{call_id}',
headers={'x-api-key': 'YOUR_API_KEY'}
)
data = response.json()
call = data['data']
if not call.get('transcript'):
return None
# Format for training
formatted = {
'call_id': call['id'],
'agent_name': call['agent']['name'],
'duration': call['duration'],
'outcome': call['status'],
'messages': [
{
'role': msg['role'],
'content': msg['content'],
'timestamp': msg['timestamp']
}
for msg in call['transcript']
]
}
return formattedQuality Assurance Review
async function performQAReview(callId) {
const response = await fetch(`https://v2.heppu.ai/api/v1/calls/${callId}`, {
headers: { 'x-api-key': 'YOUR_API_KEY' }
});
const { data: call } = await response.json();
// QA metrics
const metrics = {
callId: call.id,
agentName: call.agent.name,
duration: call.duration,
status: call.status,
// Analyze transcript
greetingUsed: checkGreeting(call.transcript),
closingUsed: checkClosing(call.transcript),
professionalLanguage: checkProfessionalism(call.transcript),
resolutionProvided: call.summary?.includes('resolved') || false,
// Timing metrics
responseTime: calculateAvgResponseTime(call.transcript),
callEfficiency: call.duration < 300 ? 'efficient' : 'lengthy',
// Overall score
score: calculateQAScore(call)
};
return metrics;
}
function checkGreeting(transcript) {
if (!transcript || transcript.length === 0) return false;
const firstMessage = transcript[0].content.toLowerCase();
return firstMessage.includes('hello') || firstMessage.includes('hi');
}
function checkClosing(transcript) {
if (!transcript || transcript.length === 0) return false;
const lastMessage = transcript[transcript.length - 1].content.toLowerCase();
return lastMessage.includes('thank') || lastMessage.includes('goodbye');
}Best Practices
- Poll for updates - For active calls, poll this endpoint to get real-time updates
- Cache completed calls - Cache call details for completed calls to reduce API usage
- Handle null fields - Transcript and summary may be null for incomplete or failed calls
- Check liveRoomStatus - Only available for calls with status: connecting, ringing, or active
- Use metadata - Store custom data in metadata for your application needs
Related Endpoints
- List Calls - Get a list of all calls
- Cancel Call - Cancel an active or scheduled call
- Schedule Call - Schedule a new call