Skip to main content

State & events

The server owns AgentView; the SDK mirrors it. Your renderer reads the view, and user actions send intents. The Events reference gives the exact schemas.

The stream: snapshot, then patches

Subscribe sends a StateUpdate containing one of these messages:

MessageEffect
snapshotReplace the entire cached AgentView on connection.
patchApply one entity change, then notify renderers.
errorReport a command rejection or warning without changing state.
keepalive, pingTransport liveness; SDKs suppress render callbacks and reply to pings.
snapshot → patch → patch → … → replacement connection → new snapshot

The immediate SDK subscribe callback returns its current cache, possibly empty. It is separate from the network snapshot and does not establish connection health.

seq: ordering and gap recovery

A snapshot establishes seq; each patch increments it, including transient notifications. Errors, keepalives and pings do not advance the state sequence. The cache reports a patch whose sequence is not the previous value plus one, but still applies it. Mark the view stale and reconnect for a fresh snapshot.

Current TypeScript caveat: BabelconnectClient sends notification patches directly to onNotification without advancing its cache sequence. The following state patch can therefore raise onGap even though the stream delivered every message. Go passes notifications through its cache for sequencing, but has no dedicated notification callback. Neither SDK replays missed notifications during snapshot recovery.

The patch types

Upserts replace the whole entity, including when only one field changed. Calls and conferences use id; SMS conversations use peer. Removes carry that key.

PatchEffect
agentReplace AgentInfo.
callUpsert, callRemoveAdd/replace or remove a call by ID.
wrapUpReplace WrapUpStatus.
smsUpsert, smsRemoveAdd/replace or remove a conversation by peer.
conferenceUpsert, conferenceRemoveAdd/replace or remove a conference by ID.
configReplace AppConfig.
notificationTransient event; never stored in AgentView.

Notifications carry kind, title, body, ts and JSON-encoded dataJson. Handle them when received through TS onNotification, and handle malformed JSON in your integration. They will not be present in a later view.

config owns feature gates: calls, messaging, history, phonebook, account, outbound, and cti each have enabled. Use calls.allowTransfer and calls.allowConference for finer call controls; cti.screenPop and cti.emitCallEvents govern CTI; account.allowDeviceSwitch and account.showStatus govern device and status UI. serverVersion identifies the server build. In TS, read optional fields defensively (view.config?.calls?.enabled); Go's generated getters are nil-safe. Registration loads deployment data in several updates, so don't assume it arrives atomically. Exact fields: StateUpdate and Patch.

A call, end to end

EventRender or act
callUpsert with RINGINGShow the caller and Answer/Reject controls when an offer exists.
Agent clicks AnswerSDK negotiates media and sends the answer; wait for state.
IN_PROGRESS / BRIDGEDShow in-call controls and reflect mute/hold/recording flags.
Call ends and callRemove arrivesRemove its card; wrap-up may follow.

Auto-answer applies only to the agent's own outbound ringing offer and excludes CallSource.CALLBACK. It defaults on in TS and off in Go. Inbound calls and callbacks need explicit acceptance. activeCalls is a list: an agent may have a call on hold while another rings. Render every call and target its ID.

CallState fieldMeaning
idTarget for call commands.
state, direction, sourceTyped lifecycle, inbound/outbound direction and origin (API, WebRTC, queue, transfer, dialer, conference or callback).
from, to, queueName, anonymousFar party is from inbound, to outbound; display Anonymous when withheld.
muted, onHold, recordingServer state for toggle controls.
recordingId, recordingTags, recordingFlaggedActive recording metadata; SDK recording methods address the call ID.
webrtcOffer, iceServersSDP offer and STUN/TURN configuration for answering; a ringing call may lack an offer.
establishedAtUnix seconds when bridged, or zero; use now − establishedAt for a timer.

A live call has no contact label; look up its number in agent.phonebook, skipping labels equal to "recent". History records and SMS summaries can carry contact labels directly.

LifecycleMeaning
INITCreated, not yet ringing.
RINGINGAwaiting acceptance.
IN_PROGRESSAnswered/connecting.
BRIDGEDConnected state; verify audible media separately.
COMPLETED, FAILEDNormal or unsuccessful ending, followed by removal.

Use named enums (CallLifecycle.RINGING in TS, CallLifecycle_CALL_LIFECYCLE_RINGING in Go). A terminal upsert can report the outcome before removal; don't assume every ending exposes one. Fetch history when you need durable records.

An SMS conversation, end to end

SMS works independently of calls. Each SmsConversation summarizes a thread keyed by peer: contactLabel, lastText, lastDirection, lastTs, unread and open describe its latest state. Its id targets markConversationRead and setConversationOpen; that ID can be empty until assigned. Only getSmsThread also accepts the peer number.

ActionUpdate
Receive SMSsmsUpsert updates the preview and unread count.
Mark readsmsUpsert clears unread.
Send a replysmsUpsert updates the latest outbound text.
Resolve/reopensmsUpsert changes open.
Remove conversationsmsRemove carries the peer.

Sort summaries by lastTs, sum unread for the badge, and fetch the full thread separately. SmsMessage has a stable id, direction, from/to, text, timestamp and a display-only state (such as received, sent, delivered, failed or scheduled). Render that string without assuming a closed enum. Messages are returned oldest first.

Timestamps (ts, lastTs, establishedAt, history time) are Unix seconds. Multiply by 1000 for a JavaScript Date; durationMs is already milliseconds.

A conference, end to end

Each conferenceUpsert replaces the full conference and member list. Starting a conference adds you and the other party; inviting adds a pending member; hold/kick updates the member; ending removes the conference. leaveConference drops only your own leg.

FieldUse
Conference.iAmModeratorGate moderator controls.
Conference.myMemberIdYour member ID.
Conference.stateDisplay label, commonly created → finishing → finished.
Member id, display, agentId / numberTarget ID, label and participant identity.
Member state, failureReasonDisplay joining/added/removing/removed/failed and any failure reason.
Member onHold, moderator, isMeHold state and badges; there is no readable member muted flag.
Member callIdMember's call leg; your own member corresponds to your CallState.id.

Conference and member states are free-form strings, not typed enums. The agent's own call remains in activeCalls: use call commands for your own mute/hold/hangup and conference commands for members. See the conference recipe.

Wrap-up, end to end

A wrapUp patch opens after-call work with active, remainingSeconds and lastCallType. Render a local countdown; updates are not guaranteed every second. Reconcile to new server values, including extensions. A local zero is only a display value: wait for active: false to confirm wrap-up ended. Show Extend/Cancel only when canExtend/canCancel allow them.

Consuming it

AgentView field (TS · Go)Holds
agent · AgentIdentity, presence, routing, capabilities and reference data.
activeCalls · ActiveCallsCalls keyed by ID.
wrapUp · WrapUpAfter-call work.
sms · SmsConversation summaries keyed by peer.
conferences · ConferencesConferences, usually zero or one.
config · ConfigDeployment feature settings.

TS lists are always arrays; message blocks such as agent and config can be absent. Go getters handle nil. Treat callback views as read-only copies and keep render work brief.

AgentInfo fieldUse
id, accountIdStable identity; names are display data.
name, username, accountNameSigned-in identity labels.
number, webrtcEnabledExternal number and WebRTC routing preference.
displayAs, availableNumbersSelected and allowed outbound caller IDs.
canRecord, availableTags, alwaysRecordOutboundRecording controls, tags and automatic recording policy.
phonebookRegistration-time contacts and recent numbers.

Availability has three separate meanings:

FieldMeaning and action
presenceServer-computed AgentState: OFFLINE, AVAILABLE, IN_CALL, RINGING, WRAP_UP, PAUSED or BUSY. Use for a status indicator.
presenceName, presenceLabel, presenceOptionsChosen presence and the available choices. Pass an option's name to setPresence; display its label and available flag.
lineBlocked, lineBlockedReasonInvoluntary routing block: unreachable, busy, declined or dnd. Reason is empty when not blocked. Offer Reset only when lineBlocked is true.

Chosen busy or a break is voluntary; it needs a presence change, not a line reset. A missed call or transfer can leave an unreachable block that lifts after a short wrap-up. Render the reason and countdown so the agent knows why calls stopped. The transferring agent may separately see transfer_target_no_answer; a failed conference member carries failureReason.

An outbound agent_not_available rejection can mean either a blocked line or an unavailable chosen presence. Check lineBlocked first. Use the banner recipe and error reference for recovery.