Heppu AI
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_KEY

Path Parameters

ParameterTypeRequiredDescription
callIdstringYesUnique 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 identifier
  • status: Current call status (initiated, connecting, ringing, active, completed, failed, cancelled, no_answer, busy)
  • direction: Call direction (inbound/outbound)
  • phoneNumber: Phone number involved in the call
  • duration: 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 object
  • summary: AI-generated call summary
  • transcript: Array of conversation messages
  • metadata: Additional call metadata
  • roomId: LiveKit room ID
  • jobId: LiveKit job ID
  • sipParticipantId: SIP participant identifier
  • liveRoomStatus: Real-time LiveKit room status (only for active calls)
  • createdAt: Call creation timestamp
  • updatedAt: 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 formatted

Quality 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

  1. Poll for updates - For active calls, poll this endpoint to get real-time updates
  2. Cache completed calls - Cache call details for completed calls to reduce API usage
  3. Handle null fields - Transcript and summary may be null for incomplete or failed calls
  4. Check liveRoomStatus - Only available for calls with status: connecting, ringing, or active
  5. Use metadata - Store custom data in metadata for your application needs

On this page