# OnCallClerk SDK Reference

> Package: `@oncallclerk/sdk`
> Runtime: Node.js, Deno, Edge
> Language: TypeScript / JavaScript
> Last updated: 2026-04-28

## Installation

```bash
npm install @oncallclerk/sdk
# or
yarn add @oncallclerk/sdk
# or
pnpm add @oncallclerk/sdk
```

## Initialization

```typescript
import OnCallClerk from '@oncallclerk/sdk'

const client = new OnCallClerk({
  apiKey: process.env.ONCALLCLERK_API_KEY,
  // Optional configuration
  baseUrl: 'https://api.oncallclerk.com',  // default
  timeout: 30000,                           // ms, default 30s
})
```

**Constructor Options:**

| Parameter | Type   | Required | Description                                                    |
|-----------|--------|----------|----------------------------------------------------------------|
| apiKey    | string | Yes      | Your OnCallClerk API key.                                      |
| baseUrl   | string | No       | Override the API base URL. Defaults to 'https://api.oncallclerk.com'. |
| timeout   | number | No       | Request timeout in milliseconds. Defaults to 30000.            |

---

## client.agents

Create, update, list, and delete AI voice agents.

### agents.list()

Retrieve all voice agents on your account.

```typescript
client.agents.list(): Promise<VoiceAgent[]>
```

**Example:**

```typescript
const agents = await client.agents.list()

for (const agent of agents) {
  console.log(agent.id, agent.agent_name, agent.status)
}
```

### agents.get(agentId)

Retrieve a single agent by ID.

```typescript
client.agents.get(agentId: string): Promise<VoiceAgent>
```

| Parameter | Type   | Required | Description                          |
|-----------|--------|----------|--------------------------------------|
| agentId   | string | Yes      | The unique identifier of the agent.  |

**Example:**

```typescript
const agent = await client.agents.get('agt_abc123')

console.log(agent.business_name)  // 'Acme Corp'
console.log(agent.phone_number)   // '+14155551234'
```

### agents.create(config)

Create and deploy a new voice agent.

> **Note:** Every account starts with a default agent already created. Call `client.agents.list()` to see your existing agents and `client.usage.get()` to check your plan's agent limit before creating a new one.

```typescript
client.agents.create(config: CreateAgentConfig): Promise<VoiceAgent>
```

| Parameter          | Type              | Required | Description                                                               |
|--------------------|-------------------|----------|---------------------------------------------------------------------------|
| business_name      | string            | Yes      | The business name the agent represents.                                   |
| agent_name         | string            | Yes      | A friendly name for the agent.                                            |
| voice_id           | string            | Yes      | The voice to use. Get IDs from client.voices.list().                      |
| greeting           | string            | Yes      | The greeting spoken when answering.                                       |
| system_prompt      | string            | Yes      | Instructions defining agent behavior.                                     |
| escalation_policy  | EscalationPolicy  | No       | 'never' \| 'complex' \| 'requested' \| 'always'. Defaults to 'never'.   |
| forwarding_number  | string            | No       | Number to forward calls to on escalation.                                 |
| escalation_number  | string            | No       | Dedicated escalation number.                                              |
| business_hours     | BusinessHours     | No       | Operating hours. Omit for 24/7.                                           |
| faq                | FAQ[]             | No       | Array of {question, answer} pairs.                                        |
| voice_settings     | VoiceSettings     | No       | Additional voice config (personality, name).                              |
| functions_enabled  | boolean           | No       | Enable built-in tool functions.                                           |

**Example:**

```typescript
const agent = await client.agents.create({
  business_name: 'Acme Corp',
  agent_name: 'After-Hours Support',
  voice_id: 'KR1TkIhkSykEjI4B0DtH', // Sarah
  greeting: 'Thanks for calling Acme Corp after hours.',
  system_prompt: `You are the after-hours support agent for Acme Corp.
    Take messages and let callers know someone will follow up
    during business hours.`,
  escalation_policy: 'requested',
  forwarding_number: '+14155559876',
  business_hours: {
    enabled: true,
    timezone: 'America/New_York',
    schedule: {
      monday: { open: '17:00', close: '09:00', enabled: true },
      tuesday: { open: '17:00', close: '09:00', enabled: true },
      wednesday: { open: '17:00', close: '09:00', enabled: true },
      thursday: { open: '17:00', close: '09:00', enabled: true },
      friday: { open: '17:00', close: '09:00', enabled: true },
      saturday: { open: '00:00', close: '23:59', enabled: true },
      sunday: { open: '00:00', close: '23:59', enabled: true },
    },
  },
  faq: [
    {
      question: 'When will someone call me back?',
      answer: 'A team member will return your call the next business day by noon.',
    },
  ],
})

console.log(agent.id)     // 'agt_def456'
console.log(agent.status) // 'active'
```

### agents.update(agentId, config)

Update an existing agent. Only pass the fields you want to change.

```typescript
client.agents.update(agentId: string, config: Partial<CreateAgentConfig>): Promise<VoiceAgent>
```

**Example:**

```typescript
const updated = await client.agents.update('agt_abc123', {
  greeting: 'Hey! Thanks for calling Acme Corp.',
  escalation_policy: 'always',
})

console.log(updated.greeting) // updated greeting
```

### agents.delete(agentId)

Permanently delete an agent and release its phone number.

```typescript
client.agents.delete(agentId: string): Promise<void>
```

**Example:**

```typescript
await client.agents.delete('agt_abc123')
// Agent and all associated data removed
```

### agents.assignPhone(agentId, phoneNumber)

Assign or change the phone number for an agent.

```typescript
client.agents.assignPhone(agentId: string, phoneNumber: string): Promise<void>
```

| Parameter   | Type   | Required | Description                                         |
|-------------|--------|----------|-----------------------------------------------------|
| agentId     | string | Yes      | The agent to assign the number to.                  |
| phoneNumber | string | Yes      | E.164 formatted number (e.g. '+14155551234').       |

**Example:**

```typescript
// First, find an available number
const numbers = await client.phoneNumbers.search({ country: 'US', areaCode: '415' })

// Then assign it to an agent
await client.agents.assignPhone('agt_abc123', numbers[0].phoneNumber)
```

### Function Management

#### agents.listFunctions(agentId)

List all available functions for an agent.

```typescript
client.agents.listFunctions(agentId: string): Promise<FunctionConfig[]>
```

| Parameter | Type   | Required | Description    |
|-----------|--------|----------|----------------|
| agentId   | string | Yes      | The agent ID.  |

**Example:**

```typescript
const functions = await client.agents.listFunctions(agent.id)

for (const fn of functions) {
  console.log(fn.function_name, fn.enabled)
}
```

#### agents.enableFunction(agentId, functionName, options)

Enable or configure a function on an agent.

```typescript
client.agents.enableFunction(agentId: string, functionName: string, options: EnableFunctionOptions): Promise<FunctionConfig>
```

| Parameter        | Type    | Required | Description                                                        |
|------------------|---------|----------|--------------------------------------------------------------------|
| agentId          | string  | Yes      | The agent ID.                                                      |
| functionName     | string  | Yes      | Function name (e.g. 'scheduleMeeting', 'sendEmail', 'captureLead').|
| options.enabled  | boolean | Yes      | Whether to enable the function.                                    |
| options.config   | object  | No       | Function-specific configuration.                                   |
| options.params   | object  | No       | Function-specific parameters.                                      |

**Example:**

```typescript
const fn = await client.agents.enableFunction(agent.id, 'scheduleMeeting', {
  enabled: true,
  params: {
    calendly_url: 'https://calendly.com/acme/30min',
  },
})

console.log(fn.function_name, fn.enabled) // 'scheduleMeeting' true
```

#### Configure email permitted recipients

Use `enableFunction` with `'email'` to control which addresses or domains your agent can email. Accepts full addresses (`user@example.com`) or entire domains (`@example.com`). Emails are sent from `agent@oncallclerk.com`.

```typescript
await client.agents.enableFunction(agent.id, 'email', {
  enabled: true,
  params: {
    permitted_recipients: [
      'james@houses4cash.co.uk',
      '@houses4cash.co.uk',
    ],
  },
})
```

#### agents.disableFunction(agentId, functionName)

Disable a function on an agent.

```typescript
client.agents.disableFunction(agentId: string, functionName: string): Promise<void>
```

**Example:**

```typescript
await client.agents.disableFunction(agent.id, 'scheduleMeeting')
```

### Integration Management

#### agents.listIntegrations(agentId)

List all integrations for an agent with summary stats.

```typescript
client.agents.listIntegrations(agentId: string): Promise<AgentIntegrationsResponse>
```

**Example:**

```typescript
const { integrations, summary } = await client.agents.listIntegrations(agent.id)

console.log(summary.connected_integrations + '/' + summary.total_integrations + ' connected')

for (const int of integrations) {
  console.log(int.function_name, int.connected ? 'connected' : 'disconnected')
}
```

#### agents.getIntegration(agentId, functionName)

Get detailed information about a single integration.

```typescript
client.agents.getIntegration(agentId: string, functionName: string): Promise<AgentIntegrationDetailResponse>
```

**Example:**

```typescript
const detail = await client.agents.getIntegration(agent.id, 'sendGmail')

console.log(detail.integration.connected) // true
console.log(detail.integration.expired)   // false
```

#### agents.updateIntegrationConfig(agentId, functionName, params)

Update the configuration parameters for an integration.

```typescript
client.agents.updateIntegrationConfig(agentId: string, functionName: string, params: Record<string, unknown>): Promise<FunctionConfig>
```

**Example:**

```typescript
const updated = await client.agents.updateIntegrationConfig(agent.id, 'readGoogleSheet', {
  spreadsheet_id: '1BxiM...',
  tab_name: 'Leads',
  header_row: 1,
})
```

### Google Sheets Helpers

The Google Sheets integration uses the narrow `drive.file` OAuth scope, which means the API cannot enumerate the user's Drive on the server side. To pick a spreadsheet, your dashboard must drive the official Google Picker in a browser using a short-lived access token issued by `getSheetsPickerSession`.

#### agents.getSheetsPickerSession(agentId)

Issue a short-lived OAuth access token your frontend hands to the Google Picker so the user can choose which spreadsheet to connect.

```typescript
client.agents.getSheetsPickerSession(agentId: string): Promise<SheetsPickerSession>
```

| Parameter | Type   | Required | Description                                          |
|-----------|--------|----------|------------------------------------------------------|
| agentId   | string | Yes      | The agent whose connected Google account to use.     |

**Example:**

```typescript
const session = await client.agents.getSheetsPickerSession(agent.id)

// Hand session.access_token to the Google Picker JS SDK in your dashboard.
// After the user picks a sheet, save the chosen spreadsheet_id via
// agents.updateIntegrationConfig(agent.id, 'readGoogleSheet', { spreadsheet_id, ... }).
console.log(session.connected_email) // 'jane@acmecorp.com'
console.log(session.expires_at)      // unix-ms timestamp or null
```

> **Browser-only step.** The Google Picker is a browser JavaScript widget. There is no headless way to enumerate the user's Drive with the `drive.file` scope. CLI/server flows can still drive Calendar and Gmail end-to-end via `client.oauth.*`, but Sheets file selection must happen in a browser.

#### agents.listSheetTabs(agentId, sheetId)

List all tabs in a Google Sheet.

```typescript
client.agents.listSheetTabs(agentId: string, sheetId: string): Promise<GoogleSheetTab[]>
```

**Example:**

```typescript
const tabs = await client.agents.listSheetTabs(agent.id, '1BxiM...')

for (const tab of tabs) {
  console.log(tab.title, tab.rowCount + ' rows')
}
```

#### agents.getSheetHeaders(agentId, sheetId, tabName)

Auto-detects header rows. Returns suggestions scored by likelihood.

```typescript
client.agents.getSheetHeaders(agentId: string, sheetId: string, tabName: string): Promise<HeaderSuggestion[]>
```

**Example:**

```typescript
const headers = await client.agents.getSheetHeaders(agent.id, '1BxiM...', 'Sheet1')

const best = headers.find(h => h.likely_header)
console.log(best?.suggested_headers.map(h => h.header_value))
// ['Name', 'Email', 'Phone', 'Notes']
```

---

## client.phoneNumbers

Search available phone numbers and manage regulatory compliance.

### phoneNumbers.search(options)

Search for phone numbers available for purchase.

```typescript
client.phoneNumbers.search(options?: SearchOptions): Promise<AvailableNumber[]>
```

| Parameter | Type   | Required | Description                                    |
|-----------|--------|----------|------------------------------------------------|
| country   | string | No       | ISO country code. Defaults to 'US'.            |
| areaCode  | string | No       | Filter by area code.                           |
| contains  | string | No       | Search for numbers containing this string.     |
| pageSize  | number | No       | Results per page (max 50). Defaults to 10.     |
| page      | number | No       | Page number (starts at 0).                     |

**Example:**

```typescript
const numbers = await client.phoneNumbers.search({
  country: 'US',
  areaCode: '415',
  pageSize: 5,
})

for (const num of numbers) {
  console.log(num.friendlyName, num.capabilities)
}
// (415) 555-1234 { voice: true, SMS: true, MMS: true }
```

### phoneNumbers.getRegulatoryBundles(country)

Get existing regulatory bundles for a country.

```typescript
client.phoneNumbers.getRegulatoryBundles(country: string): Promise<RegulatoryBundle[]>
```

**Example:**

```typescript
const bundles = await client.phoneNumbers.getRegulatoryBundles('GB')

const approved = bundles.filter(b => b.status === 'twilio-approved')
console.log(approved.length, 'approved bundles')
```

### phoneNumbers.createRegulatoryBundle(options)

Create a new regulatory bundle for a country with business or individual compliance data.

```typescript
client.phoneNumbers.createRegulatoryBundle(options: RegulatoryBundleOptions): Promise<{ bundleSid: string }>
```

| Parameter       | Type                       | Required | Description                          |
|-----------------|----------------------------|----------|--------------------------------------|
| isoCountryCode  | string                     | Yes      | Two-letter ISO country code.         |
| complianceType  | 'business' \| 'individual' | No       | Type of compliance submitter.        |
| complianceData  | ComplianceData             | No       | Business or individual details.      |

**Example:**

```typescript
const bundle = await client.phoneNumbers.createRegulatoryBundle({
  isoCountryCode: 'GB',
  complianceType: 'business',
  complianceData: {
    businessName: 'Acme Corp Ltd',
    registrationNumber: '12345678',
    businessStreet: '10 Downing Street',
    businessCity: 'London',
    businessPostalCode: 'SW1A 2AA',
    businessCountry: 'GB',
    repFirstName: 'Jane',
    repLastName: 'Doe',
    repEmail: 'jane@acmecorp.co.uk',
    repPhoneNumber: '+447700900000',
  },
})

console.log(bundle.bundleSid) // 'BU...'
```

### phoneNumbers.create(options)

Searches for an available number, purchases it, and assigns it to the specified agent in a single call. Convenience wrapper around `phoneNumbers.search()` + `agents.assignPhone()`.

```typescript
client.phoneNumbers.create(options: CreatePhoneNumberOptions): Promise<AvailableNumber>
```

| Parameter | Type   | Required | Description                              |
|-----------|--------|----------|------------------------------------------|
| agent_id  | string | Yes      | The agent to assign the number to.       |
| country   | string | No       | ISO country code. Defaults to 'US'.      |
| areaCode  | string | No       | Filter by area code.                     |
| contains  | string | No       | Search for numbers containing this string.|

**Example:**

```typescript
const number = await client.phoneNumbers.create({
  agent_id: agent.id,
  country: 'US',
  areaCode: '415',
})

console.log(number.phoneNumber)  // '+14155551234'
console.log(number.friendlyName) // '(415) 555-1234'
```

---

## client.transcripts

Access call transcripts and conversation logs.

### transcripts.list(agentId, options)

Get all transcripts for a specific agent.

```typescript
client.transcripts.list(agentId: string, options?: ListOptions): Promise<Transcript[]>
```

| Parameter | Type           | Required | Description                          |
|-----------|----------------|----------|--------------------------------------|
| agentId   | string         | Yes      | The agent to get transcripts for.    |
| limit     | number         | No       | Max number of results. Defaults to 50.|
| offset    | number         | No       | Number of results to skip.           |
| type      | TranscriptType | No       | Filter by call type.                 |
| outcome   | CallOutcome    | No       | Filter by call outcome.              |

**Example:**

```typescript
const transcripts = await client.transcripts.list('agt_abc123', {
  limit: 10,
  type: 'Sales Inquiry',
})

for (const t of transcripts) {
  console.log(`[${t.date}] ${t.caller} — ${t.outcome}`)
  console.log(`  Summary: ${t.summary}`)
  console.log(`  Duration: ${t.duration_minutes}m`)
}
```

### transcripts.get(agentId, transcriptId)

Retrieve a single transcript with the full conversation log.

```typescript
client.transcripts.get(agentId: string, transcriptId: string): Promise<Transcript>
```

**Example:**

```typescript
const transcript = await client.transcripts.get('agt_abc123', 'tr_xyz789')

for (const turn of transcript.conversation) {
  console.log(`${turn.speaker}: ${turn.text}`)
}
// agent: Hello, thanks for calling Acme Corp!
// caller: Hi, I wanted to ask about your pricing.
// agent: Of course! We have three plans...
```

---

## client.voices

Browse available AI voices.

### voices.list()

Get all available voices that can be assigned to agents.

```typescript
client.voices.list(): Promise<Voice[]>
```

**Example:**

```typescript
const voices = await client.voices.list()

for (const voice of voices) {
  console.log(`${voice.name} (${voice.accent}, ${voice.gender})`)
  console.log(`  ${voice.description}`)
}
// Kevin (American, Male)
//   Professional, warm, and articulate
// Sarah (American, Female)
//   Confident, friendly, and approachable
```

**Available Voices:**

| Name    | ID                     | Accent     | Gender |
|---------|------------------------|------------|--------|
| Kevin   | f5HLTX707KIM4SzJYzSz  | American   | Male   |
| Sarah   | KR1TkIhkSykEjI4B0DtH  | American   | Female |
| Lucy    | 4BWwbsA70lmV7RMG0Acs  | British    | Female |
| Jake    | YLbQE9U7P1K6rBNJWNSv  | Australian | Male   |
| Dominic | h2I5OFX58E5TL5AitYwR  | American   | Male   |
| Ava     | kdmDKE6EkgrWrrykO9Qt  | American   | Female |
| Elise   | EST9Ui6982FZPSi7gCHi  | American   | Female |
| Ryan    | 4e32WqNVWRquDa1OcRYZ  | American   | Male   |
| Jon     | 7WggD3IoWTIPT19PNyrW  | American   | Male   |

---

## client.integrations

Browse the integration catalog.

### integrations.catalog()

Lists all available integrations and their function schemas.

```typescript
client.integrations.catalog(): Promise<IntegrationCatalog>
```

**Example:**

```typescript
const { integrations, function_schemas } = await client.integrations.catalog()

for (const int of integrations) {
  console.log(int.name + ' (' + int.auth_type + ') -- ' + int.description)
  console.log('  Functions:', int.functions.join(', '))
}
```

---

## client.oauth

Start OAuth flows for third-party integrations. Tokens are stored automatically on callback.

### oauth.startGoogleCalendar(options)

```typescript
client.oauth.startGoogleCalendar(options: OAuthStartOptions): Promise<OAuthStartResponse>
```

### oauth.startGoogleSheets(options)

```typescript
client.oauth.startGoogleSheets(options: OAuthStartOptions): Promise<OAuthStartResponse>
```

Uses the narrow `drive.file` scope. After the user completes consent, call `client.agents.getSheetsPickerSession(agentId)` and drive the Google Picker in a browser to let the user select a spreadsheet — the API cannot list Drive files on the user's behalf with this scope.

### oauth.startGmail(options)

```typescript
client.oauth.startGmail(options: OAuthStartOptions): Promise<OAuthStartResponse>
```

**Shared Parameters:**

| Parameter | Type   | Required | Description                          |
|-----------|--------|----------|--------------------------------------|
| agent_id  | string | Yes      | The agent to authorize.              |
| user_id   | string | Yes      | The user initiating the auth flow.   |

All three methods return `{ success, authUrl, message }`. Open `authUrl` in a browser to complete OAuth. Tokens are stored automatically on callback.

**Example:**

```typescript
const { authUrl } = await client.oauth.startGoogleCalendar({
  agent_id: agent.id,
  user_id: 'user_123',
})

// Redirect or open authUrl in browser to complete authorization
console.log('Authorize at:', authUrl)
```

---

## client.user

Manage your account profile.

### user.get()

Retrieve the authenticated user's profile.

```typescript
client.user.get(): Promise<UserProfile>
```

**Example:**

```typescript
const profile = await client.user.get()

console.log(profile.email)    // 'jane@acmecorp.com'
console.log(profile.company)  // 'Acme Corp'
console.log(profile.timezone) // 'America/New_York'
```

---

## client.subscription

Query your subscription and usage.

### subscription.get()

Get your current plan, status, and usage limits.

```typescript
client.subscription.get(): Promise<Subscription>
```

**Example:**

```typescript
const sub = await client.subscription.get()

console.log(sub.plan)        // 'professional'
console.log(sub.status)      // 'active'
console.log(sub.usage.used)  // 142
console.log(sub.usage.limit) // 500

const remaining = sub.usage.limit - sub.usage.used
console.log(`${remaining} calls remaining this period`)
```

---

## client.usage

Retrieve current usage and limits for your account.

### usage.get()

Get your current plan, agent count, minute consumption, and billing period.

```typescript
client.usage.get(): Promise<Usage>
```

**Example:**

```typescript
const usage = await client.usage.get()

console.log(usage.plan)              // 'growth'
console.log(usage.agents.used)       // 2
console.log(usage.agents.limit)      // 3
console.log(usage.agents.remaining)  // 1
console.log(usage.minutes.used)      // 142.3
console.log(usage.minutes.limit)     // 600
console.log(usage.minutes.remaining) // 457.7
console.log(usage.phone_numbers.allowed) // true

// Check before creating a new agent
if (usage.agents.remaining > 0) {
  await client.agents.create({ /* ... */ })
} else {
  console.log('Agent limit reached — upgrade your plan')
}

// Check whether phone numbers can be assigned
if (!usage.phone_numbers.allowed) {
  console.log('Subscribe to a plan to assign phone numbers')
}
```

---

## Testing Your Agent

The SDK ships with a browser-based test dialer (a single HTML file) so you can talk to your agent through your microphone — no phone call, dashboard login, or local HTTP server needed. The dialer runs from a `file://` URL, which browsers treat as a secure context, so `getUserMedia` and the Twilio Voice SDK work normally.

### Available helpers

All three are exported from the package root and also exposed as static methods on the `OnCallClerk` class.

| Helper | Returns | Description |
|---|---|---|
| `openDialer(agentId, region?)` | `string` (URL) | Opens the dialer in the user's default browser. Cross-platform (Windows / macOS / Linux). Returns the URL it opened. |
| `getDialerUrl(agentId, region?)` | `string` | Absolute `file:///…/dialer.html?agentId=…` URL. Pre-fills the agent ID. |
| `getDialerPath()` | `string` | Absolute filesystem path to the bundled `dialer.html`. |

`region` is optional and accepts `'US'` or `'EU'`. When provided, it's added to the URL as `&region=…`.

### Recommended: open programmatically

```typescript
import { openDialer } from '@oncallclerk/sdk'
// or: import OnCallClerk from '@oncallclerk/sdk'; OnCallClerk.openDialer(...)

const agent = await client.agents.create({ /* ... */ })

const url = openDialer(agent.id)
console.log(`Dialer opened: ${url}`)
// → file:///C:/your-project/node_modules/@oncallclerk/sdk/src/dialer.html?agentId=abc123
```

`openDialer` shells out to the OS default opener:

| Platform | Command used |
|---|---|
| Windows | `cmd /c start "" <url>` |
| macOS | `open <url>` |
| Linux | `xdg-open <url>` |

It detaches the child process and returns synchronously. If the spawn fails, the URL is still returned so the caller can fall back to manual handling.

### Manual: get the URL and open it yourself

Useful in CI logs, dev scripts, or when the user wants to copy/paste:

```typescript
import { getDialerUrl, getDialerPath } from '@oncallclerk/sdk'

console.log(getDialerUrl(agent.id))  // file:// URL with agentId pre-filled
console.log(getDialerPath())         // absolute filesystem path
```

From a shell, pass the URL straight to your platform's opener — no special quoting tricks required because it's an absolute `file://` URL:

```bash
# macOS
open "$(node -p "require('@oncallclerk/sdk').getDialerUrl('YOUR_AGENT_ID')")"

# Windows (PowerShell)
Start-Process (node -p "require('@oncallclerk/sdk').getDialerUrl('YOUR_AGENT_ID')")

# Linux
xdg-open "$(node -p "require('@oncallclerk/sdk').getDialerUrl('YOUR_AGENT_ID')")"
```

> **Note for agentic / automation contexts:** Earlier SDK versions (≤ 0.3.0) returned a relative path like `node_modules/@oncallclerk/sdk/src/dialer.html`, which doesn't open cleanly via `Start-Process` on Windows. Since `0.3.1`, both `getDialerPath` and `getDialerUrl` return absolute values, and `openDialer` is the preferred entry point. You do **not** need to run a local HTTP server (`npx serve`, etc.) — the dialer is designed to work directly from `file://`.

### Talk to your agent

Your browser will ask for microphone permission — grant it and you'll be connected to your agent in seconds. The dialer shows a live transcript in real time. Click **Hang Up** when you're done.

### URL parameters

If you ever need to construct the URL manually, the dialer reads:

| Param | Required | Description |
|---|---|---|
| `agentId` | Yes | The voice agent ID to dial. |
| `region` | No | `'US'` or `'EU'`. Routes the call to the matching regional WebSocket endpoint. |

---

## Type Reference

### VoiceAgent

```typescript
interface VoiceAgent {
  id: string
  business_name: string
  agent_name: string
  phone_number: string | null
  phone_number_sid: string | null
  voice_id: string
  greeting: string
  system_prompt: string
  voice_settings: {
    personality?: string
    name?: string
  }
  functions_enabled: boolean
  forwarding_number: string | null
  escalation_number: string | null
  escalation_policy: 'never' | 'complex' | 'requested' | 'always'
  business_hours: BusinessHours
  faq: FAQ[]
  status: 'active' | 'inactive' | 'suspended'
  created_at: string
  updated_at: string
}
```

### BusinessHours

```typescript
interface BusinessHours {
  enabled: boolean           // false = 24/7
  timezone: string           // IANA timezone
  schedule: {
    [day: string]: {
      open: string           // "09:00"
      close: string          // "17:00"
      enabled: boolean
    }
  }
}
```

### FAQ

```typescript
interface FAQ {
  question: string
  answer: string
}
```

### VoiceSettings

```typescript
interface VoiceSettings {
  personality?: string
  name?: string
}
```

### Transcript

```typescript
interface Transcript {
  id: string
  date: string
  time: string
  duration: number           // seconds
  duration_minutes: number
  caller: string             // E.164 phone number
  type: TranscriptType
  outcome: CallOutcome
  rating: number
  summary: string
  conversation: {
    speaker: 'agent' | 'caller'
    text: string
  }[]
  agentId: string
  created_at: string
}

type TranscriptType =
  | 'Sales Inquiry'
  | 'Support Request'
  | 'General Info'
  | 'Complaint'
  | 'Feedback'
  | 'Booking'
  | 'Cancellation'

type CallOutcome =
  | 'Resolved'
  | 'Unresolved'
  | 'Escalated'
  | 'Follow-up Required'
  | 'Information Provided'
  | 'Lead Captured'
  | 'Cancelled'
  | 'No Action'
  | 'Unknown'
```

### AvailableNumber

```typescript
interface AvailableNumber {
  phoneNumber: string
  friendlyName: string
  region: string
  isoCountry: string
  type: string
  capabilities: {
    voice: boolean
    SMS: boolean
    MMS: boolean
  }
}
```

### RegulatoryBundle

```typescript
interface RegulatoryBundle {
  sid: string
  status: 'draft' | 'pending-review' | 'in-review' | 'twilio-approved' | 'provisionally-approved' | 'rejected' | 'canceled'
  isoCountry: string
  name: string
}
```

### ComplianceData

```typescript
interface ComplianceData {
  // Business fields
  businessName?: string
  registrationAuthority?: string
  registrationNumber?: string
  website?: string
  businessStreet?: string
  businessCity?: string
  businessRegion?: string
  businessPostalCode?: string
  businessCountry?: string
  // Authorized Representative
  repFirstName?: string
  repLastName?: string
  repPhoneNumber?: string
  repEmail?: string
  // Individual fields
  firstName?: string
  lastName?: string
  email?: string
  phoneNumber?: string
  birthDate?: string
  individualStreet?: string
  individualCity?: string
  individualRegion?: string
  individualPostalCode?: string
  individualCountry?: string
}
```

### UserProfile

```typescript
interface UserProfile {
  firstName?: string
  lastName?: string
  email?: string
  company?: string
  timezone?: string
  personalPhoneNumber?: string
  emailNotifications?: boolean
  callNotifications?: boolean
  weeklyReports?: boolean
}
```

### Subscription

```typescript
interface Subscription {
  plan: string
  status: 'active' | 'canceled' | 'past_due'
  current_period_start: string
  current_period_end: string
  cancel_at_period_end: boolean
  usage: {
    used: number
    limit: number
  }
}
```

### CreatePhoneNumberOptions

```typescript
interface CreatePhoneNumberOptions {
  agent_id: string
  country?: string
  areaCode?: string
  contains?: string
}
```

### FunctionConfig

```typescript
interface FunctionConfig {
  id: string
  agent_id: string
  user_id: string
  function_name: string
  enabled: boolean
  config: Record<string, unknown>
  params: Record<string, unknown>
  created_at: string
  updated_at: string
}
```

### EnableFunctionOptions

```typescript
interface EnableFunctionOptions {
  enabled: boolean
  config?: Record<string, unknown>
  params?: Record<string, unknown>
}
```

### AgentIntegration

```typescript
interface AgentIntegration {
  id: string
  function_name: string
  integration_type: string
  enabled: boolean
  connected: boolean
  expired: boolean
  scope?: string
  config: Record<string, unknown>
  params: Record<string, unknown>
  created_at: string
  updated_at: string
  metadata: {
    display_name: string
    description: string
    oauth_required: boolean
    setup_required: boolean
  }
}
```

### AgentIntegrationsResponse

```typescript
interface AgentIntegrationsResponse {
  integrations: AgentIntegration[]
  summary: {
    total_integrations: number
    connected_integrations: number
    enabled_integrations: number
    expired_integrations: number
  }
}
```

### AgentIntegrationDetailResponse

```typescript
interface AgentIntegrationDetailResponse {
  integration: AgentIntegration
  agent_id: string
}
```

### GoogleSheet

```typescript
interface GoogleSheet {
  id: string
  name: string
  createdTime: string
  modifiedTime: string
  webViewLink: string
  owners: { displayName: string; emailAddress: string }[]
  shared: boolean
}
```

### GoogleSheetTab

```typescript
interface GoogleSheetTab {
  id: number
  title: string
  index: number
  type: string
  rowCount: number
  columnCount: number
}
```

### SheetsPickerSession

```typescript
interface SheetsPickerSession {
  access_token: string            // short-lived OAuth token for the Google Picker
  expires_at: number | null       // unix-ms expiry, or null if unknown
  connected_email: string | null  // the Google account that authorized
}
```

### HeaderSuggestion

```typescript
interface HeaderSuggestion {
  row_index: number
  row_data: string[]
  score: number
  likely_header: boolean
  suggested_headers: {
    column_index: number
    column_letter: string
    header_value: string
    is_empty: boolean
  }[]
}
```

### Integration

```typescript
interface Integration {
  id: string
  name: string
  description: string
  auth_type: 'oauth' | 'api_key' | 'config' | 'none'
  auth_instructions: string
  functions: string[]
  params: Record<string, IntegrationParam>
}
```

### IntegrationCatalog

```typescript
interface IntegrationCatalog {
  integrations: Integration[]
  function_schemas: Record<string, FunctionSchema>
}
```

### OAuthStartOptions

```typescript
interface OAuthStartOptions {
  agent_id: string
  user_id: string
}
```

### OAuthStartResponse

```typescript
interface OAuthStartResponse {
  success: boolean
  authUrl: string
  message: string
}
```
