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

# React

> Provider and headless hooks for the Voice SDK

`@telzino/react` provides a context provider and hooks over `@telzino/voice`. No UI is included; you render it.

```sh theme={null}
npm i @telzino/voice @telzino/react
```

## Example

```tsx theme={null}
import { TelzinoProvider, useTelzino, useMuted, useAgentState, useTranscript, useNeedsUserGesture } from '@telzino/react';

const config = { publishableKey: 'pk_live_...' }; // inline objects are fine

function Call() {
  const { start, end, status, error } = useTelzino();
  const [muted, setMuted] = useMuted();
  const agentState = useAgentState();
  const transcript = useTranscript();
  const [needsGesture, resume] = useNeedsUserGesture();
  const live = status === 'connecting' || status === 'connected' || status === 'reconnecting';
  return (
    <div>
      <button onClick={() => (live ? end() : start({ agentId: '3f1c2a4e-8b7d-4c3a-9e2f-1a2b3c4d5e6f' }))}>{live ? 'Hang up' : 'Call'}</button>
      <button onClick={() => setMuted(!muted)} disabled={!live}>{muted ? 'Unmute' : 'Mute'}</button>
      <span>{agentState}</span>
      {needsGesture && <button onClick={resume}>Enable audio</button>}
      {error && <p role="alert">{error.message}</p>}
      <ul>{transcript.map((t) => <li key={t.id}>{t.role}: {t.text}</li>)}</ul>
    </div>
  );
}

export const App = () => <TelzinoProvider config={config}><Call /></TelzinoProvider>;
```

## `<TelzinoProvider>`

Wrap the part of your app that uses the hooks. Pass `config` with the same options as `new TelzinoVoice(config)`: `publishableKey`, `session` and `apiBaseUrl`. See [Core API](https://docs.telzino.com/sdk/core-api.md).

* Changing the identity of `config` does not recreate the client. Only a change to `publishableKey` or `apiBaseUrl` does. `session` is read at call time.
* Unmounting the provider ends any live call.
* The provider also accepts a `client` prop instead of `config`, for tests.

Hooks used outside `<TelzinoProvider>` throw a `TelzinoError` with code `invalid_request`.

## Hooks

| Hook | Returns |
| - | - |
| `useTelzino()` | `{ start(opts), end(), call, status, error }`; `start` never rejects, failures land in `error` |
| `useAgentState()` | `'initializing' \| 'listening' \| 'thinking' \| 'speaking' \| 'unknown'` |
| `useTranscript()` | `TranscriptItem[]` (new array per update) |
| `useMessages()` | `ChatMessage[]` |
| `useAudioLevel()` | `{ local, agent }` levels, 0 to 1 |
| `useMuted()` | `[muted, setMuted(m)]` |
| `useNeedsUserGesture()` | `[needsGesture, resume()]`; call `resume` from a click handler |

## Behavior notes

* `status` is `connecting` as soon as `start()` is called. A second `start()` while connecting or live is a no-op.
* `end()` while connecting cancels the call as soon as it exists; it is not an error.
* After a hang-up (yours or the agent's) the snapshot is kept (`status: 'ended'`, transcript still readable) until the next `start()`.
* `setMuted` and `resume` never reject; failures land in `error`.
* `error` is a `TelzinoError`. See [Events and errors](https://docs.telzino.com/sdk/events.md) for the codes.

## Using the core client alongside the hooks

`call` from `useTelzino()` is the underlying `VoiceCall`, so you can use its methods directly, for example `call?.sendText('Hello')` or `call?.setInputDevice(deviceId)`. The `examples/web-basic` app uses this to add a microphone picker and a text box.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.