Official spec: are phone.caller_ended / phone.callee_ended / phone.callee_missed delivered once per leg (per rung device)?

TL;DR: We need the official specification for how many phone.caller_ended / phone.callee_ended / phone.callee_missed events one call produces. Our production data shows they are delivered per leg — once per device that rang — but this behavior is not documented.

Hi,

We develop a Zoom Phone integration that records call logs into an external system. We asked Zoom developer support about the questions below and were directed to this forum.

The integration subscribes to phone.caller_ended, phone.callee_ended, phone.callee_missed, phone.recording_completed, and phone.recording_transcript_completed.

The event reference (developers.zoom.us/docs/api/phone/events/) describes each of these events in a single sentence and does not describe how many events a single call produces. However, our production data (a 47-hour window covering 10,611 call-ended events across multiple customer accounts) and a controlled test show that these events are delivered per “leg” — that is, once per device that rang. For example, in a call queue with one member signed in on two devices, one call produced: (number of ended events) = (devices that rang) × (ring rotations by the queue).

Because we ship this integration as a packaged product used across multiple customer accounts, we need to handle routing configurations that have not yet occurred in our own or our current customers’ environments. We would like to confirm the official specification rather than rely on observed behavior. Earlier topics on this forum — “Zoom Phone Webhook Caller and Callee Call Ended Events” (topic 117183) and “Unable to clearly link call events from the same call” (topic 145388) — touched on parts of this but did not reach an official answer.

A. Delivery model

  1. Is it the intended specification that phone.caller_ended, phone.callee_ended, and phone.callee_missed are delivered once per leg (per device that rang), rather than once per call?

  2. Could you provide, or point us to documentation of, the complete list of conditions under which a single call_id produces multiple caller_ended / callee_ended / callee_missed events? So far we have identified: a user signed in on multiple devices, call queues ringing multiple members, shared line groups, and mid-call transfers. Are there other routing configurations that add legs (for example, call delegation or overflow between queues)? If such a list is not maintained, an authoritative statement of the general rule asked in question 1 — what creates a leg, and that each leg produces exactly one ended/missed event — would serve our purpose.

  3. The reference describes phone.callee_ended as triggered when “the callee … terminates a call”, but we also receive callee_ended for legs that were never answered — for example, a queue member whose phone stopped ringing because another member answered. Is the intended semantics “one record per ended leg”, regardless of which party hung up?

  4. Are the following payload properties guaranteed, or merely typical? In our 47-hour window we observed no exceptions, but we cannot verify a negative from observation alone:

    • phone.callee_ended is delivered only for calls in which at least one leg was answered (calls nobody answered produced only phone.callee_missed).
    • answer_start_time is never present on phone.caller_ended (absent in 10,275 of 10,275 events).
    • handup_result is never present on phone.callee_ended (absent in 215 of 215 events).

B. Routes we could not observe

In addition to the enumeration requested in question 2, there are two routes for which we need event-level and payload-level details, because they did not occur in our observation data:

  1. When a call ends in voicemail or is handled by an auto receptionist: which ended/missed events are generated, for which legs, and does the voicemail leg carry answer_start_time? The schema documents handup_result = “Voicemail” for phone.caller_ended, but it did not appear once in 10,593 events.

  2. For group call pickup and call park/pickup, how are legs and events generated?

C. Identifiers

  1. call_id appears in two formats — a 19-digit decimal number, and a 19-character hexadecimal string containing letters — and both formats occur for both inbound and outbound calls. Do the formats carry any meaning? Is call_id guaranteed to be unique and shared by all webhook events of the same call, including recording and transcript events?

  2. For calls transferred mid-call, phone.recording_completed and phone.recording_transcript_completed sometimes carry the call_id with a “_1” suffix, while the ended events for the same call never carry it. Is this suffix documented, and what is the rule for when it is appended?

D. Redelivery

  1. We observed a second delivery of phone.caller_ended for the same call_id approximately 300 seconds after the first (3 cases). Is this the documented retry behavior (retries at 5/20/60 minutes when no 2xx response is received within 3 seconds), or can duplicate deliveries also occur after a 2xx response? What is the recommended deduplication key — the x-zm-trackingid header?

E. Roadmap

  1. phone.caller_call_history_completed and phone.callee_call_history_completed are marked deprecated in favor of phone.caller_call_element_completed and phone.callee_call_element_completed. Do you recommend that new integrations use the call element events instead of the real-time ended events? Are phone.caller_ended / phone.callee_ended / phone.callee_missed planned to remain supported?

If it is not feasible to address all ten questions, questions 1, 3, and 4 matter most to us — they determine the correctness of our record deduplication and update design.

If any of these are already documented somewhere we missed, a pointer to that documentation would be perfectly satisfactory.

Thanks!