Skip to main content

Documentation Index

Fetch the complete documentation index at: https://developers.telnyx.com/llms.txt

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

Call Class

The Call object represents a voice call. It’s created by client.newCall() (outbound) or received via telnyx.notification (inbound).

Getting a Call Object

Outbound call

const call = client.newCall({
  destinationNumber: '+12345678900',
  audio: true,
});

Inbound call

client.on('telnyx.notification', (notification) => {
  if (notification.type === 'callUpdate' && notification.call.state === 'ringing') {
    const call = notification.call;
    call.answer();
  }
});

Properties

PropertyTypeDescription
idstringUnique call identifier
stateCallStateCurrent call state (see Call States)
direction'inbound' | 'outbound'Call direction
remotePartyNumberstringRemote party’s phone number
remotePartyNamestringRemote party’s display name (if available)
localPartyNumberstringLocal party’s phone number
activebooleanWhether the call is currently active
recoveredCallIdstringPrevious call ID if this call was recovered after reconnection
peerConnectionRTCPeerConnectionUnderlying WebRTC PeerConnection (for advanced use)

Call States

StateDescription
newCall object created, not yet dialed
requestingOutbound INVITE sent to server
ringingInbound: INVITE received. Outbound: remote ringing
answeringInbound call being answered (media negotiation)
activeCall connected — media flowing
heldCall on hold
hangupCall ended (local or remote hangup)
destroyCall object cleaned up
recoveringCall being recovered after reconnection

Methods

answer()

Answer an incoming call.
client.on('telnyx.notification', (notification) => {
  if (notification.type === 'callUpdate' && notification.call.state === 'ringing') {
    notification.call.answer();
  }
});
Only call answer() when the call state is ringing. Calling answer() on an already-active call creates a duplicate PeerConnection, which causes one-way audio issues.

hangup()

End the call.
// SDK 2.25.x — synchronous
call.hangup();

// SDK 2.26.x — async (returns Promise)
await call.hangup();
See Migration Guide for upgrading from 2.25.x.

muteAudio() / unmuteAudio()

Toggle the microphone.
call.muteAudio();    // Mute
call.unmuteAudio();  // Unmute

hold() / unhold()

Put the call on hold or resume it.
call.hold();    // Put on hold (remote hears hold music)
call.unhold();  // Resume

dtmf(digit)

Send a DTMF tone (0-9, *, #).
call.dtmf('1');
call.dtmf('*');
call.dtmf('#');

sendDigits(digits)

Send a sequence of DTMF digits.
call.sendDigits('1');

Events

Register event listeners using call.on(eventName, handler):

Call State Events

EventPayloadDescription
telnyx.notificationINotificationCall state updates, media events
const call = client.newCall({
  destinationNumber: '+12345678900',
  audio: true,
});

call.on('telnyx.notification', (notification) => {
  switch (notification.call.state) {
    case 'active':
      console.log('Call connected');
      break;
    case 'hangup':
      console.log('Call ended');
      break;
  }
});

Advanced

Access the PeerConnection

For custom WebRTC monitoring or manipulation:
const pc = call.peerConnection;

// Get current ICE connection state
console.log('ICE state:', pc.iceConnectionState);

// Get current DTLS state
console.log('DTLS state:', pc.connectionState);

// Get stats
const stats = await pc.getStats();
stats.forEach((report) => {
  if (report.type === 'candidate-pair' && report.nominated) {
    console.log('Nominated pair:', report);
  }
});
Direct PeerConnection access is for advanced use cases only. The SDK manages the PeerConnection lifecycle — calling methods like close() or setRemoteDescription() directly may break the call.

Custom headers

Add SIP headers to the INVITE for server-side correlation:
const call = client.newCall({
  destinationNumber: '+12345678900',
  audio: true,
  customHeaders: [
    { name: 'X-Call-Session', value: sessionUuid },
    { name: 'X-Agent-ID', value: agentId },
  ],
});

Common Patterns

Simple outbound call with state handling

const call = client.newCall({
  destinationNumber: '+12345678900',
  audio: true,
});

call.on('telnyx.notification', (notification) => {
  switch (notification.call.state) {
    case 'requesting':
      showDialingUI();
      break;
    case 'ringing':
      showRingingUI();
      break;
    case 'active':
      showActiveCallUI();
      break;
    case 'hangup':
      cleanupCallUI();
      break;
  }
});

// Cancel the call if not yet connected
cancelButton.addEventListener('click', () => {
  call.hangup();
});

Inbound call with accept/reject UI

client.on('telnyx.notification', (notification) => {
  if (notification.type === 'callUpdate' && notification.call.state === 'ringing') {
    const call = notification.call;

    showIncomingCallUI({
      from: call.remotePartyNumber,
      onAccept: () => call.answer(),
      onReject: () => call.hangup(),
    });
  }
});

Hold and resume

// Put call on hold
holdButton.addEventListener('click', () => {
  call.hold();
});

// Resume the call
resumeButton.addEventListener('click', () => {
  call.unhold();
});

See Also