Freeze one disputed observation window
Record timestamp and timezone, node and branch, manager identity, action and ActionID, immediate response, every ContactList row, ContactListComplete, exact contact ID, URI, AoR, endpoint, expiration, status, RTT and qualification policy. Preserve any ContactStatus events with their original field names.
Classify the symptom: list incomplete; contact absent; wrong static or dynamic population; stale expiration; unexpected status; missing Removed or Updated; missing reachability transition; RTT unchanged; or contact looks reachable while calls fail.
Prove list authority and terminal framing
Verify the action exists for the installed branch and the manager account can execute it and receive command-class rows. Require ContactListComplete and reconcile its count after applying documented parser rules.
Do not interpret rejected authority, filtered events, disconnect, timeout, cancellation, parser loss or querying a different node as an empty or completed list.
Resolve exact contact ownership and lifecycle
Match ObjectName byte-for-byte, then map it to its AoR and endpoint. Determine whether it is a permanent contact created from an AoR contact= URI or a dynamic contact created by REGISTER. Compare current expiration, registrar evidence and the exact PJSIP_CONTACT fields.
An absent contact may reflect failed registration, de-registration, expiry, replacement policy, reload, restart pruning, a different node or observation timing. Correct the first demonstrated divergence instead of recreating every PJSIP object.
Audit the live-event path separately from the snapshot
Confirm system-event read authority, event filters, session continuity and the observation start time. Preserve the documented ContactStatus vocabulary rather than normalizing it to the ContactList vocabulary. Check whether refresh-update events were intentionally enabled with send_contact_status_on_update_registration.
A quiet live stream proves only that this observer received no matching event during that interval. It does not reconstruct earlier transitions or establish an unchanged contact.
Run one bounded qualification experiment
Record loaded qualify_frequency, qualify_timeout, qualify_2xx_only, proxy and authentication policy. If authorized, issue PJSIPQualify for the exact endpoint with a unique ActionID, then retain the action response, subsequent events and a fresh completed contact list.
Separate DNS time, request transmission, challenge handling, response class, timeout and status update. An accepted action, old RTT, or later Reachable label alone does not prove which packet caused the change or that calls and media work.
Correct the first divergence and verify the user symptom
Correct only the proven boundary: action availability, manager authority, filter, parser, node, exact identity, configuration ownership, registration lifecycle, expiration, periodic qualification or explicit qualify handling. Repeat the same completed snapshot and observation window.
If contact state now agrees but calls still fail, continue through endpoint selection, dialplan, signaling, SDP and media. No PBX, module, manager account, session, AoR, endpoint, contact, registration, OPTIONS exchange, packet, media stream or live call was inspected or tested.
Sources & applicability
Primary references for the technical details above. Operational examples and planning checklists are VoIP.info editorial guidance.
- Asterisk 23 PJSIPShowContacts action ↗
- Asterisk 23 ContactList event ↗
- Asterisk 23 ContactListComplete event ↗
- Asterisk 23 ContactStatus event ↗
- Asterisk 23 ContactStatusDetail event ↗
- Asterisk 23 inbound-registration contact-status action ↗
- Asterisk 23 PJSIPQualify action ↗
- Asterisk 23 PJSIP_CONTACT function ↗
- Asterisk 23 res_pjsip configuration reference ↗
- Asterisk PJSIP troubleshooting guide ↗
- Asterisk AMI v2 specification ↗
Examples require adaptation to your topology. No live PBX or hardware testing is claimed.