message.comDevelopers

Call events Live

Phone calls are conversations where channel = 'call'. The dashboard renders the call view in real time by subscribing to these events on the /agent namespace. Our carrier-grade SIP infrastructure posts call events to our backend, we normalise them, and we fan them out.

For the inbound webhook side (carrier to us) see Calls inbound. For REST control of an active call see Calls API.

Call lifecycle

  1. call:ringing, carrier received the call, we created a conversation, agents in the routing set hear it ring.
  2. call:answered, one agent picked up. Other agents see the call disappear from their queue.
  3. call:on_hold, agent placed the caller on hold. Smart Hold may engage if configured (Planned).
  4. call:resumed, agent took the caller off hold.
  5. call:transferred, agent transferred to another agent or department.
  6. call:ended, hangup from either side. Recording finalised.
  7. call:voicemail, no agent picked up before voicemail timeout; recording captured.

call:ringing

Fired when an inbound call arrives at one of your DIDs. Routing rules decide which agents see the event; default is all agents who are available and whose channel set includes calls.

Payload
{
  "type": "call:ringing",
  "conversationId": "uuid",
  "callId": "uuid",
  "fromE164": "+14155550100",
  "toE164": "+18005550100",
  "phoneNumberId": "uuid",     // your DID
  "callerName": "Alice Johnson", // CNAM lookup or visitor record
  "visitorId": "uuid",          // null if first contact
  "createdAt": "2026-05-13T15:30:00Z"
}

Answering

Emit call:answer to claim the call. First emit wins; the rest receive an already_taken ack.

JavaScript
socket.emit("call:answer", {
  callId: "uuid"
}, (err, callState) => {
  if (err === "already_taken") return; // another agent picked up
  if (err) throw new Error(err);
});

call:answered

Fired to all subscribers when one agent picks up. Other dashboards remove the call from their ringing UI.

Payload
{
  "type": "call:answered",
  "conversationId": "uuid",
  "callId": "uuid",
  "agentId": "uuid",
  "createdAt": "2026-05-13T15:30:08Z"
}

call:on_hold and call:resumed

Holds and resumes flip the call between an active media stream and a held state. While held, the caller hears the configured hold music or Smart Hold AI (when shipped).

  • Emit call:hold to place the caller on hold.
  • Emit call:resume to bring the caller back.

call:transferred

Fired when the agent transfers the call. Pass either targetAgentId or targetDepartmentId. Agent transfers run through the same 30-second handshake as chat transfers; department transfers are instant and route to the next available agent in the department.

JavaScript
socket.emit("call:transfer", {
  callId: "uuid",
  targetAgentId: "uuid",       // OR
  targetDepartmentId: "uuid"
}, (err) => { /* ... */ });

call:ended

Fired when either party hangs up or the carrier drops the leg. endedBy reports which side initiated the hangup. recordingUrl points to the final mixed-down recording (available within ~10s of hangup).

Payload
{
  "type": "call:ended",
  "conversationId": "uuid",
  "callId": "uuid",
  "endedBy": "agent" | "caller" | "carrier",
  "duration_ms": 84000,
  "recordingUrl": "https://...",
  "createdAt": "2026-05-13T15:31:32Z"
}

call:voicemail

Fired when the call rolled to voicemail before any agent answered. The recording URL is available immediately; the transcript follows within ~5s once our speech-to-text pass returns.

Payload
{
  "type": "call:voicemail",
  "conversationId": "uuid",
  "callId": "uuid",
  "recordingUrl": "https://...",
  "duration_ms": 32000,
  "transcript": "Hi, this is Alice calling about my order.",
  "createdAt": "2026-05-13T15:31:32Z"
}

Voicemails are also surfaced via Voicemails API for later retrieval.

Emit reference

EmitEffect
call:answerClaim a ringing call.
call:hangupEnd the active call from the agent side.
call:holdPut the caller on hold.
call:resumeResume from hold.
call:transferTransfer to agent or department.

Smart Hold integration

When Smart Hold ships, it engages automatically once a caller has been on hold past the configured threshold (default five minutes). The AI introduces itself honestly as AI, gathers context, and surfaces a structured summary to the agent on resume. See Smart hold (Planned).

Common pitfalls

  • Listening for call:answered to claim. The claim happens on the emit ack of call:answer, not on the broadcast event. By the time call:answered fires, the call is already taken.
  • Recording URL not ready immediately. The recordingUrl on call:ended may be a placeholder until the mix completes (~10s). Poll GET /api/v1/calls/:id if you need the final URL right away.
  • Treating calls as separate from conversations. Every call has a conversation. Use the same conversation primitive for tags, notes, and AI engagement.
  • Voicemail without DNC compliance. If you build outbound calling on top, respect the visitor's suppression list. See Suppressions API.