Skip to content

Missed / timed-out call flow

Signalling - flow-call-missed

SIG-12 - status: draft - audio, video

Stanza sequence for a 1:1 call offered but never answered: offer, per-device offer-receipt, no preaccept/accept, then a timeout-driven terminate.

Opens like any 1:1 call (see flow-incoming-1to1, call-offer) but never reaches accept.

  1. Offer. Caller sends <call to="{callee}" id="{stanza-id}"> wrapping <offer call-id call-creator> (see call-offer). Server <ack>s and fans out to each callee device.

  2. Offer-receipt (per device). Each callee device receiving the offer MUST send a <receipt> in addition to the transport <ack>:

  3. id MUST equal the inbound <call> stanza id (NOT call-id).

  4. from, when present, MUST be the acknowledging device's own addressable JID: its LID if the offer arrived addressed to a LID, otherwise its PN.
  5. This is NOT an accept and MUST NOT be treated as one.

  6. No answer. No callee device sends <preaccept> (see call-preaccept) or <accept> (see call-accept). Call stays ringing for the offer/ring timeout window.

  7. Terminate. On ring timeout with no answer, the call MUST be ended with a <terminate> inside the <call> wrapper (see call-terminate):

    [...]

  8. <terminate> MUST carry the same call-id/call-creator as the offer.

  9. When targeting a peer's other ringing devices, it MAY carry a single <destination> enumerating them with one <to jid="..."/> per device; otherwise <destination> MUST be omitted.
  10. reason, when unspecified, MUST be omitted entirely (never sent empty).

A <terminate> for an unanswered call MAY carry duration/audio_duration counters; expected zero/absent for a missed call. A receiver MUST treat their absence as "not reported", not infer a value.

A receiver that does not recognize a <call> action child MUST ignore the stanza rather than error.

Requires: call-offer, call-accept, call-preaccept, call-terminate, flow-incoming-1to1

Implemented by

Flavor Status Source Notes
whatsapp-rust working history - blame - commits d68af6c Parses inbound /, auto-emits the ack, and builds ; example bot rejects/accepts rather than ringing out, so the timeout-driven terminate is not exercised end-to-end.
zapo-caller working Signalling builders (offer/accept/terminate) ported from this flavor's signaling.ts.

Annotation wacrg:SIG-12 — a flavor marks its implementation site in source with this comment; a script clones the source, finds it, and attaches the commit blame/permalink.

Contributors

Contributor Role
Rajeh Taher Rajeh Taher wrote initial spec

protocol history / diff - blame

Open questions - The ring/offer timeout duration and which side (caller, callee, or server) drives the terminate when a call goes unanswered. - Whether a distinct reason value (e.g. a 'timeout'/'no_answer' code) marks a missed-call terminate, or whether the reason is simply omitted; the source only confirms accepted_elsewhere. - Whether the server emits its own terminate/notification for a timed-out call independent of the caller's terminate, and how a missed call is recorded in chat history. - Exact values of duration/audio_duration on a missed-call terminate (expected zero/absent but not confirmed from source).

References - wacore voip signaling builders (build_offer, build_terminate) - wacore call stanza parser and build_offer_ack_receipt

Changelog

  • 2026-06-21 — Initial spec entry.

Back to the full spec