# @quarterzip.ai/sdk

A thin, dependency-free loader for the Quarterzip embeddable voice-agent SDK.

It is responsible for managing the lifecycle of a sandboxed, cross-origin iframe that loads the live
SDK from Quarterzip's servers, mirroring the call controls into a floating Picture-in-Picture window,
and brokering a private message channel between the two. Everything Quarterzip serves runs inside
that sandbox and cannot touch your page's DOM, cookies or storage.

The latest documentation is available at [docs.quarterzip.ai](https://docs.quarterzip.ai)

## Install

The full & latest SDK installation guide can be found [here](https://docs.quarterzip.ai/sdk).

```sh
pnpm add @quarterzip.ai/sdk
```

### Grant Security Permissions

The Quarterzip SDK operates in a security sandbox separate from your site. In order for your Quarterzip
agent to communicate with your users, the following permissions must be granted if enforced.

#### CSP requirements

Only relevant if your page sends a `Content-Security-Policy` header, then it must permit Quarterzip’s SDK
origin to be framed.

```
Content-Security-Policy:
  frame-src https://sdk.quarterzip.ai;
  child-src  https://sdk.quarterzip.ai;
```

#### Permissions Policy

Only relevant if your page sends a `Permissions-Policy` header, then it must permit Quarterzip’s SDK origin
the following permissions:

```
Permissions-Policy:
  microphone=(self "https://sdk.quarterzip.ai"),
  display-capture=(self "https://sdk.quarterzip.ai"),
  autoplay=(self "https://sdk.quarterzip.ai"),
  speaker-selection=(self "https://sdk.quarterzip.ai"),
  storage-access=(self "https://sdk.quarterzip.ai")
```

## Usage

```ts
import { Quarterzip } from '@quarterzip.ai/sdk';

button.addEventListener('click', () => {
	Quarterzip.open({
		agentId: 'agt_123',
		workspaceToken: 'wt_public_abc', // public, not a secret
		user: {
			id: 'your-user-id', // required; may be opaque or hashed
			email: 'jane@example.com', // optional
			displayName: 'Jane Doe' // optional
		},
		context: 'Optional free text passed to the agent',
		locale: 'fr-CA', // optional; BCP-47
		on: {
			callStarted: () => console.log('Call started'),
			callEnded: () => console.log('Call conversation ended'),
			close: ({ reason }) => analytics.track('session_closed', { reason }),
			error: ({ code, fatal }) => console.warn('Quarterzip call failed', code, fatal)
		}
	});
});

// later
Quarterzip.close();
```

### Choosing the call language

Pass `locale` when your app knows the user's language better than their browser does — usually
because you store it against their account. It takes a BCP-47 tag, resolved to the nearest language
the agent speaks, so a region we don't voice separately narrows to its base (`fr-CA` → French).

Precedence, highest first:

1. A language the user picks in the panel
2. `locale`, if it resolves
3. The browser (`navigator.languages`)
4. The agent's configured default

A tag we can't use never fails the call — it drops to the next step and logs a console warning.
Agents that offer only certain languages in the picker don't restrict `locale`.

## Licence

MIT — see [`LICENSE`](./LICENSE).

This covers **this package**: the client-side loader that stands up the sandboxed iframe. The
Quarterzip service the frame connects to, and the bundle it serves at runtime, are not covered by it
and are not open source.
