> ## Documentation Index
> Fetch the complete documentation index at: https://developers.telnyx.com/llms.txt
> Use this file to discover all available pages before exploring further.

# webSocket()

> **webSocket**(`ws`, `req`): `void` | `Promise`\<`void`>

Default connection surface: once opted in, every socket handed to the
agent speaks the agent socket protocol with zero subclass code.

The surface is **opt-in**: it activates only when the subclass overrides
a connection seam ([`authorize`](/docs/agent-sdk/interface/authorize) or
[`onAttach`](/docs/agent-sdk/interface/onAttach)) or `webSocket` itself. Overriding
[`onConnect`](/docs/agent-sdk/interface/onConnect) alone does NOT activate it — that
hook predates the surface, so a subclass already using it stays
socketless. An agent that never opted in never asked to hold sockets —
this method then throws [AgentSocketsNotEnabledError](/docs/agent-sdk/interface/webSocket#agentsocketsnotenablederror) before
touching the socket, and the runtime rejects the connection exactly as
it does for an actor with no `webSocket` handler: nothing is sent,
nothing is held.

Once opted in, the default implementation admits the socket: clients
receive a state snapshot on connect (plus message history, and event
replay when subscribed), then live pushes of every committed
[`setState`](/docs/agent-sdk/interface/setState) / `this.messages` append /
`this.events` emit — and, once granted the `"rpc"` claim by an
[`authorize`](/docs/agent-sdk/interface/authorize) override, can invoke
[`@rpc()`](/docs/agent-sdk/interface/rpc)-decorated methods remotely. Connections pass
through [`authorize`](/docs/agent-sdk/interface/authorize) and
[`onAttach`](/docs/agent-sdk/interface/onAttach) on the way in.

Override it to take ownership of raw sockets: a socket you handle
WITHOUT calling `super.webSocket(ws, req)` never touches the protocol
layer — no frames are sent to it and it is not counted in
[`attachments`](/docs/agent-sdk/interface/attachments). Route the sockets you do want
on the protocol through `super.webSocket(ws, req)`.

The returned promise settles once the socket is wired, not once the
connection is admitted: with the host delivering frames only after this
method returns, the negotiation runs on the client's first frame (or on
the `attachGraceMs` timer for a silent client). Observe admission through
[`onAttach`](/docs/agent-sdk/interface/onAttach), not by reading
[`attachments`](/docs/agent-sdk/interface/attachments) right after the `await`.

**Parameters**

| Parameter | Type | Description |
| - | - | - |
| `ws` | `WebSocket` | The accepted socket. |
| `req` | `Request` | The handshake request (front-door headers ride here). |

**Returns**

`void` | `Promise`\<`void`>

**Overrides**

[`StatefulActor`](/docs/edge-compute/stateful-actors/api-reference/base).[`webSocket`](/docs/edge-compute/stateful-actors/api-reference/base)

## AgentSocketsNotEnabledError

Thrown by the default [`Agent.webSocket`](/docs/agent-sdk/interface/webSocket) when the
agent has not enabled its connection surface — neither
[`authorize`](/docs/agent-sdk/interface/authorize) nor [`onAttach`](/docs/agent-sdk/interface/onAttach)
is overridden, and `webSocket` itself is not overridden either. Overriding
[`onConnect`](/docs/agent-sdk/interface/onConnect) alone does not enable the surface, so
an agent whose only connection code is an `onConnect` override still throws
this. The runtime treats an agent in that state exactly like an actor with
no `webSocket` handler: the socket is rejected and nothing is held.

**Extends**

* `Error`
