# Realtime events reference

> The live events your page receives from the embedded screens with Nexafon.on, their payloads, and how they relate to webhooks.

Source: https://docs.nexafone.so/v1/web/events/

The hub frame keeps one realtime connection to Nexafon for the page and passes events to your code as they happen:
a ringing call shows in the embed within about 150 ms of Nexafon learning of it, and reaches your listeners at the
same moment.

```js
const stop = Nexafon.on('call.ringing', (call) => {
  showBanner(`Call from ${call.callerName || call.callerNumber}`)
})
// stop() removes the listener; Nexafon.off(name, listener) does the same.
```

The wrappers expose the same events: `useNexafonEvent` in [React](/v1/web/react/) and [Vue](/v1/web/vue/),
`NexafonService.events(name)` in [Angular](/v1/web/angular/).

## Events

| Event | When | Payload |
| --- | --- | --- |
| `ready` | A frame finished loading | `{ kind }`: `'hub'`, `'app'`, `'inbox'`, `'softphone'`, `'call-button'` or `'call'` |
| `session.ready` | The session started (or was renewed with a new user token) | `{ userId, stores: [{ workspaceId, name }] }` |
| `session.error` | The session could not start, such as an invalid token or no free seat | `{ code, message }`: `code` is the API’s [error code](/v1/errors/) |
| `call.ringing` | A call to this user started ringing | Call details |
| `call.answered` | A call was answered | Call details |
| `call.ended` | A call ended | Call details and `reason` |
| `message.received` | A customer’s message arrived in a conversation the user can see | `{ workspaceId, conversationId, messageId }` |
| `store.changed` | The user switched store in the [store switcher](/v1/partners/store-switcher/) | `{ workspaceId }` |

Call details are:

| Field | |
| --- | --- |
| `workspaceId` | The workspace (store) of the call |
| `callId` | The call’s id, as in the API and in webhooks |
| `kind` | `whatsapp_inbound`, `whatsapp_outbound`, `internal_direct`, `internal_group` or `meeting` |
| `callerName` | The caller’s name, when known |
| `callerNumber` | The caller’s number (E.164) for WhatsApp calls |

## Browser events or webhooks?

Events in the page are for the user in front of it: show a banner, open the order of the caller, update a badge.
They only arrive while the page is open and only for what that user may see. For anything your **systems** must not
miss (CRM sync, order processing, reports) use [webhooks](/v1/webhooks/): they are signed, retried for three days
and cover the whole workspace.

## Protocol

Events travel over a versioned, origin-checked `postMessage` bridge between Nexafon’s frames and the loader; your
code only ever sees the payloads above. The realtime WebSocket behind it is internal to the SDK and not part of the
public v1 API.
