diff --git a/.actrc b/.actrc new file mode 100644 index 000000000..2d7a5bef5 --- /dev/null +++ b/.actrc @@ -0,0 +1,3 @@ +# act configuration file +-P ubuntu-latest=catthehacker/ubuntu:act-latest +--container-architecture linux/amd64 \ No newline at end of file diff --git a/.cursor/rules/always-applied/core-principles.mdc b/.cursor/rules/always-applied/core-principles.mdc new file mode 100644 index 000000000..1e3f71803 --- /dev/null +++ b/.cursor/rules/always-applied/core-principles.mdc @@ -0,0 +1,36 @@ +--- +description: Core documentation principles and writing standards +globs: +alwaysApply: true +--- + +# Core Documentation Principles + +Provide developers with documentation that is quick to read, easy to follow, and immediately actionable. + +## Writing Style & Tone + +| Guideline | Why it matters | +|-----------|---------------| +| **Active voice** | "Connect the SDK" is clearer than "The SDK should be connected." | +| **Present tense** | Keeps instructions straightforward (e.g., "Run" not "You will run"). | +| **Second‑person ("you")** | Speaks directly to the reader. Reserve "we" for collaborative tutorials. | +| **Explain intent before action** | Briefly state *why* a step is needed, then show *how*. | +| **Concrete examples over theory** | Code snippets and visuals anchor concepts. | +| **Consistent terminology** | Define a term once; reuse it exactly the same everywhere. | +| **Parallel structure** | Lists and headings should follow consistent grammatical patterns. | +| **Descriptive link text** | Use "view the guide" rather than "click here." | +| **Comment code sparsely** | Only where intent isn't obvious from variable/function names. | + +> **Rule of thumb**: every sentence should either clarify *why* or *how*—if it does neither, remove or rewrite it. + +## Style Rules + +- **Tone**: Direct, professional, friendly +- Break up large blocks of text with line‑breaks +- Avoid marketing or promotional wording +- Link to related pages when helpful, especially the **API reference** at `/fern/api-reference` +- Use **bold** text to emphasize key names or concepts +- **Titles**: Capitalize only the first word unless a proper noun is used +- **Subtitles**: Begin with *Learn to …* for guides; otherwise keep them concise and factual +- **Emojis / decorative icons**: Use only when essential for comprehension diff --git a/.cursor/rules/always-applied/fern-components.mdc b/.cursor/rules/always-applied/fern-components.mdc new file mode 100644 index 000000000..33b8cb829 --- /dev/null +++ b/.cursor/rules/always-applied/fern-components.mdc @@ -0,0 +1,224 @@ +--- +description: Fern documentation framework components and features +globs: +alwaysApply: true +--- + +# Fern Components & Framework Features + +Fern is our documentation framework. Use Fern-specific components and features for enhanced functionality. + +## Code Blocks & Syntax Highlighting + +### Multi-language Code Blocks with Tabs +Use `` for multiple language examples that automatically synchronize: + +```mdx + +```typescript title="TypeScript SDK" +import { VapiClient } from "@vapi-ai/server-sdk"; + +const client = new VapiClient({ token: process.env.VAPI_API_KEY }); +``` +```python title="Python SDK" +from vapi import Vapi + +client = Vapi(token=os.getenv("VAPI_API_KEY")) +``` +```bash title="cURL" +curl -X POST "https://api.vapi.ai/assistant" \ + -H "Authorization: Bearer $VAPI_API_KEY" +``` + +``` + +### Code Block Features +Enhance code blocks with these attributes: +- `title="filename.ext"` - Add file title +- `{2-4}` - Highlight specific lines +- `focus` - Focus on specific lines +- `maxLines=10` - Limit visible lines (default: 20) +- `wordWrap` - Wrap long lines instead of scrolling + +```mdx +```typescript title="example.ts" {2-3} maxLines=15 wordWrap +const config = { + apiKey: process.env.VAPI_API_KEY, // highlighted + timeout: 30000 // highlighted +}; +``` +``` + +## Callouts & Alerts + +Use semantic callouts to highlight important information: + +```mdx +Helpful tips and best practices +Important information to remember +Cautions and potential issues +Critical errors and troubleshooting +Additional context and explanations +Success confirmations and completed tasks +``` + +## Interactive Components + +### Accordions for Collapsible Content +Perfect for FAQs and optional details: + +```mdx + + + Detailed answer with searchable content (Cmd+F works even when collapsed) + + + More detailed explanations + + +``` + +### Tabs for Related Content +Use for different approaches or languages: + +```mdx + + + Visual, no-code approach with screenshots + + + Programmatic implementation + + +``` + +### Steps for Sequential Processes +Automatically numbered with anchor links: + +```mdx + + + Create your Vapi account and get your API key + + + Install using your preferred package manager + + + Create your first assistant + + +``` + +## Cards & Navigation + +### Individual Cards +```mdx + + Get started with Vapi's Python SDK + +``` + +### Card Groups for Options +```mdx + + + **Best for:** First-time users + + Get up and running in 5 minutes + + + **Best for:** Production deployments + + Configure advanced features + + +``` + +## Content Layout + +### Aside for Sticky Content +Push content to the right in a sticky container: + +```mdx + +``` + +### Frames for Images +Wrap images in a styled container: + +```mdx + + Dashboard screenshot + +``` + +## API Reference Components + +### Endpoint Snippets +Reference API endpoints directly: + +```mdx + + + +``` + +### Parameter Documentation +Use structured parameter tables: + +```mdx + + The name of your assistant + + + The LLM model to use + +``` + +## Advanced Features + +### Embeds for Rich Media +```mdx + + +``` + +### Icons from Font Awesome +```mdx + + +``` + +### Tooltips for Contextual Help +```mdx + + API Key + +``` + +## Best Practices + +### Component Selection +- **CodeBlocks** - For multi-language examples that should sync +- **Tabs** - For different approaches to the same task +- **Steps** - For sequential procedures +- **Cards** - For navigation and option selection +- **Accordions** - For optional details and FAQs +- **Callouts** - For important information that needs attention + +### Content Organization +- Use **Aside** for complementary content that shouldn't interrupt the main flow +- Use **Frames** for important screenshots and diagrams +- Use **CardGroups** to present multiple options clearly +- Use **AccordionGroups** for comprehensive FAQ sections + +### Accessibility & Search +- All accordion content is searchable even when collapsed +- Components are built with accessibility in mind +- Proper semantic HTML is generated for SEO + +--- + +**Framework Note:** Fern automatically handles syntax highlighting, responsive design, and search indexing for all components. diff --git a/.cursor/rules/code-standards.mdc b/.cursor/rules/code-standards.mdc new file mode 100644 index 000000000..fcf2b0a02 --- /dev/null +++ b/.cursor/rules/code-standards.mdc @@ -0,0 +1,143 @@ +--- +description: Code quality standards and best practices for documentation examples. Should be used whenever a code snippet needs to be included in the document. +globs: +alwaysApply: false +--- + +# Code Quality Standards + +## General Principles + +### Code Documentation +- All code examples must be **tested and functional** +- Include all necessary imports and dependencies +- Use realistic placeholder values (e.g., `YOUR_API_KEY`, `your-assistant-id`) +- Follow language-specific conventions and best practices + +### Error Handling +- Include proper error handling in all examples +- Show both success and failure scenarios +- Provide meaningful error messages and debugging guidance +- Use try-catch blocks where appropriate + +### Security Best Practices +- Never hardcode API keys or sensitive data +- Use environment variables for configuration +- Include security warnings where relevant +- Follow OAuth/API key best practices + +## Language-Specific Standards + +### TypeScript/JavaScript +```typescript +// ✅ Good - Proper imports and error handling +import { VapiClient } from "@vapi-ai/server-sdk"; + +const vapi = new VapiClient({ + token: process.env.VAPI_API_KEY +}); + +try { + const assistant = await vapi.assistants.create({ + name: "Customer Support", + // ... configuration + }); + console.log(`Assistant created: ${assistant.id}`); +} catch (error) { + console.error("Failed to create assistant:", error); +} +``` + +### Python +```python +# ✅ Good - Proper imports and error handling +import os +from vapi import Vapi + +client = Vapi(token=os.getenv("VAPI_API_KEY")) + +try: + assistant = client.assistants.create( + name="Customer Support", + # ... configuration + ) + print(f"Assistant created: {assistant.id}") +except Exception as error: + print(f"Failed to create assistant: {error}") +``` + +### cURL +```bash +# ✅ Good - Proper headers and error codes +curl -X POST "https://api.vapi.ai/assistant" \ + -H "Authorization: Bearer $VAPI_API_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "name": "Customer Support" + }' \ + --fail-with-body +``` + +## Code Block Formatting + +### Multi-language Examples +Always provide multiple implementation options using Fern's ``: + +```mdx + +```typescript title="TypeScript SDK" +// Complete working example +``` +```python title="Python SDK" +# Complete working example +``` +```bash title="cURL" +# Complete working example +``` + +``` + +### Code Attributes +Use appropriate attributes for code blocks: +- `maxLines=10` for long examples +- `wordWrap` for wide content +- `title="filename.ext"` for file examples +- `{2-4}` for line highlighting + +### Placeholder Standards +- `YOUR_API_KEY` for API keys +- `YOUR_ASSISTANT_ID` for resource IDs +- `your-phone-number` for phone numbers +- `your-webhook-url` for URLs + +## Production Readiness + +### Environment Configuration +```typescript +// ✅ Good - Environment-based configuration +const config = { + apiKey: process.env.VAPI_API_KEY, + baseUrl: process.env.VAPI_BASE_URL || 'https://api.vapi.ai', + timeout: parseInt(process.env.VAPI_TIMEOUT || '30000') +}; +``` + +### Rate Limiting +```typescript +// ✅ Good - Include rate limiting considerations +async function bulkCreateAssistants(configs: AssistantConfig[]) { + const results = []; + for (const config of configs) { + try { + const assistant = await vapi.assistants.create(config); + results.push(assistant); + + // Rate limiting - wait between requests + await new Promise(resolve => setTimeout(resolve, 1000)); + } catch (error) { + console.error(`Failed to create assistant: ${error}`); + } + } + return results; +} +``` diff --git a/.cursor/rules/content-templates.mdc b/.cursor/rules/content-templates.mdc new file mode 100644 index 000000000..a92a28c63 --- /dev/null +++ b/.cursor/rules/content-templates.mdc @@ -0,0 +1,186 @@ +--- +description: Content templates and page skeletons for common documentation patterns. Use this when creating new documents, creating feature overviews, etc. +globs: +alwaysApply: false +--- + +# Content Templates + +## Page Templates + +### Standard Documentation Page +```mdx +--- +title: [Page title] +subtitle: [Brief description] +slug: [category]/[page-name] +description: [Short description for preview link] +--- + +## Overview + +[Brief description of what this page covers and who it's for] + +- [Key point or capability 1] +- [Key point or capability 2] +- [Key point or capability 3] + +For details, see **[Related Section]**. + +## [Main Content Section] + +[Core content with examples, steps, or explanations] + +## FAQ + + + + [Clear, helpful answer] + + +``` + +### Feature Overview Page +```mdx +--- +title: [Feature name] +subtitle: Learn [what users will accomplish] +--- + +## Overview + +[Feature name] enables you to [main capability]. This [type of solution] helps you [business outcome]. + +**[Feature] allows you to:** +- [Specific capability 1] +- [Specific capability 2] +- [Specific capability 3] + +## How [feature] works + +[Brief explanation of the underlying process or technology] + + + + [Brief description of first step] + + + [Brief description of second step] + + + [Brief description of third step] + + + +## Key capabilities + +- **[Capability 1]:** [Description with benefits] +- **[Capability 2]:** [Description with benefits] +- **[Capability 3]:** [Description with benefits] + +## [Implementation paths or next steps] + + + + [Description and use case] + + + [Description and use case] + + +``` + +## Content Patterns + +### Introduction Patterns +**For overviews:** +> "[Product/Feature] is [brief definition]. We handle [complex part] so you can focus on [user value]." + +**For tutorials:** +> "Build [specific outcome] step by step. Choose between using the Dashboard interface or programmatic APIs to suit your workflow." + +**For examples:** +> "Build a [use case] with [key technologies]. The [agent/workflow] handles [business scenario] using [technical approach]." + +### Step Introduction Patterns +**For setup steps:** +> "Configure [component] to [achieve specific outcome]." + +**For implementation steps:** +> "Create [thing] that [does what] for [user benefit]." + +**For testing steps:** +> "Validate [thing] works correctly with [test scenario]." + +### Closing Patterns +**For tutorials:** +> "Now that you have [accomplished goal], consider [next steps or enhancements]:" + +**For examples:** +> "Just like that, you've built [outcome]. Consider reading the following guides to further enhance your [solution]:" + +**For overviews:** +> "Ready to get started? Check out [most relevant next step] or explore [alternative path]." + +## Component Usage Patterns + +### Card Groups for Options +```mdx + + + **Best for:** [use case] + + [Brief description] + + + **Best for:** [use case] + + [Brief description] + + +``` + +### Step Lists for Procedures +```mdx + + + [Brief explanation of purpose] + + [Implementation details or sub-steps] + + + [Continue with logical flow] + + +``` + +### Tabs for Multi-modal Implementation +```mdx + + + [Visual, no-code approach] + + + [Programmatic implementation] + + + [Alternative SDK implementation] + + +``` diff --git a/.cursor/rules/examples-documentation.mdc b/.cursor/rules/examples-documentation.mdc new file mode 100644 index 000000000..bb576b564 --- /dev/null +++ b/.cursor/rules/examples-documentation.mdc @@ -0,0 +1,123 @@ +--- +description: Guidelines for example documentation and use case implementations +globs: **/examples/*.mdx,**/**/examples/*.mdx +alwaysApply: false +--- + +# Example Documentation Standards + +Examples should be **small, focused demos** that show how to implement one feature or use case. + +## Required Sections + +1. **Overview** - What the example builds and demonstrates +2. **Prerequisites** - Account requirements and setup needed +3. **Step-by-step implementation** - Detailed walkthrough +4. **Testing/validation** - How to verify it works +5. **Next steps** - Links to related examples or advanced topics + +## Content Guidelines + +### Opening Structure +```mdx +## Overview + +[1-2 sentence description of what this example demonstrates] + +**[Agent/Workflow] Capabilities:** +* [Specific capability 1] +* [Specific capability 2] + +**What You'll Build:** +* [Concrete deliverable 1] +* [Concrete deliverable 2] +* [Concrete deliverable 3] +``` + +### Implementation Approach +- **Multi-modal examples**: Always provide both Dashboard and SDK approaches +- **Complete code**: Include all imports, error handling, and setup +- **Real-world context**: Use realistic data and scenarios +- **Production-ready**: Follow best practices and include security considerations + +### Code Organization +Use `` or `` for multiple implementation approaches: +- Dashboard (visual, no-code) +- TypeScript (Server SDK) +- Python (Server SDK) +- Additional languages as relevant + +### Data and Assets +- Include downloadable sample data (CSVs, JSON files) +- Provide realistic test scenarios +- Use placeholder data that reflects real use cases + +## Quality Standards + +### Code Quality +- All code examples must be tested and functional +- Include proper error handling +- Use environment variables for sensitive data +- Follow language-specific best practices + +### Documentation Quality +- Explain the reasoning behind implementation choices +- Include common gotchas and troubleshooting +- Provide context for business use cases +- Link to relevant API documentation + +### User Experience +- Clear success criteria for each step +- Visual confirmation (screenshots, videos) +- Downloadable resources when helpful +- Progressive complexity (simple → advanced) + +## Templates + +### Example Overview +```mdx +--- +title: [Use case name] +subtitle: [Brief description of what users will build] +slug: [category]/examples/[example-name] +--- + +## Overview + +[Detailed description of the use case and what the example demonstrates] + +**[Type] Capabilities:** +* [Key capability 1] +* [Key capability 2] + +**What You'll Build:** +* [Deliverable 1 with tools/integrations] +* [Deliverable 2 with specific features] +* [Deliverable 3 with validation/testing] + +## Prerequisites + +* [Account requirement] +* [Tool/service requirement if applicable] +``` + +### Step Implementation +```mdx + + + [Brief explanation of the step's purpose] + + + + [Visual step-by-step with screenshots] + + + [Complete code example] + + + [Complete code example] + + + + +``` diff --git a/.cursor/rules/glob-based/examples-documentation.mdc b/.cursor/rules/glob-based/examples-documentation.mdc new file mode 100644 index 000000000..bb576b564 --- /dev/null +++ b/.cursor/rules/glob-based/examples-documentation.mdc @@ -0,0 +1,123 @@ +--- +description: Guidelines for example documentation and use case implementations +globs: **/examples/*.mdx,**/**/examples/*.mdx +alwaysApply: false +--- + +# Example Documentation Standards + +Examples should be **small, focused demos** that show how to implement one feature or use case. + +## Required Sections + +1. **Overview** - What the example builds and demonstrates +2. **Prerequisites** - Account requirements and setup needed +3. **Step-by-step implementation** - Detailed walkthrough +4. **Testing/validation** - How to verify it works +5. **Next steps** - Links to related examples or advanced topics + +## Content Guidelines + +### Opening Structure +```mdx +## Overview + +[1-2 sentence description of what this example demonstrates] + +**[Agent/Workflow] Capabilities:** +* [Specific capability 1] +* [Specific capability 2] + +**What You'll Build:** +* [Concrete deliverable 1] +* [Concrete deliverable 2] +* [Concrete deliverable 3] +``` + +### Implementation Approach +- **Multi-modal examples**: Always provide both Dashboard and SDK approaches +- **Complete code**: Include all imports, error handling, and setup +- **Real-world context**: Use realistic data and scenarios +- **Production-ready**: Follow best practices and include security considerations + +### Code Organization +Use `` or `` for multiple implementation approaches: +- Dashboard (visual, no-code) +- TypeScript (Server SDK) +- Python (Server SDK) +- Additional languages as relevant + +### Data and Assets +- Include downloadable sample data (CSVs, JSON files) +- Provide realistic test scenarios +- Use placeholder data that reflects real use cases + +## Quality Standards + +### Code Quality +- All code examples must be tested and functional +- Include proper error handling +- Use environment variables for sensitive data +- Follow language-specific best practices + +### Documentation Quality +- Explain the reasoning behind implementation choices +- Include common gotchas and troubleshooting +- Provide context for business use cases +- Link to relevant API documentation + +### User Experience +- Clear success criteria for each step +- Visual confirmation (screenshots, videos) +- Downloadable resources when helpful +- Progressive complexity (simple → advanced) + +## Templates + +### Example Overview +```mdx +--- +title: [Use case name] +subtitle: [Brief description of what users will build] +slug: [category]/examples/[example-name] +--- + +## Overview + +[Detailed description of the use case and what the example demonstrates] + +**[Type] Capabilities:** +* [Key capability 1] +* [Key capability 2] + +**What You'll Build:** +* [Deliverable 1 with tools/integrations] +* [Deliverable 2 with specific features] +* [Deliverable 3 with validation/testing] + +## Prerequisites + +* [Account requirement] +* [Tool/service requirement if applicable] +``` + +### Step Implementation +```mdx + + + [Brief explanation of the step's purpose] + + + + [Visual step-by-step with screenshots] + + + [Complete code example] + + + [Complete code example] + + + + +``` diff --git a/.cursor/rules/glob-based/mdx-components.mdc b/.cursor/rules/glob-based/mdx-components.mdc new file mode 100644 index 000000000..9cff6ec7f --- /dev/null +++ b/.cursor/rules/glob-based/mdx-components.mdc @@ -0,0 +1,60 @@ +--- +description: MDX front-matter, components, and formatting guidelines +globs: **/*.mdx +alwaysApply: false +--- + +# MDX Components & Formatting + +## Front‑matter Template + +```mdx +--- +title: +subtitle: +slug: path/to/page +--- +``` + +## Asset Conventions + +All images are stored in `/fern/static/images` (top‑level, not nested). +Reference images with: + +```mdx +![alt‑text](mdc:assets/images/.) +``` + +## Content Structure + +### Standard Page Layout +1. **Overview section** - What users will accomplish +2. **Prerequisites** - What users need before starting +3. **Main content** - Steps, explanations, or examples +4. **Next steps** - Where users should go next + +### Cross-References +Always link to related content: +- Use full page titles in links: `[Getting started with assistants](mdc:docs/assistants)` +- Reference API docs: `[API reference](mdc:fern/api-reference/assistants)` +- Link to examples: `[Voice widget example](mdc:docs/assistants/examples/voice-widget)` + +## Component Guidelines + +Prefer Fern's native components over basic Markdown when available: +- Use `` instead of numbered lists for procedures +- Use `` instead of separate code blocks for multi-language examples +- Use `` for important information instead of blockquotes +- Use `` for navigation and option selection + +## File Organization + +### Slugs and Paths +- Use kebab-case for file names: `voice-assistant-setup.mdx` +- Match directory structure to URL structure +- Keep slugs short but descriptive + +### Front-matter Best Practices +- **title**: Should match the main heading but can be shorter for navigation +- **subtitle**: One sentence describing what users will learn or build +- **slug**: Override only when needed for better URLs diff --git a/.cursor/rules/glob-based/quickstart-guide.mdc b/.cursor/rules/glob-based/quickstart-guide.mdc new file mode 100644 index 000000000..62d0884f1 --- /dev/null +++ b/.cursor/rules/glob-based/quickstart-guide.mdc @@ -0,0 +1,101 @@ +--- +description: Guidelines for quickstart guides and tutorials +globs: **/quickstart/*.mdx,**/**/quickstart.mdx +alwaysApply: false +--- + +# Quickstart Guide Standards + +## Objectives + +Get users to "Hello World" moment fast with minimal steps required. + +## Structure Requirements + +### Prerequisites Section +Always include: +- Account requirements (e.g., "A Vapi account") +- API key access instructions +- Any required downloads or installations + +### Implementation Paths +Provide multiple implementation options using `` or ``: +- Dashboard (no-code approach) +- TypeScript/JavaScript SDK +- Python SDK +- cURL (for API examples) + +### Step-by-Step Format +Use `` component for all tutorials: + +```mdx + + + Brief explanation of what this step accomplishes. + + [Implementation details with code examples] + + + Continue with logical progression... + + +``` + +## Content Guidelines + +### Code Examples +- Always provide working, copy-pastable code +- Include all necessary imports and setup +- Replace placeholder values clearly (e.g., `YOUR_API_KEY`) +- Test all code examples before publishing + +### Visual Elements +- Include screenshots or videos for Dashboard workflows +- Use `` components for important visual guidance +- Keep videos short and focused (< 30 seconds) + +### Language & Tone +- Start with "In this quickstart, you'll learn to:" +- Use active voice and present tense +- Keep explanations concise—save deep dives for other docs +- End with clear "Next steps" pointing to relevant guides + +### Success Validation +Each quickstart should include: +- Clear success criteria ("You should see...") +- Troubleshooting for common issues +- Testing instructions to verify implementation + +## Templates + +### Standard Opening +```mdx +## Overview + +[Brief description of what users will build and accomplish] + +**In this quickstart, you'll learn to:** +- [Specific actionable outcome 1] +- [Specific actionable outcome 2] +- [Specific actionable outcome 3] + +## Prerequisites + +- [Required account or service] +- [Required tools or access] +``` + +### Standard Closing +```mdx +## Next steps + +Now that you have [accomplished goal]: + +- **[Related advanced topic]:** [Brief description with link] +- **[Integration option]:** [Brief description with link] +- **[Scaling guidance]:** [Brief description with link] + + +[Helpful tip or link to related quickstart] + +``` diff --git a/.cursor/rules/glob-based/workflows-documentation.mdc b/.cursor/rules/glob-based/workflows-documentation.mdc new file mode 100644 index 000000000..8d1e9d6e8 --- /dev/null +++ b/.cursor/rules/glob-based/workflows-documentation.mdc @@ -0,0 +1,109 @@ +--- +description: Guidelines for workflow documentation and complex multi-step processes +globs: **/workflows/*.mdx +alwaysApply: false +--- + +# Workflow Documentation Standards + +Workflows use visual decision trees and conditional logic for complex multi-step processes. + +## Workflow Purpose + +Perfect for: +- Appointment scheduling with availability checks +- Lead qualification with branching questions +- Complex customer service flows with escalation +- Multi-step data collection and validation + +## Documentation Structure + +### Core Sections Required +1. **Overview** - Workflow purpose and business context +2. **Flow diagram** - Visual representation of the decision tree +3. **Configuration** - Step-by-step setup instructions +4. **Variables and data** - Input/output data structures +5. **Testing scenarios** - Comprehensive test cases +6. **Integration points** - External systems and APIs + +## Content Guidelines + +### Flow Visualization +- Include visual flow diagrams showing decision paths +- Use clear node labels and condition descriptions +- Highlight error handling and edge case paths +- Show data flow between steps + +### Business Context +- Explain the real-world problem being solved +- Provide specific use case scenarios +- Include success metrics and KPIs +- Reference industry best practices + +### Technical Implementation +- Detail all configuration steps +- Include variable definitions and schemas +- Provide API integration examples +- Cover error handling strategies + +## Workflow Components + +### Decision Nodes +Document: +- Condition logic and evaluation criteria +- Branch paths and outcomes +- Fallback behaviors +- Variable dependencies + +### Data Collection +Document: +- Input validation rules +- Required vs optional fields +- Data transformation logic +- Storage and retrieval patterns + +### Integrations +Document: +- External API endpoints +- Authentication requirements +- Rate limiting considerations +- Error response handling + +## Templates + +### Workflow Overview +```mdx +## Overview + +Build [workflow type] with [key capabilities]. This workflow handles [business scenario] using [decision logic approach]. + +**Business Use Case:** +[Describe the real-world problem this solves] + +**Workflow Capabilities:** +- [Primary capability with decision logic] +- [Secondary capability with data handling] +- [Integration capability with external systems] + +**Flow Overview:** +[High-level description of the workflow path] +``` + +### Testing Template +```mdx +## Test the Workflow + +### Test Scenarios + +| Scenario | Input | Expected Path | Expected Outcome | +|----------|-------|---------------|------------------| +| [Happy path] | [Sample input] | [Main flow] | [Success result] | +| [Edge case 1] | [Edge input] | [Alternative path] | [Handled result] | +| [Error case] | [Invalid input] | [Error handling] | [Error resolution] | + +### Validation Steps +1. Test each decision branch independently +2. Verify data persistence across steps +3. Confirm integration endpoints respond correctly +4. Validate error handling and recovery +``` diff --git a/.cursor/rules/index.mdc b/.cursor/rules/index.mdc new file mode 100644 index 000000000..8ea8789e3 --- /dev/null +++ b/.cursor/rules/index.mdc @@ -0,0 +1,97 @@ +--- +description: Main documentation rules index and system overview +globs: +alwaysApply: true +--- + +# Vapi Documentation Rules System + +This is the main entry point for Vapi documentation rules. All documentation should follow these core principles and leverage specific rules based on content type. + +## Core Documentation Standards + +Every page must be: + +- **Clear** - Use plain language, avoid jargon +- **Brief** - Keep sentences and paragraphs short +- **Task-oriented** - Present steps in logical order +- **Scannable** - Use headings, spacing, and components effectively +- **Outcome-focused** - Ensure every section supports user success + +## Active Rules + +### Always Applied + +- **This index** - System overview and rule navigation +- **Core principles** ([core-principles.mdc](mdc:.cursor/rules/always-applied/core-principles.mdc)) - Writing style, tone, and fundamental standards +- **Fern components** ([fern-components.mdc](mdc:.cursor/rules/always-applied/fern-components.mdc)) - Framework-specific component usage + +### Content-Type Rules + +These apply automatically based on file paths: + +- **MDX Components** ([mdx-components.mdc](mdc:.cursor/rules/glob-based/mdx-components.mdc)) - For all `.mdx` files - front-matter, components, formatting +- **Quickstart Guides** ([quickstart-guide.mdc](mdc:.cursor/rules/glob-based/quickstart-guide.mdc)) - For `/quickstart/` paths - tutorial structure and flow +- **Examples** ([examples-documentation.mdc](mdc:.cursor/rules/glob-based/examples-documentation.mdc)) - For `/examples/` paths - use case implementations +- **Workflows** ([workflows-documentation.mdc](mdc:.cursor/rules/glob-based/workflows-documentation.mdc)) - For `/workflows/` paths - complex multi-step processes + +### Agent-requested or Manually applied rules (applied via @rule-name when needed) + +- **Code Standards** ([code-standards.mdc](mdc:.cursor/rules/code-standards.mdc)) - Code quality, testing standards +- **Content Templates** ([content-templates.mdc](mdc:.cursor/rules/content-templates.mdc)) - Page templates and content patterns + +## When to Consult Specific Rules + +| Working on... | Consult Rule | For guidance on... | +|---------------|--------------|-------------------| +| Any `.mdx` file | [mdx-components.mdc](mdc:.cursor/rules/glob-based/mdx-components.mdc) + [fern-components.mdc](mdc:.cursor/rules/always-applied/fern-components.mdc) | Components, front-matter, formatting | +| Getting started guides | [quickstart-guide.mdc](mdc:.cursor/rules/glob-based/quickstart-guide.mdc) | Tutorial structure, step flow, prerequisites | +| Use case examples | [examples-documentation.mdc](mdc:.cursor/rules/glob-based/examples-documentation.mdc) | Implementation patterns, multi-modal examples | +| Complex workflows | [workflows-documentation.mdc](mdc:.cursor/rules/glob-based/workflows-documentation.mdc) | Decision trees, data flow, business context | +| Code examples | [code-standards.mdc](mdc:.cursor/rules/code-standards.mdc) | Quality, security, best practices | +| New page types | [content-templates.mdc](mdc:.cursor/rules/content-templates.mdc) | Templates, patterns, structure | +| Fern components | [fern-components.mdc](mdc:.cursor/rules/always-applied/fern-components.mdc) | Framework-specific components and features | + +## Quick Reference + +### Standard Opening +```mdx +## Overview + +[Brief description of what users will build/accomplish] + +**In this [guide/example], you'll learn to:** +- [Specific actionable outcome 1] +- [Specific actionable outcome 2] +``` + +### Implementation / User Journey Tabs (Fern) +```mdx + +```txt title="Dashboard" +// Complete working example +``` +```typescript title="TypeScript (Server SDK)" +// Complete working example +``` +```python title="Python (Server SDK)" +# Complete working example +``` +```bash title="cURL" +# Complete working example +``` + +``` + +### Standard Closing +```mdx +## Next steps + +Now that you have [accomplished goal]: +- **[Advanced topic]:** [Description with link] +- **[Related feature]:** [Description with link] +``` + +--- + +**Rule of thumb:** Every sentence should clarify *why* or *how*—if it does neither, remove or rewrite it. diff --git a/.cursorignore b/.cursorignore new file mode 100644 index 000000000..014e65e11 --- /dev/null +++ b/.cursorignore @@ -0,0 +1,6 @@ +**/.definition +**/.preview/** +node_modules/ +dist/ +.env +.DS_Store diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 000000000..b6ccd7508 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,9 @@ +## Description + + +- + +## Testing Steps + +- [ ] Run the app locally using `fern docs dev` or navigate to preview deployment +- [ ] Ensure that the changed pages and code snippets work diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index bbb9a607b..65a6b2a55 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -7,7 +7,7 @@ on: - main jobs: - run: + fern-check: runs-on: ubuntu-latest steps: - name: Checkout repository diff --git a/.github/workflows/pr-review.yml b/.github/workflows/pr-review.yml new file mode 100644 index 000000000..7d287a332 --- /dev/null +++ b/.github/workflows/pr-review.yml @@ -0,0 +1,157 @@ +name: 📚 Documentation Review (Simple) + +on: + pull_request: + types: [opened, synchronize, reopened] + paths: + - "fern/**/*.mdx" + - "fern/**/*.yml" + - "fern/**/*.yaml" + +jobs: + review: + runs-on: ubuntu-latest + if: false + permissions: + contents: read + pull-requests: write + + steps: + - uses: actions/checkout@v4 + + - name: 📂 Get changed files + id: changed-files + uses: tj-actions/changed-files@v46 + with: + files: | + fern/**/*.mdx + fern/**/*.yml + fern/**/*.yaml + + - name: ⚙️ Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: "18" + + - name: 🤖 Install Claude Code + run: npm install -g @anthropic-ai/claude-code + + - name: 🔍 Review documentation + if: steps.changed-files.outputs.any_changed == 'true' + env: + ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} + run: | + echo "## 📝✨ Documentation Review by Claude 🤖" > review.md + echo "" >> review.md + echo "Hey there! 👋 I've reviewed your documentation changes against our style guidelines. Here's what I found:" >> review.md + echo "" >> review.md + + for file in ${{ steps.changed-files.outputs.all_changed_files }}; do + echo "🔍 Reviewing $file..." + + # Read file content + content=$(cat "$file") + + # Get review from Claude + review=$(claude -p --output-format text " + You are a friendly documentation reviewer. Review this documentation file against these specific guidelines: + + ## Core Principles to Check: + - **Clarity**: Plain language, no jargon or unnecessary complexity + - **Brevity**: Short sentences and paragraphs + - **Task-orientation**: Logical step order that helps readers proceed + - **Scannability**: Good headings, spacing, and components for quick review + - **Outcome focus**: Every section supports user success + + ## Style Rules to Verify: + - **Titles**: Only first word capitalized (unless proper noun) + - **Subtitles**: Begin with 'Learn to...' for guides, otherwise concise + - **Emojis**: Only when essential for comprehension + - **Tone**: Direct, professional, friendly + - **Links**: Descriptive text (not 'click here') + - **Bold**: Used for key names/concepts + + ## Writing Style to Check: + - **Active voice**: 'Connect the SDK' not 'SDK should be connected' + - **Present tense**: 'Run' not 'You will run' + - **Second person**: 'you' (reserve 'we' for collaborative tutorials) + - **Intent before action**: Explain why, then how + - **Concrete examples**: Code snippets over theory + - **Consistent terminology**: Same terms used throughout + + ## MDX Components to Validate: + - **Accordions**: Only for FAQ sections + - **Callouts**: , , , , , + - **Cards**: Proper title, icon, href format + - **Steps**: for sequential instructions (NOT numbered lists 1,2,3,4...) + - **Frames**: For images with captions + - **Tabs**: For organizing related content + - **CodeBlocks**: For multi-language examples + + ## Specific Things to Flag: + - **Numbered lists (1. 2. 3.)**: Should use component instead + - **'Click here' links**: Use descriptive link text + - **Passive voice**: Convert to active voice + - **Long paragraphs**: Break into shorter ones + - **Missing context**: Code examples need explanation + + ## Front Matter to Check: + - title: short and clear + - subtitle: concise and helpful + + File: $file + Content: + \`\`\` + $content + \`\`\` + + Be helpful and encouraging! Use these emojis in your feedback: + - 🚨 🔥 for major issues that need fixing + - ⚠️ 🤔 for minor issues or improvements + - 💡 ✨ for suggestions and ideas + - ✅ 🎉 🚀 for things done well + - 🎯 for specific improvements + - 📝 for writing style issues + - 🧩 for MDX component suggestions + + **IMPORTANT**: If you see numbered lists (1. 2. 3. etc.), tell them to use the component instead: + + Example: + Instead of: + 1. First step + 2. Second step + 3. Third step + + Use: + + Description + Description + Description + + + Focus on the most impactful issues first. Keep it friendly and constructive. + ") + + echo "### 📄 \`$file\`" >> review.md + echo "$review" >> review.md + echo "" >> review.md + echo "---" >> review.md + echo "" >> review.md + done + + echo "📖 [Style Guidelines](.cursorrules) | Thanks for contributing! 🙏✨" >> review.md + + - name: 💬 Comment on PR + if: steps.changed-files.outputs.any_changed == 'true' + uses: actions/github-script@v7 + with: + script: | + const fs = require('fs'); + const review = fs.readFileSync('review.md', 'utf8'); + + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + body: review + }); diff --git a/.github/workflows/preview-docs.yml b/.github/workflows/preview-docs.yml index 4b9c83bf6..ce6eadf4f 100644 --- a/.github/workflows/preview-docs.yml +++ b/.github/workflows/preview-docs.yml @@ -17,6 +17,7 @@ jobs: id: generate-docs env: FERN_TOKEN: ${{ secrets.FERN_TOKEN }} + POSTHOG_PROJECT_API_KEY: ${{ secrets.POSTHOG_PROJECT_API_KEY }} run: | OUTPUT=$(fern generate --docs --preview --log-level debug 2>&1) || true echo "$OUTPUT" diff --git a/.github/workflows/preview-sdks.yml b/.github/workflows/preview-sdks.yml index 3168eef7e..297e51730 100644 --- a/.github/workflows/preview-sdks.yml +++ b/.github/workflows/preview-sdks.yml @@ -3,9 +3,9 @@ name: Preview SDKs on: pull_request: paths: - - 'fern/**' - - 'openapi.json' - - 'openapi-overrides.yml' + - "fern/**" + - "openapi.json" + - "openapi-overrides.yml" jobs: preview-typescript: @@ -17,6 +17,11 @@ jobs: - name: Setup node uses: actions/setup-node@v3 + - name: Setup pnpm + uses: pnpm/action-setup@v2 + with: + version: 8 + - name: Download Fern run: npm install -g fern-api @@ -30,10 +35,9 @@ jobs: env: FERN_TOKEN: ${{ secrets.FERN_TOKEN }} run: | - cd fern/apis/api/.preview/fern-typescript-node-sdk - yarn install - yarn build - + cd fern/apis/api/.preview/fern-typescript-sdk + pnpm install + pnpm build preview-python: runs-on: ubuntu-latest @@ -47,23 +51,55 @@ jobs: - name: Download Fern run: npm install -g fern-api - - name: Preview Python SDK + - name: Preview Python SDK env: FERN_TOKEN: ${{ secrets.FERN_TOKEN }} run: | fern generate --api api --group python-sdk --preview --log-level debug - + - name: Set up python uses: actions/setup-python@v4 with: - python-version: 3.8 + python-version: 3.12 - name: Bootstrap poetry - run: | - curl -sSL https://install.python-poetry.org | python - -y --version 1.5.1 + uses: snok/install-poetry@v1 + with: + version: latest + virtualenvs-create: true + virtualenvs-in-project: true - name: Compile - run: | + run: | cd fern/apis/api/.preview/fern-python-sdk poetry install - poetry run mypy . \ No newline at end of file + poetry run mypy . + + preview-go: + runs-on: ubuntu-latest + steps: + - name: Checkout repo + uses: actions/checkout@v4 + + - name: Setup node + uses: actions/setup-node@v3 + + - name: Download Fern + run: npm install -g fern-api + + - name: Preview Go SDK + env: + FERN_TOKEN: ${{ secrets.FERN_TOKEN }} + run: | + fern generate --api api --group go-sdk --preview --log-level debug + + - name: Set up Go + uses: actions/setup-go@v4 + with: + go-version: "1.21" + + - name: Compile + run: | + cd fern/apis/api/.preview/fern-go-sdk + go mod tidy + go build ./... diff --git a/.github/workflows/publish-docs.yml b/.github/workflows/publish-docs.yml index fee02a10e..21735321b 100644 --- a/.github/workflows/publish-docs.yml +++ b/.github/workflows/publish-docs.yml @@ -19,4 +19,5 @@ jobs: - name: Publish Docs env: FERN_TOKEN: ${{ secrets.FERN_TOKEN }} + POSTHOG_PROJECT_API_KEY: ${{ secrets.POSTHOG_PROJECT_API_KEY }} run: fern generate --docs --log-level debug \ No newline at end of file diff --git a/.github/workflows/release-all.yml b/.github/workflows/release-all.yml index 4470c3e25..9af8a74fb 100644 --- a/.github/workflows/release-all.yml +++ b/.github/workflows/release-all.yml @@ -1,73 +1,76 @@ -name: Release all SDKs +# This is deprecated - use the individual release workflows instead +# this is wrong because SDK don't just have one version, they have multiple versions -on: - workflow_dispatch: - inputs: - version: - description: "The version of the Go SDK that you would like to release" - required: true - type: string +# name: Release all SDKs -env: - FERN_TOKEN: ${{ secrets.FERN_TOKEN }} - NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }} - MAVEN_USERNAME: ${{ secrets.MAVEN_USERNAME }} - MAVEN_PASSWORD: ${{ secrets.MAVEN_PASSWORD }} - PYPI_TOKEN: ${{ secrets.PYPI_TOKEN }} - RUBYGEMS_API_KEY: ${{ secrets.RUBYGEMS_API_KEY }} - NPM_TOKEN: ${{ secrets.NPM_TOKEN }} +# on: +# workflow_dispatch: +# inputs: +# version: +# description: "The version of the Go SDK that you would like to release" +# required: true +# type: string -jobs: - csharp: - uses: ./.github/workflows/release-csharp-sdk.yml - secrets: inherit - with: - version: ${{ inputs.version }} +# env: +# FERN_TOKEN: ${{ secrets.FERN_TOKEN }} +# NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }} +# MAVEN_USERNAME: ${{ secrets.MAVEN_USERNAME }} +# MAVEN_PASSWORD: ${{ secrets.MAVEN_PASSWORD }} +# PYPI_TOKEN: ${{ secrets.PYPI_TOKEN }} +# RUBYGEMS_API_KEY: ${{ secrets.RUBYGEMS_API_KEY }} +# NPM_TOKEN: ${{ secrets.NPM_TOKEN }} + +# jobs: +# csharp: +# uses: ./.github/workflows/release-csharp-sdk.yml +# secrets: inherit +# with: +# version: ${{ inputs.version }} - go: - uses: ./.github/workflows/release-go-sdk.yml - secrets: inherit - with: - version: ${{ inputs.version }} +# go: +# uses: ./.github/workflows/release-go-sdk.yml +# secrets: inherit +# with: +# version: ${{ inputs.version }} - java: - uses: ./.github/workflows/release-java-sdk.yml - secrets: inherit - with: - version: ${{ inputs.version }} +# java: +# uses: ./.github/workflows/release-java-sdk.yml +# secrets: inherit +# with: +# version: ${{ inputs.version }} - python: - uses: ./.github/workflows/release-python-sdk.yml - secrets: inherit - with: - version: ${{ inputs.version }} +# python: +# uses: ./.github/workflows/release-python-sdk.yml +# secrets: inherit +# with: +# version: ${{ inputs.version }} - ruby: - uses: ./.github/workflows/release-ruby-sdk.yml - secrets: inherit - with: - version: ${{ inputs.version }} +# ruby: +# uses: ./.github/workflows/release-ruby-sdk.yml +# secrets: inherit +# with: +# version: ${{ inputs.version }} - ts: - uses: ./.github/workflows/release-ts-sdk.yml - secrets: inherit - with: - version: ${{ inputs.version }} +# ts: +# uses: ./.github/workflows/release-ts-sdk.yml +# secrets: inherit +# with: +# version: ${{ inputs.version }} - generate-docs: - needs: [csharp, go, java, python, ruby, ts] - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 +# generate-docs: +# needs: [csharp, go, java, python, ruby, ts] +# runs-on: ubuntu-latest +# steps: +# - uses: actions/checkout@v4 - - name: Setup Node.js - uses: actions/setup-node@v4 +# - name: Setup Node.js +# uses: actions/setup-node@v4 - - name: Install Fern - run: npm install -g fern-api +# - name: Install Fern +# run: npm install -g fern-api - - name: Generate Documentation - run: fern generate --docs - env: - FERN_TOKEN: ${{ secrets.FERN_TOKEN }} +# - name: Generate Documentation +# run: fern generate --docs +# env: +# FERN_TOKEN: ${{ secrets.FERN_TOKEN }} diff --git a/.github/workflows/release-csharp-sdk.yml b/.github/workflows/release-csharp-sdk.yml index 2258bb5fd..a2498ba2e 100644 --- a/.github/workflows/release-csharp-sdk.yml +++ b/.github/workflows/release-csharp-sdk.yml @@ -4,8 +4,8 @@ on: workflow_call: inputs: makePR: - description: Make Pull Request - default: false + description: "Compatibility input; SDK releases always open pull requests for manual approval" + default: true type: boolean version: description: "The version of the C# SDK that you would like to release" @@ -17,11 +17,6 @@ on: description: "The version of the C# SDK that you would like to release" required: true type: string - makePR: - description: Make Pull Request - required: true - default: false - type: boolean jobs: release: @@ -41,8 +36,4 @@ jobs: FERN_TOKEN: ${{ secrets.FERN_TOKEN }} NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }} run: | - if [ "${{ github.event.inputs.makePR }}" = "true" ]; then - fern generate --api api --group csharp-sdk --version ${{ inputs.version }} --mode pull-request --log-level debug - else - fern generate --api api --group csharp-sdk --version ${{ inputs.version }} --log-level debug - fi \ No newline at end of file + fern generate --api api --group csharp-sdk --version ${{ inputs.version }} --mode pull-request --log-level debug diff --git a/.github/workflows/release-go-sdk.yml b/.github/workflows/release-go-sdk.yml index 9a1944976..113b210ad 100644 --- a/.github/workflows/release-go-sdk.yml +++ b/.github/workflows/release-go-sdk.yml @@ -4,27 +4,68 @@ on: workflow_call: inputs: makePR: - description: Make Pull Request - default: false + description: "Compatibility input; SDK releases always open pull requests for manual approval" + default: true type: boolean version: - description: "The version of the C# SDK that you would like to release" - required: true + description: "The version of the Go SDK that you would like to release (optional - will auto-increment patch version if not provided)" + required: false type: string workflow_dispatch: inputs: version: - description: "The version of the Go SDK that you would like to release" - required: true + description: "The version of the Go SDK that you would like to release (optional - will auto-increment patch version if not provided)" + required: false type: string - makePR: - description: Make Pull Request - required: true - default: false - type: boolean jobs: + determine-version: + runs-on: ubuntu-latest + outputs: + version: ${{ steps.version.outputs.version }} + steps: + - name: Determine version + id: version + run: | + if [ -n "${{ inputs.version }}" ]; then + echo "Using provided version: ${{ inputs.version }}" + echo "version=${{ inputs.version }}" >> $GITHUB_OUTPUT + else + echo "Fetching latest version from VapiAI/server-sdk-go..." + + # Fetch latest release version from the Go SDK repository + LATEST_VERSION=$(curl -s https://api.github.com/repos/VapiAI/server-sdk-go/releases/latest | jq -r .tag_name || echo "") + + # If no release found, check tags + if [ -z "$LATEST_VERSION" ] || [ "$LATEST_VERSION" = "null" ]; then + echo "No release found, checking tags..." + LATEST_VERSION=$(curl -s https://api.github.com/repos/VapiAI/server-sdk-go/tags | jq -r '.[0].name' || echo "") + fi + + # If still no version found, default to 0.0.0 + if [ -z "$LATEST_VERSION" ] || [ "$LATEST_VERSION" = "null" ]; then + echo "No version found, defaulting to v0.0.0" + LATEST_VERSION="v0.0.0" + fi + + # Remove 'v' prefix if present + LATEST_VERSION=${LATEST_VERSION#v} + + echo "Latest version: $LATEST_VERSION" + + # Parse version components + IFS='.' read -r MAJOR MINOR PATCH <<< "$LATEST_VERSION" + + # Increment patch version + NEW_PATCH=$((PATCH + 1)) + NEW_VERSION="${MAJOR}.${MINOR}.${NEW_PATCH}" + + echo "New version: $NEW_VERSION" + echo "version=$NEW_VERSION" >> $GITHUB_OUTPUT + fi + release: + needs: determine-version runs-on: ubuntu-latest steps: - name: Checkout repo @@ -40,8 +81,5 @@ jobs: env: FERN_TOKEN: ${{ secrets.FERN_TOKEN }} run: | - if [ "${{ github.event.inputs.makePR }}" = "true" ]; then - fern generate --api api --group go-sdk --version ${{ inputs.version }} --mode pull-request --log-level debug - else - fern generate --api api --group go-sdk --version ${{ inputs.version }} --log-level debug - fi \ No newline at end of file + echo "Generating Go SDK for version ${{ needs.determine-version.outputs.version }} in pull request mode" + fern generate --api api --group go-sdk --version ${{ needs.determine-version.outputs.version }} --mode pull-request --log-level debug diff --git a/.github/workflows/release-java-sdk.yml b/.github/workflows/release-java-sdk.yml index bc2f90b0f..c648cfb63 100644 --- a/.github/workflows/release-java-sdk.yml +++ b/.github/workflows/release-java-sdk.yml @@ -4,11 +4,11 @@ on: workflow_call: inputs: makePR: - description: Make Pull Request - default: false + description: "Compatibility input; SDK releases always open pull requests for manual approval" + default: true type: boolean version: - description: "The version of the C# SDK that you would like to release" + description: "The version of the Java SDK that you would like to release" required: true type: string workflow_dispatch: @@ -17,11 +17,6 @@ on: description: "The version of the Java SDK that you would like to release" required: true type: string - makePR: - description: Make Pull Request - required: true - default: false - type: boolean jobs: release: @@ -42,8 +37,4 @@ jobs: MAVEN_USERNAME: ${{ secrets.MAVEN_USERNAME }} MAVEN_PASSWORD: ${{ secrets.MAVEN_PASSWORD }} run: | - if [ "${{ github.event.inputs.makePR }}" = "true" ]; then - fern generate --api api --group java-sdk --version ${{ inputs.version }} --mode pull-request --log-level debug - else - fern generate --api api --group java-sdk --version ${{ inputs.version }} --log-level debug - fi \ No newline at end of file + fern generate --api api --group java-sdk --version ${{ inputs.version }} --mode pull-request --log-level debug diff --git a/.github/workflows/release-php-sdk.yml b/.github/workflows/release-php-sdk.yml new file mode 100644 index 000000000..7fc44e859 --- /dev/null +++ b/.github/workflows/release-php-sdk.yml @@ -0,0 +1,31 @@ +name: Release PHP SDK + +on: + workflow_call: + inputs: + version: + description: "The version of the PHP SDK that you would like to release" + required: true + type: string + workflow_dispatch: + inputs: + version: + description: "The version of the PHP SDK that you would like to release" + required: true + type: string + +jobs: + release: + runs-on: ubuntu-latest + steps: + - name: Checkout repo + uses: actions/checkout@v4 + + - name: Download Fern + run: npm install -g fern-api + + - name: Release PHP SDK + env: + FERN_TOKEN: ${{ secrets.FERN_TOKEN }} + run: | + fern generate --group php-sdk --version ${{ inputs.version }} --mode pull-request --log-level debug diff --git a/.github/workflows/release-python-sdk.yml b/.github/workflows/release-python-sdk.yml index 9b5175255..2942139e3 100644 --- a/.github/workflows/release-python-sdk.yml +++ b/.github/workflows/release-python-sdk.yml @@ -4,27 +4,68 @@ on: workflow_call: inputs: makePR: - description: Make Pull Request - default: false + description: "Compatibility input; SDK releases always open pull requests for manual approval" + default: true type: boolean version: - description: "The version of the C# SDK that you would like to release" - required: true + description: "The version of the Python SDK that you would like to release (optional - will auto-increment patch version if not provided)" + required: false type: string workflow_dispatch: inputs: version: - description: "The version of the Python SDK that you would like to release" - required: true + description: "The version of the Python SDK that you would like to release (optional - will auto-increment patch version if not provided)" + required: false type: string - makePR: - description: Make Pull Request - required: true - default: false - type: boolean jobs: + determine-version: + runs-on: ubuntu-latest + outputs: + version: ${{ steps.version.outputs.version }} + steps: + - name: Determine version + id: version + run: | + if [ -n "${{ inputs.version }}" ]; then + echo "Using provided version: ${{ inputs.version }}" + echo "version=${{ inputs.version }}" >> $GITHUB_OUTPUT + else + echo "Fetching latest version from VapiAI/server-sdk-python..." + + # Fetch latest release version from the Python SDK repository + LATEST_VERSION=$(curl -s https://api.github.com/repos/VapiAI/server-sdk-python/releases/latest | jq -r .tag_name || echo "") + + # If no release found, check tags + if [ -z "$LATEST_VERSION" ] || [ "$LATEST_VERSION" = "null" ]; then + echo "No release found, checking tags..." + LATEST_VERSION=$(curl -s https://api.github.com/repos/VapiAI/server-sdk-python/tags | jq -r '.[0].name' || echo "") + fi + + # If still no version found, default to 0.0.0 + if [ -z "$LATEST_VERSION" ] || [ "$LATEST_VERSION" = "null" ]; then + echo "No version found, defaulting to v0.0.0" + LATEST_VERSION="v0.0.0" + fi + + # Remove 'v' prefix if present + LATEST_VERSION=${LATEST_VERSION#v} + + echo "Latest version: $LATEST_VERSION" + + # Parse version components + IFS='.' read -r MAJOR MINOR PATCH <<< "$LATEST_VERSION" + + # Increment patch version + NEW_PATCH=$((PATCH + 1)) + NEW_VERSION="${MAJOR}.${MINOR}.${NEW_PATCH}" + + echo "New version: $NEW_VERSION" + echo "version=$NEW_VERSION" >> $GITHUB_OUTPUT + fi + release: + needs: determine-version runs-on: ubuntu-latest steps: - name: Checkout repo @@ -41,8 +82,4 @@ jobs: FERN_TOKEN: ${{ secrets.FERN_TOKEN }} PYPI_TOKEN: ${{ secrets.PYPI_TOKEN }} run: | - if [ "${{ github.event.inputs.makePR }}" = "true" ]; then - fern generate --api api --group python-sdk --version ${{ inputs.version }} --mode pull-request --log-level debug - else - fern generate --api api --group python-sdk --version ${{ inputs.version }} --log-level debug - fi + fern generate --api api --group python-sdk --version ${{ needs.determine-version.outputs.version }} --mode pull-request --log-level debug diff --git a/.github/workflows/release-ruby-sdk.yml b/.github/workflows/release-ruby-sdk.yml index 15d6c64fe..5724f2d99 100644 --- a/.github/workflows/release-ruby-sdk.yml +++ b/.github/workflows/release-ruby-sdk.yml @@ -4,11 +4,11 @@ on: workflow_call: inputs: makePR: - description: Make Pull Request - default: false + description: "Compatibility input; SDK releases always open pull requests for manual approval" + default: true type: boolean version: - description: "The version of the C# SDK that you would like to release" + description: "The version of the Ruby SDK that you would like to release" required: true type: string workflow_dispatch: @@ -17,11 +17,6 @@ on: description: "The version of the Ruby SDK that you would like to release" required: true type: string - makePR: - description: Make Pull Request - required: true - default: false - type: boolean jobs: release: @@ -41,8 +36,4 @@ jobs: FERN_TOKEN: ${{ secrets.FERN_TOKEN }} RUBYGEMS_API_KEY: ${{ secrets.RUBYGEMS_API_KEY }} run: | - if [ "${{ github.event.inputs.makePR }}" = "true" ]; then - fern generate --api api --group ruby-sdk --version ${{ inputs.version }} --mode pull-request --log-level debug - else - fern generate --api api --group ruby-sdk --version ${{ inputs.version }} --log-level debug - fi \ No newline at end of file + fern generate --api api --group ruby-sdk --version ${{ inputs.version }} --mode pull-request --log-level debug diff --git a/.github/workflows/release-swift-sdk.yml b/.github/workflows/release-swift-sdk.yml new file mode 100644 index 000000000..85bf67a5c --- /dev/null +++ b/.github/workflows/release-swift-sdk.yml @@ -0,0 +1,31 @@ +name: Release Swift SDK + +on: + workflow_call: + inputs: + version: + description: "The version of the Swift SDK that you would like to release" + required: true + type: string + workflow_dispatch: + inputs: + version: + description: "The version of the Swift SDK that you would like to release" + required: true + type: string + +jobs: + release: + runs-on: ubuntu-latest + steps: + - name: Checkout repo + uses: actions/checkout@v4 + + - name: Download Fern + run: npm install -g fern-api + + - name: Release Swift SDK + env: + FERN_TOKEN: ${{ secrets.FERN_TOKEN }} + run: | + fern generate --group swift-sdk --version ${{ inputs.version }} --mode pull-request --log-level debug diff --git a/.github/workflows/release-ts-sdk.yml b/.github/workflows/release-ts-sdk.yml index 1d9c0ca2b..45a8845ac 100644 --- a/.github/workflows/release-ts-sdk.yml +++ b/.github/workflows/release-ts-sdk.yml @@ -4,11 +4,11 @@ on: workflow_call: inputs: makePR: - description: Make Pull Request - default: false + description: "Compatibility input; SDK releases always open pull requests for manual approval" + default: true type: boolean version: - description: "The version of the C# SDK that you would like to release" + description: "The version of the TypeScript SDK that you would like to release" required: true type: string workflow_dispatch: @@ -17,11 +17,6 @@ on: description: "The version of the TypeScript SDK that you would like to release" required: true type: string - makePR: - description: Make Pull Request - required: true - default: false - type: boolean jobs: release: @@ -41,8 +36,4 @@ jobs: FERN_TOKEN: ${{ secrets.FERN_TOKEN }} NPM_TOKEN: ${{ secrets.NPM_TOKEN }} run: | - if [ "${{ github.event.inputs.makePR }}" = "true" ]; then - fern generate --api api --group ts-sdk --version ${{ inputs.version }} --mode pull-request --log-level debug - else - fern generate --api api --group ts-sdk --version ${{ inputs.version }} --log-level debug - fi \ No newline at end of file + fern generate --api api --group ts-sdk --version ${{ inputs.version }} --mode pull-request --log-level debug diff --git a/.github/workflows/update-openapi.yml b/.github/workflows/update-openapi.yml new file mode 100644 index 000000000..8dc3484a8 --- /dev/null +++ b/.github/workflows/update-openapi.yml @@ -0,0 +1,36 @@ +name: Update OpenAPI Specification + +on: + workflow_dispatch: + schedule: + - cron: "0 0 * * *" + +jobs: + update-openapi: + runs-on: ubuntu-latest + permissions: + contents: write + pull-requests: write + steps: + - uses: actions/checkout@v4 + with: + token: ${{ secrets.GITHUB_TOKEN }} + - name: Update OpenAPI Spec + id: sync-openapi + uses: fern-api/sync-openapi@v4 + with: + token: ${{ secrets.GITHUB_TOKEN }} + branch: 'update-openapi-spec' + update_from_source: true + add_timestamp: true + - name: Enable auto-merge + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + PR_NUMBER=$(gh pr list --json number,headRefName --jq '[.[] | select(.headRefName | startswith("update-openapi-spec"))] | sort_by(.number) | last | .number') + if [ -n "$PR_NUMBER" ] && [ "$PR_NUMBER" != "null" ]; then + echo "Found PR #$PR_NUMBER, enabling auto-merge" + gh pr merge "$PR_NUMBER" --auto --squash + else + echo "No PR found for branch starting with update-openapi-spec" + fi diff --git a/.github/workflows/update-plain.yml b/.github/workflows/update-plain.yml new file mode 100644 index 000000000..bd17e18e9 --- /dev/null +++ b/.github/workflows/update-plain.yml @@ -0,0 +1,23 @@ +name: Index docs + +on: + schedule: + - cron: '0 */3 * * *' + +jobs: + index: + name: Index Documents + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: '22' + + - name: Install CLI + run: npm install -g @team-plain/cli@latest + + - name: Index Documents + run: plain index-sitemap https://docs.vapi.ai/sitemap.xml + env: + PLAIN_API_KEY: ${{ secrets.PLAIN_API_KEY }} diff --git a/.gitignore b/.gitignore index fe38d4938..587625b32 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,11 @@ **/.definition **/.preview/** +node_modules/ +dist/ +.env +.DS_Store +.tool-versions + +# Fern AI-generated examples (regenerated on each build; not committed) +fern/apis/api/ai_examples_override.yml +fern/apis/webhooks/ai_examples_override.yml diff --git a/LICENSE b/LICENSE new file mode 100644 index 000000000..4a728d29b --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2025 Vapi + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index df95b5398..f5fdbeae5 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,21 @@ -# VAPI API Documentation +# Vapi Platform Documentation This repository contains the source files for the documentation found at [docs.vapi.ai](https://docs.vapi.ai/). +Get started with Vapi here: [docs.vapi.ai/introduction](https://docs.vapi.ai/introduction) + +View the API Reference here: [docs.vapi.ai/api-reference](https://docs.vapi.ai/api-reference/) + +Explore our Client and Server SDKs here: [docs.vapi.ai/sdks](https://docs.vapi.ai/sdks) + +| Vapi Developer Ecosystem | | +|--------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| **Real-time SDKs** | [Web](https://github.com/VapiAI/web) · [Flutter](https://github.com/VapiAI/flutter) · [React Native](https://github.com/VapiAI/react-native-sdk) · [iOS](https://github.com/VapiAI/ios) · [Python](https://github.com/VapiAI/python) · [Vanilla](https://github.com/VapiAI/html-script-tag) | +| **Client Examples** | [Next.js](https://github.com/VapiAI/client-side-example-javascript-next) · [React](https://github.com/VapiAI/client-side-example-javascript-react) · [Flutter](https://github.com/VapiAI/flutter/tree/main/example) · [React Native](https://github.com/VapiAI/client-side-example-react-native) | +| **Server Examples** | [Vercel](https://github.com/VapiAI/server-side-example-serverless-vercel) · [Cloudflare](https://github.com/VapiAI/server-side-example-serverless-cloudflare) · [Supabase](https://github.com/VapiAI/server-side-example-serverless-supabase) · [Node](https://github.com/VapiAI/server-side-example-javascript-node) · [Bun](https://github.com/VapiAI/server-side-example-javascript-bun) · [Deno](https://github.com/VapiAI/server-side-example-javascript-deno) · [Flask](https://github.com/VapiAI/server-side-example-python-flask) · [Laravel](https://github.com/VapiAI/server-side-example-php-laravel) · [Go](https://github.com/VapiAI/server-side-example-go-gin) · [Rust](https://github.com/VapiAI/server-side-example-rust-actix) | +| **Resources** | [Official Docs](https://docs.vapi.ai/) · [API Reference](https://api.vapi.ai/api) | +| **Community** | [Videos](/community/videos) · [UI Library](https://www.vapiblocks.com/) | + ## How can I contribute to these docs? You can suggest edits by making a pull request. @@ -13,6 +27,7 @@ You can suggest edits by making a pull request. To run a local development server with hot-reloading you can run the following command ```sh +npm install -g fern-api fern docs dev ``` diff --git a/README_fern.md b/advanced.md similarity index 98% rename from README_fern.md rename to advanced.md index 6e44de077..97583a1fc 100644 --- a/README_fern.md +++ b/advanced.md @@ -1,4 +1,4 @@ -# VAPI Fern Configuration +# Vapi Api Configuration This repository contains our Fern Configuration: diff --git a/dev-docs.json b/dev-docs.json new file mode 100644 index 000000000..ad795ee99 --- /dev/null +++ b/dev-docs.json @@ -0,0 +1,9 @@ +{ + "gitHubApp": { + "approvalWorkflow": true, + "userDocsWorkflows": [ + "generateUserDocs" + ], + "issues": true + } +} \ No newline at end of file diff --git a/fern/GHL.mdx b/fern/GHL.mdx index 1cd63534d..90e0e5165 100644 --- a/fern/GHL.mdx +++ b/fern/GHL.mdx @@ -1,6 +1,6 @@ --- title: How to Connect Vapi with Make & GHL -slug: GHL +slug: tools/GHL --- diff --git a/fern/advanced/sip/sip-chime.mdx b/fern/advanced/sip/sip-chime.mdx new file mode 100644 index 000000000..1526c7841 --- /dev/null +++ b/fern/advanced/sip/sip-chime.mdx @@ -0,0 +1,308 @@ +--- +title: Amazon Chime SDK SIP Integration +subtitle: How to integrate Amazon Chime SDK Voice Connector with Vapi +slug: advanced/sip/amazon-chime +--- + +This guide walks you through setting up both outbound and inbound SIP trunking between Amazon Chime SDK and Vapi using a Voice Connector. + +This is a **Voice Connector-only** integration — inbound and outbound calls work with no Lambda functions or custom logic required. Vapi handles the AI assistant entirely. This approach is best for straightforward AI assistants on a phone number where no additional integration is needed. + + +This integration does not support passing custom SIP headers, metadata, or enriched escalation data (e.g., human transfer with SIP header context). For those use cases, use a **SIP Media Application** with **CallAndBridge** instead. + + +## Prerequisites + +- An AWS account with access to the [Amazon Chime SDK console](https://console.aws.amazon.com/chime-sdk/) +- A Vapi account with a [private API key](/security-and-privacy/api-keys) +- AWS CLI configured, or access to the Chime SDK console +- A phone number provisioned in Amazon Chime SDK (or the ability to order one) +- A Vapi assistant already created (for inbound calls) + +## Outbound calls (Chime SDK to Vapi) + +### Chime SDK configuration + + + + + +In the Amazon Chime SDK console, navigate to **Voice Connectors** and create a new one. + +Configure the following settings: +- **Encryption:** Enabled (default) +- **Network Type:** IPV4_ONLY + +![Create Voice Connector](../../static/images/sip/sip-chime-create-voice-connector.png) + +Save the **Outbound host name** from the Voice Connector details — you need it when configuring the Vapi SIP trunk. + + + + + +Navigate to the **Termination** tab of your Voice Connector and enable it. + +Add Vapi's static IP addresses for your Vapi region to the allowed host list: + +![Whitelist IP 1](../../static/images/sip/sip-chime-ip-1.png) + +![Whitelist IP 2](../../static/images/sip/sip-chime-ip-2.png) + +| Region | IP addresses | +| --- | --- | +| US | `44.229.228.186/32`, `44.238.177.138/32` | +| EU | `63.182.83.170/32` | + + + + + +In the **Termination** tab, scroll to the calling plan section and select the countries you want to allow outbound calls to. + + + + + +Still in the **Termination** tab, create a new credential with a username and password. Save these credentials — you need them for the Vapi SIP trunk configuration. + +![Create Credential](../../static/images/sip/sip-chime-create-credential.png) + + + + + +Navigate to the **Phone numbers** tab and click **Assign from inventory** to attach a phone number to this Voice Connector. + +![Phone Numbers Tab](../../static/images/sip/sip-chime-phone-number.png) + +Select the phone number you want to assign and confirm. + +![Assign Phone Number](../../static/images/sip/sip-chime-assign-phone-number.png) + + +If you don't have any phone numbers in your inventory, order them from **Amazon Chime SDK → Phone Number Management → Orders → Provision Phone Numbers**. + + + + + + +### Vapi configuration + + + + + +Get a [Vapi API key](/security-and-privacy/api-keys) to authenticate the API requests in this guide. + + + + + +Use the following API call to create a SIP trunk credential. Replace the placeholders with your Chime SDK Voice Connector details: + +```bash +curl -X POST https://api.vapi.ai/credential \ +-H "Content-Type: application/json" \ +-H "Authorization: Bearer YOUR_VAPI_API_KEY" \ +-d '{ + "provider": "byo-sip-trunk", + "name": "Chime SDK Trunk", + "outboundLeadingPlusEnabled": true, + "outboundAuthenticationPlan": { + "authUsername": "YOUR_CHIME_CREDENTIAL_USERNAME", + "authPassword": "YOUR_CHIME_CREDENTIAL_PASSWORD" + }, + "gateways": [ + { + "ip": "YOUR_CHIME_OUTBOUND_HOSTNAME", + "outboundEnabled": true, + "outboundProtocol": "tls/srtp", + "inboundEnabled": false, + "optionsPingEnabled": true + } + ] +}' +``` + +Note the `id` (credential ID) from the response for the next step. + + +The `outboundProtocol` must be set to `tls/srtp` when encryption is enabled on the Voice Connector (the default). + + + + + + +Associate your Chime SDK phone number with the Vapi SIP trunk: + +```bash +curl -X POST https://api.vapi.ai/phone-number \ +-H "Content-Type: application/json" \ +-H "Authorization: Bearer YOUR_VAPI_API_KEY" \ +-d '{ + "provider": "byo-phone-number", + "name": "Chime SDK SIP Number", + "number": "YOUR_CHIME_PHONE_NUMBER", + "numberE164CheckEnabled": true, + "credentialId": "YOUR_CREDENTIAL_ID" +}' +``` + +Note the phone number ID from the response for making calls. + + +The phone number must be in E.164 format (e.g., `+18312168445`). + + + + + + +You can make outbound calls in two ways: + +**Using the Vapi Dashboard:** + +The phone number appears in your dashboard. Select your assistant and enter the destination number you want to call. + +**Using the API:** + +```bash +curl -X POST https://api.vapi.ai/call/phone \ +-H "Content-Type: application/json" \ +-H "Authorization: Bearer YOUR_VAPI_API_KEY" \ +-d '{ + "assistantId": "YOUR_ASSISTANT_ID", + "customer": { + "number": "DESTINATION_PHONE_NUMBER", + "numberE164CheckEnabled": false + }, + "phoneNumberId": "YOUR_PHONE_NUMBER_ID" +}' +``` + + + + + +## Inbound calls (Chime SDK to Vapi) + +For inbound calls, a caller dials your Chime SDK phone number. The Voice Connector routes the call to Vapi through its origination settings — no Lambda or SIP Media Application required: + +```mermaid +graph LR + A[Caller] --> B[Chime Phone Number] + B --> C[Voice Connector] + C --> D[Regional Vapi SIP host] + D --> E[Vapi AI Assistant] +``` + +### Vapi configuration + + + + + +Vapi needs to know which IP addresses are allowed to send SIP traffic to it. Since the Voice Connector originates calls from its regional signaling IPs, you must register those IPs as a BYO SIP trunk credential in Vapi. + +Look up the **SIP signaling subnet** for your Voice Connector's region from the [Chime SDK Voice Connector network configuration docs](https://docs.aws.amazon.com/chime-sdk/latest/ag/network-config.html). + +Create the credential via the Vapi API: + +```bash +curl -X POST https://api.vapi.ai/credential \ +-H "Content-Type: application/json" \ +-H "Authorization: Bearer YOUR_VAPI_API_KEY" \ +-d '{ + "provider": "byo-sip-trunk", + "name": "Amazon Chime SDK Trunk", + "gateways": [ + { + "ip": "YOUR_VOICE_CONNECTOR_SIGNALING_IP", + "netmask": 24, + "inboundEnabled": true, + "outboundEnabled": false, + "outboundProtocol": "tls/srtp", + "optionsPingEnabled": true + } + ] +}' +``` + +Replace the `ip` and `netmask` with the values for your Voice Connector's region. For example: +- **US West (Oregon):** `99.77.253.0` with netmask `24` +- **US East (N. Virginia):** `3.80.16.0` with netmask `23` + +Set `outboundProtocol` to `tls/srtp` if your Voice Connector has encryption enabled (the default), or `udp` if not. + +Save the returned `id` — this is your **Credential ID** used in the following steps. + + + + + +Register your Chime SDK phone number in Vapi, linking it to the credential and your assistant: + +```bash +curl -X POST https://api.vapi.ai/phone-number \ +-H "Content-Type: application/json" \ +-H "Authorization: Bearer YOUR_VAPI_API_KEY" \ +-d '{ + "provider": "byo-phone-number", + "name": "Chime SDK Number", + "number": "YOUR_CHIME_PHONE_NUMBER", + "numberE164CheckEnabled": true, + "credentialId": "YOUR_CREDENTIAL_ID", + "assistantId": "YOUR_ASSISTANT_ID" +}' +``` + + +The `number` field must exactly match the E.164 phone number assigned to your Voice Connector (e.g., `+18312168445`). Inbound calls will fail to route if the numbers don't match. + + + + + + +### Chime SDK configuration + + + + + +Navigate to your Voice Connector's **Origination** tab and set **Origination status** to **Enabled**. + +![Enable Origination](../../static/images/sip/sip-chime-enable-origination.png) + +Click **New** to add an inbound route pointing to Vapi's SIP server for your region: + +- **Host (US):** `YOUR_CREDENTIAL_ID.sip.vapi.ai` +- **Host (EU):** `YOUR_CREDENTIAL_ID.sip.eu.vapi.ai` +- **Port:** `5061` (for encrypted connections) +- **Protocol:** TCP + +![Create Inbound Route](../../static/images/sip/sip-chime-create-inbound-route.png) + + + + + +Call your Chime SDK phone number from any phone. The call routes through the Voice Connector's origination settings to your regional Vapi SIP host, where your Vapi assistant answers. + +To debug issues, enable **SIP logging** on the Voice Connector (under the **Logging** tab) for detailed SIP message traces. + + + + + +## Next steps + +Now that you have Amazon Chime SDK SIP trunking configured: + +- **[SIP trunking overview](/advanced/sip/sip-trunk):** Learn more about SIP trunk concepts and configuration options. +- **[Networking and firewall](/advanced/sip/sip-networking):** Review network requirements and firewall rules. +- **[Troubleshoot SIP trunk credential errors](/advanced/sip/troubleshoot-sip-trunk-credential-errors):** Debug common SIP integration issues. diff --git a/fern/advanced/sip/sip-didlogic.mdx b/fern/advanced/sip/sip-didlogic.mdx new file mode 100644 index 000000000..0f1568e12 --- /dev/null +++ b/fern/advanced/sip/sip-didlogic.mdx @@ -0,0 +1,107 @@ +--- +title: didlogic SIP integration +subtitle: Connect didlogic SIP trunks and phone numbers to Vapi +description: Configure didlogic and Vapi for inbound calls, outbound calls, and SIP REFER transfers. +slug: advanced/sip/didlogic +--- + +Connect your didlogic SIP trunk to Vapi so your assistants can receive and place phone calls. This guide covers outbound calling through didlogic, inbound routing to Vapi, and optional SIP REFER transfers. + +For SIP trunking concepts and network requirements, see the [SIP trunking guide](/advanced/sip/sip-trunk). + + +Use the Vapi dashboard, SIP hostname, and API resources for the region where your organization is hosted. This guide provides both US and EU SIP routing formats. + + +## Prerequisites + +Before you begin, make sure you have: + +- An active [didlogic account](https://didlogic.com/get-started?utm_source=vapi_docs) with a positive balance +- At least one purchased phone number in the didlogic customer portal +- An active didlogic SIP account +- A Vapi account and assistant + +## Configure outbound calling + + + + In the [Vapi dashboard](https://dashboard.vapi.ai), select your organization name, then go to **Settings → Integrations → SIP Trunk** and click **Configure New SIP Trunk**. + + Configure the credential with your didlogic SIP account details: + + - **Name:** A descriptive name, such as `didlogic` + - **IP Address / Domain:** A [didlogic regional SIP gateway](https://docs.didlogic.com/docs/guides/getting-started/outbound-calling#our-sip-gateways), such as `sip.nl.didlogic.net` + - **Username:** Your five-digit didlogic SIP username + - **Password:** Your didlogic SIP password + + Save the credential and note its credential ID. You will use this ID when configuring inbound routing. + + + + To place outbound calls with the SIP trunk credential, the didlogic phone number must be available in Vapi. Go to [Phone Numbers](https://dashboard.vapi.ai/phone-numbers). If your didlogic number is not already listed, click **Create Phone Number** and select **BYO SIP Trunk Number**. If the number is already listed, open it to update its configuration. + + Enter or confirm your didlogic phone number and select the didlogic credential in the **SIP Trunk Credential** dropdown. If the number will also receive inbound calls, assign the assistant that should answer them. Save the phone number. + + + +## Configure inbound call routing + + + + Sign in to the [didlogic customer portal](https://app.didlogic.com), go to **Purchased**, find the phone number you imported into Vapi, and click **Edit** in the **Destination** section. + + + + Set **Destination Type** to **SIP URI**, then enter the URI for your Vapi region: + + ```text + # US organization + YOUR_PHONE_NUMBER@YOUR_CREDENTIAL_ID.sip.vapi.ai + + # EU organization + YOUR_PHONE_NUMBER@YOUR_CREDENTIAL_ID.sip.eu.vapi.ai + ``` + + Replace `YOUR_PHONE_NUMBER` with the didlogic number you imported and `YOUR_CREDENTIAL_ID` with the Vapi SIP trunk credential ID. Do not use a Vapi private API key in the SIP URI. + + Click **Add** to save the destination. + + + +## Test the integration + +### Test outbound calling + +1. In Vapi, select an assistant and the imported didlogic phone number. +2. Place a test call to a phone you can answer. +3. Verify that the call connects and displays the expected caller ID. + +### Test inbound calling + +1. Dial your didlogic phone number from an external phone. +2. Verify that Vapi receives the call and the assistant assigned to the number answers. + +## Configure SIP REFER transfers + +To transfer an active call through didlogic, ask your didlogic account manager to enable SIP REFER for your account. + + +didlogic may restrict SIP REFER transfers to other didlogic numbers. Confirm the supported destinations and required routing with your didlogic account manager. + + + + + In Vapi, go to **Tools → Create Tool → Transfer Call**. Add a **SIP** destination and enter a URI in the following format: + + ```text + sip:+E164_NUMBER@YOUR_didlogic_GATEWAY + ``` + + For example, `sip:+31203691111@sip.nl.didlogic.net`. + + + + Add a customer message and destination description, keep **Blind Transfer** selected so the transfer uses SIP REFER, and save the tool. Add the transfer tool to your assistant and publish the assistant. + + diff --git a/fern/advanced/sip/sip-didww.mdx b/fern/advanced/sip/sip-didww.mdx new file mode 100644 index 000000000..996763e7f --- /dev/null +++ b/fern/advanced/sip/sip-didww.mdx @@ -0,0 +1,309 @@ +--- +title: DIDWW SIP integration +subtitle: Connect DIDWW SIP trunks to Vapi so your assistants can receive calls, place outbound calls, and transfer active calls with SIP REFER. +description: Set up DIDWW SIP trunking with Vapi. Create inbound and outbound trunks, allowlist signaling IPs, and configure authenticated SIP REFER call transfers. +slug: advanced/sip/didww +--- + +## Before you begin + +- An active DIDWW account is required. [Sign in](https://my.didww.com/users/sign_in) or [create an account](https://my.didww.com/users/sign_up#/users/sign_up). +- Access to [DIDWW Outbound Trunks](https://doc.didww.com/voice/outbound-trunks/get-access.html) is required. +- A Vapi account and assistant is required. + +## 1. Route incoming calls to Vapi + +Create a DIDWW inbound SIP trunk that sends calls from your DIDWW numbers to Vapi. + + + + In the [DIDWW User Panel](https://my.didww.com/#/trunks), go to **Voice → Inbound Trunks** and select **Create New → SIP Trunk**. + + + + In the **General** tab, configure every field below: + + | Field | Value | + | --- | --- | + | **Name** | A descriptive name, such as `Vapi` | + | **Endpoint type** | **Static Endpoint** | + | **Host** | `sip.vapi.ai` for US organizations or `sip.eu.vapi.ai` for EU organizations | + | **Transport** | **UDP**, **TCP**, or **TLS** | + | **Port** | `5060` for UDP/TCP or `5061` for TLS | + | **Network Protocol** | Match the IP version allowed on the DIDWW outbound trunk; use **Prefer IPv4 over IPv6** or **IPv4 only** when allowlisting IPv4 addresses | + + + DIDWW inbound SIP trunk General tab with host, endpoint type, transport, and port fields configured for Vapi + + + + + {/* "Signalling" (double-l) intentionally matches DIDWW's on-screen tab label shown in the screenshot; do not change it. Use single-l "signaling" for our own prose everywhere else. */} + In the **Signalling** tab, set **Max transfers** to `1` or higher. This permits the in-dialog SIP REFER requests used for call transfers. + + + DIDWW inbound trunk Signalling tab with Max transfers set to 1 + + + + + Click **Create**. For additional DIDWW options, see the [inbound SIP trunk guide](https://doc.didww.com/voice/inbound-trunks/creating-a-new-sip-trunk.html). + + + +## 2. Enable outbound calling through DIDWW + +Create a DIDWW outbound trunk for Vapi calls and for authenticated SIP REFER transfers. + + + + In the DIDWW User Panel, go to **Voice → Outbound Trunks** and click **Create New**. + + + + Set a **Friendly Name**, such as `Vapi`, and keep **Credentials & IP-based** authentication selected. + + Under **Allowed SIP IP addresses**, add the signaling addresses for your Vapi region: + + | Region | Vapi signaling IPs | + | --- | --- | + | US | `44.229.228.186/32`, `44.238.177.138/32` | + | EU | `63.182.83.170/32` | + + To support call transfers, also add all DIDWW inbound signaling addresses: + + ```text + 46.19.209.14 + 46.19.210.14 + 46.19.212.14 + 46.19.213.14 + 46.19.214.14 + 46.19.215.14 + 185.238.173.14 + ``` + + + DIDWW outbound trunk Allowed SIP IP addresses list containing the Vapi and DIDWW signaling addresses + + + {/* The #sip-signalling anchor is intentionally double-l to match the current sip-networking heading; switch to #sip-signaling when that page is standardized to single-l (tracked as a separate issue). */} + + Do not use `0.0.0.0/0` in production. Restrict the trunk to the current [Vapi signaling IPs](/advanced/sip/sip-networking#sip-signalling) and [DIDWW SIP servers](https://doc.didww.com/voice/inbound-trunks/technical-data/sip.html#service-did-sip). + + + + + Click **Create** to save it. + + + + On **Voice → Outbound Trunks**, click the key icon in the trunk's **Credentials** column. Copy the **Username** and **Password**; you will use both in DIDWW and Vapi. + + + DIDWW outbound trunk credentials dialog showing the username and password fields + + + + + Edit the Vapi inbound trunk and open **Authorization**. Turn on **Enable Authorization**, paste the outbound trunk **Username** and **Password** into **Auth User** and **Auth Password**, then click **Submit**. + + + DIDWW inbound trunk Authorization tab with Enable Authorization turned on and the Auth User and Auth Password fields filled + + + For more detail, see [Add outbound credentials to the inbound trunk](https://doc.didww.com/integrations/vapi/index.html#step-5-add-outbound-credentials-to-the-inbound-trunk). + + + +## 3. Connect the SIP trunks in Vapi + +Use the same transport and port on both sides. In API examples, use `https://api.vapi.ai` for US organizations or replace it with `https://api.eu.vapi.ai` for EU organizations. + +### Step 1: Create the outbound trunk + + + + In the [Vapi dashboard](https://dashboard.vapi.ai), select your organization name in the top left, then click **Settings**. Under organization settings, go to **Integrations → SIP Trunk** and click **Configure New SIP Trunk**. + + 1. Set **Name** to `DIDWW Outbound Trunk`. + 2. Set **IP Address / Domain** to a [DIDWW outbound endpoint](https://doc.didww.com/voice/outbound-trunks/technical-data/sip-details.html#voice-out-signaling-endpoints), such as `fra.eu.out.didww.com`. + 3. Select the transport and port: `5060` for UDP/TCP or `5061` for TLS. + 4. Turn off **Allow inbound calls** and leave **Allow outbound calls** on. + + + Vapi SIP trunk configuration with the DIDWW outbound endpoint, transport, port, and outbound calls enabled + + + 5. Under **Authentication**, enter the DIDWW outbound username and password. Leave SIP registration off and save the trunk. + + + Vapi SIP trunk Authentication section with the DIDWW outbound username and password entered + + + + + ```bash + curl -X POST https://api.vapi.ai/credential \ + -H "Authorization: Bearer YOUR_VAPI_PRIVATE_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "provider": "byo-sip-trunk", + "name": "DIDWW Outbound Trunk", + "gateways": [ + { + "ip": "YOUR_DIDWW_OUTBOUND_ENDPOINT", + "port": 5060, + "inboundEnabled": false, + "outboundEnabled": true, + "outboundProtocol": "udp" + } + ], + "outboundAuthenticationPlan": { + "authUsername": "YOUR_DIDWW_TRUNK_USERNAME", + "authPassword": "YOUR_DIDWW_TRUNK_PASSWORD" + } + }' + ``` + + Replace the endpoint with the DIDWW signaling endpoint selected for your deployment. + + + +### Step 2: Create the inbound trunk + + + + Create another Vapi SIP trunk named `DIDWW Inbound Trunk`. + + 1. Add one gateway for each DIDWW IP below, using netmask `32` and the same port as the DIDWW inbound trunk. + 2. For every gateway, turn on **Allow inbound calls** and turn off **Allow outbound calls**. + + + Vapi SIP trunk with one inbound gateway per DIDWW signaling IP address + + + 3. Under **Authentication**, enter the DIDWW outbound username and password, then save the trunk. + + ```text + 46.19.209.14 + 46.19.210.14 + 46.19.212.14 + 46.19.213.14 + 46.19.214.14 + 46.19.215.14 + 185.238.173.14 + ``` + + + Vapi inbound SIP trunk Authentication section with the DIDWW credentials entered + + + + + ```bash + curl -X POST https://api.vapi.ai/credential \ + -H "Authorization: Bearer YOUR_VAPI_PRIVATE_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "provider": "byo-sip-trunk", + "name": "DIDWW Inbound Trunk", + "gateways": [ + { "ip": "46.19.209.14", "port": 5060, "netmask": 32, "inboundEnabled": true, "outboundEnabled": false }, + { "ip": "46.19.210.14", "port": 5060, "netmask": 32, "inboundEnabled": true, "outboundEnabled": false }, + { "ip": "46.19.212.14", "port": 5060, "netmask": 32, "inboundEnabled": true, "outboundEnabled": false }, + { "ip": "46.19.213.14", "port": 5060, "netmask": 32, "inboundEnabled": true, "outboundEnabled": false }, + { "ip": "46.19.214.14", "port": 5060, "netmask": 32, "inboundEnabled": true, "outboundEnabled": false }, + { "ip": "46.19.215.14", "port": 5060, "netmask": 32, "inboundEnabled": true, "outboundEnabled": false }, + { "ip": "185.238.173.14", "port": 5060, "netmask": 32, "inboundEnabled": true, "outboundEnabled": false } + ], + "outboundAuthenticationPlan": { + "authUsername": "YOUR_DIDWW_TRUNK_USERNAME", + "authPassword": "YOUR_DIDWW_TRUNK_PASSWORD" + } + }' + ``` + + Save the returned credential `id`; it is required when you [import the DIDWW number](/phone-numbers/didww). + + + +### Step 3: Create a call transfer tool + + + + In Vapi, go to **Tools → Create Tool → Transfer Call**. + + 1. Enter a tool name and describe when the assistant should transfer the caller. + 2. Add a **SIP** destination. + 3. Set **SIP URI** to `sip:+E164_NUMBER@OUTBOUND_ENDPOINT`, for example `sip:+447700900123@fra.eu.out.didww.com`. + 4. Add the customer message and destination description, keep **Blind Transfer**, and save. + + + Vapi Transfer Call tool with a SIP destination whose URI points to a DIDWW outbound endpoint + + + + + ```bash + curl -X POST https://api.vapi.ai/tool \ + -H "Authorization: Bearer YOUR_VAPI_PRIVATE_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "type": "transferCall", + "destinations": [ + { + "type": "sip", + "sipUri": "sip:+447700900123@YOUR_DIDWW_OUTBOUND_ENDPOINT", + "message": "Please wait while I transfer your call.", + "description": "Use when the caller asks to speak with a live person.", + "transferPlan": { + "mode": "blind-transfer", + "sipVerb": "refer" + } + } + ] + }' + ``` + + Save the returned tool `id` for the next step. + + + +### Step 4: Add the transfer tool to your assistant + + + + Open the assistant, go to **Tools → Add tool**, and select the transfer tool. Click **Publish**, then confirm the publication. + + + Vapi assistant Tools section with the DIDWW transfer tool added + + + + + Retrieve the assistant, add the transfer tool ID to `model.toolIds`, and PATCH the complete model back. The example uses `jq` to preserve the existing model configuration and tool IDs. + + ```bash + VAPI_API_BASE="https://api.vapi.ai" + ASSISTANT_ID="YOUR_ASSISTANT_ID" + TRANSFER_TOOL_ID="YOUR_TRANSFER_TOOL_ID" + + CURRENT_MODEL=$(curl -s "$VAPI_API_BASE/assistant/$ASSISTANT_ID" \ + -H "Authorization: Bearer YOUR_VAPI_PRIVATE_KEY" | jq '.model') + + UPDATED_MODEL=$(printf '%s' "$CURRENT_MODEL" | jq \ + --arg toolId "$TRANSFER_TOOL_ID" \ + '.toolIds = (((.toolIds // []) + [$toolId]) | unique)') + + jq -n --argjson model "$UPDATED_MODEL" '{model: $model}' | \ + curl -X PATCH "$VAPI_API_BASE/assistant/$ASSISTANT_ID" \ + -H "Authorization: Bearer YOUR_VAPI_PRIVATE_KEY" \ + -H "Content-Type: application/json" \ + --data-binary @- + ``` + + + +## Next step + +**[Import a number from DIDWW](/phone-numbers/didww):** Purchase or select a DIDWW number, assign the inbound trunk, and import the number into Vapi. diff --git a/fern/advanced/sip/sip-networking.mdx b/fern/advanced/sip/sip-networking.mdx new file mode 100644 index 000000000..e70088476 --- /dev/null +++ b/fern/advanced/sip/sip-networking.mdx @@ -0,0 +1,156 @@ +--- +title: SIP networking and firewall configuration +subtitle: Learn to configure your network to allow SIP signalling and media traffic with Vapi +slug: advanced/sip/sip-networking +--- + +## Overview + +When you integrate a SIP trunk with Vapi, your firewall and network infrastructure must allow SIP signalling and media (RTP) traffic to flow between your environment and Vapi's SIP servers. This page provides the complete set of IP addresses, ports, and protocols you need to configure. + +**In this reference, you'll find:** + +- All IP addresses and ports used by Vapi for SIP signalling +- RTP media port ranges, directionality details, and regional IP behavior +- Recommended firewall rules for inbound and outbound traffic + + + These networking details apply to **all** SIP trunk integrations with Vapi, regardless of your SIP provider. For provider-specific setup instructions, see the [SIP trunking](/advanced/sip/sip-trunk) guide. + + +## Quick reference + +The table below summarizes every IP address, port, and protocol you need to allowlist. Use the row that matches the Vapi region where your organization is hosted. + +| Traffic type | Region | Hostname | IP addresses | Ports | Protocol | Direction | +| --- | --- | --- | --- | --- | --- | --- | +| SIP signalling | US | `sip.vapi.ai` | `44.229.228.186`, `44.238.177.138` | `5060` | UDP/TCP | Bidirectional | +| SIP signalling | EU | `sip.eu.vapi.ai` | `63.182.83.170` | `5060` | UDP/TCP | Bidirectional | +| SIP signalling (TLS) | US | `sip.vapi.ai` | `44.229.228.186`, `44.238.177.138` | `5061` | TLS | Bidirectional | +| SIP signalling (TLS) | EU | `sip.eu.vapi.ai` | `63.182.83.170` | `5061` | TLS | Bidirectional | +| RTP media | US | N/A | No static IPs (dynamic) | `40000`-`60000` | UDP | Bidirectional | +| RTP media | EU | N/A | `63.182.83.170` | `40000`-`60000` | UDP | Bidirectional | + +Use your region's SIP hostname when configuring SIP URIs or SIP peers. If your firewall or SIP provider requires IP-based allowlisting, add the static signalling IP addresses for your region. For media, EU traffic can be allowlisted to `63.182.83.170`; US media uses dynamic source IPs and should be allowed by UDP port range. + +## SIP signalling + +Vapi's SIP infrastructure uses static IP addresses for signalling traffic in each region: + +| Region | Hostname | IP addresses | +| --- | --- | --- | +| US | `sip.vapi.ai` | `44.229.228.186/32`, `44.238.177.138/32` | +| EU | `sip.eu.vapi.ai` | `63.182.83.170/32` | + +These are the public IPs of Vapi's SBC (Session Border Controller) nodes. All SIP `INVITE`, `REGISTER`, `BYE`, and other signalling messages originate from and are received at the addresses for your region. + +### Ports + +| Port | Protocol | Use case | +| --- | --- | --- | +| **5060** | UDP/TCP | Default SIP signalling. UDP and TCP are both supported in US and EU. | +| **5061** | TLS | SIP over TLS (SIPS) signalling. | + +Use port **5060** unless your provider or security requirements mandate encrypted signalling. For TLS/SIPS in either region, use port **5061** with TLS. + +### Hostnames and allowlisting + +Configure your SIP client or PBX to point to the hostname for your region. For firewall rules and carrier allowlists, use the static IP addresses listed for your region. In the EU, `sip.eu.vapi.ai` currently resolves to `63.182.83.170`. + + + Allowlist every IP address for your region explicitly. DNS A records may not match every static IP that Vapi can use for carrier or firewall allowlisting. + + + + Do not use `sip-web.eu.vapi.ai` for SIP signalling or media. It is used for portal and API traffic and resolves through Cloudflare/WAF, not to Vapi's SIP infrastructure. + + +## SIP media (RTP) + +RTP media IP behavior depends on your region: + +- **US:** Vapi does not use static IP addresses for RTP media. Media source IPs are dynamically assigned and may change between calls. +- **EU:** RTP media uses the same static public IP as SIP signalling: `63.182.83.170`. + + + For US RTP media, allow traffic based on port ranges rather than specific source IPs. For EU RTP media, allowlist `63.182.83.170` with the full UDP port range. + + +### Port range + +Vapi uses **UDP ports 40000 through 60000** for RTP media traffic. + +| Setting | Value | +| --- | --- | +| Local RTP port range | `40000`-`60000` (UDP) | +| Direction | Bidirectional | + +- **Inbound RTP**: Vapi listens on ports `40000`-`60000` for incoming media packets. +- **Outbound RTP**: Vapi sends media from ports in the `40000`-`60000` range. The destination IP and port are determined by the remote SDP offer/answer, so Vapi can send to any IP and port your provider advertises. + + + Vapi does not restrict the remote RTP port range. Your provider may use any port for its RTP traffic. The `40000`-`60000` range applies only to Vapi's local ports. + + +## Firewall rules + +Configure your firewall to allow the following traffic. Every SIP signalling IP address for your region must be allowlisted. For RTP media, allow traffic on the full port range. US media uses dynamic IPs; EU media uses `63.182.83.170`. + +### Inbound rules (traffic from Vapi to your network) + +Allow these if your SIP provider or PBX needs to receive traffic from Vapi: + +| Rule | Region | Source IP | Destination | Port(s) | Protocol | +| --- | --- | --- | --- | --- | --- | +| SIP signalling | US | `44.229.228.186`, `44.238.177.138` | Your SIP server | `5060` | UDP/TCP | +| SIP signalling | EU | `63.182.83.170` | Your SIP server | `5060` | UDP/TCP | +| SIP signalling (TLS) | US | `44.229.228.186`, `44.238.177.138` | Your SIP server | `5061` | TLS | +| SIP signalling (TLS) | EU | `63.182.83.170` | Your SIP server | `5061` | TLS | +| RTP media | US | Any (dynamic) | Your media server | `40000`-`60000` | UDP | +| RTP media | EU | `63.182.83.170` | Your media server | `40000`-`60000` | UDP | + +### Outbound rules (traffic from your network to Vapi) + +Allow these if your firewall restricts outbound connections: + +| Rule | Region | Source | Destination IP | Port(s) | Protocol | +| --- | --- | --- | --- | --- | --- | +| SIP signalling | US | Your SIP server | `44.229.228.186`, `44.238.177.138` | `5060` | UDP/TCP | +| SIP signalling | EU | Your SIP server | `63.182.83.170` | `5060` | UDP/TCP | +| SIP signalling (TLS) | US | Your SIP server | `44.229.228.186`, `44.238.177.138` | `5061` | TLS | +| SIP signalling (TLS) | EU | Your SIP server | `63.182.83.170` | `5061` | TLS | +| RTP media | US | Your media server | Any (dynamic) | `40000`-`60000` | UDP | +| RTP media | EU | Your media server | `63.182.83.170` | `40000`-`60000` | UDP | + + + Allow every SIP signalling IP address for your region in your firewall rules. For RTP media, configure your firewall to allow the full port range (`40000`-`60000` UDP). US RTP media uses dynamic IPs. EU RTP media uses `63.182.83.170`. Contact support if you need a stricter media firewall policy. + + +## FAQ + + + + Use your region's hostname for SIP URI and peer configuration. For IP-based firewall rules, add the static IP addresses for your region explicitly. DNS-based firewall rules depend on TTL and caching behavior, and DNS A records may not match every static IP that Vapi can use for allowlisting. US RTP media uses dynamic IPs that cannot be resolved via DNS. EU RTP media uses `63.182.83.170`. + + + Yes. Vapi's RTP stack dynamically allocates ports within this range for each call. You cannot predict which specific port a given call will use, so the entire range must be open for reliable media flow. + + + It depends on the region. In the EU, SIP signalling and RTP media both use `63.182.83.170`. In the US, SIP signalling uses static IP addresses, but RTP media source IPs are dynamically assigned and may vary between calls. + + + Vapi supports TLS for SIP signalling on port 5061 in both US and EU regions. For encrypted media (SRTP), configure your SIP trunk gateway with the `tls/srtp` outbound protocol option. See the [gateway configuration reference](/advanced/sip/troubleshoot-sip-trunk-credential-errors#gateway-configuration-reference) for details. + + + These are standard SIP response codes, not Vapi-specific error codes. A `403 Forbidden` means a system in the SIP signaling path refused the request. A `404 Not Found` means the responding system could not find the requested user or domain. The exact cause depends on which system returned the response. See [Troubleshoot SIP response codes](/advanced/sip/troubleshoot-sip-response-codes) for the Vapi, provider, routing, and destination checks to perform. + + + +## Next steps + +Now that you have your network configured for Vapi SIP traffic: + +- **Set up a SIP trunk:** Follow the [SIP trunking](/advanced/sip/sip-trunk) guide to create your trunk credential and phone number +- **Configure a provider:** Set up with [Twilio](/advanced/sip/twilio), [Telnyx](/advanced/sip/telnyx), [Plivo](/advanced/sip/plivo), or [Zadarma](/advanced/sip/zadarma) +- **Troubleshoot errors:** Resolve gateway issues with the [SIP trunk credential troubleshooting](/advanced/sip/troubleshoot-sip-trunk-credential-errors) guide +- **Troubleshoot response codes:** Identify the likely failure point with the [SIP response code troubleshooting](/advanced/sip/troubleshoot-sip-response-codes) guide diff --git a/fern/advanced/sip/sip-plivo.mdx b/fern/advanced/sip/sip-plivo.mdx new file mode 100644 index 000000000..14d0cbacb --- /dev/null +++ b/fern/advanced/sip/sip-plivo.mdx @@ -0,0 +1,263 @@ +--- +title: Plivo SIP Integration +subtitle: Learn to connect your Plivo SIP trunk to Vapi for inbound and outbound calls +slug: advanced/sip/plivo +--- + +## Overview + +For a general introduction to SIP trunking with Vapi (concepts and architecture), see our [SIP Trunking Guide](../sip-trunk.mdx). + +This guide shows you how to connect your Plivo SIP trunk to your existing Vapi agents. It covers: + +- Step-by-step configuration of Plivo and Vapi for SIP trunking (outbound and inbound) +- How to register and associate your Plivo phone numbers with Vapi +- How to make outbound calls using the Vapi API and dashboard +- How to assign Plivo numbers for inbound call routing through Vapi + +## Prerequisites +- [A Plivo account](https://console.plivo.com/accounts/request-trial/) +- Admin access to your Plivo and PBX/SIP trunk configuration +- A phone number you want to connect to Vapi via Plivo + + +Indian phone numbers cannot be used with Plivo on Vapi due to TRAI regulations. These regulations require SIP termination to occur via an Indian server, which Vapi does not currently support. + + +## Get Started + + + + ## Plivo Configuration + + + Access the Plivo console. + + + 1. **Navigate to:** + `Zentrunk (SIP) → Outbound Trunks → IP Access Control List → Create New IP Group` + + 2. **Fill out the form:** + - **Name:** Enter a descriptive name (for example, `VAPI-IP-Group`). + - **IP Address List:** Add each IP address for the Vapi region where your organization is hosted: + + | Region | IP addresses | + | --- | --- | + | US | `44.229.228.186/32`, `44.238.177.138/32` | + | EU | `63.182.83.170/32` | + 3. **Click** **Create ACL** to save. + + ![Plivo IP Access Control List](../../static/images/sip/sip-plivo-ip-acl.png) + + + 1. **Navigate to:** + `Zentrunk (SIP) → Outbound Trunks → Trunks → Create New Outbound Trunk` + + 2. **Fill out the form:** + - **Trunk Name:** Enter a descriptive name (for example, `Vapi-Outbound-Trunk`). + - **IP Access Control List:** Select the IP ACL created in the previous step. + 3. **Click** **Create Trunk** to save. + + ![Create New Outbound Trunk](../../static/images/sip/sip-plivo-outbound-trunk.png) + + + After creating the trunk, locate the **Termination SIP Domain** in the trunk details page. It will look something like: + `12700668357XXXXXX.zt.plivo.com` + ![Termination SIP Domain](../../static/images/sip/sip-plivo-termination-sip-domain.png) + + **You will need this value when configuring your SIP trunk in Vapi.** + + + Navigate to: + `Numbers → Buy a new number` + + Once purchased, note down your new phone number. You will associate this number with your SIP trunk in a later step. + + ![Buy Phone Number](../../static/images/sip/sip-plivo-buy-phone-number.png) + + + + ## Vapi Configuration + + + Get a [Vapi API key](/security-and-privacy/api-keys) to authenticate the API requests in this guide. + + + 1. Copy the following API call. + 2. Replace `YOUR_PLIVO_TERMINATION_SIP_DOMAIN` with your actual Plivo Termination SIP Domain (for example, `12700668357XXXXXX.zt.plivo.com`). + + ```bash + curl -X POST https://api.vapi.ai/credential \ + -H "Content-Type: application/json" \ + -H "Authorization: Bearer YOUR_VAPI_PRIVATE_API_KEY" \ + -d '{ + "provider": "byo-sip-trunk", + "name": "PLIVO Trunk", + "gateways": [ + { + "ip": "YOUR_PLIVO_TERMINATION_SIP_DOMAIN", + "inboundEnabled": false + } + ] + }' + ``` + 3. You'll receive a response like the one below. Note the `id` (credentialId) for the next step. + + ```json + { + "id": "d293b924-f68d-4cbc-850f-xxxxxxxxxxxxxxx", + "orgId": "424acf80-dbea-4015-ace8-0f3924e6000xxxx", + "provider": "byo-sip-trunk", + "createdAt": "2025-05-05T16:38:08.815Z", + "updatedAt": "2025-05-05T16:38:08.815Z", + "gateways": [ + { + "ip": "1856282236xxxxxxxxxxx.zt.plivo.com", + "inboundEnabled": false + } + ], + "name": "PLIVO Trunk" + } + ``` + + + 1. Associate your Plivo number with the SIP trunk. Replace `YOUR_PLIVO_PHONE_NUMBER` and `YOUR_CREDENTIAL_ID` with the numbers from previous steps. + ```bash + curl -X POST https://api.vapi.ai/phone-number \ + -H "Content-Type: application/json" \ + -H "Authorization: Bearer YOUR_VAPI_PRIVATE_API_KEY" \ + -d '{ + "provider": "byo-phone-number", + "name": "PLIVO SIP Number", + "number": "YOUR_PLIVO_PHONE_NUMBER", + "numberE164CheckEnabled": false, + "credentialId": "YOUR_CREDENTIAL_ID" + }' + ``` + 2. Your response will look like this, note the phone number ID from the response for making calls. + ```bash + { + "id": "eba2fb13-259f-4123-abfa-xxxxxxxxxxxxxxx", + "orgId": "489ea344-c56f-4243-8723-b28362cd5a5c", + "number": "1833684XXXX", + "createdAt": "2025-03-05T18:31:30.389Z", + "updatedAt": "2025-03-05T18:31:30.389Z", + "name": "PLIVO SIP Number", + "credentialId": "a2c815b8-03f4-40f5-813c-xxxxxxxxxxxx", + "provider": "byo-phone-number", + "numberE164CheckEnabled": false, + "status": "active" + } + ``` + + + 1. [Follow this guide to create an assistant](/quickstart/phone#create-your-first-voice-assistant) + 2. Note your Assistant ID for making calls. + + + [**Using the API**](/calls/outbound-calling) + + ```bash + curl --location 'https://api.vapi.ai/call/phone' \ + --header 'Authorization: Bearer YOUR_VAPI_PRIVATE_API_KEY' \ + --header 'Content-Type: application/json' \ + --data '{ + "assistantId": "29d47d31-ba3c-451c-86ce-xxxxxxxxx", + "customer": { + "number": "9199437XXXXX", + "numberE164CheckEnabled": false + }, + "phoneNumberId": "eba2fb13-259f-4123-abfa-xxxxxxxxxxx" + }' + ``` + + [**Using the Vapi Dashboard**](/quickstart/phone#try-outbound-calling) + + 1. Select your Assistant + 2. Enter the phone number of the user you want to call + ![VAPI Dashboard Call](../../static/images/sip/sip-plivo-vapi-dashboard-call.png) + + + + + ## Plivo Configuration + + + Access the Plivo console. + + + 1. **Navigate to:** + `Zentrunk (SIP) → Inbound Trunks → Origination URI → Create New IP URI` + + 2. **Fill out the form:** + - **Name:** Enter a descriptive name (for example, `Vapi Inbound`). + - **URI:** Enter the origination URI for your Vapi region: `sip.vapi.ai;transport=udp` for US or `sip.eu.vapi.ai;transport=udp` for EU. + 3. **Click** **Create URI** to save. + + ![Create New IP URI](../../static/images/sip/sip-plivo-create-new-ip-uri.png) + + + 1. **Navigate to:** + `Zentrunk (SIP) → Inbound Trunks → Trunks → Create New Inbound Trunk` + + 2. **Fill out the form:** + - **Trunk Name:** Enter a descriptive name (for example, `Vapi Inbound Trunk`). + - **Primary URI:** Select the URI created in the previous step. + 3. **Click** **Create Trunk** to save. + + ![Create New Inbound Trunk](../../static/images/sip/sip-plivo-create-new-inbound-trunk.png) + + + 1. **Navigate to:** + `Phone Numbers → Select your purchased number` + + 2. **Configure the number:** + - In the **Application** dropdown, select **Zentrunk**. + - In the **Zentrunk** dropdown, select your inbound trunk. + 3. **Click** **Save** to apply changes. + + ![Attach Number to Inbound Trunk](../../static/images/sip/sip-plivo-attach-number-to-inbound-trunk.png) + + + + ## Vapi Configuration + + + Get a [Vapi API key](/security-and-privacy/api-keys) to authenticate the API requests in this guide. + + + ```bash + curl -X POST https://api.vapi.ai/credential \ + -H "Content-Type: application/json" \ + -H "Authorization: Bearer YOUR_VAPI_PRIVATE_API_KEY" \ + -d '{ + "provider": "byo-sip-trunk", + "name": "PLIVO Inbound Trunk", + "type": "inbound" + }' + ``` + Note the `id` (credentialId) from the response for the next step. + + + ```bash + curl -X POST https://api.vapi.ai/phone-number \ + -H "Content-Type: application/json" \ + -H "Authorization: Bearer YOUR_VAPI_PRIVATE_API_KEY" \ + -d '{ + "provider": "byo-phone-number", + "name": "PLIVO SIP Inbound Number", + "number": "1833684XXXX", + "numberE164CheckEnabled": false, + "credentialId": "a2c815b8-03f4-40f5-813c-xxxxxxxxxxxx" + }' + ``` + + + + + +## Errors + +- **Codec Support:** Limit trunk codecs to G.711 µ‑law and A‑law only. Other codecs are not supported by Plivo SIP trunks. +- **SIP REFER Not Supported:** Plivo SIP trunks do not accept SIP REFER for call transfers. +- **Origination URI Already Exists:** This was previously an error on Plivo's side and has been fixed. diff --git a/fern/advanced/sip/sip-telnyx.mdx b/fern/advanced/sip/sip-telnyx.mdx new file mode 100644 index 000000000..96d60713b --- /dev/null +++ b/fern/advanced/sip/sip-telnyx.mdx @@ -0,0 +1,160 @@ +--- +title: Telnyx SIP integration +subtitle: How to integrate SIP Telnyx to Vapi +slug: advanced/sip/telnyx +--- + +Integrate your Telnyx SIP trunk with Vapi to enable your AI voice assistants to handle calls efficiently. This guide walks you through the complete setup process for both inbound and outbound calls. + + + + Get a [Vapi private API key](/security-and-privacy/api-keys) to authenticate the API requests in this guide. + + + + + + - Go to Voice / SIP Trunking / Create + - Select FQDN + - Click "Add FQDN" + - Select A record type + - Set FQDN to the SIP host for your Vapi region: `sip.vapi.ai` for US or `sip.eu.vapi.ai` for EU + - Port should be 5060 by default + + + - Navigate to the Inbound tab of your SIP trunk + - Configure settings as shown: + + + + + + - Go to the Numbers tab + - Assign your acquired phone number to the SIP trunk + + + - Go to Numbers, edit the number you'll be using + - Navigate to Voice settings + - Scroll down to find "Translated Number" + - Set this value to match your Vapi SIP URI + + You can get your Vapi SIP URI when you create a new SIP number through the **Phone Numbers** tab in the Vapi dashboard. The URI will look like: +
+ sip:<your-unique-id>@sip.vapi.ai for US or sip:<your-unique-id>@sip.eu.vapi.ai for EU +
+ *This setting modifies the SIP Invite so invites are correctly routed to your Vapi SIP URI.* +
+
+
+ + + + + - Go to Voice / SIP Trunking / Authentication and routing + - Scroll down to "Outbound calls authentication" + - Create a new credential for Vapi to use + + + + + + - Go to Voice / Outbound Voice Profiles + - Create a new profile + - Name it appropriately + - Configure desired destinations + - Leave default configuration settings + - Assign your SIP trunk + - Complete setup + Alternatively, go to your SIP trunk / Outbound tab and select your newly created outbound voice profile. + + + - Choose the country you'll be making most calls to + *We recommend creating a separate SIP Trunk for each country you aim to be making most calls to.* + + + + + + + + + Use the Vapi API to create a SIP trunk credential: + + Use IP addresses in `gateways`. FQDNs like `sip.telnyx.com` return a `400 Bad Request`. + + ```bash + curl -X POST https://api.vapi.ai/credential \ + -H "Content-Type: application/json" \ + -H "Authorization: Bearer YOUR_VAPI_PRIVATE_KEY" \ + -d '{ + "provider": "byo-sip-trunk", + "name": "Telnyx Trunk", + "gateways": [ + { + "ip": "192.76.120.10", + "inboundEnabled": true + }, + { + "ip": "64.16.250.10", + "inboundEnabled": true + } + ], + "outboundAuthenticationPlan": { + "authUsername": "YOUR_SIP_USERNAME", + "authPassword": "YOUR_SIP_PASSWORD", + "sipRegisterPlan": { + "realm": "sip.telnyx.com" + } + } + }' + ``` + Replace `YOUR_VAPI_PRIVATE_KEY`, `YOUR_SIP_USERNAME`, and `YOUR_SIP_PASSWORD` with your actual credentials. + Replace the gateway IPs with the Telnyx gateway IPs assigned to your trunk. + Set `inboundEnabled` to `false` if you only need outbound calls. + If successful, the response will include an `id` for the created credential, which you'll use in the next step. + + + + Associate your phone number with the SIP trunk in Vapi: + ```bash + curl -X POST https://api.vapi.ai/phone-number \ + -H "Content-Type: application/json" \ + -H "Authorization: Bearer YOUR_VAPI_PRIVATE_KEY" \ + -d '{ + "provider": "byo-phone-number", + "name": "Telnyx SIP Number", + "number": "YOUR_PHONE_NUMBER", + "numberE164CheckEnabled": false, + "credentialId": "YOUR_CREDENTIAL_ID" + }' + ``` + Replace `YOUR_VAPI_PRIVATE_KEY`, `YOUR_PHONE_NUMBER`, and `YOUR_CREDENTIAL_ID` with your actual details. + + + + - In your Vapi dashboard, go to the **Build** section and select **Phone Numbers** + - Click on your **Telnyx Number** + - In the **Inbound Settings** section, assign your voice assistant to handle incoming calls + - In the **Outbound Form** section, assign your voice assistant to handle outgoing calls + + + + To initiate outbound calls through your Telnyx SIP trunk: + ```bash + curl --location 'https://api.vapi.ai/call/phone' \ + --header 'Authorization: Bearer YOUR_VAPI_PRIVATE_KEY' \ + --header 'Content-Type: application/json' \ + --data '{ + "assistantId": "YOUR_ASSISTANT_ID", + "customer": { + "number": "CUSTOMER_PHONE_NUMBER", + "numberE164CheckEnabled": false + }, + "phoneNumberId": "YOUR_PHONE_ID" + }' + ``` + Replace all placeholder values with your actual information. + +
+ +By following these steps, your Telnyx SIP trunk will be fully integrated with Vapi, allowing your AI voice assistants to manage calls effectively. diff --git a/fern/advanced/sip/sip-telynx.mdx b/fern/advanced/sip/sip-telynx.mdx deleted file mode 100644 index 56988bdad..000000000 --- a/fern/advanced/sip/sip-telynx.mdx +++ /dev/null @@ -1,167 +0,0 @@ ---- -title: Telynx SIP Integration -subtitle: How to integrate SIP Telnyx to Vapi -slug: advanced/sip/telynx ---- -## Inbound -### On Vapi - - - -First we will create a personalized origination SIP URI via the Vapi API - -```json -curl --location 'https://api.vapi.ai/phone-number' \ - --header 'Authorization: Bearer your-vapi-private-api-key' \ - --header 'Content-Type: application/json' \ - --data-raw '{ - "provider": "vapi", - "sipUri": "sip:username@sip.vapi.ai", - "assistantId": "your-assistant-id" - }' -``` - - ```provider```: This is set to "vapi". - - ```sipUri```: Replace ` username ` with your desired SIP username. - - ```assistantId```: Provide your specific `assistant ID` associated with your Vapi AI account. - - - - -Send a PATCH to /phone-number/your_phone_id - -```json - curl --location --request PATCH 'https://api.vapi.ai/phone-number/your_phone_id' \ - --header 'Content-Type: application/json' \ - --header 'Authorization: Bearer your-vapi-private-api-key' \ - --data '{ - "assistantId": null, - "serverUrl": "https://your_server_url" - }' -``` -- `your_server_url` is the webhook link that will receive the assistant request. -- `your_phone_id` is the id of your just created origination sip URI - -Now every time you make a call to this number (i.e. assigned numbers on SIP trunking to this origination URI), you'll get a webhook event requesting an assistant. - - - -### On Telynx - - -1. Go to Voice / SIP Trunking / Create -2. Select FQDN -3. Select add FQDN -4. Select A -5. Add created SIP URI -6. FQDN: sip.vapi.ai -7. Port should be 5060 by default - - -Set as follows: - - - - - -Go to numbers tab, assign number - - -Modify SIP invite so your VAPI and Telnyx accounts will be matched correctly -1. Go to numbers, edit the one your will be using -2. Navigate do voice -3. Scroll down till the end to find Translated Number - -*This setting will modify the SIP Invite to the vapi platform so invites are sent to your vapi sip URI. It will be whatever value you set when you created it.* - -4. If your chosen sipURI from previous step is username@sip.vapi.ai , this should be username -5. Done! You should now be receiving calls! - - - -## Outbound -### On Telynx - - -1. Go to Voice / Sip Trunking / Authentication and routing -2. Scroll down to outbound calls authentication and: -- Add the two fixed IPs from VAPI, select Tech Prefix and create a unique 4-digits Tech Prefix (example 1234 - don't use 1234, must be unique to your account) - - - - - -1. Go to voice / outbound voice profiles -2. Create profile -3. Name it as you will (1. details) -4. Allow as desired destination (2. destinations) -5. Leave the next screen as is (3. configuration) -6. Assign the desired sip trunk (4. …) -7. Complete - -Or you an just go to sip trunk / you sip trunk / outbound / and select your just created outbound voice profile. - - -Set as follows, choosing the country that you will be making most calls to (example Brazil) - -*We recommend creating a separate SIP Trunk for each country you aim to be making most calls to.* - - - - - -### On Vapi - - -```json -curl -X POST https://api.vapi.ai/credential \ - -H "Content-Type: application/json" \ - -H "Authorization: Bearer your-vapi-private-api-key" \ - -d '{ - "provider": "byo-sip-trunk", - "name": "Telnyx Trunk", - "gateways": [ - { - "ip": "sip.telnyx.com" - } - ] - }' -``` - - -```json -curl -X POST https://api.vapi.ai/phone-number \ - -H "Content-Type: application/json" \ - -H "Authorization: Bearer your-vapi-private-api-key" \ - -d '{ - "provider": "byo-phone-number", - "name": "Telnyx SIP Number", - "number": "your-sip-phone-number", - "numberE164CheckEnabled": false, - "credentialId": "your-new-trunk-credential-id-which-you-got-from-previous-step" - }' -``` - - -Use this cURL to trigger calls with tech prefix -```json -curl --location 'https://api.vapi.ai/call/phone' \ - --header 'Authorization: Bearer your-vapi-private-api-key' \ - --header 'Content-Type: application/json' \ - --data '{ - "assistantId": "your-assistant-id", - "customer": { - "number": "tech-prefix-with-phone-number-without-plus-signal", - "numberE164CheckEnabled": false - }, - "phoneNumberId": "your-phone-id" -}' -``` -Example of tech-prefix-with-phone-number-without-plus-signal -- Phone number: +6699999999 -- Tech Prefix: 1234 -- Should look like this: 12346699999999 -- No + as you can see - -Done! Outbound should now be working! - - \ No newline at end of file diff --git a/fern/advanced/sip/sip-trunk.mdx b/fern/advanced/sip/sip-trunk.mdx new file mode 100644 index 000000000..1cd023ea0 --- /dev/null +++ b/fern/advanced/sip/sip-trunk.mdx @@ -0,0 +1,154 @@ +--- +title: SIP Trunking +subtitle: How to integrate your SIP provider with Vapi +slug: advanced/sip/sip-trunk +--- + +SIP trunking replaces traditional phone lines with a virtual connection over the internet, allowing your business to make and receive calls via a broadband connection. It connects your internal PBX or VoIP system to a SIP provider, which then routes calls to the Public Switched Telephone Network (PSTN). This setup simplifies your communications infrastructure and often reduces costs. + +## Network requirements + +To allow SIP signaling and media between Vapi and your SIP provider, allowlist the static IP addresses for the Vapi region where your organization is hosted: + +| Region | SIP host | Signalling IP addresses | RTP media behavior | +| --- | --- | --- | --- | +| US | `sip.vapi.ai` | `44.229.228.186/32`, `44.238.177.138/32` | Dynamic media IPs; allow UDP ports `40000`-`60000` | +| EU | `sip.eu.vapi.ai` | `63.182.83.170/32` | Static media IP `63.182.83.170`; allow UDP ports `40000`-`60000` | + +For the complete list of ports, TLS options, RTP ranges, and firewall configuration details, see the [networking and firewall](/advanced/sip/sip-networking) reference. + + +If your organization is hosted in the EU, create the SIP trunk credential and BYO phone number through `https://api.eu.vapi.ai`, not `https://api.vapi.ai`. Keep the API region and SIP host in the same region: use `api.vapi.ai` with `sip.vapi.ai`, or `api.eu.vapi.ai` with `sip.eu.vapi.ai`. + + + +We generally don't recommend IP-based authentication for SIP trunks as it can lead to routing issues. Since our servers are shared by many customers, if your telephony provider has multiple customers using IP-based authentication, calls may be routed incorrectly. IP-based authentication works reliably only when your SIP provider offers a unique termination URI or a dedicated SIP server for each customer, as is the case with Plivo and Twilio integrations. + + +## Supported SIP providers + +Vapi supports multiple SIP trunk configurations, including: + +- **Plivo**: Uses a unique SIP domain and supports IP-based authentication. +- **Telnyx**: Uses SIP gateway domain (e.g., sip.telnyx.com) with IP-based authentication. +- **Zadarma**: Uses SIP credentials (username/password) with its SIP server (e.g., sip.zadarma.com). +- **Custom "BYO" SIP Trunk**: Allows integration with any SIP provider. You simply provide the SIP gateway address and the necessary authentication details. + +## Setup process + + + + Gather the SIP server address, authentication credentials (username/password or IP-based), and at least one phone number (DID) from your provider. + + + + Use the Vapi API to create a new credential (type: byo-sip-trunk) with your provider's details. This informs Vapi how to connect to your SIP network. + + Set your API base URL for the region where your organization is hosted: + + ```bash + # US organizations + export VAPI_API_BASE_URL="https://api.vapi.ai" + + # EU organizations + export VAPI_API_BASE_URL="https://api.eu.vapi.ai" + ``` + + **Example (using Zadarma):** + ```bash + curl -X POST "$VAPI_API_BASE_URL/credential" \ + -H "Content-Type: application/json" \ + -H "Authorization: Bearer YOUR_VAPI_PRIVATE_KEY" \ + -d '{ + "provider": "byo-sip-trunk", + "name": "Zadarma Trunk", + "gateways": [{ + "ip": "sip.zadarma.com", + "inboundEnabled": false + }], + "outboundLeadingPlusEnabled": true, + "outboundAuthenticationPlan": { + "authUsername": "YOUR_SIP_NUMBER", + "authPassword": "YOUR_SIP_PASSWORD" + } + }' + ``` + Save the returned Credential ID for later use. + + + + Link your external phone number (DID) to the SIP trunk credential in Vapi by creating a Phone Number resource. + + Use the same regional API base URL that you used when creating the SIP trunk credential. + + **Example:** + ```bash + curl -X POST "$VAPI_API_BASE_URL/phone-number" \ + -H "Content-Type: application/json" \ + -H "Authorization: Bearer YOUR_VAPI_PRIVATE_KEY" \ + -d '{ + "provider": "byo-phone-number", + "name": "Zadarma Number", + "number": "15551234567", + "numberE164CheckEnabled": false, + "credentialId": "YOUR_CREDENTIAL_ID" + }' + ``` + Note the returned Phone Number ID for use in test calls. + + + + + + Initiate a call through the Vapi dashboard or API to ensure outbound calls are properly routed. + + **API Example:** + ```bash + curl -X POST "$VAPI_API_BASE_URL/call/phone" \ + -H "Content-Type: application/json" \ + -H "Authorization: Bearer YOUR_VAPI_PRIVATE_KEY" \ + -d '{ + "assistantId": "YOUR_ASSISTANT_ID", + "customer": { + "number": "15557654321", + "numberE164CheckEnabled": false + }, + "phoneNumberId": "YOUR_PHONE_NUMBER_ID" + }' + ``` + + + If inbound routing is configured, call your phone number from an external line. Ensure your provider forwards calls to the correct regional SIP URI (for example, `{phoneNumber}@.sip.vapi.ai` for US or `{phoneNumber}@.sip.eu.vapi.ai` for EU). + + + Note: Please ensure that you provide all the signaling IP addresses when creating the SIP trunk. Failure to do so will prevent proper whitelisting, which may result in encountering unauthorized 401 errors for inbound calls. + + + + + + + If you need to transfer a call to another number, you will need to add a SIP Transfer based call forwarding where the transfer number will look like this: `sip:transfer-number@your-telecom-provider-domain.com` + + Example: `sip:15557654321@sip.zadarma.com` + +Note: Certain providers require phone numbers to be formatted in the proper E.164 standard. For example, the transfer URI should appear as: `sip:+15557654321@sip.zadarma.com`. + + + Example tool configuration required for SIP REFER: + ```json + { + "type": "transferCall", + "destinations": [ + { + "type": "sip", + "sipUri": "sip:14039932200@sip.telnyx.com" + } + ] + } + ``` + You might need to enable SIP REFER in your SIP provider to allow this. + + + + diff --git a/fern/advanced/sip/sip-twilio.mdx b/fern/advanced/sip/sip-twilio.mdx new file mode 100644 index 000000000..741afd1d6 --- /dev/null +++ b/fern/advanced/sip/sip-twilio.mdx @@ -0,0 +1,207 @@ +--- +title: Twilio SIP Integration +subtitle: How to integrate Twilio SIP with Vapi +slug: advanced/sip/twilio +--- + + +
+ + +### What are structured outputs? + +Structured outputs are AI-powered analysis and extraction tools that intelligently process conversation data after calls end. They go beyond simple data extraction to provide intelligent analysis and evaluation. They work by: + +1. **Processing complete call context** - After the call ends, structured outputs analyze the full transcript, messages, tool call results, and call metadata +2. **Intelligent extraction & analysis** - Based on your schema, they can extract data, evaluate outcomes, analyze sentiment, determine success criteria, and summarize complex interactions +3. **Validating and formatting** - Results are validated against your schema rules and formatted into clean, structured JSON +4. **Delivering insights** - The processed data and insights are available via API or webhooks once analysis is complete + +### When are structured outputs generated? + +Structured outputs are processed: +- **After call completion** - The full conversation is analyzed once the call ends +- **Processing time** - Typically completes within a few seconds after call termination +- **Available via** - Call artifacts in the API response or webhook events + +### What data do structured outputs have access to? + +When processing, structured outputs can analyze: +- **Complete transcript** - The full conversation between assistant and customer +- **Messages history** - All messages exchanged during the call +- **Tool call results** - Outcomes from any tools or functions executed +- **Assistant context** - System prompts and configuration used during the call + +### Why use structured outputs? + +**Beyond simple data extraction:** +- **Call evaluation** - Determine if objectives were met (appointment booked, issue resolved) +- **Sentiment analysis** - Understand customer satisfaction and emotional state +- **CSAT scoring** - Extract customer satisfaction scores from feedback +- **Intelligent summaries** - Generate contextual summaries of complex conversations +- **Success metrics** - Evaluate agent performance and call outcomes + +**Operational benefits:** +- **Automate data entry** - No more manual transcription or form filling +- **Ensure consistency** - Every call captures the same structured information +- **Enable integrations** - Automatically sync data to CRMs, ticketing systems, or databases +- **Improve analytics** - Structured data is easier to analyze and report on + +## What you'll build + +A customer support assistant that automatically extracts: +- Customer name and contact details +- Issue description and priority +- Requested follow-up actions + +## Prerequisites + + + + Sign up at [dashboard.vapi.ai](https://dashboard.vapi.ai) + + + Get a [Vapi API key](/security-and-privacy/api-keys) + + + +## Step 1: Create your structured output + +Define what information you want to extract using a [JSON Schema](https://json-schema.org/learn/getting-started-step-by-step). JSON Schema is a standard for describing data structures - [learn more about JSON Schema here](https://json-schema.org/understanding-json-schema/). + + + + + + 1. Log in to [dashboard.vapi.ai](https://dashboard.vapi.ai) + 2. Click on **Structured Outputs** in the left sidebar + 3. Click **Create New Structured Output** + + + + 1. **Name**: Enter "Support Ticket" + 2. **Type**: Select "Object" + 3. **Description**: Add "Extract support ticket information from customer calls" + + + + Use the visual schema builder: + ```json + { + "type": "object", + "properties": { + "customer": { + "type": "object", + "properties": { + "name": {"type": "string", "description": "Customer full name"}, + "email": {"type": "string", "format": "email", "description": "Customer email"}, + "phone": {"type": "string", "description": "Customer phone number"} + }, + "required": ["name"] + }, + "issue": { + "type": "object", + "properties": { + "description": {"type": "string", "description": "Issue description"}, + "category": { + "type": "string", + "enum": ["billing", "technical", "general", "complaint"], + "description": "Issue category" + }, + "priority": { + "type": "string", + "enum": ["low", "medium", "high", "urgent"], + "description": "Priority level" + } + }, + "required": ["description", "category"] + }, + "followUp": { + "type": "object", + "properties": { + "required": {"type": "boolean", "description": "Whether follow-up is needed"}, + "method": { + "type": "string", + "enum": ["email", "phone", "none"], + "description": "Preferred follow-up method" + }, + "notes": {"type": "string", "description": "Additional notes for follow-up"} + } + } + }, + "required": ["customer", "issue"] + } + ``` + + + + 1. Click **Create Structured Output** + 2. In the structured output dialog, you can directly attach it to an assistant + 3. Select an existing assistant to attach this output to that assistant + + + + + +```bash title="cURL" +curl -X POST https://api.vapi.ai/structured-output \ + -H "Authorization: Bearer $VAPI_API_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "name": "Support Ticket", + "type": "ai", + "description": "Extract support ticket information from customer calls", + "schema": { + "type": "object", + "properties": { + "customer": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Customer full name" + }, + "email": { + "type": "string", + "format": "email", + "description": "Customer email address" + }, + "phone": { + "type": "string", + "description": "Customer phone number" + } + }, + "required": ["name"] + }, + "issue": { + "type": "object", + "properties": { + "description": { + "type": "string", + "description": "Description of the customer issue" + }, + "category": { + "type": "string", + "enum": ["billing", "technical", "general", "complaint"], + "description": "Issue category" + }, + "priority": { + "type": "string", + "enum": ["low", "medium", "high", "urgent"], + "description": "Issue priority level" + } + }, + "required": ["description", "category"] + }, + "followUp": { + "type": "object", + "properties": { + "required": { + "type": "boolean", + "description": "Whether follow-up is needed" + }, + "method": { + "type": "string", + "enum": ["email", "phone", "none"], + "description": "Preferred follow-up method" + }, + "notes": { + "type": "string", + "description": "Additional notes for follow-up" + } + } + } + }, + "required": ["customer", "issue"] + } + }' +``` + + + + ```typescript +import { VapiClient } from "@vapi-ai/server-sdk"; + +const vapi = new VapiClient({ token: process.env.VAPI_API_KEY! }); + +const structuredOutput = await vapi.structuredOutputs.create({ + name: "Support Ticket", + type: "ai", + description: "Extract support ticket information from customer calls", + schema: { + type: "object", + properties: { + customer: { + type: "object", + properties: { + name: { + type: "string", + description: "Customer full name" + }, + email: { + type: "string", + format: "email", + description: "Customer email address" + }, + phone: { + type: "string", + description: "Customer phone number" + } + }, + required: ["name"] + }, + issue: { + type: "object", + properties: { + description: { + type: "string", + description: "Description of the customer issue" + }, + category: { + type: "string", + enum: ["billing", "technical", "general", "complaint"], + description: "Issue category" + }, + priority: { + type: "string", + enum: ["low", "medium", "high", "urgent"], + description: "Issue priority level" + } + }, + required: ["description", "category"] + }, + followUp: { + type: "object", + properties: { + required: { + type: "boolean", + description: "Whether follow-up is needed" + }, + method: { + type: "string", + enum: ["email", "phone", "none"], + description: "Preferred follow-up method" + }, + notes: { + type: "string", + description: "Additional notes for follow-up" + } + } + } + }, + required: ["customer", "issue"] + } +}); + +console.log('Created structured output:', structuredOutput.id); +// Save this ID - you'll need it in the next step +``` + + + + ```python +from vapi import Vapi +import os + +vapi = Vapi(token=os.environ.get("VAPI_API_KEY")) + +structured_output = vapi.structured_outputs.create( + name="Support Ticket", + type="ai", + description="Extract support ticket information from customer calls", + schema={ + "type": "object", + "properties": { + "customer": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Customer full name" + }, + "email": { + "type": "string", + "format": "email", + "description": "Customer email address" + }, + "phone": { + "type": "string", + "description": "Customer phone number" + } + }, + "required": ["name"] + }, + "issue": { + "type": "object", + "properties": { + "description": { + "type": "string", + "description": "Description of the customer issue" + }, + "category": { + "type": "string", + "enum": ["billing", "technical", "general", "complaint"], + "description": "Issue category" + }, + "priority": { + "type": "string", + "enum": ["low", "medium", "high", "urgent"], + "description": "Issue priority level" + } + }, + "required": ["description", "category"] + }, + "followUp": { + "type": "object", + "properties": { + "required": { + "type": "boolean", + "description": "Whether follow-up is needed" + }, + "method": { + "type": "string", + "enum": ["email", "phone", "none"], + "description": "Preferred follow-up method" + }, + "notes": { + "type": "string", + "description": "Additional notes for follow-up" + } + } + } + }, + "required": ["customer", "issue"] + } +) + +print(f'Created structured output: {structured_output.id}') +# Save this ID - you'll need it in the next step +``` + + + + +In the API approach, you'll need to save the returned `id` to attach it to an assistant. In the Dashboard, you can attach it directly when creating the structured output. + + +## Step 2: Create and test a call + +Now test your structured output by making a call. + + +**Prerequisites**: You need an assistant already created with: +- The structured output from Step 1 attached in `artifactPlan.structuredOutputIds` +- A model and voice configured +- System prompt appropriate for your use case + +You can create an assistant via the Dashboard or API, then use its ID in the examples below. + + + + + + + 1. Navigate to your assistant (from **Assistants** in the sidebar) + 2. Ensure your structured output is attached in the **Artifact Plan** section + 3. Click **Talk to Assistant** in the top right corner + 4. The assistant will start speaking + + + + Try saying: "Hi, my name is John Smith. My email is john@example.com. I'm having trouble logging into my account - it keeps showing an error message. This is pretty urgent for me." + + + + Click **End Call** when you're done testing + + + + + + ```typescript +import { VapiClient } from "@vapi-ai/server-sdk"; + +const vapi = new VapiClient({ token: process.env.VAPI_API_KEY! }); + +// Start a web call with your assistant (replace with your assistant ID) +const call = await vapi.calls.create({ + assistantId: "your-assistant-id", // Use an assistant with structured outputs attached + type: "webCall" +}); + +console.log('Call started:', call.id); +console.log('Join URL:', call.webCallUrl); + +// For phone calls, use: +// const call = await vapi.calls.create({ +// assistantId: "your-assistant-id", +// type: "outboundPhoneCall", +// phoneNumberId: "your-phone-number-id", +// customer: { +// number: "+1234567890" +// } +// }); +``` + + + + ```python +from vapi import Vapi +import os + +vapi = Vapi(token=os.environ.get("VAPI_API_KEY")) + +# Start a web call with your assistant (replace with your assistant ID) +call = vapi.calls.create( + assistant_id="your-assistant-id", # Use an assistant with structured outputs attached + type="webCall" +) + +print(f'Call started: {call.id}') +print(f'Join URL: {call.web_call_url}') + +# For phone calls, use: +# call = vapi.calls.create( +# assistant_id="your-assistant-id", +# type="outboundPhoneCall", +# phone_number_id="your-phone-number-id", +# customer={ +# "number": "+1234567890" +# } +# ) +``` + + + + ```bash +# Start a web call +curl -X POST https://api.vapi.ai/call \ + -H "Authorization: Bearer $VAPI_API_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "assistantId": "your-assistant-id", + "type": "webCall" + }' + +# For phone calls: +# curl -X POST https://api.vapi.ai/call \ +# -H "Authorization: Bearer $VAPI_API_KEY" \ +# -H "Content-Type: application/json" \ +# -d '{ +# "assistantId": "your-assistant-id", +# "type": "outboundPhoneCall", +# "phoneNumberId": "your-phone-number-id", +# "customer": { +# "number": "+1234567890" +# } +# }' +``` + + + + +During the call, try saying something like: "Hi, my name is John Smith. My email is john@example.com. I'm having trouble logging into my account - it keeps showing an error message. This is pretty urgent for me." + + +## Step 3: Retrieve extracted data + +After the call ends, retrieve the extracted information: + + + + + + 1. Navigate to **Call Logs** in the left sidebar + 2. Click on your recent call to view details + + + + 1. In the call details, find the **Structured Outputs** section + 2. View the extracted JSON data for your "Support Ticket" output + 3. The data will be displayed in a formatted JSON view showing each output with its ID, name, and result + + + + ### How structured outputs appear in Call Logs + + When you view a call in the Call Logs page, structured outputs are displayed in the following format: + + ```json + { + "550e8400-e29b-41d4-a716-446655440001": { + "name": "Support Ticket", + "result": { + "customer": { + "name": "John Smith", + "email": "john@example.com", + "phone": "+1234567890" + }, + "issue": { + "description": "Unable to login to account, receiving error message", + "category": "technical", + "priority": "urgent" + }, + "followUp": { + "required": true, + "method": "email", + "notes": "Customer needs immediate assistance with login issue" + } + } + } + } + ``` + + **Structure explanation:** + - **Root level**: Contains output IDs (UUIDs) as keys + - **name**: The name of the structured output configuration + - **result**: The actual extracted data based on your schema + - For object schemas: Contains the nested structure with all extracted fields + - For boolean schemas: Contains `true` or `false` + - For string schemas: Contains the extracted text + - For number schemas: Contains the numeric value + + + If you have multiple structured outputs attached to an assistant, each will appear with its own UUID key in the structuredOutputs object. + + + + + ```typescript +import { VapiClient } from "@vapi-ai/server-sdk"; + +const vapi = new VapiClient({ token: process.env.VAPI_API_KEY! }); + +// Wait a few seconds after call ends for processing +setTimeout(async () => { + const callData = await vapi.calls.get(call.id); + + const outputs = callData.artifact?.structuredOutputs; + + if (outputs) { + Object.entries(outputs).forEach(([outputId, data]) => { + console.log('Extracted Support Ticket:'); + console.log(JSON.stringify(data.result, null, 2)); + }); + } +}, 5000); +``` + + + + ```python +from vapi import Vapi +import time +import json +import os + +vapi = Vapi(token=os.environ.get("VAPI_API_KEY")) + +# Wait a few seconds after call ends for processing +time.sleep(5) + +call_data = vapi.calls.get(call.id) + +outputs = call_data.artifact.get('structuredOutputs', {}) if call_data.artifact else {} + +for output_id, data in outputs.items(): + print('Extracted Support Ticket:') + print(json.dumps(data['result'], indent=2)) +``` + + + + ```bash +curl -X GET "https://api.vapi.ai/call/YOUR_CALL_ID_HERE" \ + -H "Authorization: Bearer $VAPI_API_KEY" +``` + + + +### Expected output + +The extracted data (the `result` field from the API response) will look like this: + +```json +{ + "customer": { + "name": "John Smith", + "email": "john@example.com", + "phone": "+1234567890" + }, + "issue": { + "description": "Unable to login to account, receiving error message", + "category": "technical", + "priority": "urgent" + }, + "followUp": { + "required": true, + "method": "email", + "notes": "Customer needs immediate assistance with login issue" + } +} +``` + + +When accessing via API, this data is nested inside the structured output object at `call.artifact.structuredOutputs[outputId].result`. The Dashboard shows the complete structure including the output ID and name. + + +## HIPAA Compliance & Storage Settings + + +**Important for HIPAA users:** When HIPAA mode is enabled, Vapi does not store structured outputs by default. This protects privacy but limits your ability to view structured outputs in Insights and Call Logs. + + +### Understanding the default behavior + +When your organization or assistant has HIPAA mode enabled: +- **Structured outputs are NOT stored** - Results are generated but not persisted in Vapi's systems +- **Limited visibility** - You cannot view outputs in the Dashboard's Call Logs or Insights +- **Privacy first** - This ensures sensitive data is not retained +- **Webhook access only** - You can still receive outputs via webhooks during the call + +This default behavior protects patient privacy and ensures compliance with HIPAA regulations. + +### Enabling storage for non-sensitive outputs + +For structured outputs that extract **non-sensitive, non-PHI information**, you can override this behavior using the `compliancePlan.forceStoreOnHipaaEnabled` setting. + + +**Your responsibility:** You must ensure that any structured output with storage enabled does NOT extract or generate PHI or sensitive data. + + +#### Safe use cases for storage override + +Enable storage for these types of non-sensitive outputs: + +- **Boolean outcomes**: `appointmentBooked: true/false`, `callSuccessful: true/false` +- **General categories**: `issueCategory: "billing" | "technical" | "general"` +- **Satisfaction scores**: `csatScore: 1-10` +- **Call metrics**: `sentiment: "positive" | "neutral" | "negative"` +- **Success indicators**: `issueResolved: boolean`, `followUpRequired: boolean` + +#### Never enable storage for these + +**Do not** enable storage for outputs that extract: +- Patient names, dates of birth, or contact information +- Diagnosis, treatment, or medication information +- Medical record numbers or identifiers +- Social security numbers +- Credit card or payment details + +### Configuration examples + + + + 1. Navigate to **Structured Outputs** in the left sidebar + 2. Create or edit a structured output + 3. Expand the **Compliance Settings** section + 4. Enable the toggle for "Enable Storage of Structured Outputs while on HIPAA Mode" + 5. **Recommendation**: Only enable if your output does not extract sensitive information + + + +```bash +# Creating a HIPAA-safe structured output with storage enabled +curl -X POST https://api.vapi.ai/structured-output \ + -H "Authorization: Bearer $VAPI_API_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "name": "Appointment Booked", + "type": "ai", + "description": "Boolean indicator of whether appointment was booked", + "schema": { + "type": "boolean", + "description": "Whether an appointment was successfully booked during the call" + }, + "compliancePlan": { + "forceStoreOnHipaaEnabled": true + } + }' +``` + + + +```typescript +import { VapiClient } from "@vapi-ai/server-sdk"; + +const vapi = new VapiClient({ token: process.env.VAPI_API_KEY! }); + +// Safe: Boolean outcome, no PHI +const structuredOutput = await vapi.structuredOutputs.create({ + name: "Appointment Booked", + type: "ai", + description: "Boolean indicator of whether appointment was booked", + schema: { + type: "boolean", + description: "Whether an appointment was successfully booked during the call" + }, + compliancePlan: { + forceStoreOnHipaaEnabled: true // Safe because output contains no PHI + } +}); + +// Update existing structured output to enable storage +await vapi.structuredOutputs.update(structuredOutput.id, { + compliancePlan: { + forceStoreOnHipaaEnabled: true + } +}); +``` + + + +```python +from vapi import Vapi +import os + +vapi = Vapi(token=os.environ.get("VAPI_API_KEY")) + +# Safe: Boolean outcome, no PHI +structured_output = vapi.structured_outputs.create( + name="Appointment Booked", + type="ai", + description="Boolean indicator of whether appointment was booked", + schema={ + "type": "boolean", + "description": "Whether an appointment was successfully booked during the call" + }, + compliance_plan={ + "forceStoreOnHipaaEnabled": True + } +) + +# Update existing structured output to enable storage +vapi.structured_outputs.update( + structured_output.id, + compliance_plan={ + "forceStoreOnHipaaEnabled": True + } +) +``` + + + + +**IMPORTANT:** Only set `forceStoreOnHipaaEnabled: true` if you are certain your structured output does NOT extract PHI or sensitive data. Review your schema carefully before enabling storage. + + +### Best practices for HIPAA compliance + +1. **Default to privacy**: Keep storage disabled for all outputs that might contain PHI +2. **Review schemas carefully**: Ensure your extraction logic cannot accidentally capture sensitive data +3. **Use specific schemas**: Design narrow schemas that target only non-sensitive data +4. **Test thoroughly**: Verify outputs don't contain PHI before enabling storage +5. **Document decisions**: Maintain records of which outputs have storage enabled and why +6. **Regular audits**: Periodically review stored outputs to ensure compliance + +For more information about HIPAA compliance with Vapi, see our [HIPAA Compliance Guide](/security-and-privacy/hipaa). + +## Next steps + + + + Learn about different data types and validation options + + + + Configure different AI models for extraction + + + + See complex real-world extraction scenarios + + + + Complete API documentation for structured outputs + + + +## Common patterns + +### Multiple extractions + +You can attach multiple structured outputs to extract different types of data: + +```javascript +{ + artifactPlan: { + structuredOutputIds: [ + "550e8400-e29b-41d4-a716-446655440001", // Customer details extraction + "550e8400-e29b-41d4-a716-446655440002", // Appointment requests extraction + "550e8400-e29b-41d4-a716-446655440003" // Satisfaction feedback extraction + ] + } +} +``` + +The `structuredOutputIds` are UUIDs returned when you create each structured output configuration. + +### Example: Intelligent analysis with multiple outputs + +Structured outputs can perform sophisticated analysis beyond simple data extraction. Here's a real example showing various types of intelligent evaluation: + +```json +{ + "2ca00f20-f2c3-4d74-af2e-52842be5885c": { + "name": "informationOnFileIsCorrect", + "result": false + }, + "4748e1aa-6c7a-49e6-bbde-c4365ef69c6e": { + "name": "Appointment Rescheduled", + "result": false + }, + "4d4bac33-2cea-43d4-a3b3-4554932b8933": { + "name": "CSAT", + "result": 8 + }, + "7898e478-c8dc-4ff8-a3f6-4a46555a957f": { + "name": "Appointment Booked", + "result": true + }, + "a0ca58b1-c343-4628-b088-bf53aabacab9": { + "name": "Call Summary", + "result": "The user called to schedule a consultation appointment for next week, specifically on Wednesday afternoon..." + }, + "b5a390d8-87c5-4015-b1ad-ed237201bdf0": { + "name": "Success Evaluation - Pass/Fail", + "result": true + } +} +``` + +This example demonstrates intelligent extraction capabilities: +- **Call outcome evaluation**: `Appointment Booked` (true) - Analyzed if the call's objective was achieved +- **Data verification**: `informationOnFileIsCorrect` (false) - Evaluated if customer data needed updates +- **Success metrics**: `Success Evaluation - Pass/Fail` (true) - Determined overall call success based on multiple criteria +- **CSAT extraction**: `CSAT` (8) - Extracted satisfaction score from customer feedback +- **Intelligent summarization**: `Call Summary` - Generated contextual summary of the conversation +- **Process tracking**: `Appointment Rescheduled` (false) - Tracked specific actions taken during the call + +Each output analyzes the complete call context including transcript, tool results, and metadata to provide actionable insights. + +### Validation patterns + +Common validation patterns for reliable extraction: + +```json +{ + "email": { + "type": "string", + "format": "email", + "pattern": "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$" + }, + "phone": { + "type": "string", + "pattern": "^\\+?[1-9]\\d{1,14}$" + }, + "zipCode": { + "type": "string", + "pattern": "^\\d{5}(-\\d{4})?$" + } +} +``` + +## Tips for success + + +**Best practices for reliable extraction:** +- Start with required fields only for critical data +- Use enums for categorical data to ensure consistency +- Add descriptions to help the AI understand context +- Test with real conversations before production use +- Monitor extraction success rates and iterate on schemas + + +## Troubleshooting + +| Issue | Solution | +|-------|----------| +| No data extracted | Verify the information was mentioned in the call and check schema validity | +| Partial extraction | Make non-critical fields optional and simplify nested structures | +| Incorrect values | Add more specific validation patterns and field descriptions | +| Extraction fails | Check API logs, verify assistant configuration, and test with simpler schema | + +## Get help + +Need assistance? We're here to help: +- [API Documentation](/api-reference) +- [Discord Community](https://discord.gg/pUFNcf2WmH) +- [Support](mailto:support@vapi.ai) diff --git a/fern/assistants/structured-outputs.mdx b/fern/assistants/structured-outputs.mdx new file mode 100644 index 000000000..17e1493df --- /dev/null +++ b/fern/assistants/structured-outputs.mdx @@ -0,0 +1,854 @@ +--- +title: Structured outputs +subtitle: Extract structured data from conversations using AI-powered analysis +description: Extract structured, schema-defined data from voice calls using AI-powered analysis. Covers field types, extraction timing, limitations, and HIPAA storage behavior. +slug: assistants/structured-outputs +--- + +## Overview + +Structured outputs enable automatic extraction of specific information from voice conversations in a structured format. Define your data requirements using JSON Schema, and we will identify and extract that information from your calls. + +**Key benefits:** +- Extract customer information, appointments, and orders automatically +- Validate data with JSON Schema constraints +- Use any AI model for extraction (OpenAI, Anthropic, Google, Azure) +- Reuse extraction definitions across multiple assistants + +## How it works + + + + Create a JSON Schema that describes the data you want to extract + + + Use the API to create a reusable structured output definition + + + Connect the structured output to one or more assistants + + + Data is automatically extracted after each call and stored in call artifacts + + + +## Quick start + +### Create a structured output + + +```typescript title="TypeScript (Server SDK)" +import { VapiClient } from '@vapi-ai/server-sdk'; + +const vapi = new VapiClient({ token: process.env.VAPI_API_KEY }); + +const structuredOutput = await vapi.structuredOutputs.create({ + name: "Customer Info", + type: "ai", + description: "Extract customer contact information", + schema: { + type: "object", + properties: { + firstName: { + type: "string", + description: "Customer's first name" + }, + lastName: { + type: "string", + description: "Customer's last name" + }, + email: { + type: "string", + format: "email", + description: "Customer's email address" + }, + phone: { + type: "string", + pattern: "^\\+?[1-9]\\d{1,14}$", + description: "Phone number in E.164 format" + } + }, + required: ["firstName", "lastName"] + } +}); + +console.log('Created structured output:', structuredOutput.id); +``` + +```python title="Python (Server SDK)" +import os +from vapi import Vapi + +vapi = Vapi(token=os.environ['VAPI_API_KEY']) + +structured_output = vapi.structured_outputs.create( + name="Customer Info", + type="ai", + description="Extract customer contact information", + schema={ + "type": "object", + "properties": { + "firstName": { + "type": "string", + "description": "Customer's first name" + }, + "lastName": { + "type": "string", + "description": "Customer's last name" + }, + "email": { + "type": "string", + "format": "email", + "description": "Customer's email address" + }, + "phone": { + "type": "string", + "pattern": "^\\+?[1-9]\\d{1,14}$", + "description": "Phone number in E.164 format" + } + }, + "required": ["firstName", "lastName"] + } +) + +print(f"Created structured output: {structured_output.id}") +``` + +```bash title="cURL" +curl -X POST https://api.vapi.ai/structured-output \ + -H "Authorization: Bearer $VAPI_API_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "name": "Customer Info", + "type": "ai", + "description": "Extract customer contact information", + "schema": { + "type": "object", + "properties": { + "firstName": { + "type": "string", + "description": "Customer'\''s first name" + }, + "lastName": { + "type": "string", + "description": "Customer'\''s last name" + }, + "email": { + "type": "string", + "format": "email", + "description": "Customer'\''s email address" + }, + "phone": { + "type": "string", + "pattern": "^\\+?[1-9]\\d{1,14}$", + "description": "Phone number in E.164 format" + } + }, + "required": ["firstName", "lastName"] + } + }' +``` + + +### Link to an assistant + +Add the structured output ID to your assistant's configuration: + + +```typescript title="TypeScript (Server SDK)" +const assistant = await vapi.assistants.create({ + name: "Customer Support Agent", + // ... other assistant configuration + artifactPlan: { + structuredOutputIds: [structuredOutput.id] + } +}); +``` + +```python title="Python (Server SDK)" +assistant = vapi.assistants.create( + name="Customer Support Agent", + # ... other assistant configuration + artifact_plan={ + "structuredOutputIds": [structured_output.id] + } +) +``` + +```bash title="cURL" +curl -X POST https://api.vapi.ai/assistant \ + -H "Authorization: Bearer $VAPI_API_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "name": "Customer Support Agent", + "artifactPlan": { + "structuredOutputIds": ["output-id-here"] + } + }' +``` + + +### Access extracted data + +After a call completes, retrieve the extracted data: + + +```typescript title="TypeScript (Server SDK)" +const call = await vapi.calls.get(callId); + +// Access structured outputs from call artifacts +const outputs = call.artifact?.structuredOutputs; + +if (outputs) { + for (const [outputId, data] of Object.entries(outputs)) { + console.log(`Output: ${data.name}`); + console.log(`Result:`, data.result); + + // Handle the extracted data + if (data.result) { + // Process successful extraction + const { firstName, lastName, email, phone } = data.result; + // ... save to database, send notifications, etc. + } + } +} +``` + +```python title="Python (Server SDK)" +call = vapi.calls.get(call_id) + +# Access structured outputs from call artifacts +outputs = call.artifact.get('structuredOutputs', {}) + +for output_id, data in outputs.items(): + print(f"Output: {data['name']}") + print(f"Result: {data['result']}") + + # Handle the extracted data + if data['result']: + # Process successful extraction + result = data['result'] + first_name = result.get('firstName') + last_name = result.get('lastName') + email = result.get('email') + phone = result.get('phone') + # ... save to database, send notifications, etc. +``` + +```javascript title="Webhook Response" +// In your webhook handler +app.post('/vapi/webhook', (req, res) => { + const { message } = req.body; + + if (message.type === 'end-of-call-report') { + const outputs = message.artifact?.structuredOutputs; + + if (outputs) { + Object.entries(outputs).forEach(([outputId, data]) => { + console.log(`Extracted ${data.name}:`, data.result); + // Process the extracted data + }); + } + } + + res.status(200).send('OK'); +}); +``` + + +## Schema types + +### Primitive types + +Extract simple values directly: + + +```json title="String" +{ + "type": "string", + "minLength": 1, + "maxLength": 100, + "pattern": "^[A-Z][a-z]+$" +} +``` + +```json title="Number" +{ + "type": "number", + "minimum": 0, + "maximum": 100, + "multipleOf": 0.5 +} +``` + +```json title="Boolean" +{ + "type": "boolean", + "description": "Whether customer agreed to terms" +} +``` + +```json title="Enum" +{ + "type": "string", + "enum": ["small", "medium", "large", "extra-large"] +} +``` + + +### Object types + +Extract structured data with multiple fields: + +```json +{ + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Full name" + }, + "age": { + "type": "integer", + "minimum": 0, + "maximum": 120 + }, + "email": { + "type": "string", + "format": "email" + } + }, + "required": ["name", "email"] +} +``` + +### Array types + +Extract lists of items: + +```json +{ + "type": "array", + "items": { + "type": "object", + "properties": { + "product": { + "type": "string" + }, + "quantity": { + "type": "integer", + "minimum": 1 + } + } + }, + "minItems": 1, + "maxItems": 10 +} +``` + +### Nested structures + +Extract complex hierarchical data: + +```json +{ + "type": "object", + "properties": { + "customer": { + "type": "object", + "properties": { + "name": {"type": "string"}, + "contact": { + "type": "object", + "properties": { + "email": {"type": "string", "format": "email"}, + "phone": {"type": "string"} + } + } + } + }, + "order": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "type": "object", + "properties": { + "sku": {"type": "string"}, + "quantity": {"type": "integer"} + } + } + } + } + } + } +} +``` + +## Validation features + +### String formats + +Vapi supports standard JSON Schema formats for validation: + +| Format | Description | Example | +|--------|-------------|---------| +| `email` | Email addresses | john@example.com | +| `date` | Date in YYYY-MM-DD | 2024-01-15 | +| `time` | Time in HH:MM:SS | 14:30:00 | +| `date-time` | ISO 8601 datetime | 2024-01-15T14:30:00Z | +| `uri` | Valid URI | https://example.com | +| `uuid` | UUID format | 123e4567-e89b-12d3-a456-426614174000 | + +### Pattern matching + +Use regular expressions for custom validation: + +```json +{ + "type": "string", + "pattern": "^[A-Z]{2}-\\d{6}$", + "description": "Order ID like US-123456" +} +``` + +### Conditional logic + +Use `if/then/else` for conditional requirements: + +```json +{ + "type": "object", + "properties": { + "serviceType": { + "type": "string", + "enum": ["emergency", "scheduled"] + }, + "appointmentTime": { + "type": "string", + "format": "date-time" + } + }, + "if": { + "properties": { + "serviceType": {"const": "scheduled"} + } + }, + "then": { + "required": ["appointmentTime"] + } +} +``` + +## Conditional generation + +By default, every linked structured output runs after each call. Attach **conditions** to a structured output so it only generates when the call meets your criteria — for example, skip extraction on calls that barely started, or only run an output when the call ended a certain way. + + +Conditions gate **whether the output runs at all**. This is different from the [`if/then/else` schema logic](#conditional-logic) above, which shapes the data *within* a single extraction. + + +### How conditions work + +- Add a `conditions` array to a structured output. +- **Every condition must pass** for the output to run (AND semantics). +- When `conditions` is omitted or empty, no user-defined conditions gate the output (runtime defaults still apply). +- On update (`PATCH`), send `conditions: null` to clear a previously saved gate. + +When a condition isn't met, the output is **skipped** rather than failed. Skipped outputs are surfaced in the **assistant preview**, **call logs**, and **sessions**, so you can see which outputs ran and which were gated out. + +### Condition types + +| Type | Fields | Output runs when | +|------|--------|------------------| +| `minMessages` | `count` (integer ≥ 0) | The conversation has at least `count` messages. `count: 0` removes the runtime default minimum. | +| `minCallDuration` | `seconds` (integer ≥ 0) | The call lasted at least `seconds` seconds. | +| `endedReason` | `operator` (`oneOf` or `notOneOf`), `values` (array of strings) | The call's [ended reason](/calls/call-ended-reason) passes the membership test against `values`. `oneOf` runs the output only if the ended reason is in `values`; `notOneOf` runs it only if the ended reason is not in `values`. | + +### Example + +Only extract a call summary when the call had a real conversation (at least 4 messages and 10 seconds) and the customer ended it: + + +```typescript title="TypeScript (Server SDK)" +const structuredOutput = await vapi.structuredOutputs.create({ + name: "Call Summary", + type: "ai", + description: "Summarize the conversation", + schema: { + type: "object", + properties: { + summary: { type: "string" } + } + }, + conditions: [ + { type: "minMessages", count: 4 }, + { type: "minCallDuration", seconds: 10 }, + { type: "endedReason", operator: "oneOf", values: ["customer-ended-call"] } + ] +}); +``` + +```python title="Python (Server SDK)" +structured_output = vapi.structured_outputs.create( + name="Call Summary", + type="ai", + description="Summarize the conversation", + schema={ + "type": "object", + "properties": { + "summary": {"type": "string"} + } + }, + conditions=[ + {"type": "minMessages", "count": 4}, + {"type": "minCallDuration", "seconds": 10}, + {"type": "endedReason", "operator": "oneOf", "values": ["customer-ended-call"]} + ] +) +``` + +```bash title="cURL" +curl -X POST https://api.vapi.ai/structured-output \ + -H "Authorization: Bearer $VAPI_API_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "name": "Call Summary", + "type": "ai", + "description": "Summarize the conversation", + "schema": { + "type": "object", + "properties": { + "summary": { "type": "string" } + } + }, + "conditions": [ + { "type": "minMessages", "count": 4 }, + { "type": "minCallDuration", "seconds": 10 }, + { "type": "endedReason", "operator": "oneOf", "values": ["customer-ended-call"] } + ] + }' +``` + + +## Custom models + +By default, structured outputs are extracted with GPT-4.1. Configure the `model` to use a different provider or model, or to supply your own extraction prompts: + + +```typescript title="TypeScript" +const structuredOutput = await vapi.structuredOutputs.create({ + name: "Sentiment Analysis", + type: "ai", + schema: { + type: "object", + properties: { + sentiment: { + type: "string", + enum: ["positive", "negative", "neutral"] + }, + confidence: { + type: "number", + minimum: 0, + maximum: 1 + } + } + }, + model: { + provider: "openai", + model: "gpt-4.1", + temperature: 0.1, + messages: [ + { + role: "system", + content: "You are an expert at analyzing customer sentiment. Be precise and consistent." + }, + { + role: "user", + content: "Extract {{structuredOutput.name}} using this schema:\n{{structuredOutput.schema}}\n\nAnalyze the sentiment of this conversation:\n{{transcript}}" + } + ] + } +}); +``` + +```python title="Python" +structured_output = vapi.structured_outputs.create( + name="Sentiment Analysis", + type="ai", + schema={ + "type": "object", + "properties": { + "sentiment": { + "type": "string", + "enum": ["positive", "negative", "neutral"] + }, + "confidence": { + "type": "number", + "minimum": 0, + "maximum": 1 + } + } + }, + model={ + "provider": "openai", + "model": "gpt-4.1", + "temperature": 0.1, + "messages": [ + { + "role": "system", + "content": "You are an expert at analyzing customer sentiment. Be precise and consistent." + }, + { + "role": "user", + "content": "Extract {{structuredOutput.name}} using this schema:\n{{structuredOutput.schema}}\n\nAnalyze the sentiment of this conversation:\n{{transcript}}" + } + ] + } +) +``` + + +### Available variables + +Use these variables in custom prompts: + +- `{{transcript}}` - Full conversation transcript +- `{{messages}}` - Conversation messages array (JSON) +- `{{endedReason}}` - How the call ended +- `{{duration}}` - Call duration in seconds +- `{{startedAt}}` - Call start time (ISO 8601) +- `{{endedAt}}` - Call end time (ISO 8601) +- `{{systemPrompt}}` - The assistant's system prompt +- `{{structuredOutput}}` - The full structured output definition +- `{{structuredOutput.name}}` - Output name +- `{{structuredOutput.description}}` - Output description +- `{{structuredOutput.schema}}` - Schema definition + + +When you supply custom `messages`, reference either `{{transcript}}` or `{{messages}}` for the conversation, and a variation of `{{structuredOutput}}` so the model has the schema definition. + + +## API reference + +The full set of request fields, response types, and query parameters lives in the API reference. Refer there for all possible values rather than duplicating them here. + +### Create structured output + + + +See [Create structured output](/api-reference/structured-outputs/structured-output-controller-create) for every request field, including `type`, `conditions`, `model`, and `assistantIds`. + +### Update structured output + + + + +Updating the top-level schema type after creation requires the `?schemaOverride=true` query parameter. See [Update structured output](/api-reference/structured-outputs/structured-output-controller-update). + + +### List structured outputs + + + +See [List structured outputs](/api-reference/structured-outputs/structured-output-controller-find-all) for all query parameters, including filtering, sorting, and pagination. + +### Delete structured output + + + +## Common use cases + +### Customer information collection + +```json +{ + "name": "Customer Profile", + "type": "ai", + "schema": { + "type": "object", + "properties": { + "name": {"type": "string"}, + "email": {"type": "string", "format": "email"}, + "phone": {"type": "string"}, + "accountNumber": {"type": "string"}, + "preferredContactMethod": { + "type": "string", + "enum": ["email", "phone", "sms"] + } + } + } +} +``` + +### Appointment scheduling + +```json +{ + "name": "Appointment Request", + "type": "ai", + "schema": { + "type": "object", + "properties": { + "preferredDate": {"type": "string", "format": "date"}, + "preferredTime": {"type": "string", "format": "time"}, + "duration": {"type": "integer", "enum": [15, 30, 45, 60]}, + "serviceType": { + "type": "string", + "enum": ["consultation", "follow-up", "procedure"] + }, + "notes": {"type": "string"} + }, + "required": ["preferredDate", "preferredTime", "serviceType"] + } +} +``` + +### Order processing + +```json +{ + "name": "Order Details", + "type": "ai", + "schema": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "type": "object", + "properties": { + "product": {"type": "string"}, + "quantity": {"type": "integer", "minimum": 1}, + "specialInstructions": {"type": "string"} + }, + "required": ["product", "quantity"] + } + }, + "deliveryAddress": { + "type": "object", + "properties": { + "street": {"type": "string"}, + "city": {"type": "string"}, + "zipCode": {"type": "string", "pattern": "^\\d{5}$"} + } + }, + "deliveryInstructions": {"type": "string"} + } + } +} +``` + +### Lead qualification + +```json +{ + "name": "Lead Information", + "type": "ai", + "schema": { + "type": "object", + "properties": { + "company": {"type": "string"}, + "role": {"type": "string"}, + "budget": { + "type": "string", + "enum": ["< $10k", "$10k-50k", "$50k-100k", "> $100k"] + }, + "timeline": { + "type": "string", + "enum": ["immediate", "1-3 months", "3-6 months", "6+ months"] + }, + "painPoints": { + "type": "array", + "items": {"type": "string"} + }, + "nextSteps": {"type": "string"} + } + } +} +``` + +## Best practices + + + + Begin with basic schemas and add complexity as needed. Test with real conversations before adding advanced features. + + + + Help the AI understand what to extract by using clear field names and descriptions in your schema. + + + + Balance flexibility with validation. Too strict and extraction may fail; too loose and data quality suffers. + + + + Only mark fields as required if they're truly essential. Use optional fields for information that might not be mentioned. + + + +### Performance tips + +- **Keep schemas focused**: Extract only what you need to minimize processing time +- **Use appropriate models**: use a capable model (for example, GPT-4.1) for complex schemas; lighter models can handle simpler ones +- **Set low temperature**: Use 0.1 or lower for consistent extraction +- **Monitor success rates**: Track extraction failures and adjust schemas accordingly + +### Error handling + +Always check for null results which indicate extraction failure: + +```typescript +if (data.result === null) { + console.log(`Extraction failed for ${data.name}`); + // Implement fallback logic +} +``` + +## Troubleshooting + +### No data extracted + + + + Ensure your JSON Schema is valid and properly formatted + + + Confirm the required information was actually mentioned + + + Verify the structured output ID is linked to your assistant + + + Try a basic schema to isolate the issue + + + +### Incorrect extraction + +- Add more descriptive field descriptions +- Provide examples in custom prompts +- Use stricter validation patterns +- Lower the model temperature + +### Partial extraction + +- Make fields optional if they might not be mentioned +- Verify data types match expected values + +## Limitations + + +- Schema updates require `?schemaOverride=true` parameter +- Extraction occurs after call completion (not real-time) +- Name field limited to 40 characters + + +## Related + +- [Call analysis](/assistants/call-analysis) - Summarize and evaluate calls +- [Custom tools](/tools/custom-tools) - Trigger actions during calls +- [Webhooks](/server-url) - Receive extracted data via webhooks +- [Variables](/assistants/dynamic-variables) - Use dynamic data in conversations \ No newline at end of file diff --git a/fern/assistants/versioning/overview.mdx b/fern/assistants/versioning/overview.mdx new file mode 100644 index 000000000..a808f3520 --- /dev/null +++ b/fern/assistants/versioning/overview.mdx @@ -0,0 +1,41 @@ +--- +title: Versioning +subtitle: Save, publish, and restore versions of your assistants and tools +description: Versioning saves published assistant and tool configurations so you can make changes in a draft, review their history, and restore an earlier version. +slug: assistants/versioning +--- + +Versioning lets you change an [assistant](/assistants) or [tool](/tools) without affecting live calls. Publish the draft when it is ready, review earlier versions, or restore an earlier configuration. + +## The versioning lifecycle + +Assistants and tools both support drafts, publishing, and version history: + +- **Draft**: Contains your unpublished changes. Drafts are per user, so your edits stay separate from your teammates'. Draft changes do not affect live calls. +- **Publish**: Creates a new version from the draft. The new version becomes the current published version. +- **History**: Keeps every published version so you can review what changed and when. +- **Restore an assistant**: Immediately creates a new current version from an earlier configuration and replaces any draft changes. +- **Restore a tool**: Loads an earlier configuration into the draft. Publish the restored draft to create the next current version. + + +The **current** version is the configuration used by live calls. Publishing a draft makes the new version current. Restoring an assistant version creates a new current version immediately. + + +## Which version a call uses + +- **Inbound calls** use the assistant's current published version. You cannot select another version for an inbound call. +- **Outbound and web calls** use the current published version by default. To use a specific published version, pass `assistantVersion` with `assistantId` in the [create call request](/api-reference/calls/create). + +## Next steps + + + + Publish, view history, and restore versions of an assistant. + + + Publish, view history, and restore versions of a tool. + + + Choose the tool versions an assistant uses and learn how restoring an assistant affects them. + + diff --git a/fern/assistants/versioning/versioning-assistants.mdx b/fern/assistants/versioning/versioning-assistants.mdx new file mode 100644 index 000000000..a4c84921b --- /dev/null +++ b/fern/assistants/versioning/versioning-assistants.mdx @@ -0,0 +1,109 @@ +--- +title: Versioning with assistants +subtitle: Publish, view history, and restore versions of an assistant +description: Publish assistant changes, review version history, restore an earlier configuration as a new current version, and select the published assistant version for a call. +slug: assistants/versioning/versioning-assistants +--- + +## How assistant versioning works + +[Assistants](/assistants) follow the [versioning lifecycle](/assistants/versioning). Edit the draft, then publish it to create a version. Published versions do not change. To reuse an earlier configuration, restore it. Vapi immediately creates a new version from that configuration and makes it current. + +The assistant list and header show the selected version. A draft appears separately when the assistant has unpublished changes. + + + Jamie assistant with the Versions menu open and version v1 named First draft marked Current + + +## Publish a new version + +Publishing turns your current draft into a new version and makes it the **current** version. + + + + Make changes to the assistant. Vapi saves your edits automatically as a draft. The changes do not affect live calls. + + + Select **Publish** to compare the draft with the current published version. In the diff, you can copy individual lines, wrap long lines, move between changes, or copy the complete diff. + + + Publish Assistant dialog comparing Jamie's draft first message with the current published version + + + + Give the version a name. You can also add a short description so teammates understand what changed and why. + + + Publish Assistant dialog with Clarify opening message entered as the version name and a description of the update + + + + Select **Publish** to create the version and make it current. To publish with the default settings, select **Quick Publish**. To remove the draft changes, select **Discard Changes…**. + + + +## View version history + +Open the version menu in the assistant header to see recent versions. Select **View Full History** to see all versions. The current published version is marked **Current**. Each version includes its version number, name, description, and publication time. + + + Jamie assistant Version History panel showing Clarify opening message as the current v2 and First draft as v1 + + +From the version history, you can: + +- Select **View changes** to compare a version with the previous version +- Select **Export** to download a version as JSON +- Select **Restore** to make an earlier configuration current as a new version + + + Changes in v2 compared with v1 showing the updated firstMessage value + + +## Restore a previous version + +Open the version history and select **Restore** for an earlier version. Review the confirmation, then select **Restore version**. Vapi immediately creates a new version from the selected configuration and makes the new version current. For example, restoring v1 while v2 is current creates v3 with the v1 configuration. + + + Restore version confirmation explaining that restoring v1 as the active version takes effect immediately + + + +Restoring a version takes effect immediately and replaces any current draft changes. + + +The new version includes the tool version selections saved with the restored assistant version. A tool set to **Latest** continues to use its newest published version. See [How versioning works with assistants and tools](/assistants/versioning/versioning-with-assistants-and-tools). + +## Which version a call uses + +- **Inbound calls** use the assistant's current published version. You cannot select another version for an inbound call. +- **Outbound and web calls** use the current published version by default. To use a specific published version, pass `assistantVersion` with `assistantId` in the [create call request](/api-reference/calls/create). + +## Next steps + + + + Save, publish, and restore versions of your assistants and tools. + + + Choose the tool versions an assistant uses and learn how restoring an assistant affects them. + + diff --git a/fern/assistants/versioning/versioning-tools.mdx b/fern/assistants/versioning/versioning-tools.mdx new file mode 100644 index 000000000..3da2b2c0c --- /dev/null +++ b/fern/assistants/versioning/versioning-tools.mdx @@ -0,0 +1,90 @@ +--- +title: Versioning with tools +subtitle: Publish, view history, and restore versions of a tool +description: Publish tool changes, review version history, restore an earlier configuration to the draft, and select the specific tool version that an assistant uses. +slug: assistants/versioning/versioning-tools +--- + +## How tool versioning works + +[Tools](/tools) follow the [versioning lifecycle](/assistants/versioning). Edit the draft, then publish it to create a version. Published versions do not change. To reuse an earlier configuration, restore it to the draft and publish the draft as the next version. + +A tool's versions are independent of an assistant's versions. An assistant can use a specific tool version or the **Latest** version. See [How versioning works with assistants and tools](/assistants/versioning/versioning-with-assistants-and-tools). + +The tool header shows the selected version. A draft appears separately when the tool has unpublished changes. + +## Publish a new version + +Publishing turns your current draft into a new version and makes it the **current** version. + + + + Open the [Dashboard](https://dashboard.vapi.ai), select **Tools**, and select the tool you want to update. + + + Change the tool's configuration. Vapi saves your edits automatically as a draft. The changes do not affect live calls. + + + Select **Publish** to compare the draft with the current published version. In the diff, you can copy individual lines, wrap long lines, move between changes, or copy the complete diff. + + + Give the version a name. You can also add a short description so teammates understand what changed and why. + + + Select **Publish** to create the version and make it current. To publish with the default settings, select **Quick Publish**. To remove the draft changes, select **Discard Changes…**. + + + +## View version history + + + + Open the [Dashboard](https://dashboard.vapi.ai), select **Tools**, and select the tool whose history you want to review. + + + Select the version number in the tool header to see recent versions. The current published version is marked **Current**. + + + Select **View Full History**. Each version includes its version number, name, description, and publication time. + + + +From the version history you can: + +- Select **View changes** to compare a version with the previous version +- Select **Export** to download a version as JSON +- Select **Restore** to load a version into the draft + +## Restore a previous version + + + + Open the version history and select **Restore** for an earlier version. + + + Review the confirmation, then select **Restore**. Vapi loads the selected configuration into the editor as a draft and replaces the current draft changes. + + + Review the draft, then select **Publish** to create the next version and make it current. + + + + +Restoring a version replaces the tool's current draft changes. + + +Restoring a tool version does not change which version an assistant uses. The assistant continues to use the selected version or **Latest**. See [How versioning works with assistants and tools](/assistants/versioning/versioning-with-assistants-and-tools). + +## Next steps + + + + Save, publish, and restore versions of your assistants and tools. + + + Publish, view history, and restore versions of an assistant. + + + Choose the tool versions an assistant uses and learn how restoring an assistant affects them. + + diff --git a/fern/assistants/versioning/versioning-with-assistants-and-tools.mdx b/fern/assistants/versioning/versioning-with-assistants-and-tools.mdx new file mode 100644 index 000000000..c8d559eb8 --- /dev/null +++ b/fern/assistants/versioning/versioning-with-assistants-and-tools.mdx @@ -0,0 +1,66 @@ +--- +title: How versioning works with assistants and tools +subtitle: Choose the tool versions an assistant uses and understand how restores affect them +description: Select a specific or latest tool version for an assistant, and learn how restoring an assistant also restores the tool version selections saved with it. +slug: assistants/versioning/versioning-with-assistants-and-tools +--- + +## How version pinning works + +Assistants and tools are [versioned independently](/assistants/versioning), but an assistant configuration records which version of each tool to use. You can select a numbered version or **Current**, which appears as **Latest** when the menu is closed. When you publish the assistant, Vapi saves those selections in the assistant version. + +## Choose a tool version in the Dashboard + + + + Open the [Dashboard](https://dashboard.vapi.ai), select **Assistants**, and select the assistant that uses the tool. + + + Select **Tools**. + + + Under **Assign Tool Version**, open the version menu for the tool. Choose one of these options: + + - **Current**: Always use the tool's current version. The closed menu displays **Latest**. + - **Numbered version**: Pin the assistant to a specific version, such as **v3**. The assistant stays on that version until you change the selection and publish the assistant again. + + + Jamie assistant Tools tab with the Assign Tool Version menu open for a transfer call tool + + + + Select **Publish** and complete the publish flow to save the tool version selection in a new assistant version. + + + +## Use the latest tool version through the API + +When you [create](/api-reference/assistants/create) or [update](/api-reference/assistants/update) an assistant through the API, omit the tool version to use **Latest**. The assistant then uses the newest published version of that tool. + +## How restoring an assistant affects tools + +When you restore an assistant version, Vapi immediately creates a new current assistant version with its saved tool version selections. A specific tool version returns to the saved selection. A tool set to **Latest** continues to use its newest published version. + +For example: + +- At **v6**, the assistant uses **Tool A v4** and **Tool B v6**. +- The assistant's **v5** configuration used **Tool A v2** and **Tool B v4**. +- You restore assistant **v5**. Vapi creates assistant **v7**, makes it current, and restores the selections for Tool A v2 and Tool B v4. +- If Tool B was set to **Latest** in assistant v5, it continues to use the newest published Tool B version. + +## Next steps + + + + Save, publish, and restore versions of your assistants and tools. + + + Publish, view history, and restore versions of an assistant. + + + Publish, view history, and restore versions of a tool. + + diff --git a/fern/assistants/voice-formatting-plan.mdx b/fern/assistants/voice-formatting-plan.mdx new file mode 100644 index 000000000..f9080d550 --- /dev/null +++ b/fern/assistants/voice-formatting-plan.mdx @@ -0,0 +1,91 @@ +--- +title: Voice formatting plan +subtitle: Format LLM output for natural-sounding speech +slug: assistants/voice-formatting-plan +--- + +## Overview + +Voice formatting automatically transforms raw text from your language model (LLM) into a format that sounds natural when spoken by a text-to-speech (TTS) provider. This process—called **Voice Input Formatted**—is enabled by default for all assistants. + +Formatting helps with things like: + +- Expanding numbers and currency (e.g., `$42.50` → "forty two dollars and fifty cents") +- Expanding abbreviations (e.g., `ST` → "STREET") +- Spacing out phone numbers (e.g., `123-456-7890` → "1 2 3 4 5 6 7 8 9 0") + +You can turn off formatting if you want the TTS to read the raw LLM output. + +## How voice input formatting works + +When enabled, the formatter runs a series of transformations on your text, each handled by a specific function. Here's the order and what each function does: + +| **Step** | **Function Name** | **Description** | **Before** | **After** | **Default** | **Precedence** | +| :------- | :---------------- | :-------------- | :--------- | :-------- | :---------- | :------------ | +| 1 | `removeAngleBracketContent` | Removes anything within `<...>`, except for ``, ``, or double angle brackets `<< >>`. | `Hello world` | `Hello world` | ✅ | - | +| 2 | `removeMarkdownSymbols` | Removes markdown symbols like `_`, `` ` ``, and `~`. Asterisks (`*`) are preserved in this step. | `**Wanted** to say *hi*` | `**Wanted** to say *hi*` | ✅ | 0 | +| 3 | `removePhrasesInAsterisks` | Removes text surrounded by single or double asterisks. | `**Wanted** to say *hi*` | ` to say` | ❌ | 0 | +| 4 | `replaceNewLinesWithPeriods` | Converts new lines (`\n`) to periods for smoother speech. | `Hello world\n to say\nWe have NASA` | `Hello world . to say . We have NASA` | ✅ | 0 | +| 5 | `replaceColonsWithPeriods` | Replaces `:` with `.` for better phrasing. | `price: $42.50` | `price. $42.50` | ✅ | 0 | +| 6 | `formatAcronyms` | Converts known acronyms to lowercase (e.g., NASA → nasa) or spaces out unknown all-caps words unless they contain vowels. | `NASA and .NET` | `nasa and .net` | ✅ | 0 | +| 7 | `formatDollarAmounts` | Converts currency amounts to spoken words. | `$42.50` | `forty two dollars and fifty cents` | ✅ | 0 | +| 8 | `formatEmails` | Replaces `@` with "at" and `.` with "dot" in emails. | `JOHN.DOE@example.COM` | `JOHN dot DOE at example dot COM` | ✅ | 0 | +| 9 | `formatDates` | Converts date strings into spoken date format. | `2023 05 10` | `Wednesday, May 10, 2023` | ✅ | 0 | +| 10 | `formatTimes` | Expands or simplifies time expressions. | `14:00` | `14` | ✅ | 0 | +| 11 | `formatDistances`, `formatUnits`, `formatPercentages`, `formatPhoneNumbers` | Converts units, distances, percentages, and phone numbers into spoken words. | `5km`, `43 lb`, `50%`, `123-456-7890` | `5 kilometers`, `forty three pounds`, `50 percent`, `1 2 3 4 5 6 7 8 9 0` | ✅ | 0 | +| 12 | `formatNumbers` | Formats general numbers: years read as digits, large numbers spelled out, negative and decimal numbers clarified. | `-9`, `2.5`, `2023` | `minus nine`, `two point five`, `2023` | ✅ | 0 | +| 13 | `removeAsterisks` | Removes all asterisk characters from the text. | `**Bold** and *italic*` | `Bold and italic` | ✅ | 1 | +| 14 | `Applying Replacements` | Applies user-defined final replacements like expanding street abbreviations. | `320 ST 21 RD` | `320 STREET 21 ROAD` | ✅ | - | + +--- + +## Customizing the formatting plan + +You can control some aspects of formatting: + +### Enabled +Formatting is on by default. To disable, set: +```js +voice.chunkPlan.formatPlan.enabled = false +``` + +### Number-to-digits cutoff +Controls when numbers are read as digits instead of words. +- **Default:** `2025` (current year) +- Example: With a cutoff of `2025`, numbers above this are read as digits. +- To spell out larger numbers, set the cutoff higher (e.g., `300000`). + +### Replacements +Add exact or regex-based substitutions to customize output. +- **Example 1:** Replace `hello` with `hi`: + ```js + { type: 'exact', key: 'hello', value: 'hi' } + ``` +- **Example 2:** Replace words matching a pattern: + ```js + { type: 'regex', regex: '\b[a-zA-Z]{5}\b', value: 'hi' } + ``` + + +Currently, only replacements and the number-to-digits cutoff are customizable. Other options are not exposed. + + +--- + +## Turning formatting off + +To disable all formatting and use raw LLM output, set either of these to `false`: + +```js +voice.chunkPlan.enabled = false +// or +voice.chunkPlan.formatPlan.enabled = false +``` + +--- + +## Summary + +- Voice input formatting improves clarity and naturalness for TTS. +- Each transformation step targets a specific pattern for better speech output. +- You can customize or disable formatting as needed. diff --git a/fern/billing/billing-limits.mdx b/fern/billing/billing-limits.mdx deleted file mode 100644 index 7dadaa746..000000000 --- a/fern/billing/billing-limits.mdx +++ /dev/null @@ -1,36 +0,0 @@ ---- -title: Billing Limits -subtitle: Set billing limits on your Vapi account. -slug: billing/billing-limits ---- - - -You can set billing limits in the billing section of your dashboard. - - - You can access your billing settings at - [dashboard.vapi.ai/org/billing](https://dashboard.vapi.ai/org/billing) - - -### Concurrency Limits -Vapi has concurrency limits on both inbound and outbound calls. These limits define the maximum number of simultaneous calls your account can handle. Exceeding your concurrency limit causes new requests to queue or be rejected until existing calls finish. - -- The default concurrency limit is 10 simultaneous calls(inbound and outbound calls combined). This limit applies to your entire account and is not dependent on the number of users or organizations associated with it. - -- To increase your concurrency limit beyond the default of 10, you must purchase additional concurrent lines through the dashboard section. - -### Setting a Monthly Billing Limit - -In your billing settings you can set a monthly billing limit: - - - - - -### Exceeding Billing Limits - -Once you have used all of your starter credits, or exceeded your set monthly usage limit, you will start seeing errors in your dashboard & via the API mentioning `Billing Limits Exceeded`. - - - - diff --git a/fern/billing/cost-routing.mdx b/fern/billing/cost-routing.mdx deleted file mode 100644 index 59c887bc2..000000000 --- a/fern/billing/cost-routing.mdx +++ /dev/null @@ -1,55 +0,0 @@ ---- -title: Cost Routing -subtitle: Learn more about how your Vapi account is billed for provider expenses. -slug: billing/cost-routing ---- - - - - - - -During calls, requests will be made to different providers in the voice pipeline: - -- **transcription providers:** providers conducting speech-to-text -- **model providers:** LLM providers -- **voice providers:** providers conducting text-to-speech -- **telephony providers:** providers like [Twilio](https://www.twilio.com)/[Vonage](https://www.vonage.com) that facilitate phone calls - - - Per-minute telephony costs only occur during inbound/outbound phone calling. Web calls do not - incur this cost. - - -## Where Provider Costs End-up - -There are 2 places these charges can end up: - -1. **Provider-side:** in the account you have with the provider. -2. **With Vapi:** in your Vapi account. - - - - If we have [provider keys](customization/provider-keys) on file for a provider, the cost will be seen directly - in your account with the provider. Vapi will have made the request on your behalf with your provider key. - - No charge will be made to your Vapi account. - - Charges for inbound/outbound phone calling (telephony) will always end up where the phone number - was provisioned. If you import a phone number from Twilio or Vonage, per-minute charges for calling - those numbers will appear with them. - - - - If no key is found on-file for the provider, Vapi will make the API request itself (with Vapi's own keys, at Vapi's expense). This expense is then passed on [**at-cost**](/glossary#at-cost) to be billed directly to your Vapi account. - - No charge will show up provider-side. - - - - -## Billing That "Just Works" - -The central idea is that everything is designed to "just work". - -Whether you are billed provider-side, or on Vapi's side, you will never be charged with any margin for provider fees incurred during calls. diff --git a/fern/billing/estimating-costs.mdx b/fern/billing/estimating-costs.mdx deleted file mode 100644 index 98a7c0c94..000000000 --- a/fern/billing/estimating-costs.mdx +++ /dev/null @@ -1,229 +0,0 @@ ---- -title: Estimating Costs -subtitle: Get information on your voice pipeline's projected costs. -slug: billing/estimating-costs ---- - - -Since there are so many moving parts to the voice pipeline that can incur cost, it would be ideal for us to get a good estimate of our final projected per-minute cost for calls. - -### Dashboard Cost Estimates - -The Vapi dashboard provides static cost projections on a per-assistant basis, so you can get a rough idea of the costs your assistant will incur during live execution. - - - You can view your dashboard at [dashboard.vapi.ai](https://dashboard.vapi.ai/) - & get started with our [dashboard quickstart](/quickstart/dashboard). - - - - - - -### General Provider Estimates - -The provider costs listed below are subject to change as we get more data, but they will always reflect our best estimate of the provider costs per minute: - - - - | Provider | \$/min (≈) | \$/hour | - | -------- | -------------- | --------- | - | Deepgram | **\$0.01/min** | \$0.60/hr | - - - | Provider | $/min (≈) | $/hour | - | ----------------------- | --------------- | ------------- | - | OpenAI (gpt-4-turbo) | **$0.20/min** | $12.00/hr | - | OpenAI (gpt-3.5-turbo) | **$0.02/min** | $1.20/hr | - - - - | Provider | $/min (≈) | $/hour | - | ---------- | --------------- | ---------- | - | ElevenLabs | **$0.04/min** | $2.40/hr | - | PlayHT | **$0.07/min** | $4.20/hr | - | Deepgram | **$0.02/min** | $1.20/hr | - | OpenAI | **$0.02/min** | $1.20/hr | - | RimeAI | **$0.03/min** | $1.80/hr | - | Azure | **$0.02/min** | $1.20/hr | - | Neets | **$0.005/min** | $0.30/hr | - | LMNT | **$0.03/min** | $1.80/hr | - - - - | Provider | $/min (≈) | $/hour | - | -------- | --------------- | ---------- | - | Twilio | **$0.01/min** | $0.60/hr | - | Vonage | **$0.01/min** | $0.60/hr | - - - - -### Provider Pricings - -Here are direct links to different provider's pricing pages to assist in estimating cost: - - - - - - Deepgram transcription pricing. - - - - - - - OpenAI model pricing. - - - - - - - ElevenLabs voice pricing. - - - PlayHT voice pricing. - - - Deepgram voice pricing. - - - OpenAI voice pricing. - - - RimeAI voice pricing. - - - Azure voice pricing. - - - Neets voice pricing. - - - LMNT voice pricing. - - - - - - - Twilio phone call pricing. - - - Vonage phone call pricing. - - - - - -### Calling Your Assistant - -One good way to get an empirical per-minute cost on your whole voice pipeline is to actually call in, use it for a few minutes, & observe the average cost/minute at the call level. - - - You can view a breakdown of your cost per call in your dashboard at - [dashboard.vapi.ai/calls](https://dashboard.vapi.ai/calls) - - -Your call cost breakdowns will look something like this: - - - - - -Here is what each line item corresponds to: - -- `STT`: Speech-to-text (providers often bill per-minute, prorated) -- `LLM`: LLM inference (providers often bill per-million or per-thousand tokens) -- `TTS`: Text-to-speech (providers often bill per-character) -- `Vapi`: the Vapi platform fee of 5¢/minute (prorated per-second) -- `Transport`: telephony costs (incurred for inbound/outbound phone calls to/from a phone number) (providers often bill per-minute) - -This method can be effective because **per-minute costs will not scale** with the amount of call minutes you consume. The cost for the 1st minute will be the same as the 10,000th minute. - - - Volume pricing is available on enterprise plans. Check out - [enterprise](/enterprise) to learn more. - diff --git a/fern/billing/examples.mdx b/fern/billing/examples.mdx deleted file mode 100644 index 0e1d61837..000000000 --- a/fern/billing/examples.mdx +++ /dev/null @@ -1,188 +0,0 @@ ---- -title: Billing Examples -subtitle: End-to-end examples estimating voice workflow cost on Vapi. -slug: billing/examples ---- - - - - - - -## Case Examples - -Here are a few case-examples of what billing would look like on Vapi for different voice pipeline configurations. - - - - A customer is looking to use Vapi to assist their call center staff taking phone calls inbound: - - - -
- "I want to use Vapi voice assistants to support my human customer service reps in a call - center. However, I have a custom LLM I would prefer to use instead of the ones offered through - the platform. -
- -
- Expected monthly usage will be 10,000 calls, with an average of 2 minutes per call. For Voice, - PlayHT will suit our needs. -
- -
What is my pricing breakdown?"
- -
- - The providers used will determine per-minute cost. The following providers will be involved: - -
**Transcriber:** Deepgram
-
**Model:** custom model
-
**Voice:** PlayHT
-
**Telephony:** Twilio (receiving inbound phone calls)
- -
- - - -
- -
- - We will break down the costs of each piece of the voice pipeline, then later multiply by call volume: - -
**Deepgram:** ≈ \$0.01/min
-
**Custom Model:** ≈ \$0.04/min (vague assumption, can vary widely)
-
**PlayHT:** ≈ \$0.07/min
-
**Twilio:** ≈ \$0.02/min (inbound, toll-free) (see Twilio [phone call pricing](https://www.twilio.com/en-us/voice/pricing))
-
**Vapi:** \$0.05/min
- - Our [estimating costs](/billing/estimating-costs) guide can help you determine these values. - -
- - Call Minutes / Month: 10,000 calls x 2 min/call = **20,000 call minutes** - -
**Transcription:** \$0.01/min x 20,000 = **\$200**
-
**Custom Model:** \$0.04/min x 20,000 = **\$800**
-
**Voice:** ≈ \$0.07/min x 20,000 = **\$1,400**
-
**Telephony:** ≈ \$0.02/min x 20,000 = **\$400**
-
**Vapi:** \$0.05/min x 20,000 = **\$1,000**
- - **Total**: **\$3,800**/mo - -
-
- -
- - A customer doing real estate lead generation is looking to use Vapi to automate parts of their sales calling operation: - - - - "I have a company that does real estate lead generation, and would like to use Vapi voice - assistants to automate parts of my sales process. - - Calls would average ~4 minutes, for Model I want to use GPT-3.5-turbo through your platform, and for Voice I will be using a ElevenLabs. - - I’d like a breakdown based on sending 1,000 outbound calls in one month." - - - -
**Transcriber:** Deepgram
-
**Model:** OpenAI (GPT-3.5 Turbo)
-
**Voice:** ElevenLabs
-
**Telephony:** Vonage (sending outbound phone calls)
- -
- - - -
- -
- -
**Deepgram:** ≈ \$0.01/min
-
**OpenAI (GPT-3.5 Turbo):** ≈ \$0.02/min
-
**ElevenLabs:** ≈ \$0.04/min
-
**Vonage:** ≈ \$0.01/min (outbound call) (see Vonage's [phone call pricing](https://www.vonage.com/communications-apis/voice/pricing))
-
**Vapi:** \$0.05/min
- - Our [estimating costs](/billing/estimating-costs) guide can help you determine these values. - -
- - Call Minutes / Month: 1,000 calls x 4 min/call = **4,000 call minutes** - -
**Transcription:** \$0.01/min x 4,000 = **\$40**
-
**Model:** \$0.02/min x 4,000 = **\$80**
-
**Voice:** ≈ \$0.04/min x 4,000 = **\$160**
-
**Telephony:** ≈ \$0.01/min x 4,000 = **\$40**
-
**Vapi:** \$0.05/min x 4,000 = **\$200**
- - **Total**: **\$520**/mo - -
-
- -
- - A web engineer is looking to develop a website that helps job candidates practice for job interviews. They are looking to use Vapi for their virtual interviewers: - - - - "Hi, I'm looking to develop a web application for mock interviews. Users will be able to practice for a variety - of job interviews with AI interviewers. - - Interviews will be 30-minutes each (at max), for model I'll be using a custom open-source model hosted with Baseten & for voice I'll be using PlayHT. - - How much would this cost me each month if I service 1,000 interviews per month?" - - - -
**Transcriber:** Deepgram
-
**Model:** custom model
-
**Voice:** PlayHT
- -
- - - -
- -
- -
**Deepgram:** ≈ \$0.01/min
-
**Custom Model:** ≈ \$0.02/min (vague assumption, can vary widely)
-
**PlayHT:** ≈ \$0.07/min
-
**Vapi:** \$0.05/min
- - Our [estimating costs](/billing/estimating-costs) guide can help you determine these values. - -
- - Call Minutes / Month: 1,000 calls x 30 min/call = **30,000 call minutes** - -
**Transcription:** \$0.01/min x 30,000 = **\$300**
-
**Model:** \$0.02/min x 30,000 = **\$600**
-
**Voice:** ≈ \$0.07/min x 30,000 = **\$2,100**
-
**Vapi:** \$0.05/min x 30,000 = **\$1,500**
- - **Total**: **\$4,500**/mo - -
-
- -
-
- -### Further Reading - - - - Learn more about where provider costs end up getting billed. - - - Learn more about determining per-minute costs for providers. - - diff --git a/fern/billing/manage-billing-and-credits.mdx b/fern/billing/manage-billing-and-credits.mdx new file mode 100644 index 000000000..9af800f02 --- /dev/null +++ b/fern/billing/manage-billing-and-credits.mdx @@ -0,0 +1,70 @@ +--- +title: "Manage pay-as-you-go billing and credits" +subtitle: "Add a payment method, buy credits, configure auto reload, and download billing records." +description: "Manage pay-as-you-go billing in the Vapi Dashboard: add a payment method, buy credits, configure auto reload, and download PDF statements and invoices." +slug: billing/manage-billing-and-credits +--- + +This guide shows you how to set up billing for a pay-as-you-go subscription. By the end, you can fund the subscription and configure automatic credit purchases. + +## Prerequisites + +- An **Admin** role in the organization. + +## Steps + + + + Sign in to the [Vapi Dashboard](https://dashboard.vapi.ai), select the organization you want to fund, open **Settings**, then select **Billing & Add-Ons**. + + + Billing & Add-Ons selected in the Dashboard Settings navigation + + + + + In **Payment method**, enter the billing email and card details. Select the checkmark beside each field to save it. + + To replace a saved card, select the pencil beside **Payment method**, enter the new card details, then select the checkmark. + + + Full Payment method block with the billing email blurred, card field, and auto reload controls + + + + + At the top of the Billing page, select **Buy credits**. In **Purchase Vapi credits**, enter at least `$10` in **Amount to purchase**, then select **Purchase**. + + Complete any verification requested by the card issuer. A successful purchase increases the credit balance and appears as **Finalized** in **Credit purchase history**. + + + Purchase Vapi credits dialog with the amount to purchase field + + + + + In **Payment method**, turn on **Enable auto reload**. Enter at least `$10` in **Amount to reload**, then enter the balance that should trigger the purchase in **When threshold reaches**. + + Select **Save changes**, review the confirmation, then select **Confirm**. If the current balance is at or below the threshold, saving the plan charges the payment method immediately. + + + Auto reload controls on the live Billing page + + + + + Confirm that the page shows the saved payment method, updated credit balance, and auto reload settings. Check **Credit purchase history** for a **Finalized** payment. + + + +## Download billing records + +Select **Download monthly statement** in **Credit purchase history** to create a statement for a selected month. + +To download an invoice for an eligible payment, select the payment, then select **Download invoice (PDF)**. Enter the requested invoice information and select **Confirm**. + +## Related + + + Resolve calls blocked by an insufficient credit balance or frozen subscription. + diff --git a/fern/billing/purchase-call-concurrency.mdx b/fern/billing/purchase-call-concurrency.mdx new file mode 100644 index 000000000..a10362860 --- /dev/null +++ b/fern/billing/purchase-call-concurrency.mdx @@ -0,0 +1,49 @@ +--- +title: "Purchase call concurrency" +subtitle: "Increase your organization's call concurrency from the Dashboard." +description: "Purchase call concurrency from Billing & Add-Ons to increase the number of simultaneous calls available to your Vapi organization." +slug: billing/purchase-call-concurrency +--- + +Purchase call concurrency when your organization needs to run more simultaneous calls than its plan includes. + +## How call lines affect concurrency + +Call concurrency is the number of Vapi calls that can be active at the same time. Each reserved call line adds one simultaneous call to your organization's included concurrency. + +All inbound and outbound calls share the organization's capacity. A campaign's **Max concurrency** setting limits that campaign, but it does not purchase or reserve additional call lines. + +## Prerequisites + +- An **Admin** role in the organization. +- Enough Vapi credits to cover the prorated charge shown before purchase. + +## Purchase call concurrency + + + + Sign in to the [Vapi Dashboard](https://dashboard.vapi.ai), select the organization you want to update, open **Settings**, then select **Billing & Add-Ons**. + + + + In **Add-ons**, find **Reserved concurrency (call lines)**. Enter the total number of add-on call lines you want the organization to have. + + This value represents purchased call lines, not the organization's total concurrency. For example, if the plan includes 10 calls and you enter `5`, the organization has 15 call lines after the purchase. + + + Reserved concurrency call-line field used to purchase call concurrency in Billing and Add-Ons + + + + + Review **Add-ons summary** and **Pricing preview**. The preview shows the new monthly charge and the prorated amount due for the remainder of the current billing period. + + + + Select **Purchase add-ons**, review the confirmation dialog, then select **Confirm**. The additional call lines become available after the purchase succeeds. + + + + Confirm that **Reserved concurrency (call lines)** shows the purchased amount. The organization's concurrency limit now includes those additional call lines. + + diff --git a/fern/blocks.mdx b/fern/blocks.mdx index 1f00745ed..f19bf5860 100644 --- a/fern/blocks.mdx +++ b/fern/blocks.mdx @@ -1,12 +1,14 @@ --- -title: Introduction +title: Introduction to Blocks subtitle: Breaking down bot conversations into smaller, more manageable prompts slug: blocks --- + + **Blocks** is being deprecated in favor of [Workflows](/workflows). We recommend using Workflows for all new development as it provides a more powerful and flexible way to structure conversational AI. We're working on migration tools to help transition existing Blocks implementations to Workflows. + - -We're currently running a beta for **Blocks**, an upcoming feature from [Vapi.ai](http://vapi.ai/) aimed at improving bot conversations. The problem we've noticed is that single LLM prompts are prone to hallucinations, unreliable tool calls, and can’t handle many-step complex instructions. +We're currently running a beta for [**Blocks**](/api-reference/blocks/create), an upcoming feature from [Vapi.ai](http://vapi.ai/) aimed at improving bot conversations. The problem we've noticed is that single LLM prompts are prone to hallucinations, unreliable tool calls, and can’t handle many-step complex instructions. **By breaking the conversation into smaller, more manageable prompts**, we can guarantee the bot will do this, then that, or if this happens, then that happens. It’s like having a checklist for conversations — less room for error, more room for getting things right. diff --git a/fern/blocks/block-types.mdx b/fern/blocks/block-types.mdx index f3563afdb..5a948ac4c 100644 --- a/fern/blocks/block-types.mdx +++ b/fern/blocks/block-types.mdx @@ -4,6 +4,9 @@ subtitle: 'Building the Logic and Actions for Each Step in Your Conversation ' slug: blocks/block-types --- + + **Blocks** is being deprecated in favor of [Workflows](/workflows). We recommend using Workflows for all new development as it provides a more powerful and flexible way to structure conversational AI. We're working on migration tools to help transition existing Blocks implementations to Workflows. + [**Blocks**](https://api.vapi.ai/api#/Blocks/BlockController_create) are the functional units within a Step, defining what action happens at each stage of a conversation. Each Step can contain only one Block, and there are three main types of Blocks, each designed to handle different aspects of conversation flow. diff --git a/fern/blocks/steps.mdx b/fern/blocks/steps.mdx index b5391bf3e..918893c2f 100644 --- a/fern/blocks/steps.mdx +++ b/fern/blocks/steps.mdx @@ -4,13 +4,12 @@ subtitle: Building and Controlling Conversation Flow for Your Assistants slug: blocks/steps --- + + **Blocks** is being deprecated in favor of [Workflows](/workflows). We recommend using Workflows for all new development as it provides a more powerful and flexible way to structure conversational AI. We're working on migration tools to help transition existing Blocks implementations to Workflows. + [**Steps**](https://api.vapi.ai/api#:~:text=HandoffStep) are the core building blocks that dictate how conversations progress in a bot interaction. Each Step represents a distinct point in the conversation where the bot performs an action, gathers information, or decides where to go next. Think of Steps as checkpoints in a conversation that guide the flow, manage user inputs, and determine outcomes. - - Blocks is currently in beta. We're excited to have you try this new feature and welcome your [feedback](https://discord.com/invite/pUFNcf2WmH) as we continue to refine and improve the experience. - - #### Features - **Output:** The data or response expected from the step, as outlined in the block's `outputSchema`. diff --git a/fern/call-forwarding.mdx b/fern/call-forwarding.mdx index 0cd5b5b2d..e607e841e 100644 --- a/fern/call-forwarding.mdx +++ b/fern/call-forwarding.mdx @@ -3,7 +3,6 @@ title: Call Forwarding slug: call-forwarding --- - Vapi's call forwarding functionality allows you to redirect calls to different phone numbers based on specific conditions using tools. This guide explains how to set up and use the `transferCall` function for call forwarding. ## Key Concepts @@ -12,6 +11,13 @@ Vapi's call forwarding functionality allows you to redirect calls to different p - **`transferCall` Tool**: This tool enables call forwarding to predefined phone numbers with specific messages based on the destination. + +Looking for dynamic routing decided at runtime? Use a `transferCall` tool with an empty `destinations` array and either: +- Have the assistant supply a destination parameter (e.g., `phoneNumber`) directly; no webhook is sent. +- Or respond from your server to the `transfer-destination-request` webhook with a destination. +See: Dynamic call transfers. + + ### Parameters and Messages - **Destinations**: A list of phone numbers where the call can be forwarded. @@ -19,9 +25,21 @@ Vapi's call forwarding functionality allows you to redirect calls to different p ## Setting Up Call Forwarding -### 1. Defining Destinations and Messages +### 1. Create a Transfer Call Tool in the Dashboard + +The recommended approach is to create your transfer call tool in the Vapi dashboard: + +1. Navigate to **Tools** in your Vapi dashboard +2. Click **Create Tool** +3. Select **Transfer Call** as the tool type +4. Configure your destinations: + - **Department A**: `+1234567890` with message "I am forwarding your call to Department A. Please stay on the line." + - **Department B**: `+0987654321` with message "I am forwarding your call to Department B. Please stay on the line." + - **Department C**: `+1122334455` with message "I am forwarding your call to Department C. Please stay on the line." + +### 2. Alternative: API Configuration -The `transferCall` tool includes a list of destinations and corresponding messages to notify the caller: +You can also define the tool via API with destinations and corresponding messages: ```json { @@ -53,17 +71,11 @@ The `transferCall` tool includes a list of destinations and corresponding messag "properties": { "destination": { "type": "string", - "enum": [ - "+1234567890", - "+0987654321", - "+1122334455" - ], + "enum": ["+1234567890", "+0987654321", "+1122334455"], "description": "The destination to transfer the call to." } }, - "required": [ - "destination" - ] + "required": ["destination"] } }, "messages": [ @@ -106,7 +118,20 @@ The `transferCall` tool includes a list of destinations and corresponding messag } ``` -### 2. Using the `transferCall` Function +You can also specify the `extension` parameter to forward the call to an extension. + +```json + "destinations": [ + { + "type": "number", + "number": "+1234567890", + "extension": "4603", + "message": "I am forwarding your call to Department A. Please stay on the line." + } + ] +``` + +### 3. Using the `transferCall` Function When the assistant needs to forward a call, it uses the `transferCall` function with the appropriate destination: @@ -119,10 +144,9 @@ When the assistant needs to forward a call, it uses the `transferCall` function } } } - ``` -### 3. Customizing Messages +### 4. Customizing Messages Customize the messages for each destination to provide clear information to the caller: @@ -142,7 +166,6 @@ Customize the messages for each destination to provide clear information to the } ] } - ``` ## Instructing the Assistant @@ -170,18 +193,21 @@ Vapi supports two types of call transfers: To implement a warm transfer, add a `transferPlan` object to the `transferCall` tool syntax and specify the transfer mode. +Note: Warm transfer functionality is currently available only with Twilio-based telephony systems. + #### Modes of Warm Transfer #### 1. Warm Transfer with Summary In this mode, Vapi provides a summary of the call to the recipient before transferring. -* **Configuration:** - * Set the `mode` to `"warm-transfer-with-summary"`. - * Define a `summaryPlan` specifying how the summary should be generated. - * Use the `{{transcript}}` variable to include the call transcript. +- **Configuration:** -* **Example:** + - Set the `mode` to `"warm-transfer-with-summary"`. + - Define a `summaryPlan` specifying how the summary should be generated. + - Use the `{{transcript}}` variable to include the call transcript. + +- **Example:** ```json "transferPlan": { @@ -204,14 +230,15 @@ In this mode, Vapi provides a summary of the call to the recipient before transf #### 2. Warm Transfer with Message -In this mode, Vapi delivers a custom static message to the recipient before transferring the call. +In this mode, Vapi delivers a custom message to the recipient before transferring the call. + +- **Configuration:** -* **Configuration:** - * Set the `mode` to `"warm-transfer-with-message"`. - * Provide the custom message in the `message` property. - * Note that the `{{transcript}}` variable is not available in this mode. + - Set the `mode` to `"warm-transfer-with-message"`. + - Provide the custom message in the `message` property. + - Note that the `{{transcript}}` variable is not available in this mode. -* **Example:** +- **Example:** ```json "transferPlan": { @@ -236,7 +263,7 @@ Here is a full example of a `transferCall` payload using the warm transfer with "destinations": [ { "type": "number", - "number": "+918936850777", + "number": "+918936850523", "description": "Transfer the call", "transferPlan": { "mode": "warm-transfer-with-summary", @@ -259,4 +286,205 @@ Here is a full example of a `transferCall` payload using the warm transfer with } ``` -**Note:** In all warm transfer modes, the `{{transcript}}` variable contains the full transcript of the call and can be used within the `summaryPlan`. +#### 3. Warm Transfer with Wait and Say Message + +In this mode, Vapi waits for the recipient to speak first and then delivers a custom message to the recipient before transferring the call. + +- **Configuration:** + + - Set the `mode` to `"warm-transfer-wait-for-operator-to-speak-first-and-then-say-message"`. + - Provide the custom message in the `message` property. + - Note that the `{{transcript}}` variable is not available in this mode. + +- **Example:** + +```json +"transferPlan": { + "mode": "warm-transfer-wait-for-operator-to-speak-first-and-then-say-message", + "message": "Hey, this call has been forwarded through Vapi." +} +``` + +#### 4. Warm Transfer with Wait and Say Summary + +In this mode, Vapi waits for the recipient to speak first and then delivers a summary of the call to the recipient before transferring the call. + +- **Configuration:** + + - Set the `mode` to `"warm-transfer-wait-for-operator-to-speak-first-and-then-say-summary"`. + - Define a `summaryPlan` specifying how the summary should be generated. + - Use the `{{transcript}}` variable to include the call transcript. + +- **Example:** + +```json +"transferPlan": { + "mode": "warm-transfer-wait-for-operator-to-speak-first-and-then-say-summary", + "summaryPlan": { + "enabled": true, + "messages": [ + { + "role": "system", + "content": "Please provide a summary of the call." + }, + { + "role": "user", + "content": "Here is the transcript:\n\n{{transcript}}\n\n" + } + ] + } +} +``` + +#### 5. Warm Transfer with TwiML + +In this mode, Vapi executes TwiML instructions on the destination call leg before connecting the destination number. + +- **Configuration:** + + - Set the `mode` to `"warm-transfer-with-twiml"`. + - Provide the TwiML instructions in the `twiml` property. + - Supports only `Play`, `Say`, `Gather`, and `Pause` verbs. + - Maximum TwiML length is 4096 characters. + - TwiML must be provided as a single-line string without line breaks or tabs, and must be a valid XML string. For example: `Hello` is valid, but `Hello\n` is not. + +- **Example:** + +```json +"transferPlan": { + "mode": "warm-transfer-with-twiml", + "twiml": "Hello, transferring a customer to you.They called about billing questions." +} +``` + +Here is a full example of a `transferCall` payload using the warm transfer with TwiML mode: + +```json +{ + "type": "transferCall", + "messages": [ + { + "type": "request-start", + "content": "I'll transfer you to someone who can help." + } + ], + "destinations": [ + { + "type": "number", + "number": "+14155551234", + "description": "Transfer to customer support", + "transferPlan": { + "mode": "warm-transfer-with-twiml", + "twiml": "Hello, this is an incoming call from a customer.They have questions about their recent order.Connecting you now.", + "sipVerb": "refer" + } + } + ] +} +``` + +#### 6. Experimental Warm Transfer + +In this mode, Vapi dials the destination number and places the caller on hold (with a default ringtone). If the destination answers, Vapi connects the calls. If voicemail is detected or the call isn't answered, Vapi plays a fallback message to the caller. + +- **Configuration:** + + - Set the `mode` to `"warm-transfer-experimental"`. + - Provide a `message` to be spoken to the operator when they answer. + - Optionally define a `summaryPlan` that will take precedence over the message if enabled. + - Configure a `fallbackPlan` with a message and whether to end the call if transfer fails. + - Optionally provide a `holdAudioUrl` to play custom hold music to the customer during the transfer. + - Configure `voicemailDetectionType` to customize how human voice detection is performed (only applies when the provider is Google or OpenAI): + - `"audio"` (default): Supports a wide range of machine detection including beep detection and other audio cues + - `"transcript"`: Uses transcript-based detection with the lowest latency and faster transfer processing times + - Note that only Google or OpenAI providers are supported for voicemail detection with transfer plans, even if the assistant configuration supports other providers like Twilio or Vapi. + +- **Example:** + +```json +"transferPlan": { + "mode": "warm-transfer-experimental", + "message": "Transferring a customer to you.", + "holdAudioUrl": "https://api.twilio.com/cowbell.mp3", + "voicemailDetectionType": "transcript", + "fallbackPlan": { + "message": "Could not transfer your call, goodbye.", + "endCallEnabled": true + }, + "summaryPlan": { + "enabled": true, + "messages": [ + { + "role": "system", + "content": "Please provide a summary of the call." + }, + { + "role": "user", + "content": "Here is the transcript:\n\n{{transcript}}\n\n" + } + ] + } +} +``` + +This example uses `"transcript"` for the fastest transfer processing. For wider machine detection capabilities, use `"audio"` instead. + +Here is a full example of a `transferCall` payload using the experimental warm transfer mode: + +```json +{ + "type": "transferCall", + "function": { + "name": "myTransferCall" + }, + "destinations": [ + { + "type": "number", + "number": "+1123456789", + "message": "Transferring the call now...", + "transferPlan": { + "mode": "warm-transfer-experimental", + "message": "Transferring a customer to you.", + "holdAudioUrl": "https://assets.example.com/music.mp3", + "voicemailDetectionType": "audio", + "fallbackPlan": { + "message": "Could not transfer your call, goodbye.", + "endCallEnabled": true + }, + "summaryPlan": { + "enabled": true, + "messages": [ + { + "role": "system", + "content": "Please provide a summary of the call." + }, + { + "role": "user", + "content": "Here is the transcript:\n\n{{transcript}}\n\n" + } + ] + } + } + } + ] +} +``` + +This example uses `"audio"` for comprehensive machine detection including beep detection. This is the default option if not specified. + +#### 7. Assistant-Based Warm Transfer (Experimental) + +For use cases requiring AI-managed transfers, Vapi supports using assistants to handle the transfer process. This allows the assistant to converse with operators and make transfer decisions based on your configuration. + + + Configure AI assistants to handle call transfers with operator conversations + + +**Notes:** + +- In all warm transfer modes, the `{{transcript}}` variable contains the full transcript of the call and can be used within the `summaryPlan`. +- The `holdAudioUrl` property (available only in `warm-transfer-experimental` mode) allows you to specify a custom MP3 file URL that will be played to the customer while they are on hold during the transfer. If not provided, the default hold audio will be used. +- The `voicemailDetectionType` parameter allows you to optimize the detection method based on your needs: + - Use `"transcript"` for the fastest transfer processing with lowest latency + - Use `"audio"` (default) for comprehensive machine detection including beep detection and other audio cues +- For more details about transfer plans and configuration options, please refer to the [transferCall API documentation](/api-reference/tools/create#request.body.transferCall.destinations.number.transferPlan) diff --git a/fern/calls/assistant-based-warm-transfer.mdx b/fern/calls/assistant-based-warm-transfer.mdx new file mode 100644 index 000000000..fad473a79 --- /dev/null +++ b/fern/calls/assistant-based-warm-transfer.mdx @@ -0,0 +1,218 @@ +--- +title: Configure assistant-based warm transfer +subtitle: Let an AI assistant introduce a caller before connecting a transfer. +description: Configure an assistant-based warm transfer in the Vapi Dashboard or API, including operator prompts, fallback behavior, summaries, custom audio, and testing. +slug: calls/assistant-based-warm-transfer +--- + +Assistant-based warm transfer places the customer on hold while a transfer assistant calls the destination. The transfer assistant can give the operator context, confirm that a person is ready, and then complete or cancel the transfer. + +Use this mode when the destination must accept the call or receive context before speaking with the customer. For a direct transfer without an operator conversation, use the [transfer call tool](/tools/transfer-call) with its default blind-transfer mode. + +## Prerequisites + +Before you configure the transfer, prepare: + +- A Vapi assistant that handles phone calls +- A destination phone number in E.164 format, for example, `+14155550100` +- A private Vapi API key for the curl method +- A publicly accessible MP3 or WAV file if you want custom hold or completion audio + +## How assistant-based warm transfer works + +When the original assistant invokes the transfer call tool: + +1. The customer hears the configured transfer message and is placed on hold. +2. Vapi calls the destination and starts the transfer assistant. +3. The transfer assistant speaks with the operator and uses the previous conversation as context by default. +4. The transfer assistant calls `transferSuccessful` to connect the parties or `transferCancel` to return the customer to the original assistant. +5. If the destination is busy, unreachable, or not human, the fallback plan determines what the customer hears and whether the call ends. + +The `transferSuccessful` and `transferCancel` tools are always available to the transfer assistant. You can customize them through the API, but you do not need to add them to a basic configuration. + +## Configure the warm transfer + +Create a reusable transfer call tool, configure a phone-number destination, and add the tool to the original assistant. + + + + + + In the Vapi Dashboard, open **Tools**, click **Create Tool**, and select **Transfer Call**. Enter a name and a description that state when the assistant should use the tool. + + + + Under **Destinations**, click **Add Destination**, then select **Phone Number**. Enter the destination in E.164 format and describe when the assistant should select it. + + + + Expand **Transfer Plan**. Under **Transfer Mode**, select **Warm Transfer - Experimental**. + + + + Enter the **Message to Operator**. Under **Fallback Plan**, set the message spoken to the customer when the transfer fails and choose whether to end the call. Under **Summary Plan**, choose whether to generate a conversation summary for the operator. + + + + Click **Save**. Open **Assistants**, select the original assistant, and add the tool from the assistant's **Tools** section. Update the system prompt with the conditions for starting the transfer, then save the assistant. + + + + The Dashboard exposes the transfer mode, operator message, fallback plan, and summary plan. Use the API to configure a custom transfer-assistant model, prompt, timeouts, voice, hold audio, or completion audio. + + + + + + Replace `YOUR_API_KEY`, then create the reusable tool with the [Create Tool endpoint](/api-reference/tools/create). + + ```bash + curl --request POST \ + --url https://api.vapi.ai/tool \ + --header 'Authorization: Bearer YOUR_API_KEY' \ + --header 'Content-Type: application/json' \ + --data '{ + "type": "transferCall", + "destinations": [ + { + "type": "number", + "number": "+14155550100", + "description": "Transfer to an account specialist after the customer agrees", + "transferPlan": { + "mode": "warm-transfer-experimental", + "transferAssistant": { + "firstMessage": "Hello, I have a customer who needs help with an account issue. Are you available to take the call?", + "firstMessageMode": "assistant-speaks-first", + "maxDurationSeconds": 120, + "silenceTimeoutSeconds": 30, + "model": { + "provider": "openai", + "model": "gpt-4o", + "messages": [ + { + "role": "system", + "content": "Confirm that a human operator is ready. Use transferSuccessful when the operator accepts the call. Use transferCancel for voicemail, no answer, or a declined transfer. Keep the conversation focused on the transfer." + } + ] + } + }, + "holdAudioUrl": "https://example.com/audio/hold.mp3", + "transferCompleteAudioUrl": "https://example.com/audio/transfer-complete.mp3", + "fallbackPlan": { + "message": "I could not reach an account specialist. I can continue helping you.", + "endCallEnabled": false + } + } + } + ], + "messages": [ + { + "type": "request-start", + "content": "I will call an account specialist now. Please hold." + }, + { + "type": "request-failed", + "content": "I could not start the transfer." + } + ] + }' + ``` + + The response contains the reusable tool's `id`. Save it as `TOOL_ID` for the next request. + + + + Replace `ASSISTANT_ID` and `TOOL_ID`, then update the assistant with the [Update Assistant endpoint](/api-reference/assistants/update). + + ```bash + curl --request PATCH \ + --url https://api.vapi.ai/assistant/ASSISTANT_ID \ + --header 'Authorization: Bearer YOUR_API_KEY' \ + --header 'Content-Type: application/json' \ + --data '{ + "model": { + "toolIds": ["TOOL_ID"] + } + }' + ``` + + If the assistant already has reusable tools, include their IDs in `toolIds` so this update does not remove them. + + + + + +## Configure transfer behavior + +Use these fields to control the transfer assistant and the two call legs. + +| Field | Controls | Default or constraint | +| --- | --- | --- | +| `transferAssistant.firstMessage` | What the transfer assistant says when the operator answers | If omitted, the assistant waits for the operator and generates a response | +| `transferAssistant.firstMessageMode` | Whether the transfer assistant speaks first or waits | `assistant-speaks-first` | +| `transferAssistant.maxDurationSeconds` | Maximum length of the transfer-assistant conversation | 120 seconds; allowed range is 10–43,200 seconds | +| `transferAssistant.silenceTimeoutSeconds` | Silence allowed before the transfer is canceled | 30 seconds; allowed range is 5–3,600 seconds | +| `transferAssistant.model` | Model and instructions used for the operator conversation | Required when you configure `transferAssistant` | +| `holdAudioUrl` | MP3 or WAV audio played to the customer while on hold | Default hold audio | +| `transferCompleteAudioUrl` | MP3 or WAV audio played to the destination after the introduction | No custom completion audio | +| `fallbackPlan` | Customer message and end-call behavior when the transfer fails | Default fallback behavior when omitted | +| `contextEngineeringPlan` | Conversation context provided to the transfer assistant | All previous messages | + +`firstMessageMode` also accepts `assistant-waits-for-user` and `assistant-speaks-first-with-model-generated-message`. Use the model-generated option when the introduction should adapt to the preceding conversation. + +## Prompt the transfer assistant + +Keep the transfer assistant's system message focused on the operator conversation. Define when to use each built-in tool: + +- Call `transferSuccessful` after a human operator confirms that they will take the call +- Call `transferCancel` for voicemail, a busy signal, no answer, or an operator who declines +- Answer questions about the transfer or give a brief customer summary +- Avoid unrelated conversation and complete the decision before `maxDurationSeconds` + +The transfer assistant receives the previous conversation by default. Set `contextEngineeringPlan.type` to `none` when the operator must not receive that context, or use `lastNMessages` to limit it. + +## Verify the warm transfer + +Place a test call and trigger the transfer. Confirm that: + +1. The customer hears the transfer message and hold audio. +2. The destination receives the call and hears the transfer assistant. +3. Accepting the call connects the customer and operator. +4. Declining the call or reaching voicemail returns the customer to the original assistant or ends the call according to `fallbackPlan`. + +In **Logs → Call Logs**, inspect the original call, destination call leg, transcript, and ended reason. An `assistant-forwarded-call` ended reason confirms that the transfer was initiated; it does not confirm that the destination answered. + +## Troubleshooting + +| Symptom | Likely cause | Resolution | +| --- | --- | --- | +| The customer is transferred without an operator conversation | The destination uses a blind or non-assistant warm-transfer mode | Set `transferPlan.mode` to `warm-transfer-experimental`. | +| The transfer assistant never speaks | `firstMessage` is omitted or `firstMessageMode` waits for the operator | Set `firstMessage` and use `assistant-speaks-first`, or let the operator speak first. | +| The transfer assistant talks but never connects the parties | The prompt does not require `transferSuccessful` | Tell the transfer assistant to call `transferSuccessful` immediately after the operator accepts. | +| Voicemail or a declined transfer connects anyway | The prompt does not define cancellation conditions | Require `transferCancel` for voicemail, busy signals, no answer, and declined transfers. | +| The customer hears the wrong audio | Hold audio was configured as a tool message | Put customer hold audio in `transferPlan.holdAudioUrl`. Use `transferCompleteAudioUrl` for audio played to the destination after the introduction. | +| The customer cannot continue after a failed transfer | `fallbackPlan.endCallEnabled` is `true` | Set it to `false` so the original assistant remains on the call. | +| The transfer ends during a long operator interaction | A duration or silence timeout is too short | Increase `maxDurationSeconds` or `silenceTimeoutSeconds` within the supported ranges. | + +Check **Logs → API Logs** for validation and transfer errors. If Vapi initiated the transfer but the destination never rings, inspect the telephony provider's call detail records and follow [Troubleshoot call forwarding drops](/calls/troubleshoot-call-forwarding-drops). + +## API reference + +The [Create Tool API reference](/api-reference/tools/create) documents the public transfer call destination and transfer-plan fields. This guide shows the additional transfer-assistant configuration used with `warm-transfer-experimental`. + +## Related guides + + + + Create a transfer call tool and configure its destinations. + + + Introduce the caller with a message, summary, or TwiML. + + + Choose a transfer destination at runtime. + + + Diagnose failed or incomplete transfers. + + diff --git a/fern/calls/call-concurrency.mdx b/fern/calls/call-concurrency.mdx new file mode 100644 index 000000000..0907fdec4 --- /dev/null +++ b/fern/calls/call-concurrency.mdx @@ -0,0 +1,157 @@ +--- +title: Understanding Call Concurrency +subtitle: Plan, monitor, and scale simultaneous Vapi calls +slug: calls/call-concurrency +description: Learn how concurrency slots work, how to stay within the default limit, and how to raise capacity for larger campaigns. +--- + +## Overview + +Call concurrency represents how many Vapi calls can be active at the same time. Each call occupies one slot, similar to using a finite set of phone lines. + +**In this guide, you'll learn to:** +- Understand the default concurrency allocation and when it is usually sufficient +- Keep outbound and inbound workloads within plan limits +- Increase reserved capacity directly from the Vapi Dashboard where add-ons are available +- Inspect concurrency data through API responses and analytics queries + +## What is concurrency? + +Every Vapi account includes **10 concurrent call slots** by default. When all slots are busy, new outbound dials or inbound connections wait until a slot becomes free. + + + + Rarely hit concurrency caps unless traffic surges (launches, seasonal spikes). + + + More likely to reach limits when running large calling batches. + + + +These limits ensure the underlying compute stays reliable for every customer. Higher concurrency requires reserving additional capacity, which Vapi provides through custom or add-on plans where capacity is available. + +## Managing concurrency + +### Outbound campaigns + +Batch long lead lists into smaller chunks (for example, 50–100 numbers) and run those batches sequentially. This keeps your peak concurrent calls near the default limit while still working through large sets quickly. + +### High-volume operations + +If you regularly exceed **50,000 minutes per month**, talk with Vapi about: + +- **Custom plans** that include higher baked-in concurrency +- **Add-on bundles in the US region** that let you purchase extra call lines only when you need them + + +Use billing reports to pair minute usage with concurrency spikes so you can upgrade before calls are blocked. + + +## Increase your concurrency limit + + +Vapi's EU support and self-serve growth are frozen until 2027. Existing EU customers can continue using their accounts, but Vapi is not offering new add-ons and does not guarantee feature parity with the US region. New self-serve customers should [create an account in the US region](https://dashboard.vapi.ai/register). If you require Vapi-hosted EU data residency, [contact Sales](https://vapi.ai/sales) about selective enterprise onboarding. + + +In the US region, you can raise or reserve more call lines without contacting support: + +1. Open the [Vapi Dashboard](https://dashboard.vapi.ai/settings/billing). +2. Navigate to **Settings → Billing**. +3. Find **Reserved Concurrency (Call Lines)**. +4. Increase the limit or purchase add-on concurrency lines. + +Changes apply immediately, so you can scale ahead of known traffic surges. + +## View concurrency in call responses + +When you create a call with `POST /call`, the response includes a `subscriptionLimits` object that shows the current state of your account. + +### Example request + +```bash +curl 'https://api.vapi.ai/call' \ + -H 'authorization: Bearer {VAPI-PRIVATE-TOKEN}' \ + -H 'content-type: application/json' \ + --data-raw '{ + "assistantId": "4a170597-a0c2-4657-8c32-cb93f080cead", + "customer": {"number": "+918936850777"}, + "phoneNumberId": "c6ea6cb0-0dfb-4a65-918f-6a33abb54b64" + }' +``` + +### Example response snippet + +```json +{ + "subscriptionLimits": { + "concurrencyBlocked": false, + "concurrencyLimit": 10, + "remainingConcurrentCalls": 9 + }, + "id": "019a9046-121e-766d-bd1f-84f3ccc309c1", + "status": "queued" +} +``` + +### Field reference + +- **`concurrencyBlocked`** — `true` if the call could not start because all slots were full. +- **`concurrencyLimit`** — Total concurrent call slots currently available to your org. +- **`remainingConcurrentCalls`** — How many slots were open at the time you created the call. + +Build monitoring around these values to alert when you approach the cap. + +## Track concurrency with the Analytics API + +Use the `/analytics` endpoint to review historical concurrency usage and spot patterns that justify more capacity. + +### Example request + +```bash +curl 'https://api.vapi.ai/analytics' \ + -H 'authorization: Bearer {VAPI-PRIVATE-TOKEN}' \ + -H 'content-type: application/json' \ + --data-raw '{ + "queries": [{ + "name": "Number of Concurrent Calls", + "table": "subscription", + "timeRange": { + "start": "2025-10-16T18:30:00.000Z", + "end": "2025-11-17T05:31:10.184Z", + "step": "day" + }, + "operations": [{ + "operation": "max", + "column": "concurrency", + "alias": "concurrency" + }] + }] + }' +``` + +### Example response + +```json +[{ + "name": "Number of Concurrent Calls", + "timeRange": { + "start": "2025-10-16T18:30:00.000Z", + "end": "2025-11-17T05:31:10.184Z", + "step": "day", + "timezone": "UTC" + }, + "result": [ + { "date": "2025-11-05T00:00:00.000Z", "concurrency": 0 }, + { "date": "2025-11-10T00:00:00.000Z", "concurrency": 1 }, + { "date": "2025-11-17T00:00:00.000Z", "concurrency": 1 } + ] +}] +``` + +Adjust the `timeRange.step` to inspect usage by hour, day, or week. Peaks that align with campaign launches, seasonality, or support events highlight when you should reserve additional call lines. + +## Next steps + +- **[Call queue management](/calls/call-queue-management):** Build a Twilio queue to buffer calls when you hit concurrency caps. +- **[Outbound campaign planning](/outbound-campaigns/overview):** Design outbound strategies that pair batching with analytics. +- **[Enterprise plans](/enterprise/plans):** Review larger plans that include higher default concurrency. diff --git a/fern/calls/call-dynamic-transfers.mdx b/fern/calls/call-dynamic-transfers.mdx new file mode 100644 index 000000000..5743acf49 --- /dev/null +++ b/fern/calls/call-dynamic-transfers.mdx @@ -0,0 +1,572 @@ +--- +title: Dynamic call transfers +subtitle: Route calls to different destinations based on real-time conversation context and external data. +slug: calls/call-dynamic-transfers +description: Learn how Vapi's dynamic call transfers work and explore implementation patterns for intelligent call routing. +--- + +## Overview + +Dynamic call transfers enable intelligent routing by determining transfer destinations in real-time based on conversation context, customer data, or external system information. Unlike static transfers with predefined destinations, dynamic transfers make routing decisions on-the-fly during the call. + +**Key capabilities:** +* Real-time destination selection based on conversation analysis +* Integration with CRM systems, databases, and external APIs +* Conditional routing logic for departments, specialists, or geographic regions +* Context-aware transfers with conversation summaries +* Custom business logic execution before completing the transfer +* Programmatic transfer control via Vapi's Call Control API + +## Prerequisites + +* A [Vapi account](https://dashboard.vapi.ai/) +* A server or cloud function that can receive webhooks from Vapi +* (Optional) CRM system or customer database for enhanced routing logic + +## How It Works + +Dynamic transfers with live call control use a server-controlled pattern that gives you maximum flexibility: + +1. **User initiates transfer**: The user requests a transfer in natural language during the conversation +2. **Vapi triggers custom tool**: Vapi fires your custom tool to your HTTP server +3. **Server receives control URL**: The tool payload includes `message.call.monitor.controlUrl` for live call control +4. **Execute business logic**: Your server performs any necessary operations: + - Update CRM records with call summaries + - Extract and store conversation data + - Query databases for routing decisions + - Enrich destination systems with context +5. **Complete transfer**: Your server makes a POST request to the `controlUrl` with the transfer destination +6. **Call connected**: Vapi transfers the call to the specified SIP or PSTN destination + +Available context: Your server receives the full conversation transcript, custom parameters, call metadata, and the control URL, allowing you to make informed routing decisions and execute the transfer programmatically. + + +Parameters for custom tools are fully customizable. You can name and structure them however you like to guide routing (for example `department`, `reason`, `urgency`, `customerId`, etc.). + + +Sequence diagram + +```mermaid +sequenceDiagram + participant Customer + participant Vapi + participant Server as HTTP Server + participant CRM as CRM (Optional) + participant Dest as SIP/PSTN Destination + + Customer->>Vapi: "Can you transfer me to support?" + + Vapi->>Server: Tool call: custom_transfer_call
({ "reason": "escalation" }) + + opt Business Logic + Server->>CRM: Update customer record + CRM-->>Server: Confirm updated + end + + Server->>Vapi: POST {controlUrl}
(transfer destination) + + Vapi->>Dest: Transfer call + Dest-->>Customer: Connected to destination +``` + +--- + +## Quick Implementation Guide + + + + Create a custom tool that will receive the transfer request and provide you with the control URL to execute the transfer. + + + + - Navigate to **Tools** in your dashboard + - Click **Create Tool** + - Select **Custom** as the tool type + - Set function name: `transfer_call` + - Add a description: "Transfer the call to the appropriate department or agent" + - Define custom parameters based on your routing needs (e.g., `department`, `reason`, `urgency`, `customerId`) + - Set your server URL to receive the tool call + + + ```typescript + import { VapiClient } from "@vapi-ai/server-sdk"; + + const vapi = new VapiClient({ token: process.env.VAPI_API_KEY }); + + const transferTool = await vapi.tools.create({ + type: "function", + async: true, + function: { + name: "transfer_call", + description: "Transfer the call to the appropriate department or agent based on customer needs", + parameters: { + type: "object", + properties: { + department: { + type: "string", + description: "Department to transfer to (e.g., 'support', 'sales', 'billing')" + }, + reason: { + type: "string", + description: "Reason for the transfer" + }, + urgency: { + type: "string", + enum: ["low", "medium", "high", "critical"], + description: "Urgency level of the transfer" + } + }, + required: ["department", "reason"] + } + }, + server: { + url: "https://your-server.com/webhook" + } + }); + + console.log(`Transfer tool created: ${transferTool.id}`); + ``` + + + ```python + import requests + import os + + def create_transfer_tool(): + url = "https://api.vapi.ai/tool" + headers = { + "Authorization": f"Bearer {os.getenv('VAPI_API_KEY')}", + "Content-Type": "application/json" + } + + tool_config = { + "type": "function", + "async": True, + "function": { + "name": "transfer_call", + "description": "Transfer the call to the appropriate department or agent based on customer needs", + "parameters": { + "type": "object", + "properties": { + "department": { + "type": "string", + "description": "Department to transfer to (e.g., 'support', 'sales', 'billing')" + }, + "reason": { + "type": "string", + "description": "Reason for the transfer" + }, + "urgency": { + "type": "string", + "enum": ["low", "medium", "high", "critical"], + "description": "Urgency level of the transfer" + } + }, + "required": ["department", "reason"] + } + }, + "server": { + "url": "https://your-server.com/webhook" + } + } + + response = requests.post(url, headers=headers, json=tool_config) + return response.json() + + tool = create_transfer_tool() + print(f"Transfer tool created: {tool['id']}") + ``` + + + ```bash + curl -X POST https://api.vapi.ai/tool \ + -H "Authorization: Bearer $VAPI_API_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "type": "function", + "async": true, + "function": { + "name": "transfer_call", + "description": "Transfer the call to the appropriate department or agent based on customer needs", + "parameters": { + "type": "object", + "properties": { + "department": { + "type": "string", + "description": "Department to transfer to (e.g., support, sales, billing)" + }, + "reason": { + "type": "string", + "description": "Reason for the transfer" + }, + "urgency": { + "type": "string", + "enum": ["low", "medium", "high", "critical"], + "description": "Urgency level of the transfer" + } + }, + "required": ["department", "reason"] + } + }, + "server": { + "url": "https://your-server.com/webhook" + } + }' + ``` + + + + + + + + - Navigate to **Assistants** + - Create a new assistant or edit an existing one + - Add your custom transfer tool to the assistant + - Configure the system prompt to guide when transfers should occur + + + ```typescript + const assistant = await vapi.assistants.create({ + name: "Dynamic Transfer Assistant", + firstMessage: "Hello! How can I help you today?", + model: { + provider: "openai", + model: "gpt-4o", + messages: [ + { + role: "system", + content: "You help customers and can transfer them to the appropriate department when needed. Use the transfer_call tool when a customer requests to speak with someone or when you determine their issue requires specialist assistance. Always gather the reason for transfer before initiating it." + } + ], + toolIds: ["YOUR_TRANSFER_TOOL_ID"] + }, + voice: { + provider: "11labs", + voiceId: "burt" + } + }); + + console.log(`Assistant created: ${assistant.id}`); + ``` + + + ```python + def create_assistant_with_transfer(tool_id): + url = "https://api.vapi.ai/assistant" + headers = { + "Authorization": f"Bearer {os.getenv('VAPI_API_KEY')}", + "Content-Type": "application/json" + } + + data = { + "name": "Dynamic Transfer Assistant", + "firstMessage": "Hello! How can I help you today?", + "model": { + "provider": "openai", + "model": "gpt-4o", + "messages": [{ + "role": "system", + "content": "You help customers and can transfer them to the appropriate department when needed. Use the transfer_call tool when a customer requests to speak with someone or when you determine their issue requires specialist assistance. Always gather the reason for transfer before initiating it." + }], + "toolIds": [tool_id] + }, + "voice": {"provider": "11labs", "voiceId": "burt"} + } + + response = requests.post(url, headers=headers, json=data) + return response.json() + + assistant = create_assistant_with_transfer("YOUR_TRANSFER_TOOL_ID") + print(f"Assistant created: {assistant['id']}") + ``` + + + ```bash + curl -X POST https://api.vapi.ai/assistant \ + -H "Authorization: Bearer $VAPI_API_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "name": "Dynamic Transfer Assistant", + "firstMessage": "Hello! How can I help you today?", + "model": { + "provider": "openai", + "model": "gpt-4o", + "messages": [{ + "role": "system", + "content": "You help customers and can transfer them to the appropriate department when needed. Use the transfer_call tool when a customer requests to speak with someone or when you determine their issue requires specialist assistance." + }], + "toolIds": ["YOUR_TRANSFER_TOOL_ID"] + }, + "voice": {"provider": "11labs", "voiceId": "burt"} + }' + ``` + + + + + + Your server will receive the tool call with `message.call.monitor.controlUrl` and use it to execute the transfer via Live Call Control. + + + + ```typescript + import express from 'express'; + import axios from 'axios'; + + const app = express(); + app.use(express.json()); + + app.post('/webhook', async (req, res) => { + try { + const { message } = req.body; + + // Extract control URL from the call monitor + const controlUrl = message?.call?.monitor?.controlUrl; + + // Extract tool call from toolWithToolCallList + const toolWithToolCall = message?.toolWithToolCallList?.[0]; + const toolCall = toolWithToolCall?.toolCall; + + if (!controlUrl || !toolCall) { + return res.status(400).json({ error: 'Missing required data' }); + } + + // Extract parameters from the tool call + const { department, reason, urgency } = toolCall.function.arguments; + + // Execute business logic (optional) + console.log(`Transfer request: ${department} - ${reason} (${urgency})`); + + // Determine destination based on department + let destination; + if (department === 'support') { + destination = { + type: "number", + number: "+1234567890" + }; + } else if (department === 'sales') { + destination = { + type: "number", + number: "+1987654321" + }; + } else { + destination = { + type: "number", + number: "+1555555555" + }; + } + + // Execute transfer via Live Call Control + await axios.post(controlUrl, { + type: "transfer", + destination: destination, + content: `Transferring you to ${department} now.` + }, { + headers: { 'Content-Type': 'application/json' } + }); + + // Respond to Vapi (optional acknowledgment) + res.json({ success: true }); + + } catch (error) { + console.error('Transfer error:', error); + res.status(500).json({ error: 'Transfer failed' }); + } + }); + + app.listen(3000, () => { + console.log('Webhook server running on port 3000'); + }); + ``` + + + ```python + import os + import httpx + from fastapi import FastAPI, HTTPException, Request + + app = FastAPI() + + @app.post("/webhook") + async def handle_webhook(request: Request): + try: + body = await request.json() + message = body.get('message', {}) + + # Extract control URL from the call monitor + control_url = message.get('call', {}).get('monitor', {}).get('controlUrl') + + # Extract tool call from toolWithToolCallList + tool_with_tool_call = message.get('toolWithToolCallList', [{}])[0] + tool_call = tool_with_tool_call.get('toolCall', {}) + + if not control_url or not tool_call: + raise HTTPException(status_code=400, detail="Missing required data") + + # Extract parameters from the tool call + arguments = tool_call.get('function', {}).get('arguments', {}) + department = arguments.get('department') + reason = arguments.get('reason') + urgency = arguments.get('urgency', 'medium') + + print(f"Transfer request: {department} - {reason} ({urgency})") + + # Determine destination based on department + if department == 'support': + destination = { + "type": "number", + "number": "+1234567890" + } + elif department == 'sales': + destination = { + "type": "number", + "number": "+1987654321" + } + else: + destination = { + "type": "number", + "number": "+1555555555" + } + + # Execute transfer via Live Call Control + async with httpx.AsyncClient() as client: + await client.post( + control_url, + json={ + "type": "transfer", + "destination": destination, + "content": f"Transferring you to {department} now." + }, + headers={"Content-Type": "application/json"} + ) + + return {"success": True} + + except Exception as error: + print(f"Transfer error: {error}") + raise HTTPException(status_code=500, detail="Transfer failed") + ``` + + + + + **SIP transfers:** To transfer to a SIP endpoint, use `"type": "sip"` with `"sipUri"` instead: + + ```json + { + "type": "transfer", + "destination": { + "type": "sip", + "sipUri": "sip:+1234567890@sip.telnyx.com" + }, + "content": "Transferring your call now." + } + ``` + + + + + + + - Create a phone number and assign your assistant + - Call the number and request a transfer to different departments + - Monitor your webhook server logs to see the tool calls and control URL + - Verify transfers are executing to the correct destinations + + + ```typescript + // Test with an outbound call + const testCall = await vapi.calls.create({ + assistantId: "YOUR_ASSISTANT_ID", + customer: { + number: "+1234567890" // Your test number + } + }); + + console.log(`Test call created: ${testCall.id}`); + + // During the call, say "I need to speak with support" + // Monitor webhook server logs to see the transfer execution + ``` + + + ```python + def test_dynamic_transfers(assistant_id): + url = "https://api.vapi.ai/call" + headers = { + "Authorization": f"Bearer {os.getenv('VAPI_API_KEY')}", + "Content-Type": "application/json" + } + + data = { + "assistantId": assistant_id, + "customer": {"number": "+1234567890"} + } + + response = requests.post(url, headers=headers, json=data) + call = response.json() + print(f"Test call created: {call['id']}") + + # During the call, say "I need to speak with support" + # Monitor webhook server logs to see the transfer execution + return call + ``` + + + + + +--- + + + + **Assistant-based routing** + + Route customers to appropriate support tiers based on conversation analysis and customer data + + + **Squad-based routing** + + Direct tenant calls to the right department with automated verification + + + +## Routing Patterns + +### Common Use Cases + +* **Customer support routing** - Route based on issue type, customer tier, agent availability, and interaction history. Enterprise customers and critical issues get priority routing to specialized teams. + +* **Geographic routing** - Direct calls to regional offices based on customer location and business hours. Automatically handle time zone differences and language preferences. + +* **Load balancing** - Distribute calls across available agents to optimize wait times and agent utilization. Route to the least busy qualified agent. + +* **Escalation management** - Implement intelligent escalation based on conversation tone, issue complexity, and customer history. Automatically route urgent issues to senior agents. + +### Transfer Configuration + +1. **Warm transfers** provide context to receiving agents with AI-generated conversation summaries, ensuring smooth handoffs with full context. + +2. **Cold transfers** route calls immediately with predefined context messages, useful for simple departmental routing. + +3. **Conditional transfers** apply different transfer modes based on routing decisions, such as priority handling for enterprise customers. + +4. **Destination types** include phone numbers for human agents, SIP endpoints for VoIP systems, and Vapi assistants for specialized AI agents. + + +**Security considerations:** Always verify webhook signatures to ensure requests come from Vapi. Never log sensitive customer data, implement proper access controls, and follow privacy regulations like GDPR and CCPA when handling customer information in routing decisions. + + +## Troubleshooting + +- **Tool call not received**: Verify your server URL is correctly configured in the custom tool and is publicly accessible. Check your server logs for incoming requests. +- **Transfer not executing**: Make sure that you are sending a valid destination object (type number or sip). See API reference [here](https://docs.vapi.ai/api-reference/tools/create#request.body.TransferCallTool.destinations). +- **Invalid destination format**: For phone numbers, use `"type": "number"` with E.164 format. For SIP, use `"type": "sip"` with a valid SIP URI. +- **Transfer fails silently**: Check your server logs for errors in the axios/httpx request. + +## Related Documentation + +* **[Transfer call tool](/tools/transfer-call)** - Static transfer options and transfer plans +* **[Webhooks](/server-url)** - Webhook security and event handling patterns +* **[Custom Tools](/tools/custom-tools)** - Build custom tools for advanced routing logic diff --git a/fern/calls/call-ended-reason.mdx b/fern/calls/call-ended-reason.mdx index ae20ba440..69acb687e 100644 --- a/fern/calls/call-ended-reason.mdx +++ b/fern/calls/call-ended-reason.mdx @@ -1,57 +1,222 @@ --- -title: Call Ended Reason -subtitle: A guide to understanding all call "Ended Reason" types & errors. +title: Call ended reasons +subtitle: All possible call ended reason codes and what they mean. slug: calls/call-ended-reason --- +Every call in Vapi ends with an `endedReason` code that tells you exactly why it ended. You can find this value in the **"Ended Reason"** column of your [call logs](https://dashboard.vapi.ai/calls), or under the `endedReason` field on the [Call object](/api-reference/calls/get). -This guide will discuss all possible `endedReason`s for a call. + +For the full list of possible `endedReason` values, see the [API reference](/api-reference/calls/list#response.body.endedReason). + -You can find these under the **"Ended Reason"** section of your [call -logs](https://dashboard.vapi.ai/calls) (or under the `endedReason` field on the [Call -Object](/api-reference/calls/get-call)). +## Quick diagnosis -#### **Assistant-Related** +Start here if a call failed and you want to quickly understand what happened: -- **assistant-ended-call**: The assistant intentionally ended the call based on the user's response. -- **assistant-error**: This general error occurs within the assistant's logic or processing due to bugs, misconfigurations, or unexpected inputs. -- **assistant-forwarded-call**: The assistant successfully transferred the call to another number or service. -- **assistant-join-timed-out**: The assistant failed to join the call within the expected timeframe. -- **assistant-not-found**: The specified assistant cannot be located or accessed, possibly due to an incorrect assistant ID or configuration issue. -- **assistant-not-invalid**: The assistant ID provided is not valid or recognized by the system. -- **assistant-not-provided**: No assistant ID was specified in the request, causing the system to fail. -- **assistant-request-returned-error**: Communicating with the assistant resulted in an error, possibly due to network issues or problems with the assistant itself. -- **assistant-request-returned-forwarding-phone-number**: The assistant triggered a call forwarding action, ending the current call. -- **assistant-request-returned-invalid-assistant**: The assistant returned an invalid response or failed to fulfill the request properly. -- **assistant-request-returned-no-assistant**: The assistant didn't provide any response or action to the request. -- **assistant-said-end-call-phrase**: The assistant recognized a phrase or keyword triggering call termination. +| The caller experienced... | Look for these errors | Likely cause | +|---|---|---| +| Phone never rang | `call.start.error-*`, `assistant-not-found`, `*-transport-never-connected` | Account/billing issue, bad configuration, or Vapi infrastructure error | +| Phone rang but no answer | `customer-did-not-answer`, `customer-busy`, SIP 408/480 | Normal behavior — callee was unavailable | +| Call dropped mid-conversation | `*-worker-died`, `phone-call-provider-closed-websocket`, `worker-shutdown` | Network issue or Vapi infrastructure error (usually transient) | +| Assistant went silent or unresponsive | `*-llm-failed`, `*-voice-failed`, `*-transcriber-failed`, `*-429-*`, `*-500-*` | Provider outage or credential/quota issue — configure fallback providers for the 3 core services (TTS, LLM, STT) | +| Call worked normally, then ended | `assistant-ended-call`, `customer-ended-call`, `silence-timed-out`, `exceeded-max-duration` | Expected behavior — adjust timeout settings if calls end too early | +| Transfer failed | `*-transfer-failed`, `*-warm-transfer-*`, SIP 403/503 | Bad transfer destination or SIP configuration | -#### **Pipeline and LLM** +For a detailed symptom-based walkthrough, see [Troubleshoot call errors](/calls/troubleshoot-call-errors). -These relate to issues within the AI processing pipeline or the Large Language Models (LLMs) used for understanding and generating text: +## Understanding error prefixes -- **pipeline-error-\***: Various error codes indicate specific failures within the processing pipeline, such as function execution, LLM responses, or external service integration. Examples include OpenAI, Azure OpenAI, Together AI, and several other LLMs or voice providers. -- **pipeline-error-first-message-failed:** The system failed to deliver the first message. This issue usually occurs when you add your own provider key in the voice section. It may be due to exceeding your subscription or quota limit. -- **pipeline-no-available-llm-model**: No suitable LLM was available to process the request. +Many error codes include a prefix that indicates who is responsible for the failure: -#### **Phone Calls and Connectivity** +| Prefix | Meaning | What to do | +|---|---|---| +| `call.in-progress.error-vapifault-*` | Vapi infrastructure or platform credential failure. You are typically **not charged** for these calls. | Contact [Vapi support](/support) if persistent. | +| `call.in-progress.error-providerfault-*` | A third-party provider (OpenAI, Deepgram, etc.) returned a server error. Outside Vapi's control. | Check the provider's status page. Consider configuring a fallback provider. | +| `pipeline-error-*` | Legacy error format. When using your own provider keys (BYOK), these typically indicate credential or quota issues on your account with that provider. When using Vapi's platform keys, treat as a `vapifault`. | Verify your API key, billing status, and quota with the provider. | -- **customer-busy**: The customer's line was busy. -- **customer-ended-call**: The customer(end human user) ended the call for both inbound and outbound calls. -- **customer-did-not-answer**: The customer didn't answer the call. If you're looking to build a usecase where you need the bot to talk to automated IVRs, set `assistant.voicemailDetectionEnabled=false`. -- **customer-did-not-give-microphone-permission**: The user didn't grant the necessary microphone access for the call. -- **phone-call-provider-closed-websocket**: The connection with the call provider was unexpectedly closed. -- **twilio-failed-to-connect-call**: The Twilio service, responsible for managing calls, failed to establish a connection. -- **vonage-disconnected**: The call was disconnected by Vonage, another call management service. -- **vonage-failed-to-connect-call**: Vonage failed to establish the call connection. -- **vonage-rejected**: The call was rejected by Vonage due to an issue or configuration problem. +## Call start errors -#### **Other Reasons** +These occur before the call connects, during resource setup. -- **exceeded-max-duration**: The call reached its maximum allowed duration and was automatically terminated. -- **silence-timed-out**: The call was ended due to prolonged silence, indicating inactivity. -- **voicemail**: The call was diverted to voicemail. +### Account and billing -#### **Unknown** +- `call.start.error-subscription-frozen` — Your subscription is frozen due to a failed payment. Update your payment method in the [dashboard](https://dashboard.vapi.ai/). +- `call.start.error-subscription-insufficient-credits` — Not enough credits to start the call. Add credits or enable auto-reload. +- `call.start.error-subscription-wallet-does-not-exist` — No billing wallet found for the subscription. Contact [support](/support). +- `call.start.error-subscription-upgrade-failed` — An automatic subscription upgrade attempt failed. +- `call.start.error-subscription-concurrency-limit-reached` — You've hit the maximum number of simultaneous calls for your plan. Upgrade your plan or wait for an active call to end. +- `call.start.error-fraud-check-failed` — The call was blocked by Vapi's fraud detection system. +- `call.start.error-enterprise-feature-not-available-recording-consent` — Recording consent requires an enterprise plan. -- **unknown-error**: An unexpected error occurred, and the cause is unknown. For this, please [contact support](/support) with your `call_id` and account email address, & we will investigate. +### Resource resolution + +- `call-start-error-neither-assistant-nor-server-set` — Neither an assistant nor a server URL was configured for the call. +- `call.start.error-get-org` — Error retrieving your organization during call start. Verify your API key. +- `call.start.error-get-subscription` — Error retrieving subscription information during call start. +- `call.start.error-get-assistant` — Error retrieving the assistant. Verify the assistant ID exists. +- `call.start.error-get-phone-number` — Error retrieving the phone number. Verify the number is imported and active. +- `call.start.error-get-customer` — Error retrieving customer information. +- `call.start.error-get-resources-validation` — The assistant, tools, or other resources failed validation. +- `call.start.error-get-transport` — Error setting up the call transport (Twilio, Vonage, etc.). +- `call.start.error-vapifault-database-error` — Internal database error during call setup. Retry or contact [support](/support). + +### Phone number limits + +- `call.start.error-vapi-number-international` — International calling is not supported on this Vapi number. +- `call.start.error-vapi-number-outbound-daily-limit` — The daily outbound call limit for this Vapi number has been reached. + +### Assistant resolution (via server URL) + +- `assistant-not-found` — The specified assistant ID does not exist. +- `assistant-not-valid` — The assistant configuration is invalid. +- `assistant-request-failed` — The request to your server URL to fetch an assistant failed. +- `assistant-request-returned-error` — Your server URL returned an error response. +- `assistant-request-returned-unspeakable-error` — Your server URL returned an error that cannot be spoken to the user. +- `assistant-request-returned-invalid-assistant` — Your server URL returned a response that is not a valid assistant configuration. +- `assistant-request-returned-no-assistant` — Your server URL returned an empty response with no assistant. +- `assistant-request-returned-forwarding-phone-number` — Your server URL returned a phone number for forwarding instead of an assistant. +- `scheduled-call-deleted` — A scheduled call was deleted before it could execute. + +## Assistant actions + +These indicate the assistant intentionally ended the call — not errors. + +- `assistant-ended-call` — The assistant ended the call (via an end-call tool or function). +- `assistant-ended-call-after-message-spoken` — The assistant ended the call after speaking its final message. +- `assistant-ended-call-with-hangup-task` — The assistant ended the call using a hangup task. +- `assistant-said-end-call-phrase` — The assistant said a phrase configured to trigger call termination. +- `assistant-forwarded-call` — The assistant transferred the call to another number or service. +- `assistant-join-timed-out` — The assistant failed to join the call within the expected timeframe. + +## Customer actions + +- `customer-ended-call` — The customer hung up. +- `customer-busy` — The customer's line was busy (outbound calls). +- `customer-did-not-answer` — The customer did not answer (outbound calls). +- `customer-did-not-give-microphone-permission` — The user denied microphone access (web calls). +- `call.in-progress.error-assistant-did-not-receive-customer-audio` — No audio was received from the customer. This can indicate a network issue, mic problem, or the customer disconnected silently. +- `customer-ended-call-before-warm-transfer` — The customer hung up before a warm transfer completed. +- `customer-ended-call-after-warm-transfer-attempt` — The customer hung up after a warm transfer was attempted. +- `customer-ended-call-during-transfer` — The customer hung up during a transfer. + +## Timeouts + +- `exceeded-max-duration` — The call reached `maxDurationSeconds` and was automatically terminated. +- `silence-timed-out` — No speech was detected for the configured silence timeout duration. + +## Pipeline errors: LLM + +Each LLM provider has error codes that follow a consistent pattern. The status code in the error name tells you what went wrong: + +| Status code in error | Meaning | What to do | +|---|---|---| +| `400-bad-request-validation-failed` | Invalid request (bad model name, malformed messages, etc.) | Check your assistant's model configuration. | +| `401-unauthorized` / `401-incorrect-api-key` | Invalid API key. | Verify your API key for this provider. | +| `403-model-access-denied` | Your API key doesn't have access to the requested model. | Check model permissions in your provider account. | +| `429-exceeded-quota` / `429-rate-limit-reached` | Rate limit or quota exceeded. | Upgrade your plan with the provider or reduce call volume. | +| `500-server-error` | Provider internal server error. | Retry. Check the provider's status page. | +| `503-server-overloaded-error` | Provider temporarily overloaded. | Retry after a brief wait. | +| `llm-failed` | Generic LLM failure. | Check call logs for details. | + +**Supported providers:** OpenAI, Azure OpenAI, Anthropic, Anthropic Bedrock, Anthropic Vertex, Google, Groq, xAI, Mistral, Together AI, Perplexity AI, DeepInfra, DeepSeek, Cerebras, Inflection AI, Anyscale, OpenRouter, Runpod, Baseten, Custom LLM. + +Additional model errors: + +- `pipeline-no-available-llm-model` / `call.in-progress.error-pipeline-no-available-llm-model` — No suitable LLM model was available. Check your model configuration. +- `call.in-progress.error-pipeline-ws-model-connection-failed` — Failed to connect to a custom LLM WebSocket endpoint. + +## Pipeline errors: voice (TTS) + +Each voice provider has specific error codes. Common patterns: + +- `*-voice-failed` — Generic voice synthesis failure for that provider. +- `*-voice-not-found` / `*-invalid-voice` — The configured voice ID does not exist or is invalid. +- `*-quota-exceeded` / `*-out-of-credits` — Voice provider credits exhausted. +- `*-unauthorized-access` / `*-invalid-api-key` — Voice provider credential issue. +- `*-socket-hang-up` / `*-500-server-error` / `*-503-server-error` — Voice provider infrastructure issue. + +**Supported providers:** ElevenLabs, Cartesia, Deepgram, PlayHT, Azure, OpenAI, Rime AI, Smallest AI, Neuphonic, Hume, Sesame, Inworld, Minimax, WellSaid, Custom Voice. + +## Pipeline errors: transcriber (STT) + +Common transcriber error patterns: + +- `*-transcriber-failed` — Generic transcriber failure. +- `*-returning-400-*` — Bad request (invalid model/language combination, invalid config, etc.). +- `*-returning-401-*` — Invalid transcriber credentials. +- `*-returning-403-*` — Model access denied on the transcriber. +- `*-returning-500-*` / `*-returning-502-*` — Transcriber provider server error. + +**Supported providers:** Deepgram, AssemblyAI, Gladia, Speechmatics, Talkscriber, Azure Speech, Google, OpenAI, Soniox, ElevenLabs, Custom Transcriber. + +## Transfer errors + +- `call.in-progress.error-transfer-failed` — A call transfer attempt failed. +- `call.in-progress.error-warm-transfer-max-duration` — The warm transfer exceeded its maximum duration. +- `call.in-progress.error-warm-transfer-assistant-cancelled` — The transfer assistant cancelled the warm transfer. +- `call.in-progress.error-warm-transfer-silence-timeout` — Silence timeout during a warm transfer. +- `call.in-progress.error-warm-transfer-microphone-timeout` — Microphone timeout during a warm transfer. + +For step-by-step transfer debugging, see [Debug forwarding drops](/phone-calling/in-call-control/transfer-calls/debug-forwarding-drops). + +## Transport and connectivity + +- `phone-call-provider-closed-websocket` — The call provider's WebSocket connection closed unexpectedly. The caller experiences an abrupt call drop. +- `phone-call-provider-bypass-enabled-but-no-call-received` — Phone call provider bypass was enabled but no call arrived. +- `call.in-progress.error-vapifault-transport-never-connected` — The transport never connected. Vapi infrastructure issue. +- `call.in-progress.error-providerfault-transport-never-connected` — The transport provider failed to connect. Provider-side issue. +- `call.in-progress.error-vapifault-transport-connected-but-call-not-active` — Transport connected but the call was no longer active. +- `call.in-progress.error-vapifault-call-started-but-connection-to-transport-missing` — Call started but the transport connection was lost. +- `call.in-progress.error-vapifault-worker-not-available` — No call worker was available to process the call. +- `call.in-progress.error-vapifault-worker-died` — The call worker process crashed during the call. +- `call.in-progress.error-vapifault-chat-pipeline-failed-to-start` — The chat pipeline failed to initialize. + +### Twilio + +- `twilio-failed-to-connect-call` — Twilio failed to establish the call. +- `twilio-reported-customer-misdialed` — Twilio reported the customer dialed an invalid number. +- `call.in-progress.twilio-completed-call` — Twilio reported the call as completed on their side. + +### Vonage + +- `vonage-disconnected` — Call disconnected by Vonage. +- `vonage-failed-to-connect-call` — Vonage failed to connect the call. +- `vonage-rejected` — Call rejected by Vonage. +- `vonage-completed` — Call completed by Vonage. + +### SIP + +- `call.in-progress.error-sip-inbound-call-failed-to-connect` — Inbound SIP call failed to connect. +- `call.in-progress.error-sip-outbound-call-failed-to-connect` — Outbound SIP call failed to connect. +- `call.in-progress.error-providerfault-outbound-sip-403-forbidden` — SIP 403: call forbidden by the SIP provider. +- `call.in-progress.error-providerfault-outbound-sip-407-proxy-authentication-required` — SIP 407: proxy authentication required. +- `call.in-progress.error-providerfault-outbound-sip-408-request-timeout` — SIP 408: request timed out. +- `call.in-progress.error-providerfault-outbound-sip-480-temporarily-unavailable` — SIP 480: destination temporarily unavailable. +- `call.in-progress.error-providerfault-outbound-sip-503-service-unavailable` — SIP 503: service unavailable. +- `call.ringing.error-sip-inbound-call-failed-to-connect` — SIP inbound call failed during ringing. +- `call.ringing.sip-inbound-caller-hungup-before-call-connect` — SIP caller hung up before the call connected. +- `call.in-progress.sip-completed-call` — SIP provider reported the call as completed. + +For SIP trunk setup issues, see [Troubleshoot SIP trunk credential errors](/advanced/sip/troubleshoot-sip-trunk-credential-errors). + +## Call hooks + +- `call.ringing.hook-executed-say` — A say hook executed during ringing ended the call. +- `call.ringing.hook-executed-transfer` — A transfer hook executed during ringing ended the call. +- `call.ending.hook-executed-say` — A say hook executed during the ending phase. +- `call.ending.hook-executed-transfer` — A transfer hook executed during the ending phase. +- `call.forwarding.operator-busy` — The operator was busy during call forwarding. + +## Other reasons + +- `manually-canceled` — The call was manually canceled via the API or dashboard. +- `voicemail` — The call was diverted to or detected as voicemail. +- `worker-shutdown` — The call worker was shut down (e.g., during a deployment). The call should be retried automatically. +- `call-deleted` — The call record was deleted. + +## Next steps + +- **[Troubleshoot call errors](/calls/troubleshoot-call-errors):** Step-by-step diagnosis guide organized by what the caller experienced. +- **[Debugging voice agents](/debugging):** General debugging workflow using dashboard tools, logs, and test suites. +- **[How to report issues](/issue-reporting):** Include your `call_id` and account email when contacting support. diff --git a/fern/calls/call-features.mdx b/fern/calls/call-features.mdx index 610e77bc1..c24e6dc5e 100644 --- a/fern/calls/call-features.mdx +++ b/fern/calls/call-features.mdx @@ -17,7 +17,7 @@ To initiate a call and retrieve the `listenUrl` and `controlUrl`, send a POST re ### Sample Request ```bash -curl 'https://api.vapi.ai/call/phone' +curl 'https://api.vapi.ai/call' -H 'authorization: Bearer YOUR_API_KEY' -H 'content-type: application/json' --data-raw '{ @@ -57,23 +57,117 @@ curl 'https://api.vapi.ai/call/phone' ``` -## Call Control Feature +## Call Control Features -Once you have the `controlUrl`, you can inject a message into the live call using a POST request. This can be done by sending a JSON payload to the `controlUrl`. +Once you have the `controlUrl`, you can use various control features during a live call. Here are all the available control options: -### Example: Injecting a Message +### 1. Say Message +Makes the assistant say a specific message during the call. ```bash curl -X POST 'https://aws-us-west-2-production1-phone-call-websocket.vapi.ai/7420f27a-30fd-4f49-a995-5549ae7cc00d/control' -H 'content-type: application/json' --data-raw '{ "type": "say", - "message": "Welcome to Vapi, this message was injected during the call." + "content": "Welcome to Vapi, this message was injected during the call.", + "endCallAfterSpoken": false }' +``` + +### 2. Add Message to Conversation +Adds a message to the conversation history and optionally triggers a response. + +```bash +curl -X POST 'https://aws-us-west-2-production1-phone-call-websocket.vapi.ai/7420f27a-30fd-4f49-a995-5549ae7cc00d/control' +-H 'content-type: application/json' +--data-raw '{ + "type": "add-message", + "message": { + "role": "system", + "content": "New message added to conversation" + }, + "triggerResponseEnabled": true +}' +``` + +### 3. Assistant Control +Control the assistant's behavior during the call. + +```bash +curl -X POST 'https://aws-us-west-2-production1-phone-call-websocket.vapi.ai/7420f27a-30fd-4f49-a995-5549ae7cc00d/control' +-H 'content-type: application/json' +--data-raw '{ + "type": "control", + "control": "mute-assistant" // Options: "mute-assistant", "unmute-assistant", "say-first-message" +}' +``` + +### 4. End Call +Programmatically end the ongoing call. + +```bash +curl -X POST 'https://aws-us-west-2-production1-phone-call-websocket.vapi.ai/7420f27a-30fd-4f49-a995-5549ae7cc00d/control' +-H 'content-type: application/json' +--data-raw '{ + "type": "end-call" +}' +``` +### 5. Transfer Call +Transfer the call to a different destination. + +```bash +curl -X POST 'https://aws-us-west-2-production1-phone-call-websocket.vapi.ai/7420f27a-30fd-4f49-a995-5549ae7cc00d/control' +-H 'content-type: application/json' +--data-raw '{ + "type": "transfer", + "destination": { + "type": "number", + "number": "+1234567890" + }, + "content": "Transferring your call now" +}' +``` + +You can also transfer to a SIP URI: + +```bash +curl -X POST 'https://aws-us-west-2-production1-phone-call-websocket.vapi.ai/7420f27a-30fd-4f49-a995-5549ae7cc00d/control' +-H 'content-type: application/json' +--data-raw '{ + "type": "transfer", + "destination": { + "type": "sip", + "sipUri": "sip:+transferPhoneNumber@sip.telnyx.com" + }, + "content": "Testing transfer call." +}' +``` + +### 6. Handoff Call +Handoff the call to a different assistant. + +```bash +curl -X POST 'https://aws-us-west-2-production1-phone-call-websocket.vapi.ai/7420f27a-30fd-4f49-a995-5549ae7cc00d/control' +-H 'content-type: application/json' +--data-raw '{ + "type": "handoff", + "destination": { + "type": "assistant", + "contextEngineeringPlan": "none", + "assistant": { + "name": "new_assistant", + "voice": { + "provider": "vapi", + "version": 2, + "voiceId": "Elliot" + }, + } + }, + "content": "Handing off your call now" +}' ``` -The message will be spoken in real-time during the ongoing call. ## Call Listen Feature diff --git a/fern/calls/call-handling-with-vapi-and-twilio.mdx b/fern/calls/call-handling-with-vapi-and-twilio.mdx new file mode 100644 index 000000000..275ff8dc2 --- /dev/null +++ b/fern/calls/call-handling-with-vapi-and-twilio.mdx @@ -0,0 +1,279 @@ +--- +title: Call Handling with Vapi and Twilio +slug: calls/call-handling-with-vapi-and-twilio +--- + +This document explains how to handle a scenario where a user is on hold while the system attempts to connect them to a specialist. If the specialist does not pick up within X seconds or if the call hits voicemail, we take an alternate action (like playing an announcement or scheduling an appointment). This solution integrates Vapi.ai for AI-driven conversations and Twilio for call bridging. + +## Problem + +Vapi.ai does not provide a built-in way to keep the user on hold, dial a specialist, and handle cases where the specialist is unavailable. We want: + +1. The user already talking to the AI (Vapi). +2. The AI offers to connect them to a specialist. +3. The user is placed on hold or in a conference room. +4. We dial the specialist to join. +5. If the specialist answers, everyone is merged. +6. If the specialist does not answer (within X seconds or goes to voicemail), we want to either announce "Specialist not available" or schedule an appointment. + +## Solution + +1. An inbound call arrives from Vapi or from the user directly. +2. We store its details (e.g., Twilio CallSid). +3. We send TwiML (or instructions) to put the user in a Twilio conference (on hold). +4. We place a second call to the specialist, also directed to join the same conference. +5. If the specialist picks up, Twilio merges the calls. +6. If not, we handle the no-answer event by playing a message or returning control to the AI for scheduling. + +## Steps to Solve the Problem + +1. **Receive Inbound Call** + + - Twilio posts data to your `/inbound_call`. + - You store the call reference. + - You might also invoke Vapi for initial AI instructions. + +2. **Prompt User via Vapi** + + - The user decides whether they want the specialist. + - If yes, you call an endpoint (e.g., `/connect`). + +3. **Create/Join Conference** + + - In `/connect`, you update the inbound call to go into a conference route. + - The user is effectively on hold. + +4. **Dial Specialist** + + - You create a second call leg to the specialist’s phone. + - A `statusCallback` can detect no-answer or voicemail. + +5. **Detect Unanswered** + + - If Twilio sees a no-answer or failure, your callback logic plays an announcement or signals the AI to schedule an appointment. + +6. **Merge or Exit** + + - If the specialist answers, they join the user. + - If not, the user is taken off hold and the call ends or goes back to AI. + +7. **Use Ephemeral Call (Optional)** + - If you need an in-conference announcement, create a short-lived Twilio call that `` the message to everyone, then ends the conference. + +## Code Example + +Below is a minimal Express.js server aligned for On-Hold Specialist Transfer with Vapi and Twilio. + +1. **Express Setup and Environment** + +```js +const express = require("express"); +const bodyParser = require("body-parser"); +const axios = require("axios"); +const twilio = require("twilio"); + +const app = express(); +app.use(bodyParser.urlencoded({ extended: true })); +app.use(bodyParser.json()); + +// Load important env vars +const { + TWILIO_ACCOUNT_SID, + TWILIO_AUTH_TOKEN, + FROM_NUMBER, + TO_NUMBER, + VAPI_BASE_URL, + PHONE_NUMBER_ID, + ASSISTANT_ID, + PRIVATE_API_KEY, +} = process.env; + +// Create a Twilio client +const client = twilio(TWILIO_ACCOUNT_SID, TWILIO_AUTH_TOKEN); + +// We'll store the inbound call SID here for simplicity +let globalCallSid = ""; +``` + +2. **`/inbound_call` - Handling the Inbound Call** + +```js +app.post("/inbound_call", async (req, res) => { + try { + globalCallSid = req.body.CallSid; + const caller = req.body.Caller; + + // Example: We call Vapi.ai to get initial TwiML + const response = await axios.post( + `${VAPI_BASE_URL || "https://api.vapi.ai"}/call`, + { + phoneNumberId: PHONE_NUMBER_ID, + phoneCallProviderBypassEnabled: true, + customer: { number: caller }, + assistantId: ASSISTANT_ID, + }, + { + headers: { + Authorization: `Bearer ${PRIVATE_API_KEY}`, + "Content-Type": "application/json", + }, + } + ); + + const returnedTwiml = response.data.phoneCallProviderDetails.twiml; + return res.type("text/xml").send(returnedTwiml); + } catch (err) { + return res.status(500).send("Internal Server Error"); + } +}); +``` + +3. **`/connect` - Putting User on Hold and Dialing Specialist** + +```js +app.post("/connect", async (req, res) => { + try { + const protocol = + req.headers["x-forwarded-proto"] === "https" ? "https" : "http"; + const baseUrl = `${protocol}://${req.get("host")}`; + const conferenceUrl = `${baseUrl}/conference`; + + // 1) Update inbound call to fetch TwiML from /conference + await client.calls(globalCallSid).update({ + url: conferenceUrl, + method: "POST", + }); + + // 2) Dial the specialist + const statusCallbackUrl = `${baseUrl}/participant-status`; + + await client.calls.create({ + to: TO_NUMBER, + from: FROM_NUMBER, + url: conferenceUrl, + method: "POST", + statusCallback: statusCallbackUrl, + statusCallbackMethod: "POST", + }); + + return res.json({ status: "Specialist call initiated" }); + } catch (err) { + return res.status(500).json({ error: "Failed to connect specialist" }); + } +}); +``` + +4. **`/conference` - Placing Callers Into a Conference** + +```js +app.post("/conference", (req, res) => { + const VoiceResponse = twilio.twiml.VoiceResponse; + const twiml = new VoiceResponse(); + + // Put the caller(s) into a conference + const dial = twiml.dial(); + dial.conference( + { + startConferenceOnEnter: true, + endConferenceOnExit: true, + }, + "my_conference_room" + ); + + return res.type("text/xml").send(twiml.toString()); +}); +``` + +5. **`/participant-status` - Handling No-Answer or Busy** + +```js +app.post("/participant-status", async (req, res) => { + const callStatus = req.body.CallStatus; + if (["no-answer", "busy", "failed"].includes(callStatus)) { + console.log("Specialist did not pick up:", callStatus); + // Additional logic: schedule an appointment, ephemeral call, etc. + } + return res.sendStatus(200); +}); +``` + +6. **`/announce` (Optional) - Ephemeral Announcement** + +```js +app.post("/announce", (req, res) => { + const VoiceResponse = twilio.twiml.VoiceResponse; + const twiml = new VoiceResponse(); + twiml.say("Specialist is not available. Ending call now."); + + // Join the conference, then end it. + twiml.dial().conference( + { + startConferenceOnEnter: true, + endConferenceOnExit: true, + }, + "my_conference_room" + ); + + return res.type("text/xml").send(twiml.toString()); +}); +``` + +7. **Starting the Server** + +```js +app.listen(3000, () => { + console.log("Server running on port 3000"); +}); +``` + +## How to Test + +1. **Environment Variables** + Set `TWILIO_ACCOUNT_SID`, `TWILIO_AUTH_TOKEN`, `FROM_NUMBER`, `TO_NUMBER`, `VAPI_BASE_URL`, `PHONE_NUMBER_ID`, `ASSISTANT_ID`, and `PRIVATE_API_KEY`. + +2. **Expose Your Server** + + - Use a tool like `ngrok` to create a public URL to port 3000. + - Configure your Twilio phone number to call `/inbound_call` when a call comes in. + +3. **Place a Real Call** + + - Dial your Twilio number from a phone. + - Twilio hits `/inbound_call`, and run Vapi logic. + - Trigger `/connect` to conference the user and dial the specialist. + - If the specialist answers, they join the same conference. + - If they never answer, Twilio eventually calls `/participant-status`. + +4. **Use cURL for Testing** + - **Simulate Inbound**: + ```bash + curl -X POST https:///inbound_call \ + -F "CallSid=CA12345" \ + -F "Caller=+15551112222" + ``` + - **Connect**: + ```bash + curl -X POST https:///connect \ + -H "Content-Type: application/json" \ + -d "{}" + ``` + +## Note on Replacing "Connect" with Vapi Tools + +Vapi offers built-in functions or custom tool calls for placing a second call or transferring, you can replace the manual `/connect` call with that Vapi functionality. The flow remains the same: user is put in a Twilio conference, the specialist is dialed, and any no-answer events are handled. + +## Notes & Limitations + +1. **Voicemail** + If a phone’s voicemail picks up, Twilio sees it as answered. Consider advanced detection or a fallback. + +2. **Concurrent Calls** + Multiple calls at once require storing separate `CallSid`s or similar references. + +3. **Conference Behavior** + `startConferenceOnEnter: true` merges participants immediately; `endConferenceOnExit: true` ends the conference when that participant leaves. + +4. **X Seconds** + Decide how you detect no-answer. Typically, Twilio sets a final `callStatus` if the remote side never picks up. + +With these steps and code, you can integrate Vapi Assistant while using Twilio’s conferencing features to hold, dial out to a specialist, and handle an unanswered or unavailable specialist scenario. diff --git a/fern/calls/call-outbound.mdx b/fern/calls/call-outbound.mdx new file mode 100644 index 000000000..beec06add --- /dev/null +++ b/fern/calls/call-outbound.mdx @@ -0,0 +1,286 @@ +--- +title: Outbound Calling +subtitle: Learn how to send outbound calls from Vapi. +slug: calls/outbound-calling +--- + +## Introduction to Outbound Calling + +Vapi's outbound calling API lets you programmatically initiate single or batch calls to any phone number. You can schedule calls for specific dates and times, ideal for time-sensitive communications. Easily integrate outbound calling into your app for appointment reminders, automated surveys, and call campaigns. + +## Prerequisites + +- **Vapi Account**: Access to the Vapi Dashboard for configuration. +- **Configured Assistant**: Either a saved assistant or a transient assistant. +- **Phone Number**: Either an imported phone number from one of the supported providers. (Note: You cannot make outbound or international calls with a free Vapi number). +- **Customer's Phone Number**: The phone number that you want to call. + +## Outbound Calls + +You can place an outbound call from one of your phone numbers using the [`/call`](/api-reference/calls/create-phone-call) endpoint. + +1. **Specify an Assistant:** you must specify either a transient assistant in the `assistant` field or reuse a saved assistant in the `assistantId` field. +2. **Get a Phone Number:** provide the `phoneNumberId` of the imported number you wish to call from. +3. **Provide a Destination:** Finally, pass the customer's phone number or SIP URI in [`customer`](/api-reference/calls/create#request.body.customer). + +Provide your authorization token and now we're ready to issue the API call! + +```jsx +{ + "assistantId": "assistant-id", + "phoneNumberId": "phone-number-id", + "customer": { + "number": "+11231231234" + } +} +``` + +## Outbound calls with versioning + +By default, an outbound call placed with a saved `assistantId` uses the assistant's **current published version**. + +To pin the call to a specific published version instead, add `assistantVersion` (a version label like `v3`) alongside the `assistantId`. Version pinning works only with a saved `assistantId`; it is rejected with a transient `assistant`. + +```jsx +{ + "assistantId": "assistant-id", + "assistantVersion": "v3", + "phoneNumberId": "phone-number-id", + "customer": { + "number": "+11231231234" + } +} +``` + +For the full versioning model, including publishing, restoring, and pinning tool versions, see [Versioning](/assistants/versioning). + +## Scheduling Outbound Calls + +To schedule a call for the future, use the [`schedulePlan`](/api-reference/calls/create#request.body.schedulePlan) parameter and pass a future ISO date-time string to `earliestAt`. This will be the earliest time Vapi will attempt to trigger the outbound call. You may also provider `latestAt`, which will be the latest time Vapi will attempt to trigger the call. + +When you schedule a call, we will save the Assistant, Phone Number, and Customer Number resources and refetch them at the time of the call. If you choose to provide a saved assistant through `assistantId`, we will pick up the most up-to-date version of your assistant at the call time. Likewise, if you delete your saved assistant, the call will fail! To ensure the call is issued with a static version of an assistant, pass it as a transient assistant through the `assistant` parameter. + +```jsx +{ + "assistantId": "assistant-id", + "phoneNumberId": "phone-number-id", + "customer": { + "number": "+11231231234" + }, + "schedulePlan": { + "earliestAt": "2025-05-30T00:00:00Z" + } +} +``` + +## Batch Calling [#batch-calling] + +To call more than one number at a time, use the [`customers`](/api-reference/calls/create#request.body.customers) parameter to pass an array of `customer`. To provide customer specific assistant overrides, please call the endpoint separately for each destination number. + +Use both `customers` and `schedulePlan` together to schedule batched calls. + +```jsx +{ + "assistantId": "assistant-id", + "phoneNumberId": "phone-number-id", + "customers": [ + { + "number": "+11231231234" + }, + { + "number": "+12342342345" + } + ], + "schedulePlan": { + "earliestAt": "2025-05-30T00:00:00Z" + } +} +``` + +## Creating Outboud Calls from the Dashboard + +Learn more about how to launch [Outbound Calling Campaigns via Dashboard](/outbound-campaigns/quickstart) + +## Trusted Calling and Caller ID + +To maximize call answer rates and establish trust with recipients, you should implement proper caller identification and trusted calling standards. This involves several key components that work together to verify your identity and build caller reputation. + +### STIR/SHAKEN Implementation + +**STIR/SHAKEN** (Secure Telephone Identity Revisited / Signature-based Handling of Asserted Information using toKENs) is a framework designed to combat robocalls and caller ID spoofing by digitally signing calls to verify the caller's identity. + +When you make outbound calls, STIR/SHAKEN provides three levels of attestation: + +- **Level A (Full Attestation)**: The service provider has verified both the caller's identity and their right to use the calling number +- **Level B (Partial Attestation)**: The service provider has verified the caller's identity but not their right to use the number +- **Level C (Gateway Attestation)**: The service provider has authenticated the call source but cannot verify the caller's identity + +To enable STIR/SHAKEN on your Twilio numbers: + +1. **Complete Trust Hub verification** in your Twilio Console +2. **Submit business information** including legal business name, address, and authorized representative details +3. **Provide supporting documentation** such as business registration and tax identification +4. **Wait for approval** - the verification process typically takes 5-7 business days + + +STIR/SHAKEN is currently required for US and Canadian calling. Implementation helps ensure your calls are properly authenticated and less likely to be flagged as spam. + + +Learn more: [Twilio STIR/SHAKEN Documentation](https://www.twilio.com/docs/voice/trusted-calling-with-shakenstir) + +### CNAM Registry Registration + +**CNAM** (Caller Name) displays your business name instead of just your phone number when you call someone. This significantly improves answer rates and establishes professional credibility. + +To register your business name with the CNAM database through your phone number provider: + + + + Navigate to your phone number provider's CNAM registration portal (e.g., Twilio Console → Phone Numbers → Manage → Caller ID) + + + + Provide your complete business information: + - **Legal business name** (exactly as registered with your EIN) + - **Business address** and contact information + - **Business type** and industry classification + - **Tax identification number** or business registration details + + + + Assign a point of contact with authority to make changes: + - Full name and business title + - Direct phone number and email address + - Verification that they're authorized to represent the business + + + + Submit your application for review. Processing typically takes 3-5 business days, and you'll receive confirmation once approved. + + + + +Use an email address associated with your business domain rather than personal email addresses to expedite the approval process. + + +Learn more: [Twilio CNAM Branding Guide](https://www.twilio.com/docs/voice/brand-your-calls-using-cnam) + +### Caller Reputation Databases + +Beyond CNAM registration, registering with major caller reputation databases helps establish trust and reduces the likelihood of your calls being flagged as spam or blocked. + +#### First Orion Registration + +[First Orion](https://firstorion.com/) provides caller identification and spam protection services used by major carriers and call-blocking apps. + +**Registration benefits:** +- Displays your business name and logo on supported devices +- Reduces spam flagging and call blocking +- Provides branded calling experience + +**Registration process:** +1. Visit the First Orion business portal +2. Verify your business ownership of the phone numbers +3. Submit branding assets (logo, business description) +4. Complete the verification process + +#### Hiya (Free Caller Registry) + +[Hiya](https://www.hiya.com/) operates one of the largest caller ID and spam protection networks, powering caller identification for millions of users. + +**Benefits of Hiya registration:** +- Enhanced caller ID display across multiple platforms +- Protection against false spam reporting +- Access to call analytics and reputation monitoring + +**Registration steps:** +1. Create a business account on Hiya's platform +2. Verify ownership of your phone numbers +3. Submit business profile and branding information +4. Monitor your caller reputation through their dashboard + +### Spam Monitoring and Phone Number Health + +Proactive monitoring of your phone number reputation is essential to maintain high answer rates and prevent spam labeling. Several tools and services can help you track and remediate spam labels before they impact your campaigns. + +#### Twilio Voice Integrity + +[Twilio Voice Integrity](https://www.twilio.com/docs/voice/spam-monitoring-with-voiceintegrity) helps remediate spam labels on your phone numbers and monitor their reputation across major carrier networks. + +**What Voice Integrity provides:** +- **Spam label remediation** for T-Mobile, Sprint, and AT&T networks +- **Reputation monitoring** across carrier analytic engines +- **Automatic registration** of your Twilio phone numbers with carrier databases +- **Integration with Trust Hub** for streamlined verification + +**Getting started with Voice Integrity:** + + + + - Ensure you have an approved Primary Customer Profile in Trust Hub + - For ISVs: obtain approved secondary customer profiles for tenants + + + + - Access Voice Integrity through your Twilio Console + - Complete the registration process via Trust Hub REST API or console + - Your numbers will be automatically registered with carrier analytic engines + + + + - Voice Integrity will automatically work to remediate spam labels + - Future updates will include reputation monitoring and degradation alerts + - Verizon Wireless integration coming soon (automatic for existing users) + + + + +Voice Integrity works best when combined with STIR/SHAKEN attestation, as the highest level of attestation signals to analytic engines that you're a legitimate caller. + + +#### External Phone Number Health Monitoring + +In addition to carrier-provided services, external monitoring APIs can help you proactively check your phone number reputation across different networks and spam databases. + +**Recommended monitoring services:** + +**IPQualityScore Phone Number Validation** +- **Service**: [IPQualityScore](https://www.ipqualityscore.com/) provides comprehensive phone number reputation scoring +- **Features**: Real-time spam risk assessment, carrier identification, line type detection +- **Use case**: Check numbers before campaigns and monitor reputation changes +- **Integration**: REST API for batch checking or real-time validation + +**Nomorobo Spam Database** +- **Service**: [Nomorobo](https://www.nomorobo.com/) maintains one of the largest spam phone number databases +- **Features**: Spam reputation lookup, robocall identification, carrier reporting +- **Use case**: Verify if your numbers are flagged in spam databases +- **Integration**: API access for reputation checking + +### Best Practices for Trusted Calling + + + + Use the same business name across all registrations (CNAM, First Orion, Hiya) to avoid confusion + + + Regularly check your caller reputation scores and address any spam reports promptly + + + Ensure all outbound calls comply with TCPA regulations and obtain proper consent before calling + + + Keep your business information current across all platforms when details change + + + + +Proper caller identification setup can take 2-4 weeks to fully propagate across all networks and databases. Plan accordingly when launching new outbound calling campaigns. + + +Note: Vapi free numbers have limited number of outbound calls per day. Import a number from Twilio, Vonage, or Telnyx to scale without limits. + + + It is a violation of FCC law to dial phone numbers without consent in an + automated manner. See our [TCPA Consent Guide](/tcpa-consent) and the [Telemarketing Sales + Rule](/glossary#telemarketing-sales-rule) to learn more. + diff --git a/fern/calls/call-queue-management.mdx b/fern/calls/call-queue-management.mdx new file mode 100644 index 000000000..6eb03a5a3 --- /dev/null +++ b/fern/calls/call-queue-management.mdx @@ -0,0 +1,711 @@ +--- +title: Call queue management with Twilio +subtitle: Handle high-volume calls with Twilio queues when hitting Vapi concurrency limits +slug: calls/call-queue-management +description: Build a call queue system using Twilio to handle large volumes of calls while respecting Vapi concurrency limits, ensuring no calls are dropped. +--- + +## Overview + +When your application receives more simultaneous calls than your Vapi concurrency limit allows, calls can be rejected. A call queue system using Twilio queues solves this by holding excess calls in a queue and processing them as capacity becomes available. + +**In this guide, you'll learn to:** +- Set up Twilio call queues for high-volume scenarios +- Implement concurrency tracking to respect Vapi limits +- Build a queue processing system with JavaScript +- Handle call dequeuing and Vapi integration seamlessly + + +This approach is ideal for call centers, customer support lines, or any application expecting call volumes that exceed your Vapi concurrency limit. + + +## Prerequisites + +Before implementing call queue management, ensure you have: + +- **Vapi Account**: Access to the [Vapi Dashboard](https://dashboard.vapi.ai/) with a [Vapi API key](/security-and-privacy/api-keys) +- **Twilio Account**: Active Twilio account with Account SID and Auth Token +- **Twilio CLI**: Install from [twil.io/cli](https://twil.io/cli) for queue management +- **Phone Number**: Twilio phone number configured for incoming calls +- **Assistant**: Configured Vapi assistant ID for handling calls +- **Server Environment**: Node.js server capable of receiving webhooks +- **Redis Instance**: Redis server for persistent state management (local, cloud, or serverless-compatible) + + +You'll need to know your Vapi account's concurrency limit. Check your plan details in the [Vapi Dashboard](https://dashboard.vapi.ai/settings/billing) under billing settings. + + + +For production deployments, especially in serverless environments, Redis ensures your call counters persist across server restarts and function invocations. + + +## How it works + +The queue management system operates in three phases: + + + + Incoming calls are automatically placed in a Twilio queue when received + + + Server monitors active Vapi calls against your concurrency limit + + + When capacity is available, calls are dequeued and connected to Vapi + + + +**Call Flow:** + +1. **Incoming call** → Twilio receives call and executes webhook +2. **Queue placement** → Call is placed in Twilio queue with hold music +3. **Automatic processing** → Server processes queue immediately when capacity changes +4. **Capacity check** → Server verifies if Vapi concurrency limit allows new calls using Redis +5. **Dequeue & connect** → Available calls are dequeued and connected to Vapi assistants +6. **Persistent tracking** → Redis tracks active calls across server restarts and serverless invocations + +--- + +## Implementation Guide + + + + First, create a Twilio queue using the Twilio CLI to hold incoming calls. + + ```bash + twilio api:core:queues:create \ + --friendly-name customer-support + ``` + + **Expected Response:** + ```json + { + "account_sid": "ACaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "average_wait_time": 0, + "current_size": 0, + "date_created": "2024-01-15T18:39:09.000Z", + "date_updated": "2024-01-15T18:39:09.000Z", + "friendly_name": "customer-support", + "max_size": 100, + "sid": "QUaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "uri": "/2010-04-01/Accounts/ACaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/Queues/QUaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.json" + } + ``` + + + Save the queue `sid` (e.g., `QUaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa`) - you'll need this for queue operations. + + + + + Configure your Twilio phone number to send incoming calls to your queue endpoint. + + 1. Go to [Twilio Console > Phone Numbers](https://console.twilio.com/us1/develop/phone-numbers/manage/incoming) + 2. Select your phone number + 3. Set **A call comes in** webhook to: `https://your-server.com/incoming` + 4. Set HTTP method to `POST` + 5. Save configuration + + + + Configure Redis for persistent call counter storage. Choose the option that best fits your deployment: + + + + **Install Redis locally:** + ```bash + # macOS (using Homebrew) + brew install redis + brew services start redis + + # Ubuntu/Debian + sudo apt update + sudo apt install redis-server + sudo systemctl start redis-server + + # Docker + docker run -d -p 6379:6379 redis:alpine + ``` + + **Test connection:** + ```bash + redis-cli ping + # Should return: PONG + ``` + + + + **Popular Redis cloud providers:** + + - **[Redis Cloud](https://redis.com/redis-enterprise-cloud/)**: Free tier available + - **[AWS ElastiCache](https://aws.amazon.com/elasticache/)**: Managed Redis on AWS + - **[Google Cloud Memorystore](https://cloud.google.com/memorystore)**: Managed Redis on GCP + - **[Azure Cache for Redis](https://azure.microsoft.com/services/cache/)**: Managed Redis on Azure + + Get your connection URL from your provider's dashboard. + + + + **[Upstash Redis](https://upstash.com/)** is optimized for serverless environments: + + 1. Create free account at [console.upstash.com](https://console.upstash.com) + 2. Create new Redis database + 3. Copy the REST URL for serverless compatibility + 4. Use connection pooling for better performance + + **Upstash offers:** + - Pay-per-request pricing + - Global edge locations + - Built-in connection pooling + + + + + + Create your Node.js server with the required dependencies and environment variables. + + **Install Dependencies:** + ```bash + npm install express twilio axios dotenv redis + ``` + + **Environment Variables (.env):** + ```bash + # Vapi Configuration + VAPI_API_KEY=your_vapi_api_key_here + VAPI_PHONE_NUMBER_ID=your_phone_number_id + VAPI_ASSISTANT_ID=your_assistant_id + + # Twilio Configuration + TWILIO_ACCOUNT_SID=your_twilio_account_sid + TWILIO_AUTH_TOKEN=your_twilio_auth_token + TWILIO_QUEUE_SID=QUaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + + # Redis Configuration (for persistent state) + REDIS_URL=redis://localhost:6379 + # For Redis Cloud: REDIS_URL=rediss://username:password@host:port + # For Upstash (serverless): REDIS_URL=rediss://default:password@host:port + + # Server Configuration + PORT=3000 + MAX_CONCURRENCY=5 + ``` + + + + Create the main server file with queue handling, concurrency tracking, and Vapi integration. + + ```javascript title="server.js" + const express = require('express'); + const twilio = require('twilio'); + const axios = require('axios'); + const redis = require('redis'); + require('dotenv').config(); + + const app = express(); + const twilioClient = twilio(process.env.TWILIO_ACCOUNT_SID, process.env.TWILIO_AUTH_TOKEN); + + // Redis client for persistent state management + const redisClient = redis.createClient({ + url: process.env.REDIS_URL || 'redis://localhost:6379' + }); + + const MAX_CONCURRENCY = parseInt(process.env.MAX_CONCURRENCY) || 5; + const REDIS_KEYS = { + ACTIVE_CALLS: 'vapi:queue:active_calls', + CALLS_IN_QUEUE: 'vapi:queue:calls_in_queue' + }; + + // Middleware + app.use(express.json()); + app.use(express.urlencoded({ extended: true })); + + // Initialize Redis connection + async function initializeRedis() { + try { + await redisClient.connect(); + console.log('Connected to Redis'); + + // Initialize counters if they don't exist + const activeCalls = await redisClient.get(REDIS_KEYS.ACTIVE_CALLS); + const callsInQueue = await redisClient.get(REDIS_KEYS.CALLS_IN_QUEUE); + + if (activeCalls === null) { + await redisClient.set(REDIS_KEYS.ACTIVE_CALLS, '0'); + } + if (callsInQueue === null) { + await redisClient.set(REDIS_KEYS.CALLS_IN_QUEUE, '0'); + } + } catch (error) { + console.error('Redis connection failed:', error); + process.exit(1); + } + } + + // Helper functions for Redis operations + async function getActiveCalls() { + const count = await redisClient.get(REDIS_KEYS.ACTIVE_CALLS); + return parseInt(count) || 0; + } + + async function getCallsInQueue() { + const count = await redisClient.get(REDIS_KEYS.CALLS_IN_QUEUE); + return parseInt(count) || 0; + } + + async function incrementActiveCalls() { + return await redisClient.incr(REDIS_KEYS.ACTIVE_CALLS); + } + + async function decrementActiveCalls() { + const current = await getActiveCalls(); + if (current > 0) { + return await redisClient.decr(REDIS_KEYS.ACTIVE_CALLS); + } + return current; + } + + async function incrementCallsInQueue() { + return await redisClient.incr(REDIS_KEYS.CALLS_IN_QUEUE); + } + + async function decrementCallsInQueue() { + const current = await getCallsInQueue(); + if (current > 0) { + return await redisClient.decr(REDIS_KEYS.CALLS_IN_QUEUE); + } + return current; + } + + async function syncCallsInQueue() { + await redisClient.set(REDIS_KEYS.CALLS_IN_QUEUE, '0'); + } + + // Incoming call handler - adds calls to queue + app.post('/incoming', async (req, res) => { + try { + const twiml = ` + + customer-support + `; + + res.set('Content-Type', 'application/xml'); + res.send(twiml); + + // Increment queue counter in Redis + const queueCount = await incrementCallsInQueue(); + console.log(`Call ${req.body.CallSid} added to queue. Calls in queue: ${queueCount}`); + + // Immediately check if we can process this call + setImmediate(() => processQueue()); + + } catch (error) { + console.error('Error handling incoming call:', error); + res.status(500).send('Error processing call'); + } + }); + + async function processQueue() { + try { + const activeCalls = await getActiveCalls(); + const callsInQueue = await getCallsInQueue(); + + // Check if we have capacity for more calls + if (activeCalls >= MAX_CONCURRENCY) { + return; + } + + // Check if there are calls in queue + if (callsInQueue === 0) { + return; + } + + // Get next call from queue + const members = await twilioClient.queues(process.env.TWILIO_QUEUE_SID) + .members + .list({ limit: 1 }); + + if (members.length === 0) { + // No calls in queue - sync our counter + await syncCallsInQueue(); + return; + } + + const member = members[0]; + console.log(`Processing queued call: ${member.callSid}`); + + // Get Vapi TwiML for this call + const twiml = await initiateVapiCall(member.callSid, member.phoneNumber); + + if (twiml) { + // Update call with Vapi TwiML + await twilioClient.calls(member.callSid).update({ twiml }); + + // Update counters in Redis + const newActiveCalls = await incrementActiveCalls(); + const newQueueCount = await decrementCallsInQueue(); + + console.log(`Call connected to Vapi. Active calls: ${newActiveCalls}/${MAX_CONCURRENCY}, Queue: ${newQueueCount}`); + + // Check if we can process more calls immediately + if (newActiveCalls < MAX_CONCURRENCY && newQueueCount > 0) { + setImmediate(() => processQueue()); + } + } else { + console.error(`Failed to get TwiML for call ${member.callSid}`); + } + } catch (error) { + console.error('Error processing queue:', error); + } + } + + // Generate Vapi TwiML for a call + async function initiateVapiCall(callSid, customerNumber) { + const payload = { + phoneNumberId: process.env.VAPI_PHONE_NUMBER_ID, + phoneCallProviderBypassEnabled: true, + customer: { number: customerNumber }, + assistantId: process.env.VAPI_ASSISTANT_ID, + }; + + const headers = { + 'Authorization': `Bearer ${process.env.VAPI_API_KEY}`, + 'Content-Type': 'application/json', + }; + + try { + const response = await axios.post('https://api.vapi.ai/call', payload, { headers }); + + if (response.data && response.data.phoneCallProviderDetails) { + return response.data.phoneCallProviderDetails.twiml; + } else { + throw new Error('Invalid response structure from Vapi'); + } + } catch (error) { + console.error(`Error initiating Vapi call for ${callSid}:`, error.message); + return null; + } + } + + // Webhook for call completion - triggers immediate queue processing + app.post('/call-ended', async (req, res) => { + try { + // Handle Vapi end-of-call-report webhook + const message = req.body.message; + + if (message && message.type === 'end-of-call-report') { + const callId = message.call?.id; + + const newActiveCalls = await decrementActiveCalls(); + console.log(`Vapi call ${callId} ended. Active calls: ${newActiveCalls}/${MAX_CONCURRENCY}`); + + // Immediately process queue when capacity becomes available + setImmediate(() => processQueue()); + } + + res.status(200).send('OK'); + } catch (error) { + console.error('Error handling Vapi webhook:', error); + res.status(500).send('Error'); + } + }); + + // Manual queue processing endpoint (for testing/monitoring) + app.post('/process-queue', async (req, res) => { + try { + await processQueue(); + const activeCalls = await getActiveCalls(); + const callsInQueue = await getCallsInQueue(); + + res.json({ + message: 'Queue processing triggered', + activeCalls, + callsInQueue, + maxConcurrency: MAX_CONCURRENCY + }); + } catch (error) { + console.error('Error in manual queue processing:', error); + res.status(500).json({ error: 'Failed to process queue' }); + } + }); + + // Health check endpoint + app.get('/health', async (req, res) => { + try { + const activeCalls = await getActiveCalls(); + const callsInQueue = await getCallsInQueue(); + + res.json({ + status: 'healthy', + activeCalls, + callsInQueue, + maxConcurrency: MAX_CONCURRENCY, + availableCapacity: MAX_CONCURRENCY - activeCalls, + redis: redisClient.isOpen ? 'connected' : 'disconnected' + }); + } catch (error) { + console.error('Error in health check:', error); + res.status(500).json({ + status: 'error', + error: error.message, + redis: redisClient.isOpen ? 'connected' : 'disconnected' + }); + } + }); + + // Graceful shutdown + process.on('SIGINT', async () => { + console.log('Shutting down gracefully...'); + await redisClient.quit(); + process.exit(0); + }); + + process.on('SIGTERM', async () => { + console.log('Shutting down gracefully...'); + await redisClient.quit(); + process.exit(0); + }); + + // Start server + async function startServer() { + await initializeRedis(); + + const PORT = process.env.PORT || 3000; + app.listen(PORT, () => { + console.log(`Queue management server running on port ${PORT}`); + console.log(`Max concurrency: ${MAX_CONCURRENCY}`); + console.log('Using callback-driven queue processing (no timers)'); + }); + } + + startServer().catch(console.error); + + module.exports = app; + ``` + + + + Configure your Vapi assistant to send end-of-call-report webhooks for accurate concurrency tracking. + + **Assistant Configuration:** + You need to configure your assistant with proper webhook settings to receive call status updates. + + ```javascript title="assistant-configuration.js" + const assistantConfig = { + name: "Queue Management Assistant", + // ... other assistant configuration + + // Configure server URL for webhooks + server: { + url: "https://your-server.com", + timeoutSeconds: 20 + }, + + // Configure which messages to send to your server + serverMessages: ["end-of-call-report", "status-update"] + }; + ``` + + + The webhook will be sent to your server URL with the message type `end-of-call-report` when calls end. This allows you to decrement your active call counter accurately. See the [Assistant API reference](https://docs.vapi.ai/api-reference/assistants/create#request.body.serverMessages) for all available server message types. + + + **Webhook Payload Example:** + Your `/call-ended` endpoint will receive a webhook with this structure: + + ```json title="end-of-call-report-payload.json" + { + "message": { + "type": "end-of-call-report", + "call": { + "id": "73a6da0f-c455-4bb6-bf4a-5f0634871430", + "status": "ended", + "endedReason": "assistant-ended-call" + } + } + } + ``` + + + + Deploy your server and test the complete queue management flow. + + **Start Your Server:** + ```bash + node server.js + ``` + + **Test Scenarios:** + 1. **Single call**: Call your Twilio number - should connect immediately + 2. **Multiple calls**: Make several simultaneous calls to test queuing + 3. **Capacity limit**: Make more calls than your `MAX_CONCURRENCY` setting + 4. **Queue processing**: Check that calls are processed as others end + + **Monitor Queue Status:** + ```bash + # Check server health and capacity + curl https://your-server.com/health + + # Manually trigger queue processing + curl -X POST https://your-server.com/process-queue + ``` + + + +## Callback-Driven Queue Processing + +The system uses **event-driven queue processing** that responds immediately to capacity changes, eliminating the need for timers and preventing memory leaks: + +### How It Works + +- **Event-driven**: Queue processing is triggered by actual events (call start, call end) +- **Redis persistence**: Call counters are stored in Redis, surviving server restarts and serverless deployments +- **Immediate processing**: Uses `setImmediate()` to process queue as soon as capacity becomes available +- **No timers**: Eliminates memory leak risks from long-running intervals +- **Recursive processing**: Automatically processes multiple queued calls when capacity allows + +### Key Improvements + + + + Queue processing happens immediately when calls end or arrive + + + Redis persistence works across serverless function invocations + + + No timers means no memory leaks from long-running processes + + + Counters survive server restarts and deployments + + + +### Architecture Benefits + +- **Event-driven triggers**: Processing occurs on actual state changes, not arbitrary intervals +- **Persistent state**: Redis ensures counters are never lost, even in serverless environments +- **Efficient resource usage**: No CPU cycles wasted on empty queue checks +- **Immediate capacity utilization**: New calls are processed instantly when space becomes available +- **Graceful degradation**: Redis connection failures are handled with proper error logging + +### Processing Triggers + +Queue processing is automatically triggered when: + +1. **New call arrives** → `setImmediate(() => processQueue())` after adding to queue +2. **Call ends** → `setImmediate(() => processQueue())` after decrementing active count +3. **Successful processing** → Recursively processes more calls if capacity and queue allow + + +Redis is required for this implementation. Ensure your Redis instance is properly configured and accessible from your deployment environment. + + +## Troubleshooting + + + + **Common causes:** + - Redis server not running or unreachable + - Incorrect `REDIS_URL` configuration + - Network connectivity issues in production + + **Solutions:** + - Test Redis connection: `redis-cli ping` (should return PONG) + - Verify `REDIS_URL` format matches your provider + - Check firewall rules and security groups + - Monitor Redis logs for authentication errors + + **Health check endpoint shows Redis status:** + ```bash + curl https://your-server.com/health + # Check "redis" field in response + ``` + + + + **Common causes:** + - Server not receiving call-ended webhooks (check webhook URLs) + - Redis counter desync (rare, but possible) + - Vapi API errors (check API key and assistant ID) + + **Solutions:** + - Verify webhook URLs are publicly accessible + - Check Redis counters: `redis-cli get vapi:queue:active_calls` + - Reset counters manually if needed: `redis-cli set vapi:queue:active_calls 0` + - Test Vapi API calls independently + + **Debug Redis state:** + ```bash + # Check current counter values + redis-cli mget vapi:queue:active_calls vapi:queue:calls_in_queue + ``` + + + + **Check these items:** + - `MAX_CONCURRENCY` setting is appropriate for your Vapi plan + - Redis counters are accurate (compare with actual Twilio queue) + - No errors in Vapi TwiML generation + + **Debug steps:** + - Call `/process-queue` endpoint manually + - Check `/health` endpoint for current capacity and Redis status + - Review server logs for Redis connection errors + - Verify queue processing triggers are firing + + + + **Serverless-specific considerations:** + - Use connection pooling for Redis (Upstash recommended) + - Cold starts may cause initial Redis connection delays + - Function timeout limits may interrupt long-running operations + + **Solutions:** + - Configure appropriate function timeout (30+ seconds) + - Use Redis providers optimized for serverless (Upstash) + - Implement connection retry logic + - Monitor function execution logs for timeout errors + + + + **Potential issues:** + - Invalid phone number format (use E.164 format) + - Incorrect Vapi configuration (phone number ID, assistant ID) + - Network timeouts during TwiML generation + - Redis operations timing out + + **Solutions:** + - Validate all phone numbers before processing + - Add timeout handling to API calls and Redis operations + - Implement retry logic for failed Vapi requests + - Monitor Redis response times + + + + **Production considerations:** + - Redis connection pooling for high-traffic scenarios + - Monitor Redis memory usage and eviction policies + - Consider Redis clustering for extreme scale + - Implement circuit breakers for external API calls + + **Monitoring recommendations:** + - Track Redis connection health + - Monitor queue processing latency + - Alert on Redis counter anomalies + - Log all state transitions for debugging + + + +## Next steps + +Now that you have a production-ready call queue system with Redis persistence and callback-driven processing: + +- **[Advanced Call Features](/calls/call-features):** Explore call recording, analysis, and advanced routing options +- **[Monitoring & Analytics](/assistants/call-analysis):** Set up comprehensive call analytics and performance monitoring +- **[Scaling Considerations](/calls/call-concurrency):** Plan, monitor, and scale simultaneous calls for high-volume deployments +- **[Assistant Optimization](/assistants/personalization):** Enhance your assistants with personalization and dynamic variables + + +Consider implementing health checks, metrics collection, and alerting around your Redis counters and queue processing latency for production monitoring. + diff --git a/fern/calls/customer-join-timeout.mdx b/fern/calls/customer-join-timeout.mdx new file mode 100644 index 000000000..4866366fa --- /dev/null +++ b/fern/calls/customer-join-timeout.mdx @@ -0,0 +1,313 @@ +--- +title: Customer Join Timeout +subtitle: Configure web call join timeout for better success rates +slug: calls/customer-join-timeout +description: Set maximum time for users to join web calls before automatic termination +--- + +## Overview + +**Customer Join Timeout** sets the maximum time users have to join a web call before it's automatically terminated. This parameter helps you optimize call success rates by accounting for real-world connection challenges. + +**You'll learn to:** + +- Configure timeout values for different user scenarios +- Monitor join success rates and failures +- Troubleshoot timeout-related call issues + + + This setting applies only to **web calls**. Phone calls are not affected by + this parameter. + + +## How it works + +When a web call starts, users must complete several steps within the timeout window: + + + + Establish connection to Vapi servers + + + Grant browser microphone access + + + Complete audio handshake process + + + +**Default timeout:** 15 seconds +**Available range:** 1-60 seconds + + + If users don't complete all steps within the timeout, the call ends with an + `assistant-did-not-receive-customer-audio` error. + + +## Configuration + +Configure `customerJoinTimeoutSeconds` through the Vapi API for both permanent and transient assistants. + + + + Set timeout when creating a new assistant: + + + ```typescript title="TypeScript (Server SDK)" + import { VapiClient } from "@vapi-ai/server-sdk"; + + const client = new VapiClient({ token: process.env.VAPI_API_KEY }); + + const assistant = await client.assistants.create({ + name: "Customer Support Assistant", + model: { + provider: "openai", + model: "gpt-4.1-mini" + }, + voice: { + provider: "11labs", + voiceId: "21m00Tcm4TlvDq8ikWAM" + }, + customerJoinTimeoutSeconds: 30 + }); + ``` + ```python title="Python (Server SDK)" + from vapi import Vapi + + client = Vapi(token=os.getenv("VAPI_API_KEY")) + + assistant = client.assistants.create( + name="Customer Support Assistant", + model={"provider": "openai", "model": "gpt-4.1-mini"}, + voice={"provider": "11labs", "voiceId": "21m00Tcm4TlvDq8ikWAM"}, + customer_join_timeout_seconds=30 + ) + ``` + ```bash title="cURL" + curl -X POST "https://api.vapi.ai/assistant" \ + -H "Authorization: Bearer $VAPI_API_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "name": "Customer Support Assistant", + "model": {"provider": "openai", "model": "gpt-4.1-mini"}, + "voice": {"provider": "11labs", "voiceId": "21m00Tcm4TlvDq8ikWAM"}, + "customerJoinTimeoutSeconds": 30 + }' + ``` + + + + + + Modify timeout for an existing assistant: + + + ```typescript title="TypeScript (Server SDK)" + const updatedAssistant = await client.assistants.update("assistant-id", { + customerJoinTimeoutSeconds: 45 + }); + ``` + ```python title="Python (Server SDK)" + updated_assistant = client.assistants.update( + "assistant-id", + customer_join_timeout_seconds=45 + ) + ``` + ```bash title="cURL" + curl -X PATCH "https://api.vapi.ai/assistant/assistant-id" \ + -H "Authorization: Bearer $VAPI_API_KEY" \ + -H "Content-Type: application/json" \ + -d '{"customerJoinTimeoutSeconds": 45}' + ``` + + + + + + Use timeout with inline assistant configuration: + + + ```typescript title="TypeScript (Server SDK)" + const call = await client.calls.createWeb({ + assistant: { + model: { provider: "openai", model: "gpt-4.1-mini" }, + voice: { provider: "playht", voiceId: "jennifer" }, + customerJoinTimeoutSeconds: 60 + } + }); + ``` + ```python title="Python (Server SDK)" + call = client.calls.create_web( + assistant={ + "model": {"provider": "openai", "model": "gpt-4.1-mini"}, + "voice": {"provider": "11labs", "voiceId": "cgSgspJ2msm6clMCkdW9"}, + "customer_join_timeout_seconds": 60 + } + ) + ``` + ```bash title="cURL" + curl -X POST "https://api.vapi.ai/call/web" \ + -H "Authorization: Bearer $VAPI_API_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "assistant": { + "model": {"provider": "openai", "model": "gpt-4.1-mini"}, + "voice": {"provider": "11labs", "voiceId": "cgSgspJ2msm6clMCkdW9"}, + "customerJoinTimeoutSeconds": 60 + } + }' + ``` + + + + + + Override timeout for specific calls: + + + ```typescript title="TypeScript (Server SDK)" + const call = await client.calls.createWeb({ + assistantId: "your-assistant-id", + assistantOverrides: { + customerJoinTimeoutSeconds: 60 + } + }); + ``` + ```python title="Python (Server SDK)" + call = client.calls.create_web( + assistant_id="your-assistant-id", + assistant_overrides={ + "customer_join_timeout_seconds": 60 + } + ) + ``` + ```bash title="cURL" + curl -X POST "https://api.vapi.ai/call/web" \ + -H "Authorization: Bearer $VAPI_API_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "assistantId": "your-assistant-id", + "assistantOverrides": { + "customerJoinTimeoutSeconds": 60 + } + }' + ``` + + + + + +## Optimization guidelines + +### Recommended timeout values + +Choose timeout values based on your user scenarios: + +| User Type | Recommended Timeout | Reason | +| ----------------------- | ------------------- | ----------------------------------- | +| **Corporate users** | 45-60 seconds | Security policies, proxy delays | +| **Mobile users** | 30-45 seconds | Permission prompts, slower networks | +| **International users** | 30-60 seconds | Higher latency connections | +| **First-time users** | 45-60 seconds | Unfamiliar with interface | +| **Returning users** | 20-30 seconds | Familiar with flow | + +### Balancing considerations + + + + **Benefits:** - Improved join success rates - Better user experience - Fewer + support requests **Trade-offs:** - Resources tied up longer - Delayed error + detection + + + **Benefits:** - Faster resource cleanup - Quick failure detection - Reduced + server load **Trade-offs:** - More failed joins - Frustrated users + + + +## Monitoring and troubleshooting + +### Key metrics to track + +Monitor these call ended reasons to optimize your timeout settings: + + + + **Meaning:** Customer didn't complete join process within timeout + + **Actions:** + - Increase `customerJoinTimeoutSeconds` value + - Analyze user feedback for connection issues + - Consider user base demographics + + + + + **Meaning:** Legacy reason replaced by above (for better clarity) + + **Actions:** + - Review your browser permission prompts + - Add user guidance for microphone access + - Consider increasing timeout for permission flow + + + + +### Example scenario analysis + +A user attempting to join needs: + +- **5 seconds:** Network connection establishment +- **10 seconds:** Microphone permission prompt and user response +- **8 seconds:** WebRTC handshake completion +- **Total:** 23 seconds required + +**With 15-second timeout:** Call fails +**With 30+ second timeout:** Call succeeds + + + Start with 30-60 seconds and adjust based on your success rate analytics. + + +### Meeting has ended message + +This message appears when a call ends naturally and is **informational only**—not an error. + +## Best practices + + + + Begin with 30-60 second timeouts to establish baseline success rates. + + +{" "} + + + Track join success rates and timeout-related call ended reasons in your + dashboard. + + +{" "} + + + Validate timeout settings in staging environment before production deployment. + + +{" "} + + + Consider different timeout values for different user types or regions. + + + + Show loading indicators and connection status during the join process. + + + +## Next steps + +Now that you understand customer join timeouts: + +- **Monitor your metrics:** Check your [call analytics](/dashboard) for timeout-related failures +- **Explore call features:** Learn about [real-time call control](/calls/call-features) +- **Understand call failures:** Review [call ended reasons](/calls/call-ended-reason) for comprehensive troubleshooting diff --git a/fern/calls/troubleshoot-call-errors.mdx b/fern/calls/troubleshoot-call-errors.mdx new file mode 100644 index 000000000..bdbba3efd --- /dev/null +++ b/fern/calls/troubleshoot-call-errors.mdx @@ -0,0 +1,273 @@ +--- +title: Troubleshoot call errors +subtitle: Learn to diagnose failed calls based on what the caller experienced. +slug: calls/troubleshoot-call-errors +--- + +## Overview + +When a call fails, the fastest path to a fix is identifying **what the caller experienced**. This guide organizes errors by symptom so you can jump to the right section and resolve the issue. + +**In this guide, you'll learn to:** + +- Match caller-reported symptoms to specific error codes +- Understand the fault classification system (`vapifault` vs `providerfault`) +- Take the right corrective action for each error category + + +This guide explains errors by symptom. For a complete reference of every `endedReason` code, see [Call end reasons](/calls/call-ended-reason). + + +## Start here: identify the symptom + + + + Call failed immediately — no ring on the customer's end + + + Phone rang but was never picked up, or line was busy + + + Caller was talking, then the line went dead abruptly + + + Call connected but the assistant stopped speaking or responding + + + Assistant attempted a transfer but it didn't go through + + + Call worked as expected — someone or something decided it should end + + + +## Phone never rang + +**What the caller experiences:** Nothing. The phone never rings. For web calls, the connection fails immediately. + +**What you see in the dashboard:** The call object is created with status `ended` almost immediately. Duration is zero or near-zero. No transcript. + + + + These are the most common cause of calls failing before they start. + + | Error code | Meaning | Fix | + |---|---|---| + | `call.start.error-subscription-frozen` | Payment failed, subscription frozen | Update payment method in [dashboard](https://dashboard.vapi.ai/) | + | `call.start.error-subscription-insufficient-credits` | Not enough credits | Add credits or enable auto-reload | + | `call.start.error-subscription-concurrency-limit-reached` | Too many simultaneous calls | Upgrade plan or wait for active calls to end | + | `call.start.error-fraud-check-failed` | Blocked by fraud detection | Contact [support](/support) | + | `call.start.error-subscription-wallet-does-not-exist` | No billing wallet found | Contact [support](/support) | + + + + The call couldn't start because something is missing or misconfigured. + + | Error code | Meaning | Fix | + |---|---|---| + | `assistant-not-found` | Assistant ID doesn't exist | Verify the assistant ID in your [dashboard](https://dashboard.vapi.ai/) | + | `assistant-not-valid` | Assistant configuration is invalid | Check required fields on the assistant | + | `call-start-error-neither-assistant-nor-server-set` | No assistant or server URL configured | Set an `assistantId` or `serverUrl` on the call | + | `call.start.error-get-assistant` | Error fetching the assistant | Verify the assistant ID exists and your API key is correct | + | `call.start.error-get-phone-number` | Error fetching the phone number | Verify the number is imported and active | + | `call.start.error-get-resources-validation` | Resources failed validation | Check assistant, tools, and provider configurations | + | `call.start.error-vapi-number-international` | International calling not supported | Use a number that supports international calling | + | `call.start.error-vapi-number-outbound-daily-limit` | Daily outbound limit reached | Wait until the limit resets or use a different number | + + + + If you use a server URL to dynamically provide an assistant, these errors mean your server didn't respond correctly. + + | Error code | Meaning | Fix | + |---|---|---| + | `assistant-request-failed` | Request to your server URL failed | Check your server is running and reachable | + | `assistant-request-returned-error` | Server returned an error response | Check your server logs for the error | + | `assistant-request-returned-invalid-assistant` | Server returned invalid assistant config | Validate the response matches the [assistant schema](/api-reference/assistants/create) | + | `assistant-request-returned-no-assistant` | Server returned an empty response | Ensure your server returns an assistant object | + | `assistant-request-returned-unspeakable-error` | Server returned a non-speakable error | Return a user-friendly error message | + + + + These indicate a problem on Vapi's side. You are typically not charged. + + | Error code | Meaning | Fix | + |---|---|---| + | `call.in-progress.error-vapifault-transport-never-connected` | Transport never connected | Retry. Contact [support](/support) if persistent. | + | `call.in-progress.error-vapifault-worker-not-available` | No call worker available | Retry. This is a transient capacity issue. | + | `call.start.error-vapifault-database-error` | Internal database error | Retry. Contact [support](/support) if persistent. | + | `call.start.error-get-org` | Error fetching organization | Verify your API key is correct | + + + +## Phone rang but nobody answered + +**What the caller experiences:** The phone rings but nobody picks up, or they hear a busy signal. + +**What you see in the dashboard:** Short duration, no transcript, no messages. + +| Error code | Meaning | What to do | +|---|---|---| +| `customer-did-not-answer` | Callee didn't pick up (outbound) | Normal behavior. For IVR use cases, check your voicemail detection settings. | +| `customer-busy` | Line was busy (outbound) | Normal behavior. Retry later. | +| `customer-did-not-give-microphone-permission` | User denied mic access (web calls) | Ensure your UI requests microphone permissions before starting the call. | +| `call.ringing.sip-inbound-caller-hungup-before-call-connect` | SIP caller hung up during ringing | Normal behavior — caller abandoned before pickup. | + + +For outbound calls where you expect to reach an IVR or automated system, configure your [voicemail detection](/calls/voicemail-detection) settings to prevent the call from ending prematurely. + + +## Call dropped mid-conversation + +**What the caller experiences:** They're in the middle of a conversation and the call suddenly cuts off with no warning. The assistant stops speaking and the line goes dead. + +**What you see in the dashboard:** Partial transcript, `messages` array that ends abruptly, non-zero duration. + + + + These are on Vapi's side. You are typically not charged. Most are transient. + + | Error code | Meaning | + |---|---| + | `call.in-progress.error-vapifault-worker-died` | The Vapi process handling the call crashed | + | `call.in-progress.error-vapifault-transport-connected-but-call-not-active` | Transport connected but call was no longer active | + | `call.in-progress.error-vapifault-call-started-but-connection-to-transport-missing` | Transport connection was lost after call started | + | `worker-shutdown` | A Vapi deployment occurred while the call was active | + + **What to do:** These are transient issues. If `worker-died` errors are frequent, contact [support](/support) with the affected `call_id` values. + + + + The telephony provider (Twilio, Vonage, or your SIP trunk) dropped the connection. + + | Error code | Meaning | + |---|---| + | `phone-call-provider-closed-websocket` | Audio WebSocket between Vapi and the provider broke | + | `call.in-progress.error-providerfault-transport-never-connected` | Provider failed to maintain the connection | + | `call.in-progress.twilio-completed-call` | Twilio ended the call from their side | + | `call.in-progress.sip-completed-call` | SIP provider ended the call from their side | + | `vonage-disconnected` | Vonage disconnected the call | + + **What to do:** Check your telephony provider's dashboard for connection logs. For SIP trunks, verify your network connectivity to Vapi's SBC. + + + +## Assistant went silent or unresponsive + +**What the caller experiences:** The call is connected and the line is open, but the assistant either doesn't speak, speaks with extreme delay, responds once then stops, or produces garbled audio. The call eventually times out or the caller hangs up in frustration. + +**What you see in the dashboard:** Partial messages, the `endedReason` points to a specific pipeline component failure. + + +If you've configured **fallback providers**, some transcriber and voice errors will trigger a provider swap instead of ending the call. The caller might hear a brief 1-2 second pause while the fallback initializes, then the conversation continues normally. + + + + + The AI model that generates responses is unreachable or returning errors. + + | Status code pattern | Meaning | Fix | + |---|---|---| + | `*-401-*` / `*-incorrect-api-key` | Invalid API key | Verify your API key for this provider | + | `*-403-*` / `*-model-access-denied` | Model access denied | Check model permissions in your provider account | + | `*-429-*` / `*-exceeded-quota` | Rate limit or quota hit | Upgrade your plan with the provider or reduce volume | + | `*-500-*` / `*-server-error` | Provider internal error | Retry. Check the provider's [status page](https://status.openai.com/) | + | `*-503-*` / `*-server-overloaded` | Provider overloaded | Retry after a brief wait | + | `*-llm-failed` | Generic LLM failure | Check call logs for the detailed error message | + | `pipeline-no-available-llm-model` | No LLM model available | Check your model configuration | + + + + The text-to-speech service can't produce audio. The assistant "thinks" but can't speak. + + | Pattern | Meaning | Fix | + |---|---|---| + | `*-voice-failed` | Generic synthesis failure | Check call logs. May be a transient provider issue. | + | `*-voice-not-found` / `*-invalid-voice` | Voice ID doesn't exist | Verify the voice ID in your provider account | + | `*-quota-exceeded` / `*-out-of-credits` | Voice provider credits exhausted | Add credits to your voice provider account | + | `*-unauthorized-access` / `*-invalid-api-key` | Bad voice provider credentials | Verify your API key for this provider | + | `*-500-*` / `*-503-*` | Provider infrastructure issue | Retry. Check the provider's status page. | + + + + The speech-to-text service can't hear the caller. The assistant can speak but can't understand input. + + | Pattern | Meaning | Fix | + |---|---|---| + | `*-transcriber-failed` | Generic transcriber failure | Check call logs for details | + | `*-returning-400-*` | Bad request (invalid model/language) | Check your transcriber model and language configuration | + | `*-returning-401-*` | Invalid transcriber credentials | Verify your API key for this provider | + | `*-returning-403-*` | Model access denied | Check model permissions in your provider account | + | `*-returning-500-*` / `*-returning-502-*` | Provider server error | Retry. Check the provider's status page. | + + + + +To prevent provider outages from killing your calls, configure fallback providers for your transcriber, voice, and model. Non-fatal errors will trigger a provider swap instead of ending the call. + + +## Transfer failed + +**What the caller experiences:** The assistant says it's transferring the call, but the transfer doesn't go through. The caller may hear silence, get disconnected, or return to the original assistant (for warm transfers). + +**What you see in the dashboard:** Transcript shows the transfer attempt, followed by the error. + + + + | Error code | Meaning | Fix | + |---|---|---| + | `call.in-progress.error-transfer-failed` | Transfer attempt failed | Verify the destination number is correct and reachable | + | `call.in-progress.error-warm-transfer-max-duration` | Warm transfer exceeded max duration | Increase the warm transfer timeout or check if the destination is answering | + | `call.in-progress.error-warm-transfer-assistant-cancelled` | Transfer assistant cancelled | Check the transfer assistant's configuration | + | `call.in-progress.error-warm-transfer-silence-timeout` | Silence during warm transfer | Verify the transfer destination is responding with audio | + | `call.in-progress.error-warm-transfer-microphone-timeout` | Mic timeout during warm transfer | Check audio connectivity to the transfer destination | + + + + | Error code | Meaning | Fix | + |---|---|---| + | `*-outbound-sip-403-forbidden` | SIP provider rejected the call | Check your SIP trunk credentials and allowed destinations | + | `*-outbound-sip-407-proxy-authentication-required` | SIP auth required | Configure proxy authentication on your SIP trunk | + | `*-outbound-sip-408-request-timeout` | SIP request timed out | Check network connectivity to the SIP destination | + | `*-outbound-sip-480-temporarily-unavailable` | SIP destination unavailable | Verify the destination is online and accepting calls | + | `*-outbound-sip-503-service-unavailable` | SIP service unavailable | Check the SIP provider's service status | + + + + | Error code | Meaning | Fix | + |---|---|---| + | `twilio-failed-to-connect-call` | Twilio couldn't connect the transfer | Check the destination number format and Twilio geo permissions | + | `vonage-failed-to-connect-call` | Vonage couldn't connect the transfer | Check the destination number and Vonage configuration | + | `vonage-rejected` | Vonage rejected the transfer | Check Vonage configuration and allowed destinations | + + + +For response-class guidance and checks across Vapi, your SIP provider, and your SIP infrastructure, see [Troubleshoot SIP response codes](/advanced/sip/troubleshoot-sip-response-codes). + +For a detailed transfer debugging walkthrough, see [Debug forwarding drops](/phone-calling/in-call-control/transfer-calls/debug-forwarding-drops). + +## Call ended normally + +These are not errors — they indicate the call ended as expected. + +| Error code | Meaning | Adjust if needed | +|---|---|---| +| `assistant-ended-call` | Assistant ended the call via a tool or function | Expected behavior | +| `assistant-ended-call-after-message-spoken` | Assistant spoke its final message and ended | Expected behavior | +| `assistant-ended-call-with-hangup-task` | Assistant used a hangup task | Expected behavior | +| `assistant-said-end-call-phrase` | Assistant said a configured end-call phrase | Check your end-call phrases if calls end too early | +| `assistant-forwarded-call` | Assistant transferred the call | Expected behavior | +| `customer-ended-call` | Customer hung up | Expected behavior | +| `exceeded-max-duration` | Hit `maxDurationSeconds` | Increase `maxDurationSeconds` if calls are being cut short | +| `silence-timed-out` | Silence timeout | Increase `silenceTimeoutSeconds` if the timeout is too aggressive | +| `voicemail` | Call went to voicemail | Configure [voicemail detection](/calls/voicemail-detection) settings | +| `manually-canceled` | Canceled via API or dashboard | Expected behavior | +| `vonage-completed` | Vonage reported call completed | Expected behavior | + +## Next steps + +- **[Call end reasons](/calls/call-ended-reason):** Complete reference of every `endedReason` code. +- **[Debugging voice agents](/debugging):** General debugging workflow using dashboard tools, logs, and test suites. +- **[Debug forwarding drops](/phone-calling/in-call-control/transfer-calls/debug-forwarding-drops):** Deep dive into transfer failures. +- **[Troubleshoot SIP trunk errors](/advanced/sip/troubleshoot-sip-trunk-credential-errors):** Resolve SIP credential validation failures. +- **[Troubleshoot SIP response codes](/advanced/sip/troubleshoot-sip-response-codes):** Identify where a SIP request failed and what to check next. +- **[How to report issues](/issue-reporting):** Include your `call_id` and account email when contacting support. diff --git a/fern/calls/troubleshoot-call-forwarding-drops.mdx b/fern/calls/troubleshoot-call-forwarding-drops.mdx new file mode 100644 index 000000000..c0c606f38 --- /dev/null +++ b/fern/calls/troubleshoot-call-forwarding-drops.mdx @@ -0,0 +1,317 @@ +--- +title: "Debug call forwarding drops" +subtitle: "Learn to troubleshoot calls that drop immediately after initiating transfer" +--- + +## Overview + +When you initiate call forwarding, you expect the call to transfer to the destination. Instead, the call drops immediately after initiating the transfer, leaving both parties disconnected. + +**In this guide, you'll learn to:** + +- Identify why calls drop during forwarding +- Check call logs and API responses systematically +- Analyze telephony provider logs for transfer failures +- Resolve configuration issues preventing successful transfers + + + This guide focuses on the specific scenario where calls drop immediately after + transfer initiation, not general call quality issues. + + +## Prerequisites + +Before you start debugging, ensure you have: + +- **Call ID** from the dropped call +- **API access** to make GET requests to Vapi +- **Admin access** to your telephony provider dashboard (Twilio, Vonage, Telnyx) +- **Wireshark** installed (for SIP-based calls only) + +## Troubleshooting workflow + + + + +First, verify whether Vapi successfully initiated the forwarding. + + +```bash title="cURL" +curl -X GET "https://api.vapi.ai/call/{call_id}" \ + -H "Authorization: Bearer YOUR_API_KEY" \ + -H "Content-Type: application/json" +``` + +```typescript title="TypeScript SDK" +import { VapiClient } from "@vapi-ai/server-sdk"; + +const client = new VapiClient({ token: process.env.VAPI_API_KEY }); +const call = await client.calls.get("ca123456xxxxx"); +console.log("End reason:", call.endedReason); +``` + +```python title="Python SDK" +from vapi import Vapi + +client = Vapi(token=os.getenv("VAPI_API_KEY")) +call = client.calls.get("ca123456xxxxx") +print(f"End reason: {call.ended_reason}") +``` + + + +**Check the response:** + +```json title="Expected response" +{ + "id": "ca123456xxxxx", + "endedReason": "assistant-forwarded-call", + "status": "ended", + "destination": { + "type": "number", + "number": "+1234567890" + }, + "phoneCallProviderId": "twilio_call_abc123" +} +``` + +**What the `endedReason` tells you:** + +- `"assistant-forwarded-call"` → Vapi forwarded successfully, continue to Step 2 +- Any other value → Forwarding wasn't initiated, check your assistant configuration + + + + + +If you're handling call control through server messages, this can prevent Vapi from managing transfers. + +Check your assistant's `serverMessages` configuration: + + +```json title="Problematic configuration" +{ + "assistant": { + "serverMessages": ["phone-call-control", "status-update"] + } +} +``` + +```json title="Correct configuration" +{ + "assistant": { + "serverMessages": ["status-update"] + } +} +``` + + + + + If `"phone-call-control"` is present, your server is overriding Vapi's call + control. Remove it unless you're implementing custom transfer logic. + + + + + + +The `phoneCallProviderBypassEnabled` flag determines whether Vapi handles call control directly. + +**Recommended configuration:** + +```json title="Standard Vapi forwarding" +{ + "phoneCallProviderBypassEnabled": false +} +``` + + + Only set this to `true` if you're implementing custom call control through + your telephony provider. + + + + + + +Not all transfer scenarios are supported. Verify your use case: + +| From | To | Supported | +| ---------- | ------------ | ------------------- | +| Phone call | Phone number | ✅ Yes | +| Web call | Phone number | ❌ No | +| Phone call | SIP number | ❌ No (PSTN to SIP) | +| SIP call | SIP number | ✅ Yes | +| SIP call | Phone number | ✅ Yes | + + + Web-to-phone transfers are not supported. The call will always drop in this + scenario. + + + + + + +If the call shows `"assistant-forwarded-call"` but still drops, the issue is likely with your telephony provider. + +**Get your telephony call ID** from the Vapi call object: + +```json title="Extract telephony call ID" +{ + "id": "ca123456xxxxx", + "endedReason": "assistant-forwarded-call", + "phoneCallProviderId": "CAabc123" +} +``` + +**Check your provider's dashboard:** + + + +1. Go to [Twilio Console > Call Logs](https://console.twilio.com/us1/monitor/logs/calls) +2. Search using `phoneCallProviderId` (e.g., `CAabc123`) +3. Look for transfer-related errors in the call timeline +4. Check TwiML execution logs for failed transfers + + + + 1. Access [Vonage API Dashboard](https://dashboard.nexmo.com/) 2. Navigate to + Call Logs 3. Search using the telephony call ID and timestamp 4. Review call + flow details for transfer failures + + + +1. Open [Telnyx Mission Control Portal](https://portal.telnyx.com/) +2. Go to Call Detail Records +3. Search using the telephony call ID +4. Examine call records for forwarding errors + + + + + + + +For SIP trunking or bring-your-own-number setups, analyze the SIP signaling. + +**Download the packet capture:** + +```bash title="Get PCAP file" +curl -X GET "https://api.vapi.ai/call/{call_id}" \ + -H "Authorization: Bearer YOUR_API_KEY" +``` + +The response includes a `pcapUrl` field. Download this file and open it in Wireshark. + +**Filter for transfer packets:** + +```text title="Wireshark filter" +sip.Method == "REFER" +``` + +**What to look for:** + +- **REFER packet present** → Vapi sent the transfer request to your SIP provider +- **REFER packet missing** → Transfer wasn't initiated by Vapi +- **202 Accepted response** → SIP provider accepted the transfer +- **Error responses (4xx, 5xx)** → SIP provider rejected the transfer + + + **Important:** SIP transfers are handled by your telephony provider, not Vapi. + Once Vapi sends the REFER packet, your SIP provider manages the actual + transfer process. + + +For more details on SIP configuration, see our [SIP trunk documentation](https://docs.vapi.ai/advanced/sip/sip-trunk#inbound-call-test). + + + + +## Common solutions + +Based on your findings, here are the most frequent fixes: + +### Call shows successful forwarding but still drops + +**Root cause:** Telephony provider couldn't complete the transfer + +**Solution:** Check destination number format and availability + +- Verify the destination number includes country code +- Test calling the destination directly outside of Vapi +- Check if destination has call blocking enabled + +### endedReason is not 'assistant-forwarded-call' + +**Root cause:** Transfer wasn't initiated due to configuration + +**Solution:** Review assistant settings + +- Remove `"phone-call-control"` from `serverMessages` +- Set `phoneCallProviderBypassEnabled` to `false` +- Verify your transfer function is properly configured + +### SIP REFER packets missing in PCAP + +**Root cause:** Vapi didn't send transfer request to SIP provider + +**Solution:** Check Vapi configuration + +- Verify SIP endpoint configuration +- Ensure destination format matches SIP addressing +- Check for conflicting call control settings + +## Limitations + +### Transfer scenario limitations + +- **Web calls** cannot be transferred to phone numbers +- **PSTN-to-SIP** transfers are not supported +- Cross-provider transfers may have compatibility issues + +### Configuration dependencies + +- `phoneCallProviderBypassEnabled` must be `false` for Vapi-managed transfers +- `serverMessages` with `"phone-call-control"` overrides default behavior +- SIP configuration requires proper endpoint setup + +## When to contact support + +Escalate to support when you've completed all troubleshooting steps and: + +- Provider logs show successful transfers but calls consistently fail +- SIP packet analysis indicates Vapi-side transfer issues +- Multiple destinations fail with the same configuration +- Configuration changes don't resolve recurring failures + +**Include in your support request:** + +- Call ID and timestamp +- Complete troubleshooting results from this guide +- Telephony provider error codes and logs +- Screenshots of configuration settings + +## Next steps + +Now that you can debug call forwarding drops: + +- **Monitor call patterns:** Set up alerts for calls with unexpected `endedReason` values +- **Test systematically:** Verify transfers work across different destination types before production +- **Review SIP setup:** Ensure your SIP configuration follows our [advanced SIP guide](https://docs.vapi.ai/advanced/sip/sip-trunk) + + + + Create a transfer call tool and configure its destinations. + + + Connect a caller immediately or add a summary to a SIP header. + + + Introduce a caller with a message, summary, or TwiML. + + + Look up transfer-related ended reasons and error codes. + + diff --git a/fern/calls/voicemail-detection.mdx b/fern/calls/voicemail-detection.mdx new file mode 100644 index 000000000..4f681ba2d --- /dev/null +++ b/fern/calls/voicemail-detection.mdx @@ -0,0 +1,686 @@ +--- +title: Voicemail Detection +slug: calls/voicemail-detection +--- + +When you're running outbound voice agents, voicemails are a reality — but wasting time or missing opportunities because of them shouldn't be. + +**Vapi's voicemail detection** gives you faster, smarter, and more flexible handling of voicemail events, so you can keep your calls efficient, responsive, and professional. + +## **Why Voicemail Detection Matters** + +- **Save time** by avoiding long waits on unanswered calls. +- **Optimize costs** by cutting down on wasted minutes. +- **Improve UX** by ensuring your agent behaves naturally when encountering voicemail greetings. +- **Boost response rates** by leaving cleaner, more intentional voicemail messages. + +--- + +## **Detection Options** + +You can choose between several detection methods — but not all are created equal: + +| Detection Method | Strengths | Weaknesses | Recommendation | +| :--------------- | :-------- | :--------- | :------------- | +| **Vapi (Recommended)** | Fast, accurate, gracefully handles interruptions | None significant | ✅ Strongly recommended | +| **Google** | Very good accuracy, reliable | Slightly longer detection time than Vapi | ✅ Recommended | +| **OpenAI** | High accuracy, flexible phrasing | Higher cost | ✅ Good option if budget allows | +| **Twilio** (legacy) | Very fast machine beep detection | Prone to false positives | ⚠️ Use only in special cases | +| **[Vapi Voicemail Tool](/tools/voicemail-tool)** (beta) | Assistant-driven voicemail decisions | Most cost effective, requires good prompting | ✅ Best for customization and cost efficiency | + +--- + +## **Vapi Voicemail Detection** + +With **Vapi Voicemail Detection**, your assistant will: + +- **Detect voicemail faster** (often within the first few seconds of the call). +- **Handle real-time pickups** gracefully — if a human picks up mid-voicemail, the agent will switch back naturally. +- **Interrupt the bot's first message** appropriately if voicemail is detected mid-sentence. +- **Minimize false positives** by combining audio analysis (beeps) and transcription intelligence. + +All three providers — **Vapi, Google, and OpenAI** — support **interruption handling** and **false positive protection**. + +--- + +## **How to Configure It** + + + + Open the [Dashboard](https://dashboard.vapi.ai/assistants). Select **Assistants**, then select the assistant you want to configure. + + + + Select the **Advanced** tab, then locate **Voicemail Detection**. + + + + Under **Voicemail Detection Provider**, choose **Off**, **Vapi (Recommended)**, **Google**, **OpenAI**, or **Twilio**. + + + + For **Vapi (Recommended)**, **Google**, or **OpenAI**, set **Initial Detection Delay**, **Detection Retry Interval**, **Max Detection Retries**, and **Max Voicemail Message Wait**. **Twilio** does not expose additional tuning controls in the Dashboard. + + + + Locate **Messaging**, then enter the message the assistant should leave in **Voicemail Message**. + + + + Select **publish** in the unsaved-changes message to apply the update. + + + + + + + + + + + +## **Advanced Configuration Options** + +For each detection method, you can fine-tune the following parameters: + + +**Important:** `frequencySeconds` has a minimum allowed value of 2.5 seconds. + + +| Parameter | Description | +| :-------- | :---------- | +| **type** | Detection method: `audio` (default, best for Google/Vapi) or `transcript` (ASR-based, best for OpenAI). Only `transcript` is supported for Google and OpenAI providers. | +| **backoffPlan.startAtSeconds** | How long to wait (in seconds) before starting voicemail detection. | +| **backoffPlan.frequencySeconds** | How frequently to check for voicemail after the initial delay. | +| **backoffPlan.maxRetries** | Maximum number of detection attempts before stopping. | +| **beepMaxAwaitSeconds** | Maximum duration from call start to wait for a voicemail beep before speaking the message. If set too low, the bot may start speaking before the actual beep and get cut off. Default: 30 seconds (0-60 range). | + +These settings allow you to balance: +- **Speed** (how quickly voicemail is detected) +- **Accuracy** (reducing false positives) +- **Cost** (fewer detection attempts = lower API costs) + +### **Important: beepMaxAwaitSeconds Configuration** + +The `beepMaxAwaitSeconds` parameter is critical for voicemail message timing: + +- **What it does**: Sets the maximum time from call start to wait for a voicemail beep before the bot starts speaking its message +- **If beep detected early**: Bot speaks immediately after the beep (optimal) +- **If no beep by timeout**: Bot starts speaking the voicemail message anyway +- **Risk of low values**: Bot may start speaking before the actual beep and get cut off by the voicemail system + + +**Setting too low a value** (under 15-20 seconds) may cause your voicemail message to be cut off. Most voicemail systems play 10-20 seconds of greeting before the beep. + + +**Recommended values:** +- **Conservative**: 25-30 seconds (default: 30) +- **Aggressive**: 15-20 seconds (requires testing with your specific voicemail patterns) +- **Range**: 0-60 seconds + +--- + +## **How Vapi Detection Works** + +Vapi's detection engine combines: +- **Gemini model-based detection** (fast and highly accurate on common voicemail phrasing) +- **Twilio beep detection** (optional, for faster reaction to voicemail system beeps) +- **Real-time call monitoring** to react instantly if a human unexpectedly picks up +- **Continuous voicemail polling** during early call stages (detecting voicemail faster without waiting for a full timeout) + +This hybrid approach means **less call delay, fewer mistakes, and a much more natural call experience.** + +--- + +## **Complete Configuration Examples** + +Here are complete assistant configurations for different real-world scenarios: + +### **Sales Outreach Assistant** + +This configuration optimizes for fast detection and professional voicemail delivery in sales scenarios: + + +```json title="API Configuration" +{ + "name": "Sales Outreach Assistant", + "voice": { + "provider": "vapi", + "version": 2, + "voiceId": "Elliot" + }, + "model": { + "model": "gpt-4o", + "messages": [ + { + "role": "system", + "content": "You are a professional sales representative calling prospects about our software solutions. Be friendly, concise, and respect their time. If you reach voicemail, keep your message under 30 seconds." + } + ], + "provider": "openai", + "temperature": 0.3 + }, + "firstMessage": "Hi! This is Sarah from TechSolutions. I hope I'm catching you at a good time.", + "voicemailMessage": "Hi, this is Sarah from TechSolutions. I'm calling about the software demo you requested. I'd love to show you how we can help streamline your operations and save you time. Please call me back at 555-0123, or I'll try you again tomorrow. Thanks!", + "endCallMessage": "Thanks for your time. Have a great day!", + "transcriber": { + "model": "nova-2", + "language": "en", + "provider": "deepgram", + "smartFormat": true + }, + "firstMessageMode": "assistant-waits-for-user", + "voicemailDetection": { + "provider": "vapi", + "backoffPlan": { + "maxRetries": 5, + "startAtSeconds": 2, + "frequencySeconds": 2.5 + }, + "beepMaxAwaitSeconds": 12 + }, + "messagePlan": { + "idleMessages": ["Hello? Are you still there?"], + "idleTimeoutSeconds": 8 + }, + "startSpeakingPlan": { + "waitSeconds": 0.7, + "smartEndpointingPlan": { + "provider": "livekit", + "waitFunction": "2000 / (1 + exp(-10 * (x - 0.5)))" + } + }, + "stopSpeakingPlan": { + "numWords": 2, + "backoffSeconds": 0.8 + }, + "backgroundDenoisingEnabled": true +} +``` +```typescript title="TypeScript SDK" +import { VapiClient } from "@vapi-ai/server-sdk"; + +const vapi = new VapiClient({ token: process.env.VAPI_API_KEY }); + +const salesAssistant = await vapi.assistants.create({ + name: "Sales Outreach Assistant", + voice: { + speed: 0.9, + provider: "vapi", + version: 2, + voiceId: "Elliot" + }, + model: { + model: "gpt-4o", + messages: [{ + role: "system", + content: "You are a professional sales representative calling prospects about our software solutions. Be friendly, concise, and respect their time. If you reach voicemail, keep your message under 30 seconds." + }], + provider: "openai", + temperature: 0.3 + }, + firstMessage: "Hi! This is Sarah from TechSolutions. I hope I'm catching you at a good time.", + voicemailMessage: "Hi, this is Sarah from TechSolutions. I'm calling about the software demo you requested. I'd love to show you how we can help streamline your operations and save you time. Please call me back at 555-0123, or I'll try you again tomorrow. Thanks!", + voicemailDetection: { + provider: "vapi", + backoffPlan: { + maxRetries: 5, + startAtSeconds: 2, + frequencySeconds: 2.5 + }, + beepMaxAwaitSeconds: 12 + }, + transcriber: { + model: "nova-2", + language: "en", + provider: "deepgram", + endpointing: 8, + smartFormat: true + }, + backgroundDenoisingEnabled: true +}); +``` +```python title="Python SDK" +from vapi import Vapi + +client = Vapi(token=os.getenv("VAPI_API_KEY")) + +sales_assistant = client.assistants.create( + name="Sales Outreach Assistant", + voice={ + "provider": "vapi", + "version": 2, + "voiceId": "Elliot" + }, + model={ + "model": "gpt-4o", + "messages": [{ + "role": "system", + "content": "You are a professional sales representative calling prospects about our software solutions. Be friendly, concise, and respect their time. If you reach voicemail, keep your message under 30 seconds." + }], + "provider": "openai", + "temperature": 0.3 + }, + first_message="Hi! This is Sarah from TechSolutions. I hope I'm catching you at a good time.", + voicemail_message="Hi, this is Sarah from TechSolutions. I'm calling about the software demo you requested. I'd love to show you how we can help streamline your operations and save you time. Please call me back at 555-0123, or I'll try you again tomorrow. Thanks!", + voicemail_detection={ + "provider": "vapi", + "backoff_plan": { + "max_retries": 5, + "start_at_seconds": 2, + "frequency_seconds": 2 + }, + "beep_max_await_seconds": 12 + }, + transcriber={ + "model": "nova-2", + "language": "en", + "provider": "deepgram", + "smart_format": True + }, + background_denoising_enabled=True +) +``` + + +### **Customer Support Callback Assistant** + +Optimized for high-accuracy detection and detailed voicemail messages: + + +```json title="API Configuration" +{ + "name": "Customer Support Assistant", + "voice": { + "provider": "vapi", + "version": 2, + "voiceId": "Elliot" + }, + "model": { + "model": "gpt-4o", + "messages": [ + { + "role": "system", + "content": "You are a customer support representative calling customers back about their support tickets. Be empathetic, helpful, and provide clear next steps. Always reference their ticket number." + } + ], + "provider": "openai", + "temperature": 0.2 + }, + "firstMessage": "Hello! This is Maya from Customer Support. I'm calling back about your recent support request.", + "voicemailMessage": "Hi, this is Maya from Customer Support calling about ticket #{{ticketNumber}}. I have some updates on your issue and want to help resolve this quickly. Please call me back at 1-800-SUPPORT, or reply to your support email and I'll get back to you within 2 hours. Thanks!", + "voicemailDetection": { + "provider": "google", + "backoffPlan": { + "maxRetries": 8, + "startAtSeconds": 3, + "frequencySeconds": 3 + }, + "beepMaxAwaitSeconds": 20 + }, + "transcriber": { + "model": "nova-2", + "language": "en", + "provider": "deepgram", + "endpointing": 12, + "smartFormat": true + }, + "backgroundDenoisingEnabled": true +} +``` +```typescript title="TypeScript SDK" +const supportAssistant = await vapi.assistants.create({ + name: "Customer Support Assistant", + voice: { + provider: "vapi", + version: 2, + voiceId: "Elliot" + }, + model: { + model: "gpt-4o", + messages: [{ + role: "system", + content: "You are a customer support representative calling customers back about their support tickets. Be empathetic, helpful, and provide clear next steps. Always reference their ticket number." + }], + provider: "openai", + temperature: 0.2 + }, + voicemailDetection: { + provider: "google", // Using Google for maximum accuracy with audio detection + backoffPlan: { + maxRetries: 8, + startAtSeconds: 3, + frequencySeconds: 3 + }, + beepMaxAwaitSeconds: 20 + }, + firstMessage: "Hello! This is Maya from Customer Support. I'm calling back about your recent support request.", + voicemailMessage: "Hi, this is Maya from Customer Support calling about ticket #{{ticketNumber}}. I have some updates on your issue and want to help resolve this quickly. Please call me back at 1-800-SUPPORT, or reply to your support email and I'll get back to you within 2 hours. Thanks!" +}); +``` + + +### **Appointment Reminder Assistant** + +Balanced configuration for appointment confirmations with fallback voicemail: + + +```json title="API Configuration" +{ + "name": "Appointment Reminder Assistant", + "voice": { + "provider": "vapi", + "version": 2, + "voiceId": "Elliot" + }, + "model": { + "model": "gpt-4o", + "messages": [ + { + "role": "system", + "content": "You are calling to remind patients about their upcoming appointments. Be warm, professional, and provide all necessary details including date, time, and preparation instructions." + } + ], + "provider": "openai", + "temperature": 0.1 + }, + "firstMessage": "Hi! This is Ryan calling from Dr. Smith's office about your upcoming appointment.", + "voicemailMessage": "Hi, this is Ryan from Dr. Smith's office calling to remind you about your appointment on {{appointmentDate}} at {{appointmentTime}}. Please arrive 15 minutes early and bring your insurance card. If you need to reschedule, please call us at 555-CLINIC. Thanks!", + "voicemailDetection": { + "provider": "vapi", + "backoffPlan": { + "maxRetries": 6, + "startAtSeconds": 2.5, + "frequencySeconds": 2.5 + }, + "beepMaxAwaitSeconds": 15 + }, + "transcriber": { + "model": "nova-2", + "language": "en", + "provider": "deepgram", + "endpointing": 10, + "smartFormat": true + } +} +``` + + +--- + +## **Provider-Specific Configurations** + +### **Vapi Provider (Recommended)** +Best balance of speed and accuracy: + +```json +{ + "voicemailDetection": { + "provider": "vapi", + "backoffPlan": { + "maxRetries": 5, + "startAtSeconds": 2, + "frequencySeconds": 2.5 + }, + "beepMaxAwaitSeconds": 12 + } +} +``` + +### **Google Provider** +Maximum accuracy for critical calls (best with audio detection): + +```json +{ + "voicemailDetection": { + "provider": "google", + "backoffPlan": { + "maxRetries": 8, + "startAtSeconds": 3, + "frequencySeconds": 3 + }, + "beepMaxAwaitSeconds": 20 + } +} +``` + +### **OpenAI Provider** +High accuracy with cost consideration (best with transcript detection): + +```json +{ + "voicemailDetection": { + "provider": "openai", + "type": "transcript", + "backoffPlan": { + "maxRetries": 6, + "startAtSeconds": 2.5, + "frequencySeconds": 3 + }, + "beepMaxAwaitSeconds": 15 + } +} +``` + +--- + +## **Detection Types** + +Choose between two detection methods based on provider performance: + +| Detection Type | Performance | Providers | Recommended For | +|---------------|-------------|-----------|-----------------| +| **`audio`** (default) | Best for Google, Vapi | All providers | Google: Maximum accuracy
Vapi: General use cases | +| **`transcript`** | Best for OpenAI | Google, OpenAI only | OpenAI: Optimal performance
High-volume campaigns with OpenAI | + + +**Provider-specific recommendations:** +- **Google**: Use default `audio` detection for best accuracy +- **OpenAI**: Use `type: "transcript"` for optimal performance +- **Vapi**: Use default `audio` detection + + +--- + +## **Pre-recorded Audio Messages** + +Instead of text-to-speech, you can use pre-recorded audio files for your voicemail messages. Simply provide the URL to your audio file in the `voicemailMessage` property: + + +```json title="API Configuration" +{ + "name": "Sales Assistant with Audio Message", + "model": { + "provider": "openai", + "model": "gpt-4o" + }, + "voicemailDetection": { + "provider": "vapi" + }, + "voicemailMessage": "https://example.com/sales-voicemail.mp3" +} +``` +```typescript title="TypeScript SDK" +const assistant = await vapi.assistants.create({ + name: "Sales Assistant with Audio Message", + model: { + provider: "openai", + model: "gpt-4o" + }, + voicemailDetection: { + provider: "vapi" + }, + voicemailMessage: "https://example.com/sales-voicemail.wav" +}); +``` +```python title="Python SDK" +assistant = client.assistants.create( + name="Sales Assistant with Audio Message", + model={ + "provider": "openai", + "model": "gpt-4o" + }, + voicemail_detection={ + "provider": "vapi" + }, + voicemail_message="https://example.com/sales-voicemail.mp3" +) +``` + + +**Supported formats**: `.wav` and `.mp3` files + + +Pre-recorded audio messages provide consistent quality and pronunciation, especially useful for brand-specific messaging or complex information like phone numbers and website URLs. + + +--- + +## **Disabling Voicemail Detection** + +To completely disable voicemail detection for your assistant, set the `voicemailDetection` property to `"off"`: + + +```json title="API Configuration" +{ + "name": "Assistant Without Voicemail Detection", + "voicemailDetection": "off", + "model": { + "provider": "openai", + "model": "gpt-4o" + } +} +``` +```typescript title="TypeScript SDK" +const assistant = await vapi.assistants.create({ + name: "Assistant Without Voicemail Detection", + voicemailDetection: "off", + model: { + provider: "openai", + model: "gpt-4o" + } +}); +``` +```python title="Python SDK" +assistant = client.assistants.create( + name="Assistant Without Voicemail Detection", + voicemail_detection="off", + model={ + "provider": "openai", + "model": "gpt-4o" + } +) +``` + + + +When voicemail detection is disabled, your assistant will continue the conversation normally regardless of whether it reaches a voicemail system. + + +--- + +## **Configuration Best Practices** + +### **Tuning for Different Scenarios** + +| Use Case | Recommended Provider | startAtSeconds | frequencySeconds | maxRetries | beepMaxAwaitSeconds | +|----------|---------------------|----------------|------------------|------------|-------------------| +| **Sales Outreach** | Vapi | 2 | 2.5 | 5 | 25 | +| **Customer Support** | Google | 3 | 3 | 8 | 20 | +| **Appointment Reminders** | Vapi | 2.5 | 2.5 | 6 | 15 | +| **Lead Qualification** | Vapi | 1.5 | 2.5 | 4 | 20 | +| **Follow-up Calls** | Google | 2.5 | 3 | 7 | 18 | + +### **Cost Optimization Tips** + +1. **Lower maxRetries** for high-volume campaigns +2. **Increase startAtSeconds** to reduce false positives +3. **Use Vapi provider** for best cost-to-accuracy ratio +4. **Tune beepMaxAwaitSeconds** carefully - too low causes cut-off messages, too high delays voicemail delivery + +### **Accuracy Optimization Tips** + +1. **Use Google provider** for maximum accuracy +2. **Increase maxRetries** for important calls +3. **Lower startAtSeconds** for faster detection +4. **Tune frequencySeconds** based on your voicemail patterns (minimum 2.5 seconds) + +--- + +## **Troubleshooting Common Issues** + +### **False Positives (Detecting voicemail when human answers)** + +**Symptoms:** Assistant leaves voicemail message when human picks up + +**Solutions:** +- Increase `startAtSeconds` to 3-4 seconds +- Switch to Google or OpenAI provider +- Increase `frequencySeconds` to 3-4 seconds + +```json +{ + "voicemailDetection": { + "provider": "google", + "backoffPlan": { + "startAtSeconds": 3.5, + "frequencySeconds": 3.5, + "maxRetries": 6 + } + } +} +``` + +### **Missed Voicemails (Not detecting actual voicemail)** + +**Symptoms:** Assistant continues talking to voicemail recording + +**Solutions:** +- Decrease `startAtSeconds` to 1-2 seconds +- Increase `maxRetries` to 8-10 +- Keep `frequencySeconds` at minimum value (2.5 seconds) + +```json +{ + "voicemailDetection": { + "provider": "vapi", + "backoffPlan": { + "startAtSeconds": 1.5, + "frequencySeconds": 2.5, + "maxRetries": 8 + } + } +} +``` + +### **Slow Detection** + +**Symptoms:** Takes too long to detect voicemail + +**Solutions:** +- Use Vapi provider for fastest detection +- Decrease `startAtSeconds` (frequencySeconds minimum is 2.5) +- Ensure good audio quality + +```json +{ + "voicemailDetection": { + "provider": "vapi", + "backoffPlan": { + "startAtSeconds": 1, + "frequencySeconds": 2.5, + "maxRetries": 6 + } + } +} +``` + +--- + +By using Vapi's detection system, you'll avoid the common pitfalls of voicemail detection, while creating a **faster, smarter, and more professional experience** for your users. + + + +## **Related Documentation** + +- **[Voicemail Tool](/tools/voicemail-tool)** - Alternative assistant-controlled voicemail approach for maximum flexibility diff --git a/fern/calls/websocket-transport.mdx b/fern/calls/websocket-transport.mdx new file mode 100644 index 000000000..7ac27279a --- /dev/null +++ b/fern/calls/websocket-transport.mdx @@ -0,0 +1,224 @@ +--- +title: WebSocket Transport +description: Stream audio directly via WebSockets for real-time, bidirectional communication +slug: calls/websocket-transport +--- + +Vapi's WebSocket transport enables real-time, bidirectional audio communication directly between your application and Vapi's AI assistants. Unlike traditional phone or web calls, this transport method lets you stream raw audio data instantly with minimal latency. + +## Key Benefits + +- **Low Latency**: Direct streaming ensures minimal delays. +- **Bidirectional Streaming**: Real-time audio flow in both directions. +- **Easy Integration**: Compatible with any environment supporting WebSockets. +- **Flexible Audio Formats**: Customize audio parameters such as sample rate. +- **Automatic Sample Rate Conversion**: Seamlessly handles various audio rates. + +## Creating a WebSocket Call + +To initiate a call using WebSocket transport: + +### PCM Format (16-bit, default) + +```bash +curl 'https://api.vapi.ai/call' \ + -H 'authorization: Bearer YOUR_API_KEY' \ + -H 'content-type: application/json' \ + --data-raw '{ + "assistantId": "YOUR_ASSISTANT_ID", + "transport": { + "provider": "vapi.websocket", + "audioFormat": { + "format": "pcm_s16le", + "container": "raw", + "sampleRate": 16000 + } + } + }' +``` + +### Mu-Law Format + +```bash +curl 'https://api.vapi.ai/call' \ + -H 'authorization: Bearer YOUR_API_KEY' \ + -H 'content-type: application/json' \ + --data-raw '{ + "assistantId": "YOUR_ASSISTANT_ID", + "transport": { + "provider": "vapi.websocket", + "audioFormat": { + "format": "mulaw", + "container": "raw", + "sampleRate": 8000 + } + } + }' +``` + +### Sample API Response + +```json +{ + "id": "7420f27a-30fd-4f49-a995-5549ae7cc00d", + "assistantId": "5b0a4a08-133c-4146-9315-0984f8c6be80", + "type": "vapi.websocketCall", + "createdAt": "2024-09-10T11:14:12.339Z", + "updatedAt": "2024-09-10T11:14:12.339Z", + "orgId": "eb166faa-7145-46ef-8044-589b47ae3b56", + "cost": 0, + "status": "queued", + "transport": { + "provider": "vapi.websocket", + "websocketCallUrl": "wss://api.vapi.ai/7420f27a-30fd-4f49-a995-5549ae7cc00d/transport" + } +} +``` + +## Audio Format Configuration + +When creating a WebSocket call, the audio format can be customized: + +| Parameter | Description | Default | +|-------------|-------------------------|---------------------| +| `format` | Audio encoding format | `pcm_s16le` (16-bit PCM) | +| `container` | Audio container format | `raw` (Raw audio) | +| `sampleRate`| Sample rate in Hz | `16000` for PCM, `8000` for Mu-Law | + +### Supported Audio Formats + +Vapi supports the following audio formats: + +- **`pcm_s16le`**: 16-bit PCM, signed little-endian (default) +- **`mulaw`**: Mu-Law encoded audio (ITU-T G.711 standard) + +Both formats use the `raw` container format for direct audio streaming. + +### Format Selection Guidelines + +- **PCM (`pcm_s16le`)**: Higher quality audio, larger bandwidth usage. Ideal for high-quality applications. +- **Mu-Law (`mulaw`)**: Lower bandwidth, telephony-standard encoding. Ideal for telephony integrations and bandwidth-constrained environments. + + +Vapi automatically converts sample rates as needed. You can stream audio at 8kHz, 44.1kHz, etc., and Vapi will handle conversions seamlessly. The system also handles format conversions internally when needed. + + +## Connecting to the WebSocket + +Use the WebSocket URL from the response to establish a connection: + +```javascript +const socket = new WebSocket("wss://api.vapi.ai/7420f27a-30fd-4f49-a995-5549ae7cc00d/transport"); + +socket.onopen = () => console.log("WebSocket connection opened."); +socket.onclose = () => console.log("WebSocket connection closed."); +socket.onerror = (error) => console.error("WebSocket error:", error); +``` + +## Sending and Receiving Data + +The WebSocket supports two types of messages: + +- **Binary audio data** (format depends on your configuration: PCM or Mu-Law) +- **Text-based JSON control messages** + +### Audio Data Format + +The binary audio data format depends on your `audioFormat` configuration: + +- **PCM (`pcm_s16le`)**: 16-bit signed little-endian samples +- **Mu-Law (`mulaw`)**: 8-bit Mu-Law encoded samples (ITU-T G.711) + +### Sending Audio Data + +```javascript +function sendAudioChunk(audioBuffer) { + if (socket.readyState === WebSocket.OPEN) { + socket.send(audioBuffer); + } +} + +navigator.mediaDevices.getUserMedia({ audio: true }).then(stream => { + const audioContext = new AudioContext(); + const source = audioContext.createMediaStreamSource(stream); + const processor = audioContext.createScriptProcessor(1024, 1, 1); + + processor.onaudioprocess = (event) => { + const pcmData = event.inputBuffer.getChannelData(0); + const int16Data = new Int16Array(pcmData.length); + + for (let i = 0; i < pcmData.length; i++) { + int16Data[i] = Math.max(-32768, Math.min(32767, pcmData[i] * 32768)); + } + + sendAudioChunk(int16Data.buffer); + }; + + source.connect(processor); + processor.connect(audioContext.destination); +}); +``` + +### Receiving Data + +```javascript +socket.onmessage = (event) => { + if (event.data instanceof Blob) { + event.data.arrayBuffer().then(buffer => { + const audioData = new Int16Array(buffer); + playAudio(audioData); + }); + } else { + try { + const message = JSON.parse(event.data); + handleControlMessage(message); + } catch (error) { + console.error("Failed to parse message:", error); + } + } +}; +``` + +### Sending Control Messages + +```javascript +function sendControlMessage(messageObj) { + if (socket.readyState === WebSocket.OPEN) { + socket.send(JSON.stringify(messageObj)); + } +} + +// Example: hangup call +function hangupCall() { + sendControlMessage({ type: "hangup" }); +} +``` + +## Ending the Call + +The recommended way to end a call is using [Live Call Control](/calls/call-features#end-call) which provides more control and proper cleanup. + +Alternatively, you can end the WebSocket call directly: + +```javascript +sendControlMessage({ type: "end-call" }); +socket.close(); +``` + +## Comparison: WebSocket Transport vs. Call Listen Feature + +Vapi provides two WebSocket options: + +| WebSocket Transport | Call Listen Feature | +|-------------------------------------|------------------------------------| +| Primary communication method | Secondary, monitoring-only channel | +| Bidirectional audio streaming | Unidirectional (listen-only) | +| Replaces phone/web as transport | Supplements existing calls | +| Uses `provider: "vapi.websocket"` | Accessed via `monitor.listenUrl` | + +Refer to [Live Call Control](/calls/call-features) for more on the Call Listen feature. + + +When using WebSocket transport, phone-based parameters (`phoneNumber` or `phoneNumberId`) are not permitted. These methods are mutually exclusive. + + diff --git a/fern/changelog/2024-10-09.mdx b/fern/changelog/2024-10-09.mdx index 239430db8..2d5ba66b3 100644 --- a/fern/changelog/2024-10-09.mdx +++ b/fern/changelog/2024-10-09.mdx @@ -1,3 +1,3 @@ -1. **Call Cost Information**: You can now use `call.costs[type=vapi].subType` to determine if a VAPI cost is `normal` or an `overage`. +1. **Call Cost Information**: You can now use `call.costs[type=vapi].subType` to determine if a Vapi cost is `normal` or an `overage`. 2. **Updated Billing Page**: Your payments are now returned inside a table with pages on the [billing page](https://dashboard.vapi.ai/org/billing). \ No newline at end of file diff --git a/fern/changelog/2025-01-05.mdx b/fern/changelog/2025-01-05.mdx new file mode 100644 index 000000000..7b1d1734b --- /dev/null +++ b/fern/changelog/2025-01-05.mdx @@ -0,0 +1,9 @@ +1. **New Transfer Plan Mode Added**: You can now include call summaries in the SIP header during blind transfers without assistant involvement with `blind-transfer-add-summary-to-sip-header` (a new `TransferPlan.mode` option). Doing so will make `ServerMessageStatusUpdate` include a `summary` when the call status is `forwarding` - which means you can access call summaries for real-time display or logging purposes in your SIP calls. + +2. **Azure Speech Transcription Support**: You can now specify a new property called `AzureSpeechTranscriber.language` in Azure's Speech-to-Text service to improve the accuracy of processing spoken input. + +3. **New Groq Model Available**: You can now use `'llama-3.3-70b-versatile'` in `GroqModel.model`. + + + + diff --git a/fern/changelog/2025-01-07.mdx b/fern/changelog/2025-01-07.mdx new file mode 100644 index 000000000..f59ed3fad --- /dev/null +++ b/fern/changelog/2025-01-07.mdx @@ -0,0 +1,9 @@ +# New Gemini 2.0 Models, Realtime Updates, and Configuration Options + +1. **New Gemini 2.0 Models**: You can now use two new models in `Assistant.model[model='GoogleModel']`: `gemini-2.0-flash-exp` and `gemini-2.0-flash-realtime-exp`, which give you access to the latest real-time capabilities and experimental features. + +2. **Support for Real-time Configuration with Gemini 2.0 Models**: Developers can now fine-tune real-time settings for the Gemini 2.0 Multimodal Live API using `Assistant.model[model='GoogleModel'].realtimeConfig`, enabling more control over text generation and speech output. + +3. **Customize Speech Output for Gemini Multimodal Live APIs**: You can now customize the assistant's voice using the `speechConfig` and `voiceConfig` properties, with options like `"Puck"`, `"Charon"`, and more. + +4. **Advanced Gemini Text Generation Parameters**: You can also tune advanced hyperparameters such as `topK`, `topP`, `presencePenalty`, and `frequencyPenalty` to control how the assistant generates responses, leading to more natural and dynamic conversations. \ No newline at end of file diff --git a/fern/changelog/2025-01-11.mdx b/fern/changelog/2025-01-11.mdx new file mode 100644 index 000000000..ace6a6ba2 --- /dev/null +++ b/fern/changelog/2025-01-11.mdx @@ -0,0 +1,98 @@ +1. **Integration of Smallest AI Voices**: Assistants can now utilize voices from Smallest AI by setting the voice provider to `Assistant.voice[provider="smallest-ai"]`, allowing selection from a variety of 25 preset voices and customization of voice attributes. + +2. **Support for DeepSeek Language Models**: Developers can now configure assistants to use DeepSeek LLMs by setting the `Assistant.model[provider="deep-seek"]` and `Assistant.model[model="deepseek-chat"]`. You can also specify custom credentials by passing the following payload: + +```json +{ + "credentials": [ + { + "provider": "deep-seek", + "apiKey": "YOUR_API_KEY", + "name": "YOUR_CREDENTIAL_NAME" + } + ], + "model": { + "provider": "deep-seek", + "model": "deepseek-chat" + } +} +``` + +3. **Additional Call Ended Reasons for DeepSeek and Cerebras**: New `Call.endedReason` have been added to handle specific DeepSeek and Cerebras call termination scenarios, allowing developers to better manage error handling. + +4. **New API Endpoint to Delete Logs**: A new `DELETE /logs` endpoint has been added, enabling developers to programmatically delete logs and manage log data. + +5. **Enhanced Call Transfer Options with SIP Verb**: You can now specify a `sipVerb` when defining a `TransferPlan` with `Assistant.model.tools[type=transferCall].destinations[type=sip].transferPlan` giving you the ability to specify the SIP verb (`refer` or `bye`) used during call transfers for greater control over call flow. + +6. **Azure Credentials and Blob Storage Support**: You can now configure Azure credentials with support for AzureCredential.service[service=blob_storage] service and use AzureBlobStorageBucketPlan withAzureCredential.bucketPlan, enabling you to store call artifacts directly in Azure Blob Storage. + +7. **Add Authentication Support for Azure OpenAI API Management with the 'Ocp-Apim-Subscription-Key' Header**: When configuring Azure OpenAI credentials, you can now include the AzureOpenAICredential.ocpApimSubscriptionKey to authenticate with Azure's OpenAI services for the API Management proxy in place of an API Key. + +8. **New CloudflareR2BucketPlan**: You can now use CloudflareR2BucketPlan to configure storage with Cloudflare R2 buckets, enabling you to store call artifacts directly. + +9. **Enhanced Credential Support**: It is now simpler to configure provider credentials in `Assistant.credentials`. Additionally, credentials can be overridden with `AssistantOverride.credentials` enables granular credential management per assistant. Our backend improvements add type safety and autocompletion for all supported credential types in the SDKs, making it easier to configure and maintain credentials for the following providers: + +- S3Credential +- GcpCredential +- XAiCredential +- GroqCredential +- LmntCredential +- MakeCredential +- AzureCredential +- TavusCredential +- GladiaCredential +- GoogleCredential +- OpenAICredential +- PlayHTCredential +- RimeAICredential +- RunpodCredential +- TrieveCredential +- TwilioCredential +- VonageCredential +- WebhookCredential +- AnyscaleCredential +- CartesiaCredential +- DeepgramCredential +- LangfuseCredential +- CerebrasCredential +- DeepSeekCredential +- AnthropicCredential +- CustomLLMCredential +- DeepInfraCredential +- SmallestAICredential +- AssemblyAICredential +- CloudflareCredential +- ElevenLabsCredential +- OpenRouterCredential +- TogetherAICredential +- AzureOpenAICredential +- ByoSipTrunkCredential +- GoHighLevelCredential +- InflectionAICredential +- PerplexityAICredential + +10. **Specify Type When Updating Tools, Blocks, Phone Numbers, and Knowledge Bases**: You should now specify the type in the request body when [updating tools](https://api.vapi.ai/api#/Tools/ToolController_update), [blocks](https://api.vapi.ai/api#/Blocks/BlockController_update), [phone numbers](https://api.vapi.ai/api#/Phone%20Numbers/PhoneNumberController_update), or [knowledge bases](https://api.vapi.ai/api#/Knowledge%20Base/KnowledgeBaseController_update) using the appropriate payload for each type. Specifying the type now provides type safety and autocompletion in the SDKs. Refer to [the schemas](https://api.vapi.ai/api) to see the expected payload for the following types: + +- UpdateBashToolDTO +- UpdateComputerToolDTO +- UpdateDtmfToolDTO +- UpdateEndCallToolDTO +- UpdateFunctionToolDTO +- UpdateGhlToolDTO +- UpdateMakeToolDTO +- UpdateOutputToolDTO +- UpdateTextEditorToolDTO +- UpdateTransferCallToolDTO +- BashToolWithToolCall +- ComputerToolWithToolCall +- TextEditorToolWithToolCall +- UpdateToolCallBlockDTO +- UpdateWorkflowBlockDTO +- UpdateConversationBlockDTO +- UpdateByoPhoneNumberDTO +- UpdateTwilioPhoneNumberDTO +- UpdateVonagePhoneNumberDTO +- UpdateVapiPhoneNumberDTO +- UpdateCustomKnowledgeBaseDTO +- UpdateTrieveKnowledgeBaseDTO + diff --git a/fern/changelog/2025-01-14.mdx b/fern/changelog/2025-01-14.mdx new file mode 100644 index 000000000..6f03b2ef8 --- /dev/null +++ b/fern/changelog/2025-01-14.mdx @@ -0,0 +1 @@ +**End Call Message Support in ClientInboundMessage**: Developers can now programmatically end a call by sending an `end-call` message type within `ClientInboundMessage`. To use this feature, include a message with the `type` property set to `"end-call"` when sending inbound messages to the client. \ No newline at end of file diff --git a/fern/changelog/2025-01-15.mdx b/fern/changelog/2025-01-15.mdx new file mode 100644 index 000000000..017124e6b --- /dev/null +++ b/fern/changelog/2025-01-15.mdx @@ -0,0 +1,5 @@ +1. **Updated Log Endpoints:** +Both the `GET /logs` and `DELETE /logs` endpoints have been simplified by removing the `orgId` parameter. + +2. **Updated Log Schema:** +The following fields in the Log schema are no longer required: `requestDurationSeconds`, `requestStartedAt`, `requestFinishedAt`, `requestBody`, `requestHttpMethod`, `requestUrl`, `requestPath`, and `responseHttpCode`. \ No newline at end of file diff --git a/fern/changelog/2025-01-20.mdx b/fern/changelog/2025-01-20.mdx new file mode 100644 index 000000000..3bd56344b --- /dev/null +++ b/fern/changelog/2025-01-20.mdx @@ -0,0 +1,16 @@ +# Workflow Steps, Trieve Knowledge Base Updates, and Concurrent Calls Tracking + +1. **Use Workflow Blocks to Simplify Blocks Steps:** You can now compose complicated Blocks steps with smaller, resuable [Workflow blocks](https://api.vapi.ai/api#:~:text=Workflow) that manage conversations and take actions in external systems. + +In addition to normal operations inside [Block steps](https://docs.vapi.ai/blocks/steps) - you can now [Say messages](https://api.vapi.ai/api#:~:text=Say), [Gather information](https://api.vapi.ai/api#:~:text=Gather), or connect to other workflow [Edges](https://api.vapi.ai/api#:~:text=Edge) based on a [LLM evaluating a condition](https://api.vapi.ai/api#:~:text=SemanticEdgeCondition), or a more [logic-based condition](https://api.vapi.ai/api#:~:text=ProgrammaticEdgeCondition). Workflows can be used through `Assistant.model["VapiModel"]` to create custom call workflows. + +2. **Trieve Knowledge Base Integration Improvements:** You should now configure [Trieve knowledge bases](https://api.vapi.ai/api#:~:text=TrieveKnowledgeBase) using the new `createPlan` and `searchPlan` fields instead of specifying the raw vector plans directly. The new plans allow you to create or import trieve plans directly, and specify the type of search more precisely than before. + +3. **Updated Concurrency Tracking:** Your subscriptions now track active calls with `concurrencyCounter`, replacing `concurrencyLimit`. This does not affect how you reserve concurrent calls through [billing add-ons](https://dashboard.vapi.ai/org/billing/add-ons). + + + + + +4. **Define Allowed Values with `type` using `JsonSchema`:** You can restrict model outputs to specific values inside Blocks or tool calls using the new `type` property in [JsonSchema](https://api.vapi.ai/api#:~:text=JsonSchema). Supported types include `string`, `number`, `integer`, `boolean`, `array` (which also needs `items` to be defined), and `object` (which also needs `properties` to be defined). + diff --git a/fern/changelog/2025-01-21.mdx b/fern/changelog/2025-01-21.mdx new file mode 100644 index 000000000..a5df2257c --- /dev/null +++ b/fern/changelog/2025-01-21.mdx @@ -0,0 +1,7 @@ +# Updated Azure Regions for Credentials + +1. **Updated Azure Regions for Credentials**: You can now specify `canadacentral`, `japaneast`, and `japanwest` as valid regions when specifying your Azure credentials. Additionally, the region `canada` has been renamed to `canadaeast`, and `japan` has been replaced with `japaneast` and `japanwest`; please update your configurations accordingly. + + + + diff --git a/fern/changelog/2025-01-22.mdx b/fern/changelog/2025-01-22.mdx new file mode 100644 index 000000000..eb07492e8 --- /dev/null +++ b/fern/changelog/2025-01-22.mdx @@ -0,0 +1,8 @@ +# Tool Calling Updates, Final Transcripts, and DeepSeek Reasoner +1. **Migrate `ToolCallFunction` to `ToolCall`**: You should update your client and server tool calling code to use the [`ToolCall` schema](https://api.vapi.ai/api#:~:text=ToolCall) instead of `ToolCallFunction`, which includes properties like `name`, `tool`, and `toolBody` for more detailed tool call specifications. ToolCallFunction has been removed. + +2. **Include `ToolCall` Nodes in Workflows**: You can now incorporate [`ToolCall` nodes](https://api.vapi.ai/api#:~:text=ToolCall) directly into workflow block steps, enabling tools to be invoked as part of the workflow execution. + +3. **New Model Option `deepseek-reasoner`**: You can now select `deepseek-reasoner` as a model option inside your assistants with `Assistant.model["deep-seek"].model["deepseek-reasoner"]`, offering enhanced reasoning capabilities for your applications. + +4. **Support for Final Transcripts in Server Messages**: The API now supports `'transcript[transcriptType="final"]'` in server messages, allowing your application to handle and process end of conversation transcripts. \ No newline at end of file diff --git a/fern/changelog/2025-01-29.mdx b/fern/changelog/2025-01-29.mdx new file mode 100644 index 000000000..f1613df8e --- /dev/null +++ b/fern/changelog/2025-01-29.mdx @@ -0,0 +1,20 @@ +# New workflow nodes, improved call handling, better phone number management, and expanded tool calling capabilities + +1. **New Hangup Workflow Node**: You can now include a [`Hangup`](https://api.vapi.ai/api#:~:text=Hangup) node in your workflows to end calls programmatically. + +2. **New HttpRequest Workflow Node**: Workflows can now make HTTP requests using the new [`HttpRequest`](https://api.vapi.ai/api#:~:text=HttpRequest) node, enabling integration with external APIs during workflow execution. + +3. **Updates to Tool Calls**: The [`ToolCall`](https://api.vapi.ai/api#:~:text=ToolCall) schema has been revamped; you should update your tool calls to use the new `function` property with `id` and `function` details (instead of older `tool` and `toolBody` properties). + +4. **Improvements to [Say](https://api.vapi.ai/api#:~:text=Say), [Edge](https://api.vapi.ai/api#:~:text=Edge), [Gather](https://api.vapi.ai/api#:~:text=Gather), and [Workflow](https://api.vapi.ai/api#:~:text=Workflow) Nodes**: +- The `name`, `to`, and `from` properties in these nodes now support up to 80 characters, letting you use more descriptive identifiers. +- A `metadata` property has been added to these nodes, allowing you to store additional information. +- The [`Gather`](https://api.vapi.ai/api#:~:text=Gather) node now supports a `confirmContent` option to confirm collected data with users. + +5. **Regex Validation with Json Outputs**: You can now validate inputs and outputs from your conversations, tool calls, and OpenAI structured outputs against regular expressions using the `regex` property in [`JSON outputs`](https://api.vapi.ai/api#:~:text=JsonSchema) node. + +6. **New Assistant Transfer Mode**: A new [transfer mode](https://api.vapi.ai/api#:~:text=TransferPlan) `swap-system-message-in-history-and-remove-transfer-tool-messages` allows more control over conversation history during assistant transfers. + +7. **Area Code Selection for Vapi Phone Numbers**: You can now specify a desired area code when creating Vapi phone numbers using `numberDesiredAreaCode`. + +8. **Chat Completions Support**: You can now handle chat messages and their metadata within your applications using familiar chat completion messages in your workflow nodes. diff --git a/fern/changelog/2025-02-01.mdx b/fern/changelog/2025-02-01.mdx new file mode 100644 index 000000000..a2930abb3 --- /dev/null +++ b/fern/changelog/2025-02-01.mdx @@ -0,0 +1,25 @@ +# API Request Node, Improved Retries, and Enhanced Message Controls + +1. **HttpRequest Node Renamed to ApiRequest**: The `HttpRequest` workflow node has been renamed to [`ApiRequest`](https://api.vapi.ai/api#:~:text=ApiRequest), and can be accessed through `Assistant.model.workflow.nodes[type="api-request"]`. Key changes: + - New support for POST requests with customizable headers and body + - New async request support with `isAsync` flag + - Task status messages for waiting, starting, failure and success states +The `HttpRequest` node is now deprecated and will be removed in a future release. Please migrate to the new `ApiRequest` node. + +2. **New Backoff and Retry Controls**: You can now configure [`Assistant.model.tools[type=dtmf].server.backoffPlan`](https://api.vapi.ai/api#:~:text=BackoffPlan) to handle failed requests with customizable retry strategies and delays. + - Supports fixed or exponential backoff strategies + - Configure `maxRetries` (up to 10) and `baseDelaySeconds` (up to 10 seconds) + - Available in server configurations via `backoffPlan` property + +3. **Enhanced Gather Node**: The [`Assistant.model.workflow.nodes[type=gather]`](https://api.vapi.ai/api#:~:text=Gather) node has been improved with the following changes: + - Added `maxRetries` property to control retry attempts + - Now accepts a single JsonSchema instead of an array + - Removed default value for `confirmContent` property + +4. **Improved Message Controls**: [`Assistant.messagePlan`](https://api.vapi.ai/api#:~:text=MessagePlan) has been improved with the following changes: + - Increased `idleTimeoutSeconds` maximum from 30 to 60 seconds + - Added `silenceTimeoutMessage` to customize call ending due to silence + +5. **New Distilled Deepseek Model with Groq**: You can now select `deepseek-r1-distill-llama-70b` when using [Groq](https://api.vapi.ai/api#:~:text=Groq) as the provider in [`Assistant.model[provider='groq']`](https://api.vapi.ai/api#:~:text=UpdateCallDTO-,Assistant,-UpdateAssistantDTO) + +6. **Edge Condition Updates**: Edge conditions now require explicit matching criteria to improve workflow control and readability. Semantic edges must specify a `matches` property while programmatic edges require a `booleanExpression` property to define transition logic. diff --git a/fern/changelog/2025-02-04.md b/fern/changelog/2025-02-04.md new file mode 100644 index 000000000..2e51c9944 --- /dev/null +++ b/fern/changelog/2025-02-04.md @@ -0,0 +1,8 @@ +# Hooks, PCI Compliance, and Blocking Messages + +1. **Introduction of `Hook`s in Workflows**: You can now use [`Hooks`](https://api.vapi.ai/api#:~:text=Hook) in your workflows to automatically execute actions when specific events occur, like task start or confirmation. Hooks are now available in [`ApiRequest`](https://api.vapi.ai/api#:~:text=ApiRequest) and [`Gather`](https://api.vapi.ai/api#:~:text=Gather) workflow nodes. + +2. **Make your Assistant PCI Compliant**: You can now configure [`Assistant.pciEnabled`](https://api.vapi.ai/api#:~:text=UpdateCallDTO-,Assistant,-UpdateAssistantDTO) to indicate if your assistant deals with sensitive cardholder data that requires PCI compliance, helping you meet security standards for financial information. + +3. **Blocking Messages before Tool Calls**: You can now configure your tool calls to wait until a message is fully spoken before starting with [`ToolMessageStart.blocking=true`](https://api.vapi.ai/api#:~:text=ToolMessageStart) (default is `false`). + diff --git a/fern/changelog/2025-02-10.mdx b/fern/changelog/2025-02-10.mdx new file mode 100644 index 000000000..1e7b313eb --- /dev/null +++ b/fern/changelog/2025-02-10.mdx @@ -0,0 +1,35 @@ +# API Enhancements, Call Features, and Workflow Improvements + +1. **`POST` requests to `/analytics` (migrate from `GET`)**: You should now make `POST` requests (instead of `GET`) to the [`/analytics`](https://api.vapi.ai/api#/Analytics/AnalyticsController_query) endpoint. Structure your analytics query as a JSON payload using [`AnalyticsQuery`](https://api.vapi.ai/api#/Analytics/AnalyticsQuery) in the request body. + +2. **Use `SayHook` to Intercept and Modify Text for Assistant Speech**: You can use [`SayHook`](https://api.vapi.ai/api#/Hooks/SayHook) to intercept and modify text before it's spoken by your assistant. Specify the text to be spoken using the `exact` or `prompt` properties. + +3. **Call Transfer Support**: The `Transfer` node type is now available in workflows. Configure the `destination` property to define the transfer target. + +4. **Workflow Edge Condition Updates**: [`AIEdgeCondition`](https://api.vapi.ai/api#:~:text=AIEdgeCondition) (which replaces `SemanticEdgeCondition`) enables AI-powered routing decisions by analyzing conversation context and intent, while [`LogicEdgeCondition`](https://api.vapi.ai/api#:~:text=LogicEdgeCondition) (which replaces `ProgrammaticEdgeCondition`) allows for rule-based routing using custom logical expressions. The previous `SemanticEdgeCondition` and `ProgrammaticEdgeCondition` are now deprecated, and a new `FailedEdgeCondition` has been added to handle node failures in workflows. + +5. **`Gather` Node: Data Collection Refactor**: The [`Gather` node](https://api.vapi.ai/api#:~:text=Gather) now requires an `output` property to define the expected data schema. The `instruction` and `schema` properties have been removed. + +6. **Call Packet Capture (PCAP) Configuration**: Your call [`Artifact`](https://api.vapi.ai/api#:~:text=Artifact)s now support links to download a call's network packet capture (PCAP) file, providing you with detailed network traffic analysis and troubleshooting for calls. PCAP is only supported by `vapi` and `byo-phone-number` providers. Enable PCAP through `pcapEnabled`, automatically upload to S3 bucket with `pcapS3PathPrefix`, and access via `pcapUrl`. + +7. **`ApiRequest` Node Improvements**: [`ApiRequest`](https://api.vapi.ai/api#:~:text=ApiRequest) now supports `GET` requests. You can also define the expected response schema. You can make API requests as `blocking` or run in the `background` with `ApiRequest.mode`. + +8. **`Call` and `ServerMessage` `endedReason` Updates**: The `assistant-not-invalid` `Call.endedReason` has been corrected to `"assistant-not-valid"`. Also added `"assistant-ended-call-with-hangup-task"` to the `Call.endedReason`. + +9. **New Azure OpenAI Model `gpt-4o-2024-08-06-ptu`**: You can now use `gpt-4o-2024-08-06-ptu` from Azure OpenAI inside your [Assistant](https://dashboard.vapi.ai/assistants/2ec63711-f867-4066-8c54-7833346783b1). + + + Azure OpenAI Model GPT-4o-2024-08-06-ptu + + + +10. **Deprecated Schemas and Properties**: The following properties and schemas are now deprecated in the [API reference](https://api.vapi.ai/api/): + * `SemanticEdgeCondition` + * `ProgrammaticEdgeCondition` + * `Workflow.type` + * `ApiRequest.waitTaskMessage` + * `ApiRequest.startTaskMessage` + * `ApiRequest.failureTaskMessage` + * `ApiRequest.successTaskMessage` + * `OpenAIModel.semanticCachingEnabled` + * `CreateWorkflowDTO.type` diff --git a/fern/changelog/2025-02-17.mdx b/fern/changelog/2025-02-17.mdx new file mode 100644 index 000000000..df4d03749 --- /dev/null +++ b/fern/changelog/2025-02-17.mdx @@ -0,0 +1,66 @@ +## What's New + +### Compliance & Security Enhancements +- **New [CompliancePlan](https://api.vapi.ai/api#:~:text=CompliancePlan) Consolidates HIPAA and PCI Compliance Settings**: You should now enable HIPAA and PCI compliance settings with `Assistant.compliancePlan.hipaaEnabled` and `Assistant.compliancePlan.pciEnabled` which both default to `false` (replacing the old HIPAA and PCI flags on `Assistant` and `AssistantOverrides`). + +- **Phone Number Status Tracking**: You can now view your phone number `status` with `GET /phone-number/{id}` for all phone number types ([Bring Your Own Number](https://api.vapi.ai/api#:~:text=ByoPhoneNumber), [Vapi](https://api.vapi.ai/api#:~:text=VapiPhoneNumber), [Twilio](https://api.vapi.ai/api#:~:text=TwilioPhoneNumber), [Vonage](https://api.vapi.ai/api#:~:text=VonagePhoneNumber)) for better monitoring. + +### Advanced Call Control + +- **Assistant Hooks System**: You can now use [`AssistantHooks`](https://api.vapi.ai/api#:~:text=AssistantHooks) to support `call.ending` events with customizable filters and actions + - Enable transfer actions through [`TransferAssistantHookAction`](https://api.vapi.ai/api#:~:text=TransferAssistantHookAction). For example: +```javascript +{ + "hooks": [{ + "on": "call.ending", + "do": [{ + "type": "transfer", + "destination": { + // Your transfer configuration + } + }] + }] +} +``` + + - Conditionally execute hooks with `Assistant.hooks.filter`. For example, trigger different hooks for call completed, system errors, or customer hangup / transfer: + +```json +{ + "assistant": { + "hooks": [{ + "filters": [{ + "type": "oneOf", + "key": "call.endedReason", + "oneOf": ["pipeline-error-custom-llm-500-server-error", "pipeline-error-custom-llm-llm-failed"] + }] + } + ] + } +} +``` + +### Model & Voice Updates + +- **New Models Added**: You can now use new models inside `Assistant.model[provider="google", "openai", "xai"]` and `Assistant.fallbackModels[provider="google", "openai", "xai"]` + - Google: Gemini 2.0 series (`flash-thinking-exp`, `pro-exp-02-05`, `flash`, `flash-lite-preview`) + - OpenAI: o3 mini `o3-mini` + - xAI: Grok 2 `grok-2` + + + New Assistant Models + + +- **New `PlayDialog` Model for [PlayHT Voices](https://api.vapi.ai/api#:~:text=PlayHTVoice)**: You can now use the `PlayDialog` model in `Assistant.voice[provider="playht"].model["PlayDialog"]`. + +- **New `nova-3` and `nova-3-general` Models for [Deepgram Transcriber](https://api.vapi.ai/api#:~:text=DeepgramTranscriber)**: You can now use the `nova-3` and `nova-3-general` models in `Assistant.transcriber[provider="deepgram"].model["nova-3", "nova-3-general"]` + +### API Improvements + +- **Workflow Updates**: You can now send a [`workflow.node.started`](https://api.vapi.ai/api#:~:text=ClientMessageWorkflowNodeStarted) message to track the start of a workflow node for better call flow tracking + +- **Analytics Enhancement**: Added subscription table and concurrency columns in [POST /analytics](https://api.vapi.ai/api#/Analytics/AnalyticsController_query) for richer queries about your subscriptions and concurrent calls. + +### Deprecations + +The `/logs` endpoints are now marked as deprecated - plan to update your implementation accordingly. diff --git a/fern/changelog/2025-02-20.mdx b/fern/changelog/2025-02-20.mdx new file mode 100644 index 000000000..f98e323f9 --- /dev/null +++ b/fern/changelog/2025-02-20.mdx @@ -0,0 +1,25 @@ +## What's New +1. **Configure 16 text normalization processors in [FormatPlan](https://api.vapi.ai/api#:~:text=FormatPlan)**: You can now control how text is transcribed and spoken for currency, dates, etc. by setting the `formattersEnabled` array in `Assistant.voice.chunkPlan.formatPlan` (not specifying `formattersEnabled` defaults to all formatters being enabled). See all available formatters in the [FormatPlan.formattersEnabled reference](https://api.vapi.ai/api#:~:text=FormatPlan). + +2. **Deepgram [Keyterm Prompting](https://developers.deepgram.com/docs/keyterm)**: The `keyterm` array in [DeepgramTranscriber](https://api.vapi.ai/api#:~:text=DeepgramTranscriber) implements Deepgram's [Keyterm Prompting](https://developers.deepgram.com/docs/keyterm) technology, boosting recall for domain-specific terminology. Compared to the existing `keywords` field: + +| Feature | `keywords` | `keyterm` | +|------------------|--------------------|--------------------| +| Recall Boost | 15-20% | Up to 90% | +| Format | Word:Weight | Raw phrases | +| Use Case | General vocabulary | Critical terms | + +You should reserve `keyterm` for compliance-sensitive terms like medical codes while using `keywords` for proper nouns / brand names. + +3. **Subscription usage tracking improvements**: The `minutesUsedNextResetAt` timestamp now appears in all subscription tiers (not just enterprise), exposed at `subscription.minutesUsedNextResetAt` for predictable billing cycle integration. Combine with existing `minutesUsed` and `minutesIncluded` metrics to build custom usage dashboards, regardless of subscription tier. + +4. **Neuphonic voice synthesis**: You can now configure Neuphonic as a voice provider with `Assistant.voice[provider="neuphonic"]`. Handle appropriate errors with `pipeline-error-neuphonic-voice-failed`. Test latency thresholds as Neuphonic requires 200ms additional processing time compared to ElevenLabs. + + + Neuphonic Voice Synthesis + + +5. **Support for pre-transfer announcements in [ClientInboundMessageTransfer](https://api.vapi.ai/api#:~:text=ClientInboundMessageTransfer)**: The `content` field in `ClientInboundMessageTransfer` now supports pre-transfer announcements ("Connecting you to billing...") before SIP/number routing. Implement via WebSocket messages using type: "transfer" with destination object. + +### Deprecation Notice +**OrgWithOrgUser** is now deprecated, and impacts endpoints returning organization-user composites. This has been replaced with separate [`Org`](https://api.vapi.ai/api#:~:text=Org) and [`User`](https://api.vapi.ai/api#:~:text=User) schemas for better clarity and consistency. \ No newline at end of file diff --git a/fern/changelog/2025-02-25.mdx b/fern/changelog/2025-02-25.mdx new file mode 100644 index 000000000..be8964c3d --- /dev/null +++ b/fern/changelog/2025-02-25.mdx @@ -0,0 +1,54 @@ +## Test Suite APIs, Enhanced Call Transfers, Voice Model Enhancements + +1. **Introducing Test Suite Management APIs:** You can now test your assistant conversations before deploying them by creating [end-to-end tests](https://docs.vapi.ai/test/voice-testing#step-1-create-a-new-test-suite), [adding test cases](https://docs.vapi.ai/test/voice-testing#step-3-add-test-cases), and [running and reviewing test suites](https://docs.vapi.ai/test/voice-testing#step-5-run-and-review-tests). You can configure these tests through the [Test Suites dashboard page](https://dashboard.vapi.ai/test-suites) and [Test Suite APIs](https://docs.vapi.ai/api-reference/test-suites/test-suite-controller-find-all-paginated), and learn more in the [docs](https://docs.vapi.ai/test/voice-testing). + + + Test Suite Management APIs + + + +2. **Enhanced Call Transfers with TwiML Control:** You can now use `twiml` ([Twilio Markup Language](https://www.twilio.com/docs/voice/twiml)) in [`Assistant.model.tools[type=transferCall].destinations[].transferPlan[mode=warm-transfer-twiml]`](https://api.vapi.ai/api#:~:text=TransferPlan) to execute TwiML instructions before connecting the call, allowing for pre-transfer announcements or data collection with Twilio. + +3. **New Voice Models and Experimental Controls:** + * **`mistv2` Rime AI Voice:** You can now use the `mistv2` model in [`Assistant.voice[provider="rime-ai"].model[model="mistv2"]`](https://api.vapi.ai/api#:~:text=RimeAIVoice). + * **OpenAI Models:** You can now use `chatgpt-4o-latest` model in [`Assistant.model[provider="openai"].model[model="chatgpt-4o-latest"]`](https://api.vapi.ai/api#:~:text=OpenAIModel). + +4. **Experimental Controls for Cartesia Voices:** You can now specify your Cartesia voice speed (string) and emotional range (array) with [`Assistant.voice[provider="cartesia"].experimentalControls`](https://api.vapi.ai/api#:~:text=CartesiaExperimentalControls). For example: + +```json +{ + "speed": "fast", + "emotion": [ + "anger:lowest", + "curiosity:high" + ] +} +``` + +| Property | Option | +|----------|--------| +| speed | slowest | +| | slow | +| | normal (default) | +| | fast | +| | fastest | +| emotion | anger:lowest | +| | anger:low | +| | anger:high | +| | anger:highest | +| | positivity:lowest | +| | positivity:low | +| | positivity:high | +| | positivity:highest | +| | surprise:lowest | +| | surprise:low | +| | surprise:high | +| | surprise:highest | +| | sadness:lowest | +| | sadness:low | +| | sadness:high | +| | sadness:highest | +| | curiosity:lowest | +| | curiosity:low | +| | curiosity:high | +| | curiosity:highest | diff --git a/fern/changelog/2025-02-27.mdx b/fern/changelog/2025-02-27.mdx new file mode 100644 index 000000000..27a6b6c50 --- /dev/null +++ b/fern/changelog/2025-02-27.mdx @@ -0,0 +1,49 @@ +# Phone Keypad Input Support, OAuth2 and Analytics Improvements + +1. **Keypad Input Support for Phone Calls:** A new [`keypadInputPlan`](https://api.vapi.ai/api#:~:text=KeypadInputPlan) feature has been added to enable handling of DTMF (touch-tone) keypad inputs during phone calls. This allows your voice assistant to collect numeric input from callers, like account numbers, menu selections, or confirmation codes. + +Configuration options: +```json +{ + "keypadInputPlan": { + "enabled": true, // Default: false + "delimiters": ["#"], // Options: ["#"], ["*"], [""] + "timeoutSeconds": 2 // Range: 0.5-10 seconds, Default: 2 + } +} +``` + +The feature can be configured in: +- `assistant.keypadInputPlan` +- `call.squad.members.assistant.keypadInputPlan` +- `call.squad.members.assistantOverrides.keypadInputPlan` + +2. **OAuth2 Authentication Enhancement:** The [`OAuth2AuthenticationPlan`](https://api.vapi.ai/api#:~:text=OAuth2AuthenticationPlan) now includes a `scope` property to specify access scopes when authenticating. This allows more granular control over permissions when integrating with OAuth2-based services. + +```json +{ + "credentials": [ + { + "authenticationPlan": { + "type": "oauth2", + "url": "https://example.com/oauth2/token", + "clientId": "your-client-id", + "clientSecret": "your-client-secret", + "scope": "read:data" // New property, max length: 1000 characters + } + } + ] +} +``` + +The scope property can be configured at: +- `assistant.credentials.authenticationPlan` +- `call.squad.members.assistant.credentials.authenticationPlan` + +3. **New Analytics Metric: Minutes Used** The [`AnalyticsOperation`](https://api.vapi.ai/api#:~:text=AnalyticsOperation) schema now includes a new column option: `minutesUsed`. This metric allows you to track and analyze the duration of calls in your usage reports and analytics dashboards. + + +4. **Removed TrieveKnowledgeBaseCreate Schema:** Removed `TrieveKnowledgeBaseCreate` schema from +- `TrieveKnowledgeBase.createPlan` +- `CreateTrieveKnowledgeBaseDTO.createPlan` +- `UpdateTrieveKnowledgeBaseDTO.createPlan` diff --git a/fern/changelog/2025-03-02.mdx b/fern/changelog/2025-03-02.mdx new file mode 100644 index 000000000..ca8e42a48 --- /dev/null +++ b/fern/changelog/2025-03-02.mdx @@ -0,0 +1,49 @@ +## Claude 3.7 Sonnet and GPT 4.5 preview, New Hume AI Voice Provider, New Supabase Storage Provider, Enhanced Call Transfer Options + +1. **Claude 3.7 Sonnet with Thinking Configuration Support**: +You can now use the latest claude-3-7-sonnet-20250219 model with a new "thinking" feature via the [`AnthropicThinkingConfig`](https://api.vapi.ai/api#:~:text=AnthropicThinkingConfig) schema. +Configure it in `assistant.model` or `call.squad.members.assistant.model`: +```json +{ + "model": "claude-3-7-sonnet-20250219", + "provider": "anthropic", + "thinking": { + "type": "enabled", + "budgetTokens": 5000 // min 1024, max 100000 + } +} +``` + +2. **OpenAI GPT-4.5-Preview Support**: +You can now use the latest gpt-4.5-preview model as a primary model or fallback option via the [`OpenAIModel`](https://api.vapi.ai/api#:~:text=OpenAIModel) schema. +Configure it in `assistant.model` or `call.squad.members.assistant.model`: +```json +{ + "model": "gpt-4.5-preview", + "provider": "openai" +} +``` + +3. **New Hume Voice Provider**: +Integrated Hume AI as a new voice provider with the "octave" model for text-to-speech synthesis. + + + Hume Voice Provider + + +4. **Supabase Storage Integration**: +New Supabase S3-compatible storage support for file operations. This integration lets developers configure buckets and paths across 16 regions, enabling structured file storage with proper authentication. +Configure [`SupabaseBucketPlan`](https://api.vapi.ai/api#:~:text=SupabaseBucketPlan) in `assistant.credentials.bucketPlan`,`call.squad.members.assistant.credentials.bucketPlan` + +5. **Voice Speed Control** +Added a speed parameter to ElevenLabs voices ranging from 0.7 (slower) to 1.2 (faster) [`ElevenLabsVoice`](https://api.vapi.ai/api#:~:text=ElevenLabsVoice). This enhancement gives developers more control over speech cadence for more natural-sounding conversations. + +6. **Enhanced Call Transfer Options in TransferPlan** +Added a new dial option to the sipVerb parameter for call transfers. This complements the existing refer (default) and bye options, providing more flexibility in call handling. +- 'dial': Uses SIP DIAL to transfer the call + +7. **Zero-Value Minumum Subscription Minutes** +Changed the minimum value for minutesUsed and minutesIncluded from 1 to 0. This supports tracking of new subscriptions and free tiers with no included minutes. + +8. **Zero-Value Minimum KeypadInputPlan Timeout** +Adjusted the KeypadInputPlan.timeoutSeconds minimum from 0.5 to 0. diff --git a/fern/changelog/2025-03-06.mdx b/fern/changelog/2025-03-06.mdx new file mode 100644 index 000000000..a7d98d4c2 --- /dev/null +++ b/fern/changelog/2025-03-06.mdx @@ -0,0 +1,62 @@ +## New Query Tool and Vapi Voice Provider, Updates to Language Support and Error Handling + +1. **New Query Tool Feature and Knowledge Base Integration** + +* The API now supports a new query tool that allows assistants to search through knowledge bases. Add this tool to any assistant model by configuring it at `assistant.model.tools[type=query]` path. +* You can now link knowledge bases to query tools, providing structured information sources for assistants to access. Define knowledge bases with a name, model, provider, description, and associated file IDs. + + +```json +{ + "type": "query", + "async": false, + "server": { + "url": "https://api.example.com/query-handler" + }, + "function": { + "name": "query_knowledge", + "description": "Query knowledge bases for information", + "parameters": { + "type": "object", + "properties": { + "query": { + "type": "string", + "description": "The query to search for" + } + }, + "required": ["query"] + } + }, + "knowledgeBases": [ + { + "name": "Product Documentation", + "model": "gemini-1.5-flash", + "provider": "google", + "description": "Contains all product manuals", + "fileIds": ["file-123", "file-456"] + } + ] +} +``` + + + +2. **New Voice Provider Support** + +A new voice provider "vapi" has been added with support for a voice called "Jordan" in [`FallbackVapiVoice`](https://api.vapi.ai/api#:~:text=FallbackVapiVoice). Configure it in our assistant fallback plans at `assistant.voice.fallbackPlan.voices`. + + + Vapi Voice Provider + + +3. **Language Support Updates** + +Myanmar language ("my") has been added to supported languages, while "jp" and "mymr" codes have been removed. Use "ja" for Japanese language and "my" for Myanmar. Reference [`GladiaTranscriber`](https://api.vapi.ai/api#:~:text=GladiaTranscriber) for more language codes. + +4. **Error Handling Improvements** + +Added new error code `pipeline-error-11labs-transcriber-failed` for `ServerMessageStatusUpdate.endedReason` and `ServerMessageEndOfCallReport.endedReason`. Also added an explicit `failed` status for test suite runs in [`TestSuiteRun`](https://api.vapi.ai/api#:~:text=TestSuiteRun). These additions provide more detailed error reporting. + +5. **Azure OpenAI Model Update** + +The model `gpt-4o-2024-08-06-ptu` has been removed from Azure OpenAI credential schemas. Update any credential configurations that were using this model. \ No newline at end of file diff --git a/fern/changelog/2025-03-09.mdx b/fern/changelog/2025-03-09.mdx new file mode 100644 index 000000000..273d7feba --- /dev/null +++ b/fern/changelog/2025-03-09.mdx @@ -0,0 +1,66 @@ +## Enhanced Voicemail Detection, File Processing, Knowledge Base Integration, and Invoicing Updates + +1. **Track Voicemail Detection Cost, Configure Google and Twilio Voicemail Detection Plans** + +* You can now configure provider-specific settings and track voicemail detection costs through the new `VoicemailDetectionCost` schema at `call.costs[type=voicemail-detection]`. +* Configure Google or Twilio voicemail detection settings using the new [`GoogleVoicemailDetectionPlan`](https://api.vapi.ai/api#:~:text=GoogleVoicemailDetectionPlan) and [`TwilioVoicemailDetectionPlan`](https://api.vapi.ai/api#:~:text=TwilioVoicemailDetectionPlan) schemas. + +```json +// Google configuration example +{ + "provider": "google", + "voicemailExpectedDurationSeconds": 15 // Range: 5-60 seconds +} +``` + +```json +// Twilio configuration example +{ + "provider": "twilio", + "enabled": true, + "machineDetectionTimeout": 30, // Range: 3-59 seconds + "voicemailDetectionTypes": ["machine_end_beep", "machine_end_silence"] +} +``` + +2. **Improved File Processing Statuses and Parsed Text Content** + +* File processing statuses have been renamed to better reflect their purpose: `processing` → `done` → `failed`. +* Two new properties have been added to the [`File`](https://api.vapi.ai/api#:~:text=File) schema: `parsedTextUrl` and `parsedTextBytes`, providing direct access to parsed text content from processed files. + +3. **Google Gemini Models for Knowledge Base Integration** + +* The [`KnowledgeBase`](https://api.vapi.ai/api#:~:text=KnowledgeBase) schema now fully supports Google's Gemini models with specific model options. +* You can use Gemini models in your knowledge bases at `assistant.model.tools[type=query].knowledgeBases`. + +```json +"model": { + "enum": [ + "gemini-2.0-flash-thinking-exp", + "gemini-2.0-pro-exp-02-05", + "gemini-2.0-flash", + "gemini-2.0-flash-lite-preview-02-05", + "gemini-2.0-flash-exp", + "gemini-2.0-flash-realtime-exp", + "gemini-1.5-flash", + "gemini-1.5-flash-002", + "gemini-1.5-pro", + "gemini-1.5-pro-002", + "gemini-1.0-pro" + ] +} +``` + +4. **New Invoicing Features** + +* You can now use [`InvoicePlan`](https://api.vapi.ai/api#:~:text=InvoicePlan) schema for customizing invoice information with company details. +* This can be accessed via the new `invoicePlan` property on the [`Subscription`](https://api.vapi.ai/api#:~:text=Subscription) schema. +* Customize company name, email, tax ID, and address for your invoices. + +5. **Additional Voice Options** + +* Five new voice options have been added to the [`FallbackVapiVoice`](https://api.vapi.ai/api#:~:text=FallbackVapiVoice) schema: `Adi`, `Julia`, `Maibri (Web)`, `Maibri (Phone)`, and `Ashley`. +* Configure these voices in your assistant fallback plans at `assistant.voice.fallbackPlan.voices`. + + Additional Vapi Voices + \ No newline at end of file diff --git a/fern/changelog/2025-03-13.mdx b/fern/changelog/2025-03-13.mdx new file mode 100644 index 000000000..007373425 --- /dev/null +++ b/fern/changelog/2025-03-13.mdx @@ -0,0 +1,103 @@ +## New Workflows API, Telnyx Phone Number Support, Voice Options, and much more + +1. **Workflows Replace Blocks**: The API has migrated from blocks to workflows with new `/workflow` endpoints. [Introduction to Workflows](https://docs.vapi.ai/workflows) +You can now use [`UpdateWorkflowDTO`](https://api.vapi.ai/api#:~:text=UpdateWorkflowDTO) where conversation components (`Say`, `Gather`, `ApiRequest`, `Hangup`, `Transfer` nodes) are explicitly connected via edges to create directed conversation flows. + + + ```json + { + "name": "Customer Support Workflow", + "nodes": [ + { + "id": "greeting", + "type": "Say", + "text": "Hello, welcome to customer support. Do you need help with billing or technical issues?" + }, + { + "id": "menu", + "type": "Gather", + "options": ["billing", "technical", "other"] + }, + { + "id": "billing", + "type": "Say", + "text": "I'll connect you with our billing department." + }, + { + "id": "technical", + "type": "Say", + "text": "I'll connect you with our technical support team." + }, + { + "id": "transfer_billing", + "type": "Transfer", + "destination": { + "type": "number", + "number": "+1234567890" + } + }, + { + "id": "transfer_technical", + "type": "Transfer", + "destination": { + "type": "number", + "number": "+1987654321" + } + } + ], + "edges": [ + { + "from": "greeting", + "to": "menu" + }, + { + "from": "menu", + "to": "billing", + "condition": { + "type": "logic", + "liquid": "{% if input == 'billing' %} true {% endif %}" + } + }, + { + "from": "menu", + "to": "technical", + "condition": { + "type": "logic", + "liquid": "{% if input == 'technical' %} true {% endif %}" + } + }, + { + "from": "billing", + "to": "transfer_billing" + }, + { + "from": "technical", + "to": "transfer_technical" + } + ] + } + ``` + + +2. **Telnyx Phone Number Support**: Telnyx is now available as a phone number provider alongside Twilio and Vonage. + - Use the [`TelnyxPhoneNumber`](https://api.vapi.ai/api#:~:text=TelnyxPhoneNumber), [`CreateTelnyxPhoneNumberDTO`](https://api.vapi.ai/api#:~:text=CreateTelnyxPhoneNumberDTO), and [`UpdateTelnyxPhoneNumberDTO`](https://api.vapi.ai/api#:~:text=UpdateTelnyxPhoneNumberDTO) schemas with [`/phone-number`](https://api.vapi.ai/api#/Phone%20Numbers) endpoints to create and update Telnyx phone numbers. + - The `Call.phoneCallProviderId` now includes Telnyx's `callControlId` alongside Twilio's `callSid` and Vonage's `conversationUuid`. + +3. **New Voice Options**: + - **Vapi Voices**: New Vapi voices - `Elliot`, `Rohan`, `Lily`, `Savannah`, and `Hana` + - **Hume Voice**: New provider with `octave` model and customizable voice settings + - **Neuphonic Voice**: New provider with `neu_hq` (higher quality) and `neu_fast` (faster) models + +4. **New Cerebras Model**: [`CerebrasModel`](https://api.vapi.ai/api#:~:text=CerebrasModel) Supports `llama3.1-8b` and `llama-3.3-70b` models + +5. **Enhanced Transcription**: + - **New Providers**: [ElevenLabs](https://api.vapi.ai/api#:~:text=ElevenLabsTranscriber) and [Speechmatics](https://api.vapi.ai/api#:~:text=SpeechmaticsTranscriber) transcribers now available. + - **DeepgramTranscriber Numerals**: New `numerals` option converts spoken numbers to digits (e.g., "nine-seven-two" → "972") + +6. **Improved Voicemail Detection**: You can now use multiple provider implementations for `assistant.voicemailDetection` (Google, OpenAI, Twilio). OpenAI implementation allows configuring detection duration (5-60 seconds, default: 15). + +7. **Smart Endpointing Upgrade**: Now supports LiveKit as an alternative to Vapi's custom-trained model in [`StartSpeakingPlan.smartEndpointingEnabled`](https://api.vapi.ai/api#:~:text=StartSpeakingPlan). LiveKit only supports English but may offer different endpointing characteristics. + +8. **Observability with Langfuse**: New `assistant.observabilityPlan` property allows integration with Langfuse for tracing and monitoring of assistant calls. Configure with [LangfuseObservabilityPlan](https://api.vapi.ai/api#:~:text=LangfuseObservabilityPlan). + +9. **More Credential Support**: Added support for Cerebras, Google, Hume, InflectionAI, Mistral, Trieve, and Neuphonic credentials in `assistant.credentials` \ No newline at end of file diff --git a/fern/changelog/2025-03-14.mdx b/fern/changelog/2025-03-14.mdx new file mode 100644 index 000000000..0b75854e5 --- /dev/null +++ b/fern/changelog/2025-03-14.mdx @@ -0,0 +1,9 @@ +## Blocks Schema Deprecations, Scheduling Enhancements, and New Voice Options for Vapi Voice + + +2. **'scheduled' Status Added to Calls and Messages**: You can now set the status of a call or message to `scheduled`, allowing it to be executed at a future time. This enables scheduling functionality within your application for calls and messages. + +3. **New Voice Options for Text-to-Speech**: Four new voices—`Neha`, `Cole`, `Harry`, and `Paige`—have been added for text-to-speech services. You can enhance user experience by setting the `voiceId` to one of these options in your configurations. + +3. **Removal of Step and Block Schemas**: +Blocks and Steps are now officially deprecated. Developers should update their applications to adapt to these changes, possibly by using new or alternative schemas provided. \ No newline at end of file diff --git a/fern/changelog/2025-03-15.mdx b/fern/changelog/2025-03-15.mdx new file mode 100644 index 000000000..322bfa798 --- /dev/null +++ b/fern/changelog/2025-03-15.mdx @@ -0,0 +1,9 @@ +# Enhancements in Assistant Responses, New Gemini Model, and Call Handling + +1. **Introduction of 'gemini-2.0-flash-lite' Model Option**: You can now use `gemini-2.0-flash-lite` in [`Assistant.model[provider="google"].model[model="gemini-2.0-flash-lite"]`](https://api.vapi.ai/api#:~:text=GoogleModel) for a reduced latency, lower cost Gemini model with a 1 million token context window. + + + gemini-2.0-flash-lite Model Option + + +2. **New Assistant Paginated Response**: All [`Assistant`](https://api.vapi.ai/api#:~:text=Assistants) endpoints now return paginated responses. Each response specifies `itemsPerPage`, `totalItems`, and `currentPage`, which you can use to navigate through a list of assistants. \ No newline at end of file diff --git a/fern/changelog/2025-03-17.mdx b/fern/changelog/2025-03-17.mdx new file mode 100644 index 000000000..76ba87daf --- /dev/null +++ b/fern/changelog/2025-03-17.mdx @@ -0,0 +1,3 @@ +# New `timeoutSeconds` Property in Custom LLM Model + +1. **New `timeoutSeconds` Property in [`Custom LLM Model`](https://api.vapi.ai/api#:~:text=CustomLLMModel):** Developers can now specify a custom timeout duration (between 20 and 600 seconds) for connections to their [custom language model provider](https://api.vapi.ai/api#:~:text=CustomLLMModel) using the new `timeoutSeconds` property. This enhancement allows for better control over response waiting times, accommodating longer operations or varying network conditions. diff --git a/fern/changelog/2025-03-19.mdx b/fern/changelog/2025-03-19.mdx new file mode 100644 index 000000000..b4c5a23bb --- /dev/null +++ b/fern/changelog/2025-03-19.mdx @@ -0,0 +1,12 @@ + +# Test Suite, Smart Endpointing, and Compliance Plans, Chat Completion Message Workflows, and Voicemail Detection + +1. **Test Suite Enhancements**: Developers can now define `targetPlan` and `testerPlan` when creating or updating [test suites](https://api.vapi.ai/api#:~:text=TestSuite), allowing for customized testing configurations without importing phone numbers to Vapi. + +2. **Smart Endpointing Updates**: You can now select between [`Vapi`](https://api.vapi.ai/api#:~:text=VapiSmartEndpointingPlan) and [`Livekit`](https://api.vapi.ai/api#:~:text=LivekitSmartEndpointingPlan) smart endpointing providers using the `Assistant.startSpeakingPlan.smartEndpointingPlan`; the `customEndpointingRules` property is deprecated and should no longer be used. + +3. **Compliance Plan Enhancements**: Organizations can now specify compliance settings using the new `compliancePlan` property, enabling features like PCI compliance at the org level. + +4. **Chat Completion Message Updates**: When working with OpenAI chat completions, you should now use [`ChatCompletionMessageWorkflows`](https://api.vapi.ai/api#:~:text=ChatCompletionMessageWorkflows) instead of the deprecated `ChatCompletionMessage`. + +5. **Voicemail Detection Defaults Updated**: The default `voicemailExpectedDurationSeconds` for voicemail detection plans has increased from 15 to 25 seconds, affecting how voicemail detection timings are handled. \ No newline at end of file diff --git a/fern/changelog/2025-03-20.mdx b/fern/changelog/2025-03-20.mdx new file mode 100644 index 000000000..5cb4e9607 --- /dev/null +++ b/fern/changelog/2025-03-20.mdx @@ -0,0 +1,13 @@ +# Introducing Google Calendar Integration, and Chat Test Suite / Rime AI Voice Enhancements + +1. **Integration with Google Calendar**: You can now create and manage Google Calendar events directly within your tools. Configure OAuth2 credentials through the [dashboard > Build > Provider Keys](https://dashboard.vapi.ai/keys#:~:text=Google%20Calendar) to authenticate and interact with Google Calendar APIs. + + + Google Calendar Integration + + +2. **Enhanced Voice Customization for RimeAIVoice**: Gain more control over [Rime AI voice](https://api.vapi.ai/api#:~:text=RimeAIVoice) properties with new options like `reduceLatency`, `inlineSpeedAlpha`, `pauseBetweenBrackets`, and `phonemizeBetweenBrackets`. These settings let you optimize voice streaming and adjust speech delivery to better suit your assistant's needs. + +3. **Chat Test Suite Enhancements**: You can now create and run chat-based tests in your test suites using the new [`TestSuiteTestChat`](https://api.vapi.ai/api#:~:text=TestSuiteTestChat) to more comprehensively test conversational interactions in your assistant. + +4. **Maximum Length for Test Suite Chat Scripts**: When creating or updating chat tests, note that the `script` property now has a maximum length of 10,000 characters. Ensure your test scripts conform to this limit to avoid any validation errors. \ No newline at end of file diff --git a/fern/changelog/2025-03-21.mdx b/fern/changelog/2025-03-21.mdx new file mode 100644 index 000000000..d749c4099 --- /dev/null +++ b/fern/changelog/2025-03-21.mdx @@ -0,0 +1,4 @@ + +1. **OpenAI Voice Enhancements**: When using [OpenAI Voice models in `Assistant.voice`](https://api.vapi.ai/api#:~:text=OpenAIVoice), you can now use specific text to speech models and add custom instructions to control your assistant's voice output + +2. **Improved Call Error Reporting**: You can now use new [`Call.endedReason`](https://api.vapi.ai/api#:~:text=Call,-CallBatchError) codes when a call fails to start or ends unexpectedly due to failing to retrieve Vapi objects. Refer to [Call.endedReason](https://api.vapi.ai/api#:~:text=Call,-CallBatchError) for more details. \ No newline at end of file diff --git a/fern/changelog/2025-03-22.mdx b/fern/changelog/2025-03-22.mdx new file mode 100644 index 000000000..e4f64be76 --- /dev/null +++ b/fern/changelog/2025-03-22.mdx @@ -0,0 +1,6 @@ + +1. **Customizable Background Sound**: You can now use a custom audio file as the background sound in calls by providing a URL in the `backgroundSound` property. This allows you to enhance the call experience with personalized ambient sounds or music. + +2. **New Recording Format Options in `ArtifactPlan`**: You can specify the recording format as either `'wav;l16'` or `'mp3'` in `Assistant.artifactPlan` or `Call.artifactPlan`. This gives you control over the audio format of call recordings to suit your storage and playback preferences. + +3. **Integrate with Langfuse for Enhanced Observability**: You can now integrate with Langfuse by setting `assistant.observabilityPlan` to `langfuse`. Add `tags` and `metadata` to your traces to improve monitoring, categorization, and debugging of your application's behavior. \ No newline at end of file diff --git a/fern/changelog/2025-03-23.mdx b/fern/changelog/2025-03-23.mdx new file mode 100644 index 000000000..612ba11a5 --- /dev/null +++ b/fern/changelog/2025-03-23.mdx @@ -0,0 +1,5 @@ +1. **Multi-Structured Data Extraction with `StructuredDataMultiPlan`:** You can now extract multiple sets of structured data from calls by configuring `assistant.analysisPlan.structuredDataMultiPlan`. This allows you to define various extraction plans, each producing structured outputs accessible via `call.analysis.structuredDataMulti`. + +2. **Customizable Voice Speed and Language Settings:** You can now adjust the speech speed and language for your assistant's voice by using the new `speed` and `language` properties in `Assistant.voice`. This enables you to fine-tune the voice output to better match your user's preferences and localize the experience. + +3. **Integration of OpenAI Transcriber:** The `transcriber` property in assistants now supports `OpenAITranscriber`, allowing you to utilize OpenAI's transcription services. A corresponding `Call.endedReason` value, `pipeline-error-openai-transcriber-failed`, has been added to help you identify when a call ends due to an OpenAI transcriber error. \ No newline at end of file diff --git a/fern/changelog/2025-03-27.mdx b/fern/changelog/2025-03-27.mdx new file mode 100644 index 000000000..4be50b2e9 --- /dev/null +++ b/fern/changelog/2025-03-27.mdx @@ -0,0 +1,7 @@ +1. **Batch Call Operations**: You can now place multiple calls to different customers at once by providing a list of `customer`s as an array in [`POST /call`](https://api.vapi.ai/api#/Calls/CallController_create). + +2. **Google Sheets Row Append Tool Added**: You can now append rows to Google Sheets directly from your assistant using [`GoogleSheetsRowAppendTool`](https://api.vapi.ai/api#/Tools/GoogleSheetsRowAppendTool). This allows integration with Google Sheets via the API for automating data entry tasks. + +3. **Call Control and Scheduling**: You can now schedule calls using the new `SchedulePlan` feature, specifying earliest and latest times for calls to occur. This gives you more control over call timing and scheduling. + +4. **New Transcriber Options and Fallback Plans**: New transcribers like `GoogleTranscriber` and `OpenAITranscriber` have been added, along with the ability to set `fallbackPlan` for transcribers. This provides more choices and reliability for speech recognition in your applications. \ No newline at end of file diff --git a/fern/changelog/2025-03-28.mdx b/fern/changelog/2025-03-28.mdx new file mode 100644 index 000000000..77a9d793c --- /dev/null +++ b/fern/changelog/2025-03-28.mdx @@ -0,0 +1,15 @@ +1. **New Slack and Google Calendar Tools Added**: You can now use the built-in [Slack tool](https://docs.vapi.ai/tools/slack) to send messages and use the [Google Calendar tool](https://docs.vapi.ai/tools/google-calendar) to check calendar availability directly from your assistant, with full CRUD operations available via the [`/tool` API endpoint](https://docs.vapi.ai/api-reference/tools/list). You can authenticate the [Slack tool](https://dashboard.vapi.ai/keys#:~:text=Slack) and the [Google Calendar tool](https://dashboard.vapi.ai/keys#:~:text=Google%20Calendar) using OAuth2 from the [Vapi provider keys page](https://dashboard.vapi.ai/keys). + + + Slack Tool + + + + Google Calendar Tool + + +2. **Select LLM Model in Workflow Nodes**: You can now select and update which LLM model you want to use within workflow nodes, allowing more precise control over the assistant's behavior in different workflow nodes and easier configuration updates. + +4. **Enhanced Call Monitoring and Reporting**: We've improved call monitoring with conversation turn tracking, millisecond-precision timestamps, and provided more detailed call end reasons. These enhancements make it easier to track conversation flow, perform precise time calculations, and diagnose specific call termination issues like server overloads or database errors. + +5. **Enable Background Denoising**: You can now filter out background noise during calls by setting `Assistant.backgroundDenoisingEnabled` to `true`. \ No newline at end of file diff --git a/fern/changelog/2025-03-30.mdx b/fern/changelog/2025-03-30.mdx new file mode 100644 index 000000000..7c13340b0 --- /dev/null +++ b/fern/changelog/2025-03-30.mdx @@ -0,0 +1,5 @@ +1. **TestSuiteRunTestAttempt now accepts `callId` and `metadata`**: You can now include a `callId` and `metadata` when creating a test suite run attempt, allowing you to reference calls by ID and attach session-related information. + +2. **`call` property in [TestSuiteRunTestAttempt](https://api.vapi.ai/api#:~:text=TestSuiteRunTestAttemptMetadata) is no longer required**: It's now optional to include the full `call` object in a test attempt, providing flexibility for cases where call details are unnecessary or already known. + +3. **Attach Metadata to Test Suite Run Attempts**: You can now attach [metadata](https://api.vapi.ai/api#:~:text=TestSuiteRunTestAttemptMetadata) like `sessionId` to test attempts for better tracking and analysis. diff --git a/fern/changelog/2025-04-03.mdx b/fern/changelog/2025-04-03.mdx new file mode 100644 index 000000000..e073411aa --- /dev/null +++ b/fern/changelog/2025-04-03.mdx @@ -0,0 +1,5 @@ +1. **Introducing `SmsSendTool` for SMS messaging support**: You can now create and manage tools of type `sms` using the new [SMS Send Tool](https://api.vapi.ai/api#:~:text=SmsSendTool), allowing you to send SMS messages via defined servers. The `sms` tool type is also now recognized in API endpoints, ensuring that SMS send tools are correctly processed during CRUD operations. + +2. **New configuration options for voice and transcriber settings**: The `autoMode` property has been added to [Eleven Labs Voice Settings](https://api.vapi.ai/api#:~:text=ElevenLabsVoice), letting developers control automatic voice settings. Additionally, `confidenceThreshold` has been introduced in transcriber settings, allowing developers to set thresholds to discard low-confidence transcriptions and improve accuracy. + +3. **Enhanced speed control in `CartesiaExperimentalControls`**: The `speed` property now accepts both predefined speeds (`'slowest'`, `'slow'`, `'normal'`, `'fast'`, `'fastest'`) and numeric values between -1 and 1. This gives you more precise control over speed settings for better customization. \ No newline at end of file diff --git a/fern/changelog/2025-04-04.mdx b/fern/changelog/2025-04-04.mdx new file mode 100644 index 000000000..f90530d0d --- /dev/null +++ b/fern/changelog/2025-04-04.mdx @@ -0,0 +1 @@ +1. **Addition of `assistantId` to `TargetPlan` settings**: You can now specify an `assistantId` when testing [target plans](https://api.vapi.ai/api#:~:text=TargetPlan), allowing you to test scenarios involving specific assistants directly. \ No newline at end of file diff --git a/fern/changelog/2025-04-05.mdx b/fern/changelog/2025-04-05.mdx new file mode 100644 index 000000000..50fa72027 --- /dev/null +++ b/fern/changelog/2025-04-05.mdx @@ -0,0 +1,9 @@ +1. **Introducing `SmsSendTool` for SMS messaging support**: You can now create and send `sms` text messages using the new `[Send Text`](https://api.vapi.ai/api#:~:text=SmsSendTool) tool, enabling assistants to send SMS messages via defined servers. + + + SmsSendTool + + +2. **[Eleven Labs Voice](https://api.vapi.ai/api#:~:text=ElevenLabsVoice) Auto Mode and Confidence Threshold configuration options**: When using [`Eleven Labs Voice`](https://api.vapi.ai/api#:~:text=ElevenLabsVoice) in your Assistant, you can now configure `autoMode` (default: false) to automatically manage manage chunking strategies for long texts; Eleven Labs automatically determines the best way to process and generate audio, optimizing for latency and efficiency. Additionally, `confidenceThreshold` has been introduced in transcriber schemas, allowing developers to set thresholds to discard low-confidence transcriptions and improve accuracy. + +3. **Changes to `CartesiaExperimentalControls` Speed property**: The `speed` property now accepts both predefined speeds (`'slowest'`, `'slow'`, `'normal'`, `'fast'`, `'fastest'`) and numeric values between -1 and 1. This simplifies the process of controlling the speed of the generated audio with Cartesia. \ No newline at end of file diff --git a/fern/changelog/2025-04-08.mdx b/fern/changelog/2025-04-08.mdx new file mode 100644 index 000000000..e6896d434 --- /dev/null +++ b/fern/changelog/2025-04-08.mdx @@ -0,0 +1,7 @@ +1. **Simplified `transport` property in `Call` configuration**: You should now configure the `transport` property in [`Call`](https://api.vapi.ai/api#:~:text=Call) as an object when creating or updating a [`Call`](https://api.vapi.ai/api#:~:text=Call), since the separate `Transport` schema has been deprecated. This simplification makes it easier to work with transport details without referencing a separate transport configuration. + + + The `Transport` schema is now deprecated and will be removed in a future release. + + +2. **New call type `vapi.websocketCall`**: You can now make [phone calls over WebSockets](https://docs.vapi.ai/calls/websocket-transport) with Vapi. The `Call` schema now supports a new `type` value: `vapi.websocketCall`. \ No newline at end of file diff --git a/fern/changelog/2025-04-11.mdx b/fern/changelog/2025-04-11.mdx new file mode 100644 index 000000000..a67283eab --- /dev/null +++ b/fern/changelog/2025-04-11.mdx @@ -0,0 +1,9 @@ +1. **Updated AI Edge Condition with Prompt**: When defining an AI edge condition, the `matches` property has been renamed to `prompt`. The `prompt` allows you to provide a natural language condition (up to 1000 characters) that guides AI decision-making in workflows. + + + AI Edge Condition with Prompt + + +2. **Assistant Overrides per Customer**: You can now customize assistant settings for individual customers using `assistantOverrides` when [creating customers](https://api.vapi.ai/api#:~:text=CreateCustomerDTO). This enables personalized assistant interactions for each customer in batch calls. + +3. **New Call Ended Reasons**: New error codes have been added to `endedReason` enums, providing more detailed insights into call terminations related to providers like Anthropic Bedrock and Vertex. This helps in better error handling and debugging of call issues. \ No newline at end of file diff --git a/fern/changelog/2025-04-12.mdx b/fern/changelog/2025-04-12.mdx new file mode 100644 index 000000000..11422e844 --- /dev/null +++ b/fern/changelog/2025-04-12.mdx @@ -0,0 +1,2 @@ + +1. **Expanded Voice Selection for Assistant Voices**: You can now specify any valid `voiceId` for assistant voices without being limited to a predefined list. This provides greater flexibility to use different voices in `Assistant.voice`, and related configurations. \ No newline at end of file diff --git a/fern/changelog/2025-04-15.mdx b/fern/changelog/2025-04-15.mdx new file mode 100644 index 000000000..5ceb1541b --- /dev/null +++ b/fern/changelog/2025-04-15.mdx @@ -0,0 +1,5 @@ +1. **New GPT-4.1 Models Available**: You can now use `'gpt-4.1'`, `'gpt-4.1-mini'`, and `'gpt-4.1-nano'` as options for the `model` and `fallbackModels` with your [OpenAI models](https://api.vapi.ai/api#:~:text=OpenAIModel). These models may offer improved performance or features over previous versions. + + + New GPT-4.1 Models Available + diff --git a/fern/changelog/2025-04-16.mdx b/fern/changelog/2025-04-16.mdx new file mode 100644 index 000000000..d3166827e --- /dev/null +++ b/fern/changelog/2025-04-16.mdx @@ -0,0 +1,12 @@ +1. **Assistant Overrides in Testing (`TargetPlan.assistantOverrides`)**: You can now apply `assistantOverrides` when testing an assistant with a [Target Plan](https://api.vapi.ai/api#:~:text=TargetPlan), allowing modifications to the assistant's configuration specifically for tests without changing the original assistant. This helps in testing different configurations or behaviors of an assistant without affecting the live version. + +2. **Specify Voice Model with Deepgram**: You can now specify the `model` to be used by Deepgram voices by setting the `model` property to `"aura"` or `"aura-2"` (default: `"aura-2"`). + +3. **Expanded Deepgram Voice Options (`voiceId` in `DeepgramVoice` and `FallbackDeepgramVoice`)**: The list of available deepgram voice options has been greatly expanded, providing a wider selection of voices for assistants. This allows you to customize the assistant's voice to better match your desired persona with `Assistant.voice["DeepgramVoice"].voiceId`. + + + Expanded Deepgram Voice Options + + + +4. **Control Text Replacement Behavior (`replaceAllEnabled` in `ExactReplacement`)**: A new property `replaceAllEnabled` allows you to decide whether to replace all instances of a specified text (`key`) or just the first occurrence in [`ExactReplacement`](https://api.vapi.ai/api#:~:text=ExactReplacement) configurations. Setting `replaceAllEnabled` to `true` ensures that all instances are replaced. \ No newline at end of file diff --git a/fern/changelog/2025-04-17.mdx b/fern/changelog/2025-04-17.mdx new file mode 100644 index 000000000..e5e99b493 --- /dev/null +++ b/fern/changelog/2025-04-17.mdx @@ -0,0 +1,8 @@ +**1. **Custom Hooks When a Call is Ringing**: You can now define custom hooks on your phone numbers to automatically perform actions when a call is ringing. This enables you to play messages or transfer calls without additional server-side code by using the new `hooks` property in `Call.phoneNumber.hooks["phoneNumberHookCallRinging"]`. + +**2. **Say and Transfer Actions in Hooks**: The new [phone number hook call ringing](https://api.vapi.ai/api#:~:text=PhoneNumberHookCallRinging) allows you to specify actions that trigger when a call is ringing (`on: 'call.ringing'`). like [redirecting calls](https://api.vapi.ai/api#:~:text=TransferPhoneNumberHookAction) or [playing a message](https://api.vapi.ai/api#:~:text=SayPhoneNumberHookAction). Include these actions in the `do` array of your hook. + +**3. **Enhanced Call Tracking with endedReason**: When implementing call analytics, you can now track calls that ended due to hook actions through new `endedReason` values: +- `'call.ringing.hook-executed-say'`: Call ended after playing a message via hook +- `'call.ringing.hook-executed-transfer'`: Call ended after being transferred via hook +These values let you distinguish between different automated call handling outcomes in your reporting. \ No newline at end of file diff --git a/fern/changelog/2025-04-18.mdx b/fern/changelog/2025-04-18.mdx new file mode 100644 index 000000000..08b5dbd48 --- /dev/null +++ b/fern/changelog/2025-04-18.mdx @@ -0,0 +1 @@ +1. **Idle Message Count Reset in `Assistant.messagePlan`**: You can now enable `Assistant.messagePlan.idleMessageResetCountOnUserSpeechEnabled` (default: false) to allow the idle message count to reset whenever the user speaks. This means the assistant can repeatedly remind an idle user throughout the conversation. diff --git a/fern/changelog/2025-04-23.mdx b/fern/changelog/2025-04-23.mdx new file mode 100644 index 000000000..f57a79e63 --- /dev/null +++ b/fern/changelog/2025-04-23.mdx @@ -0,0 +1,3 @@ +1. **Create Sesame Voices Programmatically**: You can now create and manage [Sesame Voices](https://api.vapi.ai/api#:~:text=CreateSesameVoiceDTO) via the API by specifying a `voiceName` and `transcription`. + +2. **AWS STS Support in OAuth2 Authentication**: You can now use AWS Security Token Service for authentication by setting the `type` of `OAuth2AuthenticationPlan` to `'aws-sts'`, enabling integration with AWS's secure token services. \ No newline at end of file diff --git a/fern/changelog/2025-04-24.mdx b/fern/changelog/2025-04-24.mdx new file mode 100644 index 000000000..a50725564 --- /dev/null +++ b/fern/changelog/2025-04-24.mdx @@ -0,0 +1,3 @@ +1. **Per-Voice Caching Control Added**: Developers can now enable or disable voice caching for each assistant's voice using the new `cachingEnabled` property in voice configurations. This allows you to optimize performance or comply with data policies by controlling whether voice responses are cached. + +2. **'Condition' Value Now Accepts Strings**: When specifying conditions, the `value` property should now be provided as a string instead of an object. This simplifies condition definitions and makes it easier to set and interpret condition values. \ No newline at end of file diff --git a/fern/changelog/2025-04-25.mdx b/fern/changelog/2025-04-25.mdx new file mode 100644 index 000000000..37e38b723 --- /dev/null +++ b/fern/changelog/2025-04-25.mdx @@ -0,0 +1,5 @@ +1. **New OpenAI Models 'o3' and 'o4-mini' Added**: You can now use the '`o3`' and '`o4-mini`' models with OpenAI models in `Assistant.model["OpenAIModel"].model`. + +2. **'whisper' Model Added to Deepgram Transcribers**: The '`whisper`' model is now available in [Deepgram transcriber](https://api.vapi.ai/api#:~:text=DeepgramTranscriber) models for audio transcription. Select '`whisper`' in the `Assistant.transcriber["DeepgramTranscriber"].model` property to utilize this advanced transcription model. + +3. **Expanded Language Support in Deepgram Transcribers**: You can now transcribe audio in '`ar`' (Arabic), '`he`' (Hebrew), and '`ur`' (Urdu) when using Deepgram transcriber in your assistant. \ No newline at end of file diff --git a/fern/changelog/2025-04-26.mdx b/fern/changelog/2025-04-26.mdx new file mode 100644 index 000000000..924e1b7ca --- /dev/null +++ b/fern/changelog/2025-04-26.mdx @@ -0,0 +1,5 @@ +1. **Adding metadata to ToolCallResult and ToolCallResultMessage**: You can now include optional metadata in tool call results and messages. This allows you to send additional context or information to clients alongside standard tool responses. + +2. **Adding `tool.completed` client message type**: Assistants can now handle a new client message type, `tool.completed`. This enables you to notify clients when a tool has finished executing. + +3. **Customizable assistant messages via `message` property in [ToolCallResult](https://api.vapi.ai/api#:~:text=ToolCallResult)**: You can now specify exact messages for the assistant to say upon tool completion or failure using the `message` property. This gives you greater control over user interactions by allowing custom, context-specific responses. diff --git a/fern/changelog/2025-04-27.mdx b/fern/changelog/2025-04-27.mdx new file mode 100644 index 000000000..04cdad11b --- /dev/null +++ b/fern/changelog/2025-04-27.mdx @@ -0,0 +1,9 @@ +1. **New Assistant Hook for Call Ending Events**: You can now define actions to execute when a call is ending using [`Assistant.hooks\["AssistantHookCallEnding"\]`](https://api.vapi.ai/api#:~:text=AssistantHookCallEnding). This allows you to specify actions like transferring the call, saying a message, or invoking a function at the end of a call. + +2. **Enhanced Voicemail Detection Configuration**: Configure voicemail detection more precisely with new `Assistant.voicemailDetection.backoffPlan` and `Assistant.voicemailDetection.beepMaxAwaitSeconds` properties. This lets you control retry strategies and set maximum wait times for voicemail beeps. + +3. **Twilio Authentication Using API Keys**: Authenticate with Twilio using `apiKey` and `apiSecret` when importing a [Twilio Phone Number](https://dashboard.vapi.ai/phone-numbers/) This replaces the need for `authToken`. + +4. **Support for New Voicemail Detection Provider and Model**: Utilize the new `vapi` provider for voicemail detection by configuring `Assistant.voicemailDetection.provider`. Additionally, the `gemini-2.5-flash-preview-04-17` model is now supported in various schemas for advanced capabilities. + +5. **Expanded Workflow Nodes**: Workflows now support `Start` and `Assistant` nodes, enabling more complex and customizable call flow designs. This allows for greater flexibility in defining how calls are handled. diff --git a/fern/changelog/2025-04-29.mdx b/fern/changelog/2025-04-29.mdx new file mode 100644 index 000000000..fe1b5d3f2 --- /dev/null +++ b/fern/changelog/2025-04-29.mdx @@ -0,0 +1,21 @@ +1. **Simplified Assistant Schema**: The `Assistant` schema is now simplified to focus on essential properties like `assistantId`, `name`, `type`, and `metadata`. Other advanced settings have been moved to the Call schema. + +Configure advanced call-specific assistant parameters using `Call.assistant` instead of `Assistant`. + +2. **New Structured Recording Properties in Artifact Schema**: You can now access recording details through `Call.artifact.recording`, which provides a structured way to obtain mono, stereo, and video recordings. This replaces the old recording url properties with a more organized format. You can also access this data through the [dashboard (Observe > Call Logs)](https://dashboard.vapi.ai/calls) + + + Call Artifact Recording + + + +The `Call.recordingUrl`, `Call.videoRecordingUrl`, `Call.stereoRecordingUrl`, and `Call.videoRecordingStartDelaySeconds` properties are now deprecated. Transition to using `Call.artifact.recording` for accessing recording information. + + +3. **Include SIP Headers in Refer-To URI for Transfers**: By enabling `sipHeadersInReferToEnabled` in your `Call.assistant.hooks.do[type=transfer].destination.transferPlan`, you can now include SIP headers as URL-encoded query parameters during call transfers. + +4. **Increased Length Limits for Liquid and Rubric Fields**: You can now write longer [LiquidJS](https://liquidjs.com/) expressions in `LogicEdgeCondition.liquid` (up to 1000 characters) and more detailed rubrics in `TestSuiteRunScorerAI.rubric` and `TestSuiteTestScorerAI.rubric` (up to 10,000 characters). Refer to [Advanced Date and Time Formatting documentation](https://docs.vapi.ai/assistants/dynamic-variables#advanced-date-and-time-usage) for more information. + +5. **Introduction of Start Node in Workflow**: A new [`Start`](https://api.vapi.ai/api#:~:text=Start) node type is available in the assistant's workflow. Use this to define the starting point of your assistant's conversational flow with customizable metadata. Refer to [Workflows documentation](https://docs.vapi.ai/workflows#step-4-build-your-workflow) for more information. + +6. **Standardized Assistant Version Pagination Response**: When fetching assistant versions, responses now conform to the [`AssistantVersionPaginatedResponse`](https://api.vapi.ai/api#:~:text=AssistantVersionPaginatedResponse). This standardization makes it easier to handle paginated data. diff --git a/fern/changelog/2025-04-30.mdx b/fern/changelog/2025-04-30.mdx new file mode 100644 index 000000000..b480f70da --- /dev/null +++ b/fern/changelog/2025-04-30.mdx @@ -0,0 +1,5 @@ +1. **New Voicemail Detection Configuration**: You can now configure voicemail detection for assistants with Vapi using the new [`VapiVoicemailDetectionPlan`](https://api.vapi.ai/api#:~:text=VapiVoicemailDetectionPlan). This feature allows you to control how Vapi handles voicemail detection, including specifying the provider, backoff strategy, and maximum wait time for a voicemail beep. Refer to [Voicemail Detection documentation](https://docs.vapi.ai/calls/voicemail-detection) for more information, and configure it on the [Assistants tab](https://dashboard.vapi.ai/assistants#:~:text=Voicemail%20Detection). + +![Vapi Voicemail Detection Configuration](/static/images/advanced-tab/vapi-voicemail-detection.png) + +2. **Control SMS Capabilities on Twilio Numbers**: You can now enable or disable SMS functionality on your Twilio phone numbers with the new `smsEnabled` property. By setting `smsEnabled` to `false`, Vapi will not update the messaging webhook URL during phone number import or creation, allowing you to manage SMS settings independently. \ No newline at end of file diff --git a/fern/changelog/2025-05-01.mdx b/fern/changelog/2025-05-01.mdx new file mode 100644 index 000000000..b5c3f4248 --- /dev/null +++ b/fern/changelog/2025-05-01.mdx @@ -0,0 +1,8 @@ + +1. **Customize Server Messages with Flexible Array Input**: Before, [`serverMessages`](https://api.vapi.ai/api#:~:text=ServerMessage) could only be one of a set list of string values (enforced by enum). Now, `serverMessages` is an array of objects with no restrictions on what those objects are as long as they match the [`ServerMessage`](https://api.vapi.ai/api#:~:text=ServerMessage) schema, making the schema more open and future-proof, though less strict. + +We provide an example list that matches the previous values: `["conversation-update", "end-of-call-report", "function-call", "hang", "speech-update", "status-update", "tool-calls", "transfer-destination-request", "user-interrupted"]`. + + +You now need to include the `serverMessages` property when creating or updating an assistant, ensuring you explicitly define which messages your assistant sends to your server. + diff --git a/fern/changelog/2025-05-03.mdx b/fern/changelog/2025-05-03.mdx new file mode 100644 index 000000000..f3031506a --- /dev/null +++ b/fern/changelog/2025-05-03.mdx @@ -0,0 +1,9 @@ +1. **New `KnowledgeBaseCost` in Call Costs:**: You can now access detailed costs related to knowledge base queries in a call through the new `KnowledgeBaseCost` type in `call.costs[type=knowledge-base]`. This helps in tracking expenses when using knowledge base features during calls. + +2. **Deprecated `smartEndpointingEnabled` Property:** The `smartEndpointingEnabled` property in `StartSpeakingPlan` is now deprecated. Developers should update their applications to use the new `smartEndpointingPlan` or `customEndpointingRules` for controlling endpointing behavior. + +3. **Advanced Endpointing with `smartEndpointingPlan` and `customEndpointingRules`:** The `StartSpeakingPlan` now includes `smartEndpointingPlan` and `customEndpointingRules` properties, providing enhanced control over speech endpointing. Developers can specify endpointing methods or define custom rules to improve conversational interactions. + + +The `smartEndpointingEnabled` property in `StartSpeakingPlan` is now deprecated. Developers should update their applications to use the new `smartEndpointingPlan` or `customEndpointingRules` for controlling endpointing behavior. + diff --git a/fern/changelog/2025-05-06.mdx b/fern/changelog/2025-05-06.mdx new file mode 100644 index 000000000..0fee23b79 --- /dev/null +++ b/fern/changelog/2025-05-06.mdx @@ -0,0 +1,5 @@ +1. **Use Workflows as Call Entry Points**: You can now start calls or configure phone numbers using a `workflow` or `workflowId`, just like you would with `assistant`, `assistantId`, `squad`, or `squadId`. This provides more flexibility in defining how calls are initiated and allows direct use of workflows. Refer to the [Workflows documentation](https://docs.vapi.ai/workflows) and [API documentation](https://docs.vapi.ai/api-reference/calls/list#:~:text=Workflow) for more information. + +2. **New Warm Transfer Mode and Hold Music in `TransferPlan`**: There's a new transfer mode `warm-transfer-experimental` in `call.squad.members.assistant.hooks.do[type=transfer].destination.transferPlan`that enhances call transfer capabilities, including voicemail detection and customer hold experience. You can also customize the hold music by specifying a `holdAudioUrl`. + +3. **Simplified `clientMessages` Configuration**: The `clientMessages` property has been updated and is now required in `AssistantOverrides`, `CreateAssistantDTO`, and `UpdateAssistantDTO`. This change simplifies how you specify which messages are sent to your Client SDKs. diff --git a/fern/changelog/2025-05-07.mdx b/fern/changelog/2025-05-07.mdx new file mode 100644 index 000000000..81d79595a --- /dev/null +++ b/fern/changelog/2025-05-07.mdx @@ -0,0 +1,14 @@ +1. **`ClientMessage` Additions**: Several new client message schemas have been added with additional information about `call`, `customer`, `assistant`, `timestamp`, and `phoneNumber`. This includes: + +- [`Client Message Tool Calls`](https://api.vapi.ai/api#:~:text=ClientMessageToolCalls) +- [`Client Message Transcript`](https://api.vapi.ai/api#:~:text=ClientMessageTranscript) +- [`Client Message Speech Update`](https://api.vapi.ai/api#:~:text=ClientMessageSpeechUpdate) +- [`Client Message Transfer Update`](https://api.vapi.ai/api#:~:text=ClientMessageTransferUpdate) + +2. **New Hooks for Speech Interruption Events**: Two new hooks, [`Speech Interrupted Assistant Hook`](https://api.vapi.ai/api#:~:text=AssistantHookAssistantSpeechInterrupted) and [`Speech Interrupted Customer Hook`](https://api.vapi.ai/api#:~:text=AssistantHookCustomerSpeechInterrupted), enable you to define actions when speech is interrupted during a call. + +3. **Call Schema Updates**: There are several notable updates to how `Call` is structured: + +- `costs` array now includes a new cost type: [`KnowledgeBaseCost`](https://api.vapi.ai/api#:~:text=KnowledgeBaseCost) +- `phoneCallProvider` and `phoneCallProviderId` are now deprecated. +- `waitFunction` in `LivekitSmartEndpointingPlan` has been updated to improve how long the assistant waits before speaking, enhancing call flow responsiveness. diff --git a/fern/changelog/2025-05-08.mdx b/fern/changelog/2025-05-08.mdx new file mode 100644 index 000000000..76be6f133 --- /dev/null +++ b/fern/changelog/2025-05-08.mdx @@ -0,0 +1,6 @@ + +1. **New 'Conversation' Node in Workflows**: You can now use the **Conversation** node in your workflows to create conversation tasks, enhancing how assistants interact during calls. + +2. **Integration with GoHighLevel via OAuth2 Credentials**: You can now connect with GoHighLevel services using new **GoHighLevelMCPCredential** credentials in the [Provider Keys](https://dashboard.vapi.ai/keys#:~:text=GoHighLevel) section of the Vapi Dashboard. + +3. **Standardized Message Types for `clientMessages` and `serverMessages`**: When configuring assistants, you now specify [Client Messages](https://api.vapi.ai/api#:~:text=ClientMessage) and [Server Messages](https://api.vapi.ai/api#:~:text=ServerMessage) using predefined message types, ensuring consistency and preventing invalid message configurations. diff --git a/fern/changelog/2025-05-09.mdx b/fern/changelog/2025-05-09.mdx new file mode 100644 index 000000000..802bb3e9f --- /dev/null +++ b/fern/changelog/2025-05-09.mdx @@ -0,0 +1,5 @@ +1. **Workflows Now Marked as Beta Features**: The workflow endpoints and related properties have now moved to **[BETA]**, indicating they're slightly more stable but still in active development. Refer to the [Workflows documentation](https://docs.vapi.ai/workflows) and [API documentation](https://docs.vapi.ai/api-reference/calls/list#:~:text=Workflow) for more information. + +2. **New `{{endedReason}}` Variable in Templates**: You can now include the `{{endedReason}}` variable in your post-call analysis templates to access why a call ended. This helps generate more insightful summaries and evaluations based on the call's outcome. + +3. **Introduction of `SayAssistantHookAction` Schema**: A new action, [`SayAssistantHookAction`](https://api.vapi.ai/api#:~:text=SayAssistantHookAction), allows the assistant to say specific messages during calls. Use this by adding it to `call.squad.members.assistant.hooks.do[type=say]` to enhance call interactions. \ No newline at end of file diff --git a/fern/changelog/2025-05-10.mdx b/fern/changelog/2025-05-10.mdx new file mode 100644 index 000000000..c4258985a --- /dev/null +++ b/fern/changelog/2025-05-10.mdx @@ -0,0 +1,3 @@ +1. **Configure Conversation Nodes with OpenAI Models**: You can now set up your assistant's workflow conversation nodes to use OpenAI models by specifying [`WorkflowOpenAIModel`](https://api.vapi.ai/api#:~:text=WorkflowOpenAIModel). Choose from a range of OpenAI models and customize parameters like `maxTokens` and `temperature` to control responses. + +2. **Configure Conversation Nodes with Anthropic Models, Including *Thinking* Feature**: Your assistant's conversation nodes can now use Anthropic models by specifying [`WorkflowAnthropicModel`](https://api.vapi.ai/api#:~:text=WorkflowAnthropicModel). Select from various Anthropic models and, for `claude-3-7-sonnet-20250219`, enable the optional `thinking` feature for advanced reasoning capabilities. \ No newline at end of file diff --git a/fern/changelog/2025-05-13.mdx b/fern/changelog/2025-05-13.mdx new file mode 100644 index 000000000..540e5a67a --- /dev/null +++ b/fern/changelog/2025-05-13.mdx @@ -0,0 +1,10 @@ +# GoHighLevel Tools for Calendar and Contact Management + +You can now use new [GoHighLevel tools](https://www.gohighlevel.com) in all models, templates, and workflows directly through the [`/tool`](https://api.vapi.ai/api#:~:text=/tool) and [`/tool/{id}`](https://api.vapi.ai/api#:~:text=/tool/%7Bid%7D) endpoints with the following capabilities: + - **Contact Management**: + - [GoHighLevelContactGetTool](https://api.vapi.ai/api#:~:text=GoHighLevelContactGetTool): Fetch contact information from GoHighLevel + - [GoHighLevelContactCreateTool](https://api.vapi.ai/api#:~:text=GoHighLevelContactCreateTool): Create new contacts in GoHighLevel + + - **Calendar Management**: + - [GoHighLevelCalendarEventCreateTool](https://api.vapi.ai/api#:~:text=GoHighLevelCalendarEventCreateTool): Schedule new calendar events programmatically + - [GoHighLevelCalendarAvailabilityTool](https://api.vapi.ai/api#:~:text=GoHighLevelCalendarAvailabilityTool): Check calendar availability for scheduling diff --git a/fern/changelog/2025-05-14.mdx b/fern/changelog/2025-05-14.mdx new file mode 100644 index 000000000..84e96d893 --- /dev/null +++ b/fern/changelog/2025-05-14.mdx @@ -0,0 +1,20 @@ +1. **Specify Start Node in Workflows with `isStart` Property**: You can now explicitly define the starting point of your workflow by setting the `isStart` property to `true` on any node like [`Say`](https://api.vapi.ai/api#:~:text=Say), [`Gather`](https://api.vapi.ai/api#:~:text=Gather), or [`Hangup`](https://api.vapi.ai/api#:~:text=Hangup). + +2. **Updated Model Options in `GroqModel`**: You can now use the following new Assistant modles with [Groq](https://api.vapi.ai/api#:~:text=GroqModel): + - `meta-llama/llama-4-maverick-17b-128e-instruct` + - `meta-llama/llama-4-scout-17b-16e-instruct` + - `mistral-saba-24b` + - `compound-beta` + - `compound-beta-mini` + + + New Groq Models + + +Note that some older models have been removed, including `llama-3.1-70b-versatile` and `mixtral-8x7b-32768`. + +3. **New `Kylie` Voice Available in Vapi**: You can now use the new `Kylie` voice when using [`Vapi` as your voice provider](https://dashboard.vapi.ai/assistants#:~:text=Voice%20Configuration). You can learn more in the [Vapi voices documentation](https://docs.vapi.ai/providers/voice/vapi-voicesn). + + + New Kylie Voice + diff --git a/fern/changelog/2025-05-15.mdx b/fern/changelog/2025-05-15.mdx new file mode 100644 index 000000000..f274ccdab --- /dev/null +++ b/fern/changelog/2025-05-15.mdx @@ -0,0 +1,4 @@ +# New Azure OpenAI GPT 4.1 Models +1. **Access to New Azure OpenAI Models**: You can now use new GPT 4.1 models in Azure OpenAI such as `gpt-4.1-2025-04-14`, `gpt-4.1-mini-2025-04-14`, and `gpt-4.1-nano-2025-04-14`. + +The above models will be available to configure through the console at a later date. For now, configure your assistant to use these models through [the API](https://docs.vapi.ai/api-reference/assistants/update). \ No newline at end of file diff --git a/fern/changelog/2025-05-16.mdx b/fern/changelog/2025-05-16.mdx new file mode 100644 index 000000000..a0267d56a --- /dev/null +++ b/fern/changelog/2025-05-16.mdx @@ -0,0 +1,7 @@ +# Strip Asterisks from Transcribed Text with `stripAsterisk` Formatter + +1. **New `stripAsterisk` Formatter in [FormatPlan](https://api.vapi.ai/api#:~:text=FormatPlan)**: You can now remove asterisks from transcribed text by adding it to your `Assistant.voice[VOICE_PROVIDER].chunkPlan.formatPlan.formattersEnabled` configuration. + + +Ensure `Assistant.voice[VOICE_PROVIDER].chunkPlan.formatPlan.enabled` is set to `true` to use the `stripAsterisk` formatter. + diff --git a/fern/changelog/2025-05-17.mdx b/fern/changelog/2025-05-17.mdx new file mode 100644 index 000000000..8d43ca349 --- /dev/null +++ b/fern/changelog/2025-05-17.mdx @@ -0,0 +1,14 @@ + +1. **Introduction of `WorkflowAssistant` Schema in Workflows**: [`WorkflowAssistant`](https://api.vapi.ai/api#:~:text=WorkflowAssistant) now replaces `Assistant` in workflow definitions. Use `WorkflowAssistant` when defining assistant nodes in workflows moving forward. + +2. **Adding `dataExtractionPlan` and `variableExtractionPlan` to Conversations**: You can now include [`dataExtractionPlan`](https://api.vapi.ai/api#:~:text=DataExtractionPlan) and [`variableExtractionPlan`](https://api.vapi.ai/api#:~:text=VariableExtractionPlan) to extract structured data or variables from user responses. Utilize these plans to define what data to extract during conversations in your workflows. + +3. **New `McpTool` for Model Configuration**: You can now add `McpTool` to your assistant's `tools` array to use MCP (Model Control Protocol) tool calls. This tool allows your assistant to use any MCP-compatible server in your workflow. + +4. **Changes to `ToolCallResult` Message Property**: The `message` property in `ToolCallResult` now accepts a single object instead of an array. Ensure that you return a single `ToolMessageComplete` or `ToolMessageFailed` object when providing messages in tool call results. + +5. **Updated Required Properties in `Assistant` Schema**: [`Assistant`](https://api.vapi.ai/api#:~:text=Assistant) now requires `id`, `orgId`, `createdAt`, and `updatedAt` when creating or updating assistants. Make sure to provide these fields when creating or updating assistants. + + +`TransferDestinationStep` is now deprecated. Update your code to use the new method for specifying transfer destinations in the `transferCall` tool. + \ No newline at end of file diff --git a/fern/changelog/2025-05-18.mdx b/fern/changelog/2025-05-18.mdx new file mode 100644 index 000000000..c64f02926 --- /dev/null +++ b/fern/changelog/2025-05-18.mdx @@ -0,0 +1,17 @@ +1. **Introduction of New Workflow Nodes**: New nodes `ConversationNode`, `ToolNode`, and `HangupNode` have been added to simplify workflow design. You can now use these nodes to start conversations, integrate tools, and end calls in your workflows more efficiently. + +2. **SesameVoice Added as a New Voice Option**: The `SesameVoice` provider is now available for assistant voices. You can configure your assistant's voice to use Sesame by setting `assistant.voice` to `SesameVoice`. + +3. **Voice Schema Titles Updated for Clarity**: Voice provider schemas have updated titles, e.g., from `OpenAI` to `OpenAIVoice`. This helps avoid confusion by clearly indicating that these configurations are for voice settings. + +4. **Enhancements to MonitorPlan Security Options**: New properties `listenAuthenticationEnabled` and `controlAuthenticationEnabled` have been added to `MonitorPlan`. You can now enforce authentication for live listening and controlling calls by enabling these options. + +5. **Addition of New Tools for Workflow Integration**: New tools such as `BashTool`, `ComputerTool`, and `SmsSendTool` have been added. These allow your assistant to perform system commands, interact with computers, and send SMS messages within workflows. + +6. **Deprecation of Voicemail Tool Type**: The `voicemail` tool type in `CreateVoicemailToolDTO` has been deprecated. You should transition to alternative methods for handling voicemails in your applications. + +7. **Replacement of VoicemailTool with TextEditorTool**: References to `VoicemailTool` have been replaced with `TextEditorTool` in model configurations. Update your models to use `TextEditorTool` for text editing functionality. + +8. **Simplification of Transfer Destination Options**: The `Step` destination type has been removed from `TransferCallTool` destinations. Use other destination types like `assistant` or `phoneNumber` when configuring call transfers. + +9. **Introduction of Gemini Model in Google Platforms**: The model `gemini-2.5-pro-preview-05-06` is now available in `GoogleModel` and `KnowledgeBase`. You can select this model to utilize Google's latest AI capabilities in your assistant. diff --git a/fern/changelog/2025-05-19.mdx b/fern/changelog/2025-05-19.mdx new file mode 100644 index 000000000..54ac64004 --- /dev/null +++ b/fern/changelog/2025-05-19.mdx @@ -0,0 +1,7 @@ +1. **Renaming `SmsSendTool` to `SmsTool`:** The tool previously known as `SmsSendTool` is now `SmsTool`. You can now use the new `SmsTool` schema to send SMS messages with enhanced configuration options like `async`, `server`, `function`, and `messages`. + +2. **Update Text Editor Tool Type to `'text-editor'`:** The `type` for Text Editor tools has changed from `'textEditor'` to `'text-editor'`. Make sure to update your configurations to use `type`: `'text-editor'` when specifying a Text Editor tool. + +3. **Removal of `backgroundSound.maxLength` Property:** The `maxLength` constraint has been removed from the `backgroundSound` property in Assistant schemas. You no longer need to limit the length of `backgroundSound`; it can now be of any length. + +4. **Deprecation of `MakeTool`:** The `MakeTool` has been removed from the available tools in various model schemas. Please update your models to remove any references to `MakeTool` and use alternative tools as needed. \ No newline at end of file diff --git a/fern/changelog/2025-05-20.mdx b/fern/changelog/2025-05-20.mdx new file mode 100644 index 000000000..f6f822c95 --- /dev/null +++ b/fern/changelog/2025-05-20.mdx @@ -0,0 +1,19 @@ +1. **New API Request Tool (`apiRequest`):** Developers can now create custom API request tools using the `apiRequest` tool type, allowing assistants to make HTTP requests to specified URLs. + +2. **'TextEditor' Tool Type Renamed:** The `type` value for the Text Editor tool has changed from `text-editor` to `textEditor`. Update your code to use `textEditor` when specifying this tool type. + +3. **Enhanced Call Entry Points Descriptions:** The properties related to starting calls with assistants, squads, or workflows have updated descriptions, providing clearer guidance on how to use `assistant`, `assistantId`, `squad`, `squadId`, `workflow`, and `workflowId`. + +4. **Extended Server Timeout Limit:** The maximum value for `timeoutSeconds` in server configurations has increased from 120 to 300 seconds, allowing server requests to take up to 5 minutes. + +5. **Removal of `secret` Property in Server Schema:** The `secret` property has been removed from the `Server` schema. Adjust your server configurations by removing any references to `server.secret`. + +6. **New Voice Option `Kylie`:** The voice ID `Kylie` is now available for use in `VapiVoice` and `FallbackVapiVoice`, providing an additional voice option for your assistants. + +7. **Workflows in Server Message Responses:** You can now specify `workflow` and `workflowId` in `ServerMessageResponseAssistantRequest`, enabling the use of workflows when responding to server messages. + +8. **`assistantId` No Longer Nullable:** The `assistantId` property in `ServerMessageResponseAssistantRequest` is no longer nullable, which may require you to always provide an `assistantId` or adjust your logic accordingly. + +9. **Pattern Constraint on Variable Titles:** The `VariableExtractionSchema` now includes a regex pattern for `title`, restricting it to letters, numbers, and underscores. Ensure your variable titles conform to this pattern. + +10. **Updated Server Property Descriptions:** Descriptions for `url`, `headers`, `backoffPlan`, and `timeoutSeconds` in the `Server` schema have been updated for clarity, helping you better understand their purposes and how to configure them. \ No newline at end of file diff --git a/fern/changelog/2025-05-22.mdx b/fern/changelog/2025-05-22.mdx new file mode 100644 index 000000000..7e7d532a6 --- /dev/null +++ b/fern/changelog/2025-05-22.mdx @@ -0,0 +1 @@ +1. **New Anthropic Models Available**: Two new models, `claude-opus-4-20250514` and `claude-sonnet-4-20250514`, have been added to the `model` options in `AnthropicModel` and `WorkflowAnthropicModel`. You can now specify these models in your requests to take advantage of their features. \ No newline at end of file diff --git a/fern/changelog/2025-05-23.mdx b/fern/changelog/2025-05-23.mdx new file mode 100644 index 000000000..cb2062977 --- /dev/null +++ b/fern/changelog/2025-05-23.mdx @@ -0,0 +1,15 @@ +1. **New Chat API Schemas Introduced**: The Chat API now features new schemas like `Chat` and `CreateChatDTO` for enhanced chat management, replacing older schemas. You can use these updated structures to create and interact with chats more effectively. + +2. **Session Management Now Available**: Session-related schemas like `Session` and `CreateSessionDTO` have been added to support conversation sessions. This allows you to maintain context over multiple interactions and manage session-specific configurations. + + Session-related schemas like `Session` and `CreateSessionDTO` have been added to support conversation sessions. This allows you to maintain context over multiple interactions and manage session-specific configurations. + +3. **Additional Message Types for Enhanced Roles**: New message types `ToolMessage`, `AssistantMessage`, and `DeveloperMessage` enable representing different participants in a conversation. You can now handle messages from tools, assistants, and developers, enriching the dialogue experience. + +4. **Updates to Tool Function Calls with `ToolCallFunction`**: The schema for tool calls has been updated with the introduction of `ToolCallFunction`. Adjust your implementations to use `ToolCallFunction`, noting that `arguments` are now passed as strings and `name` has a maximum length of 40 characters. + + The schema for tool calls has been updated with the introduction of `ToolCallFunction`. Adjust your implementations to use `ToolCallFunction`, noting that `arguments` are now passed as strings and `name` has a maximum length of 40 characters. + +5. **Updated Property Descriptions and Constraints**: Property descriptions have been clarified, and length constraints like `maxLength` have been added to certain fields. Ensure your data conforms to these updates, such as keeping `content` under 10,000 characters. + +6. **Removal of Deprecated Schemas**: Deprecated schemas like `ChatCompletionsDTO` have been removed from the API. Update your code to use the new schemas to maintain compatibility and access the latest features. \ No newline at end of file diff --git a/fern/changelog/2025-05-24.mdx b/fern/changelog/2025-05-24.mdx new file mode 100644 index 000000000..4b90ebcc9 --- /dev/null +++ b/fern/changelog/2025-05-24.mdx @@ -0,0 +1,9 @@ +1. **New `minutesUsed` Property for Organizations**: Developers can now track the total call minutes used by their organization via the new `minutesUsed` property in the `Org` schema. + +2. **Removed `server` Property from Certain Tools**: The `server` property has been removed from several tools, such as `SmsTool` and `DtmfTool`; developers should update their implementations accordingly. + +3. **Updated `server` Property Description in Tools**: The `server` property's description has been updated in tools like `McpTool` and `BashTool` to clarify webhook behavior when tool calls are made. + +4. **New Model `gemini-2.5-flash-preview-05-20` Available**: A new model `gemini-2.5-flash-preview-05-20` is now supported, allowing developers to utilize its features in their applications. + +5. **Additional Subscription Types Added**: New subscription types—`agency`, `startup`, `growth`, and `scale`—are now available, providing more options to fit different organizational needs. \ No newline at end of file diff --git a/fern/changelog/2025-05-25.mdx b/fern/changelog/2025-05-25.mdx new file mode 100644 index 000000000..9636f01f5 --- /dev/null +++ b/fern/changelog/2025-05-25.mdx @@ -0,0 +1,3 @@ +1. **New `transferCompleteAudioUrl` Property in `TransferPlan`:** You can now specify a custom audio file URL using `transferCompleteAudioUrl` in `TransferPlan` when using `warm-transfer-experimental` mode to play a sound after the transfer is complete. This allows you to add a custom notification (like a beep) for the destination party after delivering the message or summary. + +2. **`body` Parameter in `CreateApiRequestToolDTO` Is Now Optional:** The `body` property has been removed from the required fields in `CreateApiRequestToolDTO`, so you no longer need to include it when creating an API request tool. This means you can create API requests without a body, useful for HTTP methods like GET or DELETE. \ No newline at end of file diff --git a/fern/changelog/2025-05-26.mdx b/fern/changelog/2025-05-26.mdx new file mode 100644 index 000000000..10c1b5815 --- /dev/null +++ b/fern/changelog/2025-05-26.mdx @@ -0,0 +1,9 @@ +**Removed `async` Property from Tool Schemas**: Developers no longer need to set the `async` property when using various tool schemas like `GhlTool`, `SmsTool`, `BashTool`, and others. These tools now operate synchronously by default; please update your code to remove any references to `async` in these schemas. + +**Default Roles in Message Schemas**: The `role` property in `ToolMessage`, `AssistantMessage`, and `DeveloperMessage` now has default values of `"tool"`, `"assistant"`, and `"developer"`, respectively. You can omit the `role` field when creating these messages, simplifying message construction. + +**Improved Descriptions for Chat Inputs and Messages**: The `input` and `messages` properties in the `Chat`, `CreateChatDTO`, and `OpenAIResponsesRequest` schemas now have clearer descriptions. This helps you understand that `input` can be a string or an array of chat messages, and `messages` provide context for multi-turn conversations. + +**Clarified `async` Behavior in `FunctionTool`**: The `async` property's description in `FunctionTool` and related schemas has been updated for clarity. It now better explains how setting `async` to `true` or `false` affects the assistant's behavior, facilitating more effective use of this feature. + +**Added Titles to Schema Definitions**: The `oneOf` definitions in the `input` property of `Chat`, `CreateChatDTO`, and `OpenAIResponsesRequest` now include `title` attributes like `"String"` and `"MessageArray"`. This improves schema documentation and assists tools in processing these definitions. \ No newline at end of file diff --git a/fern/changelog/2025-05-27.mdx b/fern/changelog/2025-05-27.mdx new file mode 100644 index 000000000..37258e043 --- /dev/null +++ b/fern/changelog/2025-05-27.mdx @@ -0,0 +1,7 @@ +1. **New Chat and Session API Endpoints**: You can now manage chats and sessions using the new API endpoints `/chat`, `/chat/{id}`, `/chat/responses`, `/session`, and `/session/{id}`. This enables you to programmatically create, retrieve, and manage chat conversations and sessions within your applications. + +2. **Variable Extraction Feature Removed**: The variable extraction functionality has been removed from the API. You'll need to update your workflows if you previously used variable extraction, as it is no longer supported. + +3. **Specify Regions for OpenAI Models**: You can now specify the region for OpenAI models in `OpenAIModel` and `WorkflowOpenAIModel` by including a region in the `model` property, like `gpt-4.1-2025-04-14:westus`. This helps you comply with data residency rules or regional requirements by ensuring data processing occurs in specified locations. + +4. **New OpenAI Models Added**: A range of new OpenAI models, including regional variants, are now available for use. You can choose these new models to better align with your application's performance needs and regional compliance requirements. \ No newline at end of file diff --git a/fern/changelog/2025-05-28.mdx b/fern/changelog/2025-05-28.mdx new file mode 100644 index 000000000..0b6ab8268 --- /dev/null +++ b/fern/changelog/2025-05-28.mdx @@ -0,0 +1,12 @@ +1. **Removal of `language` Property in Voice Settings**: The `language` property has been removed from the `VapiVoice` and `FallbackVapiVoice` configurations. You no longer need to set `language` when configuring voice settings; voice language may now be handled automatically or through a different configuration. + +2. **Introduction of Detailed Node Artifacts**: A new `NodeArtifact` schema has been added, accessible via `call.artifact.nodes`, providing detailed information about each node in a call's workflow. You can now access messages, node names, and variables for each node to gain deeper insights into call executions. + +3. **Addition of `nodes` and `variables` to Call Artifacts**: + The `Artifact` schema now includes `nodes` and `variables` properties, enhancing the data available in `call.artifact`. This allows you to retrieve the history of executed workflow nodes and the final state of variables after a call. + +4. **Removal of `Metrics` Schema**: The `Metrics` schema has been completely removed. If your application relies on `Metrics`, you will need to update your code to accommodate this change and explore alternative solutions. + +5. **Update Voice Configuration Paths**: With the changes to voice configurations, paths like `assistant.voice` and `call.squad.members.assistant.voice` may require updates. Ensure your configurations align with the new schema definitions and remove any references to the deprecated `language` property. + +6. **Enable Recording in Artifacts**: To access call recordings in your artifacts, set `assistant.artifactPlan.recordingEnabled` in your configuration. This enables the `recording` property in `call.artifact`, allowing you to review call recordings for analysis or debugging. \ No newline at end of file diff --git a/fern/changelog/2025-05-30.mdx b/fern/changelog/2025-05-30.mdx new file mode 100644 index 000000000..43b278971 --- /dev/null +++ b/fern/changelog/2025-05-30.mdx @@ -0,0 +1,5 @@ +# Session and Workflow Enhancements + +1. **Addition of `expirationSeconds` to Session Schemas**: You can now set custom session expiration times using the `expirationSeconds` property when creating or updating sessions. This allows sessions to expire anywhere between 1 minute and 30 days, providing greater control over session lifecycles. + +2. **Introduction of `globalPrompt` in Workflow Schemas**: A new `globalPrompt` property allows you to define a default prompt for entire workflows. By setting a `globalPrompt` up to 5,000 characters, you can streamline your workflow configurations without setting prompts for each individual node. diff --git a/fern/changelog/2025-05-31.mdx b/fern/changelog/2025-05-31.mdx new file mode 100644 index 000000000..225e21292 --- /dev/null +++ b/fern/changelog/2025-05-31.mdx @@ -0,0 +1,17 @@ +# SIP Call Error Handling Updates + +The following specific SIP error codes have been added to help identify call failures: + + +- `call.in-progress.error-sip-inbound-call-failed-to-connect` +- `call.in-progress.error-providerfault-outbound-sip-403-forbidden` +- `call.in-progress.error-providerfault-outbound-sip-407-proxy-authentication-required` +- `call.in-progress.error-providerfault-outbound-sip-503-service-unavailable` +- `call.in-progress.error-providerfault-outbound-sip-480-temporarily-unavailable` +- `call.in-progress.error-sip-outbound-call-failed-to-connect` +- `call.in-progress.error-vapifault-worker-died` + + + + The generic error code `call.in-progress.error-sip-telephony-provider-failed-to-connect-call` has been removed. Update your error handling to use the new specific error codes instead. + diff --git a/fern/changelog/2025-06-03.mdx b/fern/changelog/2025-06-03.mdx new file mode 100644 index 000000000..19a5dbc66 --- /dev/null +++ b/fern/changelog/2025-06-03.mdx @@ -0,0 +1,6 @@ +# Azure OpenAI Compatibility Mode and JSON Schema Updates + +1. **`toolStrictCompatibilityMode` for Azure OpenAI Models**: Added a new option to handle Azure OpenAI's validation limitations. Set `toolStrictCompatibilityMode` in your `OpenAIModel` config to either: + - `strip-parameters-with-unsupported-validation`: Removes entire parameters that have unsupported validations + - `strip-unsupported-validation`: Keeps parameters but removes unsupported validation aspects + Default is `strip-unsupported-validation`. diff --git a/fern/changelog/2025-06-04.mdx b/fern/changelog/2025-06-04.mdx new file mode 100644 index 000000000..ef6cdec0e --- /dev/null +++ b/fern/changelog/2025-06-04.mdx @@ -0,0 +1,27 @@ +## Assistant Configuration Updates + +1. **Set Minimum Messages for Analysis**: Skip analysis for very short conversations by setting `Assistant.analysisPlan.minMessagesThreshold` (default: 2). + +2. **Configure Transfer Timeout**: You can now set the timeout for warm transfer modes with `Assistant.hooks.do[type=transfer].destination.transferPlan.timeout` (default: 60). Warm transfer modes allow for a smooth handoff between agents by maintaining context and conversation history during the transfer process. + + + This timeout setting determines how long the system will wait for the transfer to complete before timing out. + + + +3. **Enable AssemblyAI Universal Streaming API**: You can now enable the new Universal Streaming API for AssemblyAI transcribers with `Assistant.transcriber.enableUniversalStreamingApi` and `Assistant.transcriber.fallbackPlan.transcribers.enableUniversalStreamingApi`. + + + Set this to `true` to use AssemblyAI's new Universal Streaming API for improved transcription. + + + + + **Removal of regex in JsonSchema**: You can no longer use regular expressions in your [JSON schema validations](https://api.vapi.ai/api#:~:text=JsonSchema). + + **Dot paths affected:** + - `assistant.analysisPlan.structuredDataPlan.schema.regex` + - `assistant.hooks.do[type=function].function.parameters.properties.regex` + - `assistant.model.tools[type=apiRequest].body.regex` + - `assistant.model.tools[type=apiRequest].headers.regex` + \ No newline at end of file diff --git a/fern/changelog/2025-06-06.mdx b/fern/changelog/2025-06-06.mdx new file mode 100644 index 000000000..7929e8554 --- /dev/null +++ b/fern/changelog/2025-06-06.mdx @@ -0,0 +1,7 @@ +# Workflows Out of Beta and Gladia Transcriptions + +1. **Workflows Are Out of Beta**: You can now use workflows in production as we've removed all `[BETA]` labels from workflow-related properties and API endpoints. See [Workflow API Documentation](/docs/api/workflows) for complete details. + +2. **Per-Call Workflow Customization with Overrides**: You can now customize workflows on a per-call basis using the new `Call.workflowOverrides` property. Override workflow settings and template variables using [LiquidJS syntax](https://liquidjs.com/tutorials/intro-to-liquid.html). See [Workflow Documentation](/docs/workflows) for details. + +3. **Enhanced Gladia Transcriptions**: You can now transcribe audio in multiple languages using the new `languages` property in `GladiaTranscriber` and `FallbackGladiaTranscriber` (when `languageBehaviour` is `manual`). You can also use the new `solaria-1` transcription model for potentially improved results. Learn more in our [Transcription Documentation](/docs/transcription). diff --git a/fern/changelog/2025-06-07.mdx b/fern/changelog/2025-06-07.mdx new file mode 100644 index 000000000..dc74f90bc --- /dev/null +++ b/fern/changelog/2025-06-07.mdx @@ -0,0 +1,10 @@ +# New Ended Reasons for SIP Inbound Calls + + + You can now handle SIP inbound call failures with two new `endedReason` values: + + +- `call.ringing.sip-inbound-caller-hungup-before-call-connect`: Use this when a caller hangs up before the call connects +- `call.ringing.error-sip-inbound-call-failed-to-connect`: Use this when there's a connection error + +These values are available in all call event schemas, including `Call`, `ServerMessageStatusUpdate`, and `ServerMessageEndOfCallReport`. Implement precise error handling for your SIP inbound calls by checking for these specific failure scenarios. diff --git a/fern/changelog/2025-06-09.mdx b/fern/changelog/2025-06-09.mdx new file mode 100644 index 000000000..1f142c9eb --- /dev/null +++ b/fern/changelog/2025-06-09.mdx @@ -0,0 +1,7 @@ +# New Call End Reason `pipeline-error-eleven-labs-vapi-voice-disabled-by-owner` + + + Calls can now end with the reason `pipeline-error-eleven-labs-vapi-voice-disabled-by-owner`, indicating the Eleven Labs voice service is disabled by the owner. + + +This call ended reason are available to handle in [`Call`](https://api.vapi.ai/api#:~:text=Call), [`ServerMessageStatusUpdate`](https://api.vapi.ai/api#:~:text=ServerMessageStatusUpdate), and [`ServerMessageEndOfCallReport`](https://api.vapi.ai/api#:~:text=ServerMessageEndOfCallReport). You can update your application to handle this new end reason, ensuring proper notification and handling when this occurs. diff --git a/fern/changelog/2025-06-11.mdx b/fern/changelog/2025-06-11.mdx new file mode 100644 index 000000000..5bbf8f12b --- /dev/null +++ b/fern/changelog/2025-06-11.mdx @@ -0,0 +1,29 @@ +# Assembly AI Transcriber Improvements, chat cost tracking, and API tool enhancements + +1. **Chat Cost Tracking**: You can now access detailed cost information per [Chat](https://api.vapi.ai/api#:~:text=FunctionCall-,Chat,-CreateChatDTO) and [Call](https://api.vapi.ai/api#:~:text=SchedulePlan-,Call,-CallBatchError), including total and per-component breakdowns. Use `Call.cost` and `Chat.cost` to get the total cost, and `Call.costs` and `Chat.costs` to get the breakdown.` + + + ```json title="Chat Schema (excerpt)" + { + "cost": 0.12, + "costs": [ + { "type": "model", "cost": 0.22 }, + { "type": "chat", "cost": 0.10 }, + ] + } + ``` + + +2. **Enhanced AssemblyAI Transcriber Configuration**: You can now fine-tune the AssemblyAI transcriber with: + - `maxTurnSilence`: The maximum amount of silence in milliseconds before a turn is considered complete. + - `endOfTurnConfidenceThreshold`: The confidence threshold for determining the end of a turn. + - `minEndOfTurnSilenceWhenConfident`: The minimum amount of silence in milliseconds before a turn is considered complete when the confidence is high. + - `wordFinalizationMaxWaitTime`: The maximum amount of time in milliseconds to wait for word finalization. + +3. **New Cartesia Transcriber Option**: You can now use the [Cartesia "Ink Whisper" transcriber](https://api.vapi.ai/api#:~:text=CartesiaTranscriber) for your for assistants and workflow nodes using `Assistant.transcriber` and `ConversationNode.transcriber`. Set this in your [Vapi Assistant dashboard today](https://dashboard.vapi.ai/assistants#:~:text=Transcriber). + + + Cartesia Transcriber + + +4. **API Request Tool Variable Extraction**: You can now use [`assistant.model.tools[type=apiRequest].variableExtractionPlan`](https://api.vapi.ai/api#:~:text=VariableExtractionPlan) to extract and validate variables from API responses by defining a variable schema. diff --git a/fern/changelog/2025-06-13.mdx b/fern/changelog/2025-06-13.mdx new file mode 100644 index 000000000..21d5587c8 --- /dev/null +++ b/fern/changelog/2025-06-13.mdx @@ -0,0 +1,40 @@ +# Background Speech Denoising, Cartesia Transcriber, Workflow Enhancements, and Call Error Handling + +1. **Background Speech Denoising Plan**: You can now enhance call quality by configuring advanced background speech denoising options using the new [`assistant.backgroundSpeechDenoisingPlan.smartDenoisingPlan`](https://api.vapi.ai/api#:~:text=SessionPaginatedResponse-,Assistant,-AssistantPaginatedResponse) (default: `false`), which replaces the previous `backgroundDenoisingEnabled` setting. + + + + Use the `SmartDenoisingPlan` to filter out background speech and noise using [Krisp technology](https://krisp.ai/). + + + Fine-tune noise reduction with the new `FourierDenoisingPlan` for more control over audio clarity. + + + + + Smart and Fourier denoising can be combined for optimal results. Order of precedence: Smart denoising, then Fourier denoising. + + +2. **Workflow Server Property**: Workflows now support a [`server`](https://api.vapi.ai/api#:~:text=TrieveKnowledgeBaseImport-,Workflow,-UpdateWorkflowDTO) property, allowing you to specify a server URL to receive webhook callbacks for workflow events directly. + +3. **New Workflow Models**: You can now integrate Google's LLMs or custom models into your workflows by specifying [`Google`](https://api.vapi.ai/api#:~:text=WorkflowGoogleModel) or [`Custom LLM`](https://api.vapi.ai/api#:~:text=WorkflowCustomModel) in your workflow model settings. Select your model under [Model Settings](https://dashboard.vapi.ai/workflows#:~:text=Model%20Settings) + + + Workflow Google Custom LLM + + +4. **Enhanced Error Reporting for Cartesia Services**: A new `endedReason` value `pipeline-error-cartesia-502-server-error` has been added to help you identify and handle specific errors related to Cartesia server issues. + +5. **Enhanced Error Handling and Status Enums**: We've added new error enums and status codes to help you better handle and debug call-related issues: + + - **VAPI Fault Errors**: Detect specific VAPI-related errors during call start using `call.start.error-vapifault-get-org` and `call.start.error-vapifault-get-subscription` + + - **Subscription Status Errors**: Identify subscription-related issues with new enums: + - `call.start.error-subscription-frozen` (replaces `unknown-error`) + - `call.start.error-subscription-insufficient-credits` + + - **Call Completion Statuses**: Track how calls are completed with new enums: + - `call.in-progress.twilio-completed-call` + - `call.in-progress.sip-completed-call` + + - **In-Call Error Detection**: Handle specific errors during active calls using enums like `call.in-progress.error-vapifault-chat-pipeline-failed-to-start` \ No newline at end of file diff --git a/fern/changelog/2025-06-14.mdx b/fern/changelog/2025-06-14.mdx new file mode 100644 index 000000000..4faf53d60 --- /dev/null +++ b/fern/changelog/2025-06-14.mdx @@ -0,0 +1,3 @@ +# Access to `chat` Object in Server Messages + +1. **Access to `chat` Object in Server Messages**: You can now access the `chat` object within various server messages, providing additional context about the conversation. diff --git a/fern/changelog/2025-06-15.mdx b/fern/changelog/2025-06-15.mdx new file mode 100644 index 000000000..7f75eaa74 --- /dev/null +++ b/fern/changelog/2025-06-15.mdx @@ -0,0 +1,3 @@ +# New Storage Credentials Providers + +1. **New Storage Provider Credentials Added**: You can now use new credential types [`S3Credential`](https://api.vapi.ai/api#:~:text=S3Credential), [`GcpCredential`](https://api.vapi.ai/api#:~:text=GcpCredential), [`AzureCredential`](https://api.vapi.ai/api#:~:text=AzureCredential), [`SupabaseCredential`](https://api.vapi.ai/api#:~:text=SupabaseCredential), and [`CloudflareCredential`](https://api.vapi.ai/api#:~:text=CloudflareCredential) to integrate with various storage services. This expands your options for storing data seamlessly across different providers. \ No newline at end of file diff --git a/fern/changelog/2025-06-16.mdx b/fern/changelog/2025-06-16.mdx new file mode 100644 index 000000000..8b39d9517 --- /dev/null +++ b/fern/changelog/2025-06-16.mdx @@ -0,0 +1,17 @@ +# New Model Selection, Enhanced Edge Conditions, Simplified Credentials, and More + +1. **New Model Selection in Workflows**: You can now specify the AI model used in workflows by setting the `model` property in workflow schemas. This allows choosing between OpenAI, Anthropic, Google, or custom models to better suit application requirements. + +2. **Enhanced Workflow Edge Conditions**: Workflows now support [`Logic Edge Conditions`](https://api.vapi.ai/api#:~:text=LogicEdgeCondition) and [`Failed Edge Conditions`](https://api.vapi.ai/api#:~:text=FailedEdgeCondition) for edges. Specify logic edge conditions with [Liquid JS templates](https://liquidjs.com/) to enable more complex logic and error handling within workflows, allowing for dynamic and responsive workflow designs. + +3. **Simplified Credential Configuration**: Your uploaded credentials are now automatically configured with the correct fallback index, simplifying the setup process with cloud providers. + +4. **Updated End Reasons for ElevenLabs**: The following `endedReason` values been removed from `Call`: + - `pipeline-error-eleven-labs-503-server-error` + - `call.in-progress.error-providerfault-eleven-labs-503-server-error` + + You should update your error handling code to reflect the current set of possible end reasons. + + +**Prompt Length Limitations**: The `globalPrompt` in workflows now has a maximum length of 5000 characters, and the `liquid` property in `LogicEdgeCondition` now has a maximum length of 1000 characters. Ensure prompts and conditions stay within these limits to prevent errors. + diff --git a/fern/changelog/2025-06-18.mdx b/fern/changelog/2025-06-18.mdx new file mode 100644 index 000000000..7e0dc9447 --- /dev/null +++ b/fern/changelog/2025-06-18.mdx @@ -0,0 +1,15 @@ +## Overview + +1. **API Request Tool**: You can now create [API request tools](https://api.vapi.ai/api#:~:text=ApiRequestTool) that allow the assistant to make REST API calls during conversations + + + + + +2. **Specify GCP Region**: You can now specify the region for your [GCP Credentials](https://dashboard.vapi.ai/settings/integrations#:~:text=Save-,GCP%20credentials,-For%20storing%20the), This gives you control over where your call artifacts are stored. + + + + + +3. **Transcriber Formatting Option**: A new `formatTurns` option in your [`Assembly AI Transcriber`](https://api.vapi.ai/api#:~:text=AssemblyAITranscriber) that lets you enable or disable formatting of transcripts when using AssemblyAI's Universal Streaming API. This helps you format transcript outputs to show speaker turns. diff --git a/fern/changelog/2025-06-19.mdx b/fern/changelog/2025-06-19.mdx new file mode 100644 index 000000000..c03f5e327 --- /dev/null +++ b/fern/changelog/2025-06-19.mdx @@ -0,0 +1,7 @@ +# Workflow Configuration Enhancements and Assistant Updates + +1. **Workflow-Level Configuration of Voice and Plans**: Developers can now configure `voice`, `transcriber`, and various plans like `monitorPlan` and `artifactPlan` at the workflow level. These configurations can still be overridden at the node level if needed. + +2. **Use of Dynamic Credentials in Workflows**: Workflows now support `credentials` and `credentialIds`, allowing you to specify dynamic credentials for workflow calls. This offers more flexibility in credential management, enabling credentials to be tied directly to specific workflows. + +3. **`backgroundDenoisingEnabled` Deprecated in Assistants**: The `backgroundDenoisingEnabled` property in Assistant is now deprecated. You should use the new [`Assistant.backgroundSpeechDenoisingPlan`](https://api.vapi.ai/api#:~:text=SessionPaginatedResponse-,Assistant,-AssistantPaginatedResponse) to configure advanced background noise and speech denoising features. diff --git a/fern/changelog/2025-06-20.mdx b/fern/changelog/2025-06-20.mdx new file mode 100644 index 000000000..f578b9b04 --- /dev/null +++ b/fern/changelog/2025-06-20.mdx @@ -0,0 +1,21 @@ +# New Campaigns APIs and Assistant Improvements + + + **Create, retrieve, and manage campaigns** using the new [`/campaign` endpoints](https://docs.vapi.ai/api-reference/calls/list#:~:text=Campaign). Build automated call campaigns with specified customers and schedules. + + + + **General Availability**: [`Assistant.modelOutputInMessagesEnabled`](https://api.vapi.ai/api#:~:text=SessionPaginatedResponse-,Assistant,-AssistantPaginatedResponse) is now generally available without beta limitations. You can decide whether to use the model's output in conversation history instead of the assistant's speech transcription. + + +1. **Simplified Assistant Property Structure**: Properties like `serverMessages`, `clientMessages`, and `serverUrl` have been moved under [`Assistant.monitorPlan`](https://api.vapi.ai/api#:~:text=SessionPaginatedResponse-,Assistant,-AssistantPaginatedResponse). This reorganization simplifies how you configure monitoring for your assistants. + +2. **Node-Level Overrides for Model and Voice**: In [`Conversation Node`](https://api.vapi.ai/api#:~:text=ConversationNode), properties like `model`, `voice`, and `transcriber` now explicitly override the workflow's settings. This allows you to customize these settings for individual nodes within a workflow for greater control. + +3. **Enhanced Credential Configuration in Assistants**: Assistants now support `credentials` and `credentialIds`, similar to workflows. This allows you to specify dynamic credentials specifically for assistant calls, enhancing security and flexibility. + +4. **New Models Available in `ConversationNode`**: You can now use [`Google Models`](https://api.vapi.ai/api#:~:text=WorkflowGoogleModel) and [`Custom Models`](https://api.vapi.ai/api#:~:text=WorkflowCustomModel) in conversation nodes. This expands the range of language models that can be integrated into conversation nodes. + + + + \ No newline at end of file diff --git a/fern/changelog/2025-06-24.mdx b/fern/changelog/2025-06-24.mdx new file mode 100644 index 000000000..f5275d57c --- /dev/null +++ b/fern/changelog/2025-06-24.mdx @@ -0,0 +1,20 @@ + + You can now use Inworld as a voice provider by selecting [`Inworld`](https://dashboard.vapi.ai/assistants#:~:text=VOICE-,Voice%20Configuration,-Select%20a%20voice) in your configuration. You can also route your InWorld credentials under [Settings > Integrations](https://dashboard.vapi.ai/settings/integrations#:~:text=Save-,Inworld,-For%20using%20voices). Finally, there are new `Call.endedReason` codes to help you better understand why calls ended due to Inworld voice issues. + + + + + + +2. **HMAC Authentication for Webhook Credentials**: Secure your webhooks with HMAC authentication by configuring [`Assistant.credentials.authenticationPlan`](https://api.vapi.ai/api#:~:text=Assistant,-AssistantPaginatedResponse) with [`HMACAuthenticationPlan`](https://api.vapi.ai/api#:~:text=HMACAuthenticationPlan), providing an alternative to OAuth2. + +3. **Detailed Call End Reasons for Inworld Voice**: New `endedReason` codes provide more insight when calls end due to Inworld voice issues. + + + +**Breaking Change**: The `codeSwitchingEnabled` property has been removed from Deepgram transcribers. If you're currently using this property in your Deepgram transcriber configurations, you'll need to remove it to avoid errors. + + + +**Org Concurrency Limit Deprecated**: The `concurrencyLimit` field in [`Org`](https://api.vapi.ai/api#:~:text=Org), [`CreateOrgDTO`](https://api.vapi.ai/api#:~:text=CreateOrgDTO), and [`UpdateOrgDTO`](https://api.vapi.ai/api#:~:text=UpdateOrgDTO) is now marked as deprecated. + \ No newline at end of file diff --git a/fern/changelog/2025-06-25.mdx b/fern/changelog/2025-06-25.mdx new file mode 100644 index 000000000..71cf020fc --- /dev/null +++ b/fern/changelog/2025-06-25.mdx @@ -0,0 +1,32 @@ +# Custom Models, Enhanced Campaigns, and MCP Tool Improvements + + + **Bring your own hosted LLMs and Google Gemini models** to workflows with new [`WorkflowCustomModel`](https://api.vapi.ai/api#:~:text=WorkflowCustomModel) and [`WorkflowGoogleModel`](https://api.vapi.ai/api#:~:text=WorkflowGoogleModel) objects. Control payload structure for advanced integrations and expand your model choices beyond OpenAI. + + + + + + + **Gain deeper insight into campaign performance** with new call counters including `callsCounterQueued`, `callsCounterScheduled`, `callsCounterInProgress`, and `callsCounterEndedVoicemail` for comprehensive campaign tracking. + + + + **Flexible tool integrations** with new [`McpToolMetadata`](https://api.vapi.ai/api#:~:text=McpToolMetadata) field. Select between Server-Sent Events (`sse`) or Streamable HTTP (`shttp`) protocols for tool communication. + + + + **Create support tickets directly through Vapi ** using the new [`/support/ticket`](https://api.vapi.ai/api#:~:text=SupportTicket) endpoint, simplifying how you request assistance. + + +1. **Multilingual LMNT Voice Support**: The [`LMNTVoice`](https://api.vapi.ai/api#:~:text=LMNTVoice) and [`FallbackLMNTVoice`](https://api.vapi.ai/api#:~:text=FallbackLMNTVoice) objects now support a `language` property (ISO 639-1 or `auto`) for selecting or auto-detecting spoken language in synthesized voices. + +2. **Assistant Overrides in Chats**: The `assistantOverrides` property is now available in [`Chat`](https://api.vapi.ai/api#:~:text=Chat), [`CreateChatDTO`](https://api.vapi.ai/api#:~:text=CreateChatDTO), and [`OpenAIResponsesRequest`](https://api.vapi.ai/api#:~:text=OpenAIResponsesRequest), allowing you to dynamically override assistant settings and template variables per chat session. + +3. **New API Endpoints and Objects**: Added `POST /workflow/generate` endpoint for workflow generation with tool IDs, plus new objects including `GenerateWorkflowDTO` and enhanced `CreateMcpToolDTO`/`UpdateMcpToolDTO` with metadata support. + +4. **Include Messages in Server Response from Transfer Requests**: When transferring calls, you can now include a `message` to communicate with users during the process with [`ServerMessageResponse.message.message`](https://api.vapi.ai/api#:~:text=ServerMessageResponse). + + +**Breaking Change**: The `'aws-sts'` type is no longer supported in [`OAuth2AuthenticationPlan`](https://api.vapi.ai/api#:~:text=OAuth2AuthenticationPlan). If you're currently using this type in your OAuth2 authentication configurations, you'll need to update it to avoid errors. + diff --git a/fern/changelog/2025-06-26.mdx b/fern/changelog/2025-06-26.mdx new file mode 100644 index 000000000..2740fb315 --- /dev/null +++ b/fern/changelog/2025-06-26.mdx @@ -0,0 +1,18 @@ + + **Create web-based chat sessions with your assistants** using the new [`Web Chat`](https://api.vapi.ai/api#:~:text=WebChat) integration with [`OpenAI Web Chat Requests`](https://api.vapi.ai/api#:~:text=OpenAIWebChatRequest). Accept user input as strings or message arrays and manage conversations with session and customer information. + + +2. **Inworld TTS Voice Provider Integration**: You can now customize which language [`Inworld Voices`](https://api.vapi.ai/api#:~:text=InworldVoice) use like `English`, `Chinese`, and `Korean`. You can also set the TTS `model` and toggle voice caching with `cachingEnabled`. + + + + + + +3. **Additional Customer Information Fields**: You can now include `email` and `externalId` fields when [creating customers](https://api.vapi.ai/api#:~:text=CreateCustomerDTO). You can also disable the E164 number format check with `numberE164CheckEnabled` – setting it to `false` lets you use non-E164 numbers like `1234` or `abc`, useful for dialing non-standard numbers on SIP trunks. This lets you store extra contact information and link customers to external systems. + +4. **`schedulePlan` No Longer Required in Campaigns**: You can now [create campaigns](https://docs.vapi.ai/api-reference/campaigns/campaign-controller-create) without specifying a `schedulePlan`. + + +**Behavior Change**: The `Chat.assistantOverrides` property now only supports variable substitution in chat contexts, limiting its functionality compared to previous versions. + diff --git a/fern/changelog/2025-07-10.mdx b/fern/changelog/2025-07-10.mdx new file mode 100644 index 000000000..a785b6f1f --- /dev/null +++ b/fern/changelog/2025-07-10.mdx @@ -0,0 +1,3 @@ +# Addition of `keypadInputPlan` for Workflow Calls** + +You can now configure keypad input handling during workflow calls by specifying `workflow.keypadInputPlan`. This enables interactive features like menu selections or data entry using user keypad inputs. diff --git a/fern/changelog/2025-07-11.mdx b/fern/changelog/2025-07-11.mdx new file mode 100644 index 000000000..5295e4b64 --- /dev/null +++ b/fern/changelog/2025-07-11.mdx @@ -0,0 +1,9 @@ +1. **Define Hooks at Workflow Level**: You can now define call-level hooks using `Workflow.hooks` to trigger actions on call events. + +2. **New Actions Available in Hooks**: Hooks support new actions like `say`, `tool`, `transfer`, and `function`, providing more options to define what happens when a hook is triggered. + +3. **Hooks Triggered by Additional Events**: Hooks can now be set to trigger on new events such as `Call.ending`, `Customer.speech.timeout`, `Customer.speech.interrupted`, and `Assistant.speech.interrupted`, giving you more flexibility in handling different call scenarios. + +4. **Conditional Hook Execution with Filters**: You can use the [`CallHookFilter`](https://api.vapi.ai/api#:~:text=CallHookFilter) to specify conditions under which a hook should trigger, allowing for precise control over hook activation based on call data. + +5. **Enhanced Prompt Configuration in Actions**: With [`SayHookAction`](https://api.vapi.ai/api#:~:text=SayHookAction), you can configure prompts as a string or an array of messages, providing flexibility in how messages are delivered to callers. diff --git a/fern/changelog/2025-07-15.mdx b/fern/changelog/2025-07-15.mdx new file mode 100644 index 000000000..b3a89f21d --- /dev/null +++ b/fern/changelog/2025-07-15.mdx @@ -0,0 +1,5 @@ +1. **Standardized 'Provider Resources' API Summaries and Tags**: The API endpoints for provider resources now have clearer summaries and are grouped under the **Provider Resources** tag, making them easier to find and understand. + +2. **Added `'westus2'` Azure Region Support**: You can now specify `'westus2'` as a region when configuring Azure credentials, allowing access to services in this new region. + +3. **Removed `'trial'` Subscription Type**: The `'trial'` option has been removed from subscription types; ensure your application no longer uses `'trial'` and updates to valid subscription types. diff --git a/fern/changelog/2025-07-16.mdx b/fern/changelog/2025-07-16.mdx new file mode 100644 index 000000000..a9033822c --- /dev/null +++ b/fern/changelog/2025-07-16.mdx @@ -0,0 +1,8 @@ +1. **Addition of `model` property to Workflows**: You can now set a default language model for your workflows using [`Workflow.model`](https://api.vapi.ai/api#:~:text=TrieveKnowledgeBaseImport-,Workflow,-UpdateWorkflowDTO). This simplifies configuration by allowing you to specify the model once for the entire workflow instead of at each node. + +2. **Removal of `westus2` region from Azure credentials**: The `westus2` region is no longer supported in Azure credential configurations. Update your Azure credentials to use a different region to maintain access to Azure services. + + + The following OpenAI models have been removed and are no longer available: `gpt-4.5-preview`, `o1-preview`, and `o1-preview-2024-09-12`. + Update your workflows to use supported models to avoid interruptions. + \ No newline at end of file diff --git a/fern/changelog/2025-07-17.mdx b/fern/changelog/2025-07-17.mdx new file mode 100644 index 000000000..02bde0f91 --- /dev/null +++ b/fern/changelog/2025-07-17.mdx @@ -0,0 +1,7 @@ +# Use Transient Tools in Conversation Nodes + +1. **Add Transient Tools to Conversation Nodes with `tools`:** You can now define transient tools directly within a [`Conversation Node`](https://api.vapi.ai/api#:~:text=ConversationNode) using `Call.workflow.nodes[type=conversation].tools`. This allows for the customization of tools specific to a conversation without altering global tool configurations. + +2. **Incorporate Existing Tools into Conversation Nodes with `toolIds`:** You can now reference existing tools in a [`Conversation Node`](https://api.vapi.ai/api#:~:text=ConversationNode) by listing their IDs using the `toolIds` property. This enables the reuse of predefined tools across different nodes and workflows for consistency and easier maintenance. + +This allows you to mix transient, node-specific tools with existing tools within a `ConversationNode`. Learn more about how to use this in the [Conversation Node documentation](https://docs.vapi.ai/workflows/overview#conversation-node). diff --git a/fern/changelog/2025-07-18.mdx b/fern/changelog/2025-07-18.mdx new file mode 100644 index 000000000..bcd114397 --- /dev/null +++ b/fern/changelog/2025-07-18.mdx @@ -0,0 +1 @@ +1. **Custom headers for custom LLM models**: You can now add custom `headers` to both [`Custom LLM Models`](https://api.vapi.ai/api#:~:text=CustomLLMModel) and [`Workflow Custom Models`](https://api.vapi.ai/api#:~:text=WorkflowCustomModel) (including in assistants, squads, and workflows). This lets you send custom HTTP headers—such as for authentication or extra metadata—when Vapi calls your custom LLM API. The `headers` property overrides default headers (except `Authorization`, which should be set via your custom-llm credential). \ No newline at end of file diff --git a/fern/changelog/2025-07-25.mdx b/fern/changelog/2025-07-25.mdx new file mode 100644 index 000000000..b54168adb --- /dev/null +++ b/fern/changelog/2025-07-25.mdx @@ -0,0 +1,12 @@ +1. **Minimax Voice Provider Integration and Error Handling**: You can now use [MinimaxVoice](https://api.vapi.ai/api#:~:text=MinimaxVoice) as a voice provider in your [assistants](https://api.vapi.ai/api#:~:text=SessionPaginatedResponse-,Assistant,-AssistantPaginatedResponse) and [workflows](https://api.vapi.ai/api#:~:text=Workflow), with support for [Minimax credentials](https://api.vapi.ai/api#:~:text=CreateMinimaxCredentialDTO) for seamless authentication and integration. Additionally, calls can now terminate with Minimax-specific error reasons such as `pipeline-error-minimax-voice-failed` and `call.in-progress.error-vapifault-minimax-voice-failed`. This gives you access to customizable voice characteristics like pitch, speed, and emotion for more natural-sounding conversations. + +2. **AssemblyAI Transcriber Updates**: The [AssemblyAITranscriber](https://api.vapi.ai/api#:~:text=AssemblyAITranscriber) configuration has been simplified: + - The `enableUniversalStreamingApi` property has been removed. + - The `formatTurns` property now defaults to `true` and no longer depends on the universal streaming API setting. + - Several properties have updated descriptions and defaults, with references to the deprecated universal streaming API removed. + +3. **Enhanced Chat and Session Events**: New message types have been added for handling chat and session events: `chat.created`, `chat.deleted`, `session.created`, `session.updated`, and `session.deleted`. These events are available in both [ClientMessage](https://api.vapi.ai/api#:~:text=ClientMessage) and [ServerMessage](https://api.vapi.ai/api#:~:text=ServerMessage) objects, giving you better control over interactive conversations. + +4. **Expanded API Request Tool Capabilities**: The [ApiRequestTool](https://api.vapi.ai/api#:~:text=ApiRequestTool) now supports `PUT`, `PATCH`, and `DELETE` HTTP methods alongside the existing `GET` and `POST` methods. This enables your tools to perform full CRUD operations on external APIs. + +5. **Targeted Call Analysis**: You can now specify `outcomeIds` in your [AnalysisPlan](https://api.vapi.ai/api#:~:text=AnalysisPlan) to calculate specific outcomes during call analysis. This allows for more focused analytics based on your defined metrics and KPIs. diff --git a/fern/changelog/2025-07-31.mdx b/fern/changelog/2025-07-31.mdx new file mode 100644 index 000000000..cd1ffe2c5 --- /dev/null +++ b/fern/changelog/2025-07-31.mdx @@ -0,0 +1,15 @@ +1. **Artifact Logging**: You can now access call logs directly through the new `logUrl` property in the [`Artifact`](https://api.vapi.ai/api#:~:text=Artifact) schema, providing a direct URL to call logs for each workflow execution to aid in debugging and compliance. + +2. **Azure Speech Transcriber Segmentation**: You can now fine-tune speech segmentation in [`AzureSpeechTranscriber`](https://api.vapi.ai/api#:~:text=AzureSpeechTranscriber) using `segmentationStrategy`, `segmentationMaximumTimeMs`, and `segmentationSilenceTimeoutMs` properties for better transcription control. + + +**Breaking Changes** + +The following changes may require updates to your existing integrations: + +- The `messagePlan` and `backgroundDenoisingEnabled` properties have been removed from [`Assistant`](https://api.vapi.ai/api#:~:text=Assistant), [`AssistantOverrides`](https://api.vapi.ai/api#:~:text=AssistantOverrides), [`CreateAssistantDTO`](https://api.vapi.ai/api#:~:text=CreateAssistantDTO), and [`UpdateAssistantDTO`](https://api.vapi.ai/api#:~:text=UpdateAssistantDTO). Use `backgroundSpeechDenoisingPlan` instead for background denoising configuration. + +- The `segmentationMaxTimeMs` property in [`AzureSpeechTranscriber`](https://api.vapi.ai/api#:~:text=AzureSpeechTranscriber) has been replaced by `segmentationMaximumTimeMs` for consistency. + +- The `variables` field in [`Artifact`](https://api.vapi.ai/api#:~:text=Artifact) and [`NodeArtifact`](https://api.vapi.ai/api#:~:text=NodeArtifact) has been replaced by `variableValues` to standardize how extracted data is stored and referenced. + diff --git a/fern/changelog/2025-08-01.mdx b/fern/changelog/2025-08-01.mdx new file mode 100644 index 000000000..c45764853 --- /dev/null +++ b/fern/changelog/2025-08-01.mdx @@ -0,0 +1,35 @@ +# New Features & Enhancements + +1. **Enhanced Call [`Artifacts`](https://api.vapi.ai/api#:~:text=Artifact)**: You can now store detailed information about call workflows and outcomes using [`Artifact`](https://api.vapi.ai/api#:~:text=Artifact) objects. Key properties include: + - `nodes`: History of workflow nodes executed during the call. + - `messages`: All messages spoken during the call. + - `logUrl`: **New!** Direct URL to detailed call logs for debugging. + - `pcapUrl`: Packet capture URL for phone calls (provider: `vapi` or `byo-phone-number`). + - `recording`: Recording URL (requires `assistant.artifactPlan.recordingEnabled`). + - `transcript`: Convenient full call transcript. + - `variableValues`: Final workflow variable states. + - `messagesOpenAIFormatted`: Spoken messages, formatted for OpenAI. + + + `recordingUrl`, `videoRecordingUrl`, `stereoRecordingUrl`, and `videoRecordingStartDelaySeconds` are now deprecated in favor of the new `recording` and related properties within the `Artifact` object. + + +2. **Improved Azure Speech Segmentation Tuning**: You can now fine-tune speech segmentation in your [`Azure Speech Transcriber`](https://api.vapi.ai/api#:~:text=AzureSpeechTranscriber) using `segmentationStrategy`, `segmentationMaximumTimeMs`, and `segmentationSilenceTimeoutMs` properties for better transcription control. This applies to both [`Azure Speech Transcriber`](https://api.vapi.ai/api#:~:text=AzureSpeechTranscriber) and [`Fallback Azure Speech Transcriber`](https://api.vapi.ai/api#:~:text=FallbackAzureSpeechTranscriber). + + + The `segmentationMaxTimeMs` property in [`AzureSpeechTranscriber`](https://api.vapi.ai/api#:~:text=AzureSpeechTranscriber) has been replaced by `segmentationMaximumTimeMs` for consistency. + + +## Deprecations + + + messagePlan and backgroundDenoisingEnabled are now part of Assistant.backgroundSpeechDenoisingPlan instead of Assistant and AssistantOverrides directly. + + + stripeCustomerId is now part of Subscription instead of Org. + + + segmentationMaxTimeMs property has been renamed to segmentationMaximumTimeMs for consistency. + + + diff --git a/fern/changelog/2025-08-02.mdx b/fern/changelog/2025-08-02.mdx new file mode 100644 index 000000000..1a536ea11 --- /dev/null +++ b/fern/changelog/2025-08-02.mdx @@ -0,0 +1,3 @@ +# Azure Speech Segmentation Strategy Tuning + +1. You can now tune `Assistant.transcriber[provider="AzureSpeechTranscriber"].segmentationStrategy` using `"Default"`, `"Time"`, and `"Semantic"` strategies, offering more control over phrase boundary detection. diff --git a/fern/changelog/2025-08-03.mdx b/fern/changelog/2025-08-03.mdx new file mode 100644 index 000000000..a22b865eb --- /dev/null +++ b/fern/changelog/2025-08-03.mdx @@ -0,0 +1,28 @@ + +#### 🎤 New Gladia Transcription Provider Support +1. **Custom vocabulary support**: Enable a custom vocabulary with [`Gladia`](https://api.vapi.ai/api#:~:text=GladiaTranscriber) using `Assistant.transcriber[provider="GladiaTranscriber"].customVocabularyEnabled`. You can also specify simple strings or detailed objects with fields for value, language, intensity, and alternative pronunciations using `Assistant.transcriber[provider="GladiaTranscriber"].customVocabularyConfig` - letting you fine-tune recognition of domain-specific terms. + +2. **Endpointing & Speech Threshold**: Configure endpointing time (wait time before considering speech ended) and speech sensitivity, enabling more accurate and responsive transcription with `Assistant.transcriber[provider="GladiaTranscriber"].endpointing` and `Assistant.transcriber[provider="GladiaTranscriber"].speechThreshold`. + +3. **Prosody & Audio Enhancer**: Optionally enable prosody (for transcribing non-verbal cues like laughter) and audio enhancement for improved accuracy with `Assistant.transcriber[provider="GladiaTranscriber"].prosodyEnabled` and `Assistant.transcriber[provider="GladiaTranscriber"].audioEnhancerEnabled`. + +4. **Flexible Language Detection**: Choose between manual and automatic language detection modes with `Assistant.transcriber[provider="GladiaTranscriber"].languageDetectionMode`. + +5. **Confidence Thresholds & Hints**: Discard low-confidence transcripts and provide context hints for improved accuracy with `Assistant.transcriber[provider="GladiaTranscriber"].confidenceThreshold` and `Assistant.transcriber[provider="GladiaTranscriber"].hints`. + +## 💳 Subscription Updates + + + + Role-based access control (RBAC):
+ Enable RBAC for your subscription using Subscription.rbacEnabled. +
+ + Retention settings:
+ Configure how long calls and chats are stored with Subscription.callRetentionDays and Subscription.chatRetentionDays. +
+ + Reset frequency:
+ Set how often included minutes reset using Subscription.minutesIncludedResetFrequency. +
+
diff --git a/fern/changelog/2025-08-08.mdx b/fern/changelog/2025-08-08.mdx new file mode 100644 index 000000000..1933751fd --- /dev/null +++ b/fern/changelog/2025-08-08.mdx @@ -0,0 +1,29 @@ +# New: Smarter Conditions & Security Filters + +1. **New Condition & Filter Types**: You can now use the following new condition and filter types to build more robust rejection plans and security filter plans: +- **MessageTarget**: Target specific messages by role and position for conditions using `Assistant.hooks.do[type=tool].tool.rejectionPlan.conditions[type=regex].target`. +- **GroupCondition**: Combine multiple conditions using AND/OR logic, with support for recursive nesting using `Assistant.hooks.do[type=tool].tool.rejectionPlan.conditions[type=group]`. +- **RegexCondition**: Flexible pattern matching, with full support for JavaScript regex and negation using `Assistant.hooks.do[type=tool].tool.rejectionPlan.conditions[type=regex]`. +- **LiquidCondition**: Use Liquid templates for complex, context-aware logic using `Assistant.hooks.do[type=tool].tool.rejectionPlan.conditions[type=liquid]`. +- **Security Filters**: New filter types for RCE, XSS, SSRF, SQL injection, prompt injection, and regex-based filtering using `Assistant.compliancePlan.securityFilterPlan.filters`. + +2. **Tool Rejection Plans**: You can now use [`Assistant.hooks.do[type=tool].tool.rejectionPlan`](https://api.vapi.ai/api#:~:text=ToolRejectionPlan) in all tool calls to prevent accidental tool execution, enforce confirmation steps, and build more robust conversation flows. This helps you to define complex logic for when a tool call should be rejected, enhancing both safety and call experience. Rejection plans can be built using regex conditions, [Liquid templates](https://liquidjs.com/), or logical groups (AND/OR). For example, you can prevent an `endCall` tool from executing unless the user says goodbye, or block a transfer if the user is actually asking a question. + +**Example:** +```json +{ + "conditions": [ + { + "type": "regex", + "regex": "(?i)\\b(bye|goodbye|farewell|see you later|take care)\\b", + "target": { "position": -1, "role": "user" }, + "negate": true + } + ] +} +``` + +3. **Security Filter Plans for Transcripts and Messages**: You can now use [`Assistant.compliancePlan.securityFilterPlan`](https://api.vapi.ai/api#:~:text=SecurityFilterPlan) to define how transcripts and messages are filtered against threats like SQL injection, XSS, prompt injection, and more. Choose between `sanitize`, `reject`, or `replace` when threats are detected, and specify custom replacement text. User messages and transcript objects now include: + - `isFiltered`: Indicates if content was filtered for security. + - `detectedThreats`: Lists detected threats. + - `originalMessage` / `originalTranscript`: Preserves original content if filtering occurred. diff --git a/fern/changelog/2025-08-09.mdx b/fern/changelog/2025-08-09.mdx new file mode 100644 index 000000000..ef8e81bb8 --- /dev/null +++ b/fern/changelog/2025-08-09.mdx @@ -0,0 +1,57 @@ +## New: Call Metrics & Artifact Improvements + +You can now access detailed call performance metrics and structured output IDs directly from your call artifacts. + + + + Each conversation turn's latency +
+ Call.artifact.performanceMetrics.turnLatencies +
+ + Average time for the model to generate a response +
+ Call.artifact.performanceMetrics.modelLatencyAverage +
+ + Average time to synthesize voice +
+ Call.artifact.performanceMetrics.voiceLatencyAverage +
+
+ + + + Average time to transcribe voice +
+ Call.artifact.performanceMetrics.transcriberLatencyAverage +
+ + Time to detect end of a conversation turn +
+ Call.artifact.performanceMetrics.endpointingLatencyAverage +
+ + Average latency to complete a conversation turn +
+ Call.artifact.performanceMetrics.turnLatencyAverage +
+
+ + + Track and extract structured outputs from your calls +
    +
  • + During call: Access array of output IDs
    + Call.artifactPlan.structuredOutputIds +
  • +
  • + After call: Extracted outputs are stored here
    + Call.artifact.structuredOutputs +
  • +
+
+ + + These improvements help you monitor, debug, and analyze your calls with greater detail. + diff --git a/fern/changelog/2025-08-14.mdx b/fern/changelog/2025-08-14.mdx new file mode 100644 index 000000000..97827036d --- /dev/null +++ b/fern/changelog/2025-08-14.mdx @@ -0,0 +1,16 @@ +1. **Handoff Tool and Dynamic Agent Routing**: You can now hand off conversations when building multi-agent systems with [`Assistant.model.tools[type=handoff]`](https://api.vapi.ai/api#:~:text=HandoffTool). Supported destinations include: +- **Assistant Destinations**: Directly hand off to a specific assistant by assistantId or assistantName. +- **Dynamic Destinations**: Route handoffs dynamically via a webhook to your server, which can determine the destination assistant in real time. Custom parameters such as customer intent, sentiment, or area code can be passed to the webhook for advanced routing logic. +- **Multiple Destinations**: Support for both single handoff destination per tool with multiple tools (recommended for OpenAI) and multiple handoff destinations with one tool (recommended for Anthropic). + +You can read more about how to configure the handoff tool in the [API Reference](https://api.vapi.ai/api#:~:text=HandoffTool) + +2. **Context Engineering for Handoffs**: When handing off a conversation, you can now control what context is passed to the next assistant: +- **All Messages**: Pass the entire conversation history. Refer to [Context Engineering Plan All](https://api.vapi.ai/api#:~:text=ContextEngineeringPlanAll) +- **Last N Messages**: Pass only the most recent N messages. Refer to [Context Engineering Plan LastNMessages](https://api.vapi.ai/api#:~:text=ContextEngineeringPlanLastNMessages) +- **None**: Pass no prior context. Refer to [Context Engineering Plan None](https://api.vapi.ai/api#:~:text=ContextEngineeringPlanNone) +This gives you fine-grained control over privacy, relevance, and prompt size during agent transitions. + +3. **Message Metadata**: [Tool Messages](https://api.vapi.ai/api#:~:text=ToolMessage), [Assistant Messages](https://api.vapi.ai/api#:~:text=AssistantMessage), and [Developer Messages](https://api.vapi.ai/api#:~:text=DeveloperMessage) objects now support an optional metadata field, allowing you to attach arbitrary metadata to messages for downstream processing or analytics. + +4. **Pagination Meta Enhancement**: You can now reference `itemsBeyondRetention` boolean in paginated responses to indicate if additional items exist beyond the retention window. diff --git a/fern/changelog/2025-08-21.mdx b/fern/changelog/2025-08-21.mdx new file mode 100644 index 000000000..e6a29b4f4 --- /dev/null +++ b/fern/changelog/2025-08-21.mdx @@ -0,0 +1,13 @@ +1. **Enhanced Artifact Plans**: All [`Artifact Plans`](https://api.vapi.ai/api#:~:text=ArtifactPlan) now support the following properties: +- **`loggingEnabled`** - Toggle to enable call logs +- **`loggingPath`** - Custom path for call log uploads +- **`structuredOutputs`** - Toggle for structured output extraction + +2. **Enhanced Artifact Management**: You can now extract structured data during calls with the new `structuredOutputs` property in [`Artifact`](https://api.vapi.ai/api#:~:text=Artifact). + +3. **Improved Cost Analysis**: You can now view detailed call costs with new fields in [`Analysis Cost Breakdown`](https://api.vapi.ai/api#:~:text=AnalysisCostBreakdown): +- **`structuredOutput`** - Cost for structured output evaluation +- **`structuredOutputPromptTokens`** - Prompt tokens for structured output +- **`structuredOutputCompletionTokens`** - Completion tokens for structured output + +4. **Phone Number Hooks**: You can now configure hooks for call ending events with the new [`Call Ending hook for phone numbers`](https://api.vapi.ai/api#:~:text=PhoneNumberHookCallEnding) and exclude events to exclude from the hook with [`the relevant filter`](https://api.vapi.ai/api#:~:text=PhoneNumberCallEndingHookFilter) diff --git a/fern/changelog/2025-08-23.mdx b/fern/changelog/2025-08-23.mdx new file mode 100644 index 000000000..d8f2fd593 --- /dev/null +++ b/fern/changelog/2025-08-23.mdx @@ -0,0 +1,7 @@ +# Voicemail Detection Enhancements + +1. **Voicemail Detection Enhancements**: You can now configure voicemail detection across providers with [`Assistant.voicemailDetection`](https://api.vapi.ai/api#:~:text=https://api.vapi.ai/api#:~:text=SessionPaginatedResponse-,Assistant,-AssistantPaginatedResponse), for example with [Vapi](https://api.vapi.ai/api#:~:text=VapiVoicemailDetectionPlan), [Google](https://api.vapi.ai/api#:~:text=GoogleVoicemailDetectionPlan), and [OpenAI](https://api.vapi.ai/api#:~:text=OpenAIVoicemailDetectionPlan).Each plan now supports a `type` property to select between: + - `audio`: Native audio model detection (default) + - `transcript`: ASR/transcript-based detection + +2. **Fine-tuned control**: Under each voicemail detection plan, you can configure backoff plans and beep detection timing with [`Assistant.voicemailDetection["yourVoicemailDetectionPlan"].beepMaxAwaitSeconds`](https://api.vapi.ai/api#:~:text=https://api.vapi.ai/api#:~:text=VapiVoicemailDetectionPlan) for improved voicemail handling in automated calls. diff --git a/fern/changelog/2025-08-25.mdx b/fern/changelog/2025-08-25.mdx new file mode 100644 index 000000000..a80d021e0 --- /dev/null +++ b/fern/changelog/2025-08-25.mdx @@ -0,0 +1,9 @@ +1. **New Structured Output Endpoints**: You can now use [new APIs for structured outputs](https://docs.vapi.ai/api-reference/calls/list#:~:text=Delete%20Logs-,Structured%20Outputs,-GET) to define, extract, and manage structured data from conversations. + +2. **Configure Structured Output Resources**: You can now define reusable structured data extraction templates, including: + - **Custom JSON Schema**: Specify the exact structure and validation rules for extracted data using full JSON Schema support (objects, arrays, enums, validation constraints, and more). + - **Model Selection**: Choose the LLM (OpenAI, Anthropic, Google, or custom) for extraction, or provide custom system/user prompts with Liquid templating for advanced scenarios. + - **Context Linking**: Link structured outputs to specific workflows or assistants for context-aware extraction. + - **Metadata**: Track creation/update timestamps, org linkage, and provide rich descriptions for each structured output. + +3. **Assistant Transfer Improvements**: You can now include an optional `name` property to better identify and manage your transfer assistants. diff --git a/fern/changelog/2025-08-27.mdx b/fern/changelog/2025-08-27.mdx new file mode 100644 index 000000000..a44c53eb6 --- /dev/null +++ b/fern/changelog/2025-08-27.mdx @@ -0,0 +1,7 @@ +1. **Enhanced Tool Retry Logic with Backoff Plans**: You can now use [`Assistant.hooks.do[type=tool].tool.backoffPlan`](https://api.vapi.ai/api#:~:text=CartesiaTranscriber-,BackoffPlan,-%7B) and [`Assistant.hooks.do[type=tool].tool.server.backoffPlan`](https://api.vapi.ai/api#:~:text=CartesiaTranscriber-,BackoffPlan,-%7B) to configure retry behavior for tool calls. Options include: + +- **`fixed` backoff** (default): Consistent delay between retries. +- **`exponential` backoff**: Increasing delays for subsequent retries +- **Configurable retry limits**: Set `maxRetries` (0-10, default: 0) +- **Flexible timing**: Adjust `baseDelaySeconds` (0-10 seconds) +- **Smart status code handling**: Exclude specific HTTP status codes from retry attempts. \ No newline at end of file diff --git a/fern/changelog/2025-08-28.mdx b/fern/changelog/2025-08-28.mdx new file mode 100644 index 000000000..6aeaa9540 --- /dev/null +++ b/fern/changelog/2025-08-28.mdx @@ -0,0 +1 @@ +1. **End AI call transfers after set timeout period**: You can now configure [AI-managed transfers](https://docs.vapi.ai/call-forwarding#7-assistant-based-warm-transfer-experimental) with a [Transfer Assistant](https://api.vapi.ai/api#:~:text=TransferAssistant) to automatically end the call after a specified period of silence with `silenceTimeoutSeconds` (default 30 seconds). This helps prevent idle calls from lingering and saves costs. diff --git a/fern/changelog/2025-08-29.mdx b/fern/changelog/2025-08-29.mdx new file mode 100644 index 000000000..8341591a7 --- /dev/null +++ b/fern/changelog/2025-08-29.mdx @@ -0,0 +1,5 @@ +1. **Per-Artifact Storage Routing in [Artifact Plans](https://api.vapi.ai/api#:~:text=ArtifactPlan)**: You can now override artifact storage behavior per assistant/call for SIP packet capture (PCAP), logging, and call recording artifacts: + +- `Assistant.artifactPlan.pcapUseCustomStorageEnabled` (default true): Use custom storage for SIP packet capture, which are stored in `Assistant.artifactPlan.pcapUrl`. +- `Assistant.artifactPlan.loggingUseCustomStorageEnabled` (default true): Determines whether to use your custom storage (S3 or GCP) for call logs when storage credentials are configured; set to false to store logs on Vapi's storage for this assistant, even if custom storage is set globally. +- `Assistant.artifactPlan.recordingUseCustomStorageEnabled` (default true): Determines whether to use your custom storage (S3 or GCP) for call recordings when storage credentials are configured; set to false to store recordings on Vapi's storage for this assistant, even if custom storage is set globally. diff --git a/fern/changelog/2025-08-30.mdx b/fern/changelog/2025-08-30.mdx new file mode 100644 index 000000000..5fac2a92d --- /dev/null +++ b/fern/changelog/2025-08-30.mdx @@ -0,0 +1,17 @@ +# Enhanced Authentication & Custom Credentials + +1. **Custom Credential System**: You can now create and manage custom authentication credentials using the new [`CustomCredential`](https://api.vapi.ai/api#:~:text=CustomCredential) system. This powerful new feature supports multiple authentication methods: + - **OAuth2 RFC 6749**: Full OAuth2 implementation for secure third-party integrations + - **HMAC Signing**: Cryptographic message authentication for enhanced security + - **Bearer Token**: Simple token-based authentication for API access + +2. **Bearer Authentication Plans**: Implement secure token-based authentication with [`BearerAuthenticationPlan`](https://api.vapi.ai/api#:~:text=BearerAuthenticationPlan). Key features include: + - `token`: Your secure bearer token value + - `headerName`: Custom header name (defaults to 'Authorization') + - `bearerPrefixEnabled`: Toggle 'Bearer ' prefix inclusion (defaults to true) + +3. **Enhanced Webhook Credentials**: Webhook integrations now support advanced authentication through [`WebhookCredential.authenticationPlan`](https://api.vapi.ai/api#:~:text=WebhookCredential.authenticationPlan), enabling secure webhook communications with OAuth2, HMAC, or Bearer authentication. + +4. **Server Authentication**: Secure your server endpoints with credential-based authentication using [`Server.credentialId`](https://api.vapi.ai/api#:~:text=Server.credentialId) to link your custom credentials to webhook destinations. + +5. **Tool Authentication Integration**: API request tools can now use custom credentials for secure external API calls via [`ApiRequestTool.credentialId`](https://api.vapi.ai/api#:~:text=ApiRequestTool.credentialId), eliminating the need to embed sensitive authentication details directly in tool configurations. diff --git a/fern/changelog/2025-09-02.mdx b/fern/changelog/2025-09-02.mdx new file mode 100644 index 000000000..9ebf516cf --- /dev/null +++ b/fern/changelog/2025-09-02.mdx @@ -0,0 +1,36 @@ +# Recording Consent & Compliance Management + +1. **Recording Consent Plans**: Ensure legal compliance with call recording regulations using the new [`CompliancePlan.recordingConsentPlan`](https://api.vapi.ai/api#:~:text=CompliancePlan.recordingConsentPlan). This feature helps you meet GDPR, CCPA, and other privacy regulations by properly obtaining user consent before recording calls. + +2. **Verbal Consent Collection**: Implement active consent collection with [`RecordingConsentPlanVerbal`](https://api.vapi.ai/api#:~:text=RecordingConsentPlanVerbal) where users explicitly agree or decline recording: + - `message`: Custom consent message (e.g., "This call may be recorded for quality purposes. Say 'I agree' to consent.") + - `voice`: Optional dedicated voice for consent messages for better user experience + - `declineTool`: Execute specific tools when users decline consent + - `declineToolId`: Reference existing tools for decline handling + +3. **Stay-on-Line Consent**: Use passive consent collection with [`RecordingConsentPlanStayOnLine`](https://api.vapi.ai/api#:~:text=RecordingConsentPlanStayOnLine) where staying on the call implies consent: + - `message`: Informational message about recording (e.g., "For quality purposes, this call may be recorded. Please hang up if you do not consent.") + - `waitSeconds`: Configurable wait time (1-6 seconds) before proceeding + - `voice`: Optional separate voice for consent announcements + +4. **Recording Consent Tracking**: Monitor consent status throughout the call lifecycle with [`Call.compliance.recordingConsent`](https://api.vapi.ai/api#:~:text=Call.compliance.recordingConsent): + - `type`: The type of consent obtained + - `grantedAt`: Timestamp when consent was granted (null if not granted) + +5. **Enhanced End-of-Call Reports**: Recording consent information is now included in [`ServerMessageEndOfCallReport.compliance`](https://api.vapi.ai/api#:~:text=ServerMessageEndOfCallReport.compliance), providing complete compliance audit trails for your records. + +## Compliance Features + + + Meet GDPR, CCPA, and other privacy regulations with built-in consent management and audit trails. + + + Choose between verbal consent requiring explicit agreement or stay-on-line consent with implied agreement. + + + Customize consent messages to match your brand voice and legal requirements with up to 1000 characters. + + + Complete compliance records with timestamps and consent status in call artifacts and end-of-call reports. + + \ No newline at end of file diff --git a/fern/changelog/2025-09-05.mdx b/fern/changelog/2025-09-05.mdx new file mode 100644 index 000000000..3fca7b352 --- /dev/null +++ b/fern/changelog/2025-09-05.mdx @@ -0,0 +1,47 @@ +# Evaluation System Foundation + +1. **Evaluation Framework**: You can now systematically test your Vapi voice assistants with the new [`Eval`](https://api.vapi.ai/api#:~:text=Eval) system. Create comprehensive test scenarios to validate assistant behavior, conversation flow, and tool usage through mock conversations. + +2. **Mock Conversation Builder**: Design test conversations using [`Eval.messages`](https://api.vapi.ai/api#:~:text=Eval.messages) with support for multiple message types: + - [`ChatEvalUserMessageMock`](https://api.vapi.ai/api#:~:text=ChatEvalUserMessageMock): Simulate user inputs and questions + - [`ChatEvalSystemMessageMock`](https://api.vapi.ai/api#:~:text=ChatEvalSystemMessageMock): Inject system messages mid-conversation + - [`ChatEvalToolResponseMessageMock`](https://api.vapi.ai/api#:~:text=ChatEvalToolResponseMessageMock): Mock tool responses for consistent testing + - [`ChatEvalAssistantMessageEvaluation`](https://api.vapi.ai/api#:~:text=ChatEvalAssistantMessageEvaluation): Define evaluation checkpoints + +3. **Evaluation Types**: Currently focused on `chat.mockConversation` type evaluations, with the framework designed to support additional evaluation methods in future releases. + +4. **Evaluation Management**: Organize your tests with [`CreateEvalDTO`](https://api.vapi.ai/api#:~:text=CreateEvalDTO) and [`UpdateEvalDTO`](https://api.vapi.ai/api#:~:text=UpdateEvalDTO): + - `name`: Descriptive names up to 80 characters (e.g., "Customer Support Flow Validation") + - `description`: Detailed descriptions up to 500 characters explaining the test purpose + - `messages`: The complete mock conversation flow + +5. **Evaluation Endpoints**: Access your evaluations through the new [`/eval`](https://api.vapi.ai/api#:~:text=/eval) endpoint family: + - `GET /eval`: List all evaluations with pagination support + - `POST /eval`: Create new evaluations + - `GET /eval/{id}`: Retrieve specific evaluation details + - `PUT /eval/{id}`: Update existing evaluations + +6. **Judge Plan Architecture**: Define how assistant responses are validated using [`AssistantMessageJudgePlan`](https://api.vapi.ai/api#:~:text=AssistantMessageJudgePlan) with three evaluation methods: + - **Exact Match**: [`AssistantMessageJudgePlanExact`](https://api.vapi.ai/api#:~:text=AssistantMessageJudgePlanExact) for precise content and tool call validation + - **Regex Pattern**: [`AssistantMessageJudgePlanRegex`](https://api.vapi.ai/api#:~:text=AssistantMessageJudgePlanRegex) for flexible pattern-based evaluation + - **AI Judge**: [`AssistantMessageJudgePlanAI`](https://api.vapi.ai/api#:~:text=AssistantMessageJudgePlanAI) for intelligent evaluation using LLM-as-a-judge + + + This is the foundation release for the evaluation system. Evaluation execution and results processing will be available in upcoming releases. Start designing your test scenarios now to be ready for full evaluation capabilities. + + +## Testing Capabilities + + + Create realistic test scenarios with user messages, system prompts, and expected assistant responses for comprehensive flow validation. + + + Validate that your assistant calls the right tools with correct parameters using ChatEvalAssistantMessageMockToolCall. + + + Choose from exact matching, regex patterns, or AI-powered evaluation to suit different testing needs and complexity levels. + + + Organize tests with descriptive names and detailed documentation to maintain clear testing workflows across your team. + + \ No newline at end of file diff --git a/fern/changelog/2025-09-08.mdx b/fern/changelog/2025-09-08.mdx new file mode 100644 index 000000000..5b2441c95 --- /dev/null +++ b/fern/changelog/2025-09-08.mdx @@ -0,0 +1,44 @@ +# Enhanced Transcription Features & Speech Processing + +1. **Gladia Transcription Enhancements**: Improve transcription accuracy and performance with new [`GladiaTranscriber`](https://api.vapi.ai/api#:~:text=GladiaTranscriber) features: + - `region`: Choose between `us-west` and `eu-west` for optimal latency and data residency compliance + - `receivePartialTranscripts`: Enable low-latency streaming transcription for real-time conversation flow + - Enhanced language detection with support for both single and multiple language modes + +2. **Advanced Deepgram Controls**: Fine-tune speech recognition with enhanced [`DeepgramTranscriber`](https://api.vapi.ai/api#:~:text=DeepgramTranscriber) settings: + - `eotThreshold`: End-of-turn detection threshold for precise conversation boundaries (e.g., 0.7) + - `eotTimeoutMs`: Maximum wait time for end-of-turn detection in milliseconds (e.g., 5000ms) + - `eagerEotThreshold`: Early end-of-turn detection for responsive conversations (e.g., 0.3) + +3. **AssemblyAI Keyterms Enhancement**: Boost recognition accuracy for critical terms with [`AssemblyAITranscriber.keytermsPrompt`](https://api.vapi.ai/api#:~:text=AssemblyAITranscriber.keytermsPrompt): + - Support for up to 100 keyterms, each up to 50 characters + - Improved recognition for specific words and phrases + - Additional cost: $0.04/hour when enabled + +4. **Speechmatics Custom Vocabulary**: Enhance recognition accuracy with [`SpeechmaticsCustomVocabularyItem`](https://api.vapi.ai/api#:~:text=SpeechmaticsCustomVocabularyItem): + - `content`: The word or phrase to add (e.g., "Speechmatics") + - `soundsLike`: Alternative phonetic representations (e.g., ["speech mattix"]) for better pronunciation handling + +5. **Word-Level Confidence**: Access detailed transcription confidence data with [`CustomLLMModel.wordLevelConfidenceEnabled`](https://api.vapi.ai/api#:~:text=CustomLLMModel.wordLevelConfidenceEnabled), providing word-by-word accuracy metrics for quality assessment and debugging. + +6. **Enhanced Message Metadata**: Store transcription confidence and other metadata in [`UserMessage.metadata`](https://api.vapi.ai/api#:~:text=UserMessage.metadata), enabling detailed analysis of transcription quality and user speech patterns. + + + `AssemblyAITranscriber.wordFinalizationMaxWaitTime` is now deprecated. Use the new smart endpointing plans for better speech timing control. The deprecated property will be removed in a future release. + + +## Transcription Improvements + + + Choose optimal transcription regions with Gladia's us-west and eu-west options for reduced latency and compliance. + + + Enable partial transcripts for immediate response processing, reducing perceived latency in conversations. + + + Fine-tune end-of-turn detection with configurable thresholds and timeouts for natural conversation flow. + + + Improve accuracy for domain-specific terms, company names, and technical jargon with enhanced vocabulary support. + + \ No newline at end of file diff --git a/fern/changelog/2025-09-11.mdx b/fern/changelog/2025-09-11.mdx new file mode 100644 index 000000000..4a631ec9c --- /dev/null +++ b/fern/changelog/2025-09-11.mdx @@ -0,0 +1,37 @@ +# Voice Enhancements & Minimax Improvements + +1. **Minimax Voice Language Support**: Enhance multilingual conversations with [`MinimaxVoice.languageBoost`](https://api.vapi.ai/api#:~:text=MinimaxVoice.languageBoost). Support for 40+ languages including: + - `Chinese` and `Chinese,Yue` for Mandarin and Cantonese + - `English`, `Spanish`, `French`, `German`, `Japanese`, `Korean` + - Regional variants and specialized languages like `Arabic`, `Hindi`, `Thai` + - `auto` mode for automatic language detection + +2. **Text Normalization**: Improve number reading and formatting with [`MinimaxVoice.textNormalizationEnabled`](https://api.vapi.ai/api#:~:text=MinimaxVoice.textNormalizationEnabled). When enabled, spoken numbers, dates, and formatted text are properly pronounced for natural-sounding conversations. + +3. **Enhanced Voice Caching**: Voice responses are now cached by default with [`MinimaxVoice.cachingEnabled`](https://api.vapi.ai/api#:~:text=MinimaxVoice.cachingEnabled) set to `true`, reducing latency for repeated phrases and improving overall conversation performance. + +4. **Fallback Voice Configuration**: Ensure conversation continuity with [`FallbackMinimaxVoice`](https://api.vapi.ai/api#:~:text=FallbackMinimaxVoice) featuring the same language boost and text normalization capabilities as the primary voice configuration. + +5. **Speaker Labeling**: Track multiple speakers in conversations with [`BotMessage.speakerLabel`](https://api.vapi.ai/api#:~:text=BotMessage.speakerLabel), providing stable speaker identification (e.g., "Speaker 1") for better conversation analysis and diarization. + +6. **Voice Region Support**: Choose optimal performance regions with Minimax's `worldwide` (default) or `china` regional settings for better latency and compliance with local regulations. + + + Language boost settings help the text-to-speech model better understand context and pronunciation for specific languages, resulting in more natural and accurate voice synthesis. + + +## Voice Quality Features + + + Support for 40+ languages with automatic detection and language-specific optimizations for natural pronunciation. + + + Intelligent normalization of numbers, dates, and formatted text for natural-sounding speech synthesis. + + + Voice caching reduces latency for common phrases, while regional settings optimize for local performance. + + + Speaker labeling and diarization support for multi-participant conversation analysis and management. + + \ No newline at end of file diff --git a/fern/changelog/2025-09-14.mdx b/fern/changelog/2025-09-14.mdx new file mode 100644 index 000000000..2248b3303 --- /dev/null +++ b/fern/changelog/2025-09-14.mdx @@ -0,0 +1,35 @@ +# Squad Management & Session Enhancement + +1. **Squad-Based Sessions**: Organize your assistants into collaborative teams with [`Session.squad`](https://api.vapi.ai/api#:~:text=Session.squad) and [`Session.squadId`](https://api.vapi.ai/api#:~:text=Session.squadId). Sessions can now be associated with squads for team-based conversation management and coordinated assistant behavior. + +2. **Squad Chat Integration**: Enable squad-based chat conversations using [`Chat.squad`](https://api.vapi.ai/api#:~:text=Chat.squad) and [`Chat.squadId`](https://api.vapi.ai/api#:~:text=Chat.squadId). This allows multiple assistants to participate in or be aware of chat contexts for more sophisticated conversation handling. + +3. **Enhanced Session Creation**: Create squad-enabled sessions with [`CreateSessionDTO.squad`](https://api.vapi.ai/api#:~:text=CreateSessionDTO.squad) and [`CreateSessionDTO.squadId`](https://api.vapi.ai/api#:~:text=CreateSessionDTO.squadId), enabling persistent conversation contexts across multiple assistants and interaction types. + +4. **Chat Management by Squad**: Filter and organize chats by squad membership using [`GetChatPaginatedDTO.squadId`](https://api.vapi.ai/api#:~:text=GetChatPaginatedDTO.squadId) for better conversation management and team-based analytics. + +5. **Session Management by Squad**: Query sessions by squad association with [`GetSessionPaginatedDTO.squadId`](https://api.vapi.ai/api#:~:text=GetSessionPaginatedDTO.squadId), providing team-based session organization and management capabilities. + +6. **Full Message History**: Control conversation context retention with [`ArtifactPlan.fullMessageHistoryEnabled`](https://api.vapi.ai/api#:~:text=ArtifactPlan.fullMessageHistoryEnabled). When enabled, artifacts contain complete message history even after handoff context engineering, preserving full conversation flow for analysis. + +7. **Transfer Records**: Track warm transfer details with [`Artifact.transfers`](https://api.vapi.ai/api#:~:text=Artifact.transfers), providing comprehensive records of transfer destinations, transcripts, and status information for multi-assistant conversations. + + + Squad management enables sophisticated multi-assistant workflows where different specialists can handle different parts of a conversation while maintaining shared context and coordination. + + +## Team Collaboration Features + + + Enable multiple assistants to work together within squads for specialized conversation handling and seamless handoffs. + + + Maintain conversation context across squad members and session boundaries for continuous conversation experiences. + + + Filter conversations, sessions, and analytics by squad membership for team-based performance insights and management. + + + Track all transfers and handoffs with detailed records including destinations, transcripts, and status information. + + \ No newline at end of file diff --git a/fern/changelog/2025-09-17.mdx b/fern/changelog/2025-09-17.mdx new file mode 100644 index 000000000..f9a8b4d90 --- /dev/null +++ b/fern/changelog/2025-09-17.mdx @@ -0,0 +1,36 @@ +# API Versioning & Infrastructure Updates + +1. **API Version 2 Introduction**: Access enhanced functionality through new versioned endpoints while maintaining full backward compatibility: + - [`/v2/call`](https://api.vapi.ai/api#:~:text=/v2/call): Enhanced call management with new features and improved response formats + - [`/v2/phone-number`](https://api.vapi.ai/api#:~:text=/v2/phone-number): Advanced phone number management with extended capabilities + +2. **Enhanced Pagination**: Improved pagination controls across all endpoints with [`PaginationMeta`](https://api.vapi.ai/api#:~:text=PaginationMeta) enhancements: + - `createdAtGe` and `createdAtLe`: Date range filtering for creation timestamps + - Better sorting and filtering options for large datasets + - Enhanced metadata for pagination state management + +3. **Workflow Message Configuration**: Customize voicemail handling in workflows with [`CreateWorkflowDTO.voicemailMessage`](https://api.vapi.ai/api#:~:text=CreateWorkflowDTO.voicemailMessage) and [`CreateWorkflowDTO.voicemailDetection`](https://api.vapi.ai/api#:~:text=CreateWorkflowDTO.voicemailDetection) for comprehensive call flow management. + +4. **Credential Integration**: Seamless credential management across all workflow and assistant configurations with enhanced [`credentials.items.discriminator.mapping.custom-credential`](https://api.vapi.ai/api#:~:text=credentials.items.discriminator.mapping.custom-credential) support. + +5. **Transport Infrastructure**: Foundation for advanced communication channels with improved transport configuration and management capabilities. + + + Version 2 endpoints provide enhanced features while v1 endpoints remain fully functional. Migrate to v2 when you need access to new capabilities or improved performance characteristics. + + +## Infrastructure Improvements + + + Existing v1 endpoints continue to work unchanged, ensuring smooth transitions and zero downtime for existing integrations. + + + Improved date range filtering and pagination controls for better data management and API performance. + + + Enhanced workflow configuration with better voicemail handling and credential management throughout the call flow. + + + Foundation for advanced features and capabilities that will be built on the v2 API structure. + + \ No newline at end of file diff --git a/fern/changelog/2025-09-20.mdx b/fern/changelog/2025-09-20.mdx new file mode 100644 index 000000000..6064b183a --- /dev/null +++ b/fern/changelog/2025-09-20.mdx @@ -0,0 +1,41 @@ +# Chat Transport & SMS Integration + +1. **Twilio SMS Transport**: Send chat responses directly via SMS using [`TwilioSMSChatTransport`](https://api.vapi.ai/api#:~:text=TwilioSMSChatTransport) in [`CreateChatDTO.transport`](https://api.vapi.ai/api#:~:text=CreateChatDTO.transport). This enables programmatic SMS conversations with your voice assistants, bridging the gap between voice and text communication. + +2. **SMS Session Management**: Create new sessions automatically when using SMS transport by providing: + - `customer`: Customer information for SMS delivery + - `phoneNumberId`: SMS-enabled phone number from your organization + - Automatic session creation when both fields are provided + +3. **LLM-Generated vs Direct SMS**: Control message processing with [`TwilioSMSChatTransport.useLLMGeneratedMessageForOutbound`](https://api.vapi.ai/api#:~:text=TwilioSMSChatTransport.useLLMGeneratedMessageForOutbound): + - `true` (default): Input processed by assistant for intelligent responses + - `false`: Direct message forwarding without LLM processing for notifications and alerts + +4. **Enhanced Chat Creation**: [`CreateChatDTO`](https://api.vapi.ai/api#:~:text=CreateChatDTO) now supports sophisticated session management: + - `transport`: SMS delivery configuration + - `sessionId`: Use existing session data + - Mutual exclusivity between `sessionId` and transport fields for clear session boundaries + +5. **OpenAI Responses Integration**: Streamlined chat processing with [`OpenAIResponsesRequest`](https://api.vapi.ai/api#:~:text=OpenAIResponsesRequest) supporting the same transport and squad integration features for consistent API experience. + +6. **Cross-Platform Continuity**: Seamlessly transition between voice calls and SMS conversations within the same session, maintaining context and conversation history across communication channels. + + + SMS transport requires SMS-enabled phone numbers in your organization. The phone number must support SMS functionality and belong to your account for successful message delivery. + + +## SMS Communication Features + + + Send and receive SMS messages through your voice assistant, enabling text-based interactions alongside voice conversations. + + + Choose between AI-processed responses and direct message forwarding based on your use case requirements. + + + Maintain conversation context across SMS and voice interactions within unified sessions for seamless user experiences. + + + Automatic session creation and management when using transport fields, simplifying SMS conversation setup. + + \ No newline at end of file diff --git a/fern/changelog/2025-09-23.mdx b/fern/changelog/2025-09-23.mdx new file mode 100644 index 000000000..f2479defe --- /dev/null +++ b/fern/changelog/2025-09-23.mdx @@ -0,0 +1,43 @@ +# Advanced Analytics & Variable Grouping + +1. **Variable Value Analytics**: Gain deeper insights into your assistant performance with [`AnalyticsQuery.groupByVariableValue`](https://api.vapi.ai/api#:~:text=AnalyticsQuery.groupByVariableValue). Group analytics data by specific variable values extracted during calls for granular performance analysis. + +2. **Enhanced Grouping Options**: Use [`VariableValueGroupBy`](https://api.vapi.ai/api#:~:text=VariableValueGroupBy) to specify custom grouping criteria: + - `key`: The variable value key to group by (up to 100 characters) + - Combine with existing grouping options like `assistantId`, `endedReason`, and `status` + +3. **Multi-Dimensional Analysis**: Create complex analytics queries by combining traditional grouping fields with variable values: + - Group by assistant performance AND custom business metrics + - Analyze conversation outcomes by extracted data points + - Track success rates across different variable value segments + +4. **Advanced Query Capabilities**: Enhanced [`AnalyticsQuery`](https://api.vapi.ai/api#:~:text=AnalyticsQuery) functionality enables sophisticated data analysis: + - Multiple grouping dimensions for comprehensive insights + - Variable-based segmentation for business intelligence + - Custom metric tracking through extracted call variables + +5. **Business Intelligence Integration**: Connect your call data to business outcomes by grouping analytics on: + - Customer satisfaction scores extracted from calls + - Product interest levels determined during conversations + - Lead qualification status gathered through assistant interactions + - Custom KPIs specific to your business logic + + + Variable values are extracted during calls using tool response schemas and aliases. Set up variable extraction in your tools to enable powerful analytics grouping based on conversation outcomes. + + +## Analytics Enhancements + + + Group analytics by any variable extracted during calls, enabling business-specific performance insights and KPI tracking. + + + Combine traditional call metrics with custom variable grouping for comprehensive conversation analysis. + + + Connect call performance to business outcomes through variable-based analytics and custom grouping options. + + + Create detailed reports by grouping on extracted conversation data like satisfaction scores, intent categories, or custom business metrics. + + \ No newline at end of file diff --git a/fern/changelog/2025-09-26.mdx b/fern/changelog/2025-09-26.mdx new file mode 100644 index 000000000..706f757f6 --- /dev/null +++ b/fern/changelog/2025-09-26.mdx @@ -0,0 +1,39 @@ +# Voicemail Detection & Handling Improvements + +1. **Enhanced Beep Detection**: Improve voicemail detection accuracy with [`CreateVoicemailToolDTO.beepDetectionEnabled`](https://api.vapi.ai/api#:~:text=CreateVoicemailToolDTO.beepDetectionEnabled) specifically for Twilio-based calls. This feature detects the characteristic beep sound that indicates voicemail recording has started. + +2. **Workflow Voicemail Integration**: Configure comprehensive voicemail handling in workflows with enhanced message and detection capabilities: + - [`Workflow.voicemailMessage`](https://api.vapi.ai/api#:~:text=Workflow.voicemailMessage): Custom messages for voicemail scenarios (up to 1000 characters) + - [`Workflow.voicemailDetection`](https://api.vapi.ai/api#:~:text=Workflow.voicemailDetection): Configurable detection methods for different providers + +3. **Assistant Voicemail Enhancement**: Improved voicemail handling in assistant configurations with [`Assistant.voicemailMessage`](https://api.vapi.ai/api#:~:text=Assistant.voicemailMessage) and [`Assistant.voicemailDetection`](https://api.vapi.ai/api#:~:text=Assistant.voicemailDetection) for consistent behavior across all conversation types. + +4. **Multiple Detection Methods**: Choose from various voicemail detection providers: + - **Google**: [`GoogleVoicemailDetectionPlan`](https://api.vapi.ai/api#:~:text=GoogleVoicemailDetectionPlan) for AI-powered detection + - **OpenAI**: [`OpenAIVoicemailDetectionPlan`](https://api.vapi.ai/api#:~:text=OpenAIVoicemailDetectionPlan) for intelligent voicemail recognition + - **Twilio**: [`TwilioVoicemailDetectionPlan`](https://api.vapi.ai/api#:~:text=TwilioVoicemailDetectionPlan) for carrier-level detection + - **Vapi**: [`VapiVoicemailDetectionPlan`](https://api.vapi.ai/api#:~:text=VapiVoicemailDetectionPlan) for integrated detection + +5. **Beep Detection for Call Flows**: The new beep detection capability works specifically with Twilio transport, providing reliable voicemail identification when traditional detection methods may not be sufficient. + +6. **Voicemail Tool Configuration**: Enhanced tool rejection and messaging capabilities ensure appropriate handling when voicemail is detected, with configurable responses based on your business requirements. + + + Beep detection is currently available only for Twilio-based calls. If you're using other providers, consider combining multiple detection methods for better accuracy. + + +## Voicemail Management Features + + + Support for Google, OpenAI, Twilio, and Vapi detection methods, allowing you to choose the best option for your use case. + + + Advanced audio analysis to detect voicemail beeps on Twilio calls for more reliable voicemail identification. + + + Configure personalized voicemail messages up to 1000 characters for better user experience and brand consistency. + + + Comprehensive voicemail handling throughout workflow nodes with consistent configuration across conversation flows. + + \ No newline at end of file diff --git a/fern/changelog/2025-09-28.mdx b/fern/changelog/2025-09-28.mdx new file mode 100644 index 000000000..0d6c91e31 --- /dev/null +++ b/fern/changelog/2025-09-28.mdx @@ -0,0 +1,49 @@ +# Evaluation Execution & Results Processing + +1. **Evaluation Execution Engine**: Run comprehensive assistant evaluations with [`EvalRun`](https://api.vapi.ai/api#:~:text=EvalRun) and [`CreateEvalRunDTO`](https://api.vapi.ai/api#:~:text=CreateEvalRunDTO). Execute your mock conversations against live assistants and squads to validate performance and behavior in controlled environments. + +2. **Multiple Evaluation Models**: Choose from various AI models for LLM-as-a-judge evaluation: + - [`EvalOpenAIModel`](https://api.vapi.ai/api#:~:text=EvalOpenAIModel): GPT models including GPT-4.1, o1-mini, o3, and regional variants + - [`EvalAnthropicModel`](https://api.vapi.ai/api#:~:text=EvalAnthropicModel): Claude models with optional thinking features for complex evaluations + - [`EvalGoogleModel`](https://api.vapi.ai/api#:~:text=EvalGoogleModel): Gemini models from 1.0 Pro to 2.5 Pro for diverse evaluation needs + - [`EvalGroqModel`](https://api.vapi.ai/api#:~:text=EvalGroqModel): High-speed inference models including Llama and custom options + - [`EvalCustomModel`](https://api.vapi.ai/api#:~:text=EvalCustomModel): Your own evaluation models with custom endpoints + +3. **Evaluation Results**: Comprehensive result tracking with [`EvalRunResult`](https://api.vapi.ai/api#:~:text=EvalRunResult): + - `status`: Pass/fail evaluation outcomes + - `messages`: Complete conversation transcript from the evaluation + - `startedAt` and `endedAt`: Precise timing information for performance analysis + +4. **Target Flexibility**: Run evaluations against different targets: + - [`EvalRunTargetAssistant`](https://api.vapi.ai/api#:~:text=EvalRunTargetAssistant): Test individual assistants with optional overrides + - [`EvalRunTargetSquad`](https://api.vapi.ai/api#:~:text=EvalRunTargetSquad): Evaluate entire squad performance and coordination + +5. **Evaluation Status Tracking**: Monitor evaluation progress with detailed status information: + - `running`: Evaluation in progress + - `ended`: Evaluation completed + - `queued`: Evaluation waiting to start + - Detailed `endedReason` including success, error, timeout, and cancellation states + +6. **Judge Configuration**: Optimize evaluation accuracy with model-specific settings: + - `maxTokens`: Recommended 50-10000 tokens (1 token for simple pass/fail responses) + - `temperature`: 0-0.3 recommended for LLM-as-a-judge to reduce hallucinations + + + For LLM-as-a-judge evaluations, the judge model must respond with exactly \"pass\" or \"fail\". Design your evaluation prompts to ensure clear, deterministic responses. + + +## Evaluation Capabilities + + + Choose from OpenAI, Anthropic, Google, Groq, or custom models for evaluation, matching your quality and performance requirements. + + + Detailed pass/fail results with complete conversation transcripts and timing information for thorough analysis. + + + Test individual assistants or entire squads with optional configuration overrides for comprehensive validation. + + + Real-time evaluation status tracking with detailed reason codes for failures, timeouts, and cancellations. + + \ No newline at end of file diff --git a/fern/changelog/2025-09-29.mdx b/fern/changelog/2025-09-29.mdx new file mode 100644 index 000000000..8de49ca2d --- /dev/null +++ b/fern/changelog/2025-09-29.mdx @@ -0,0 +1,66 @@ +# Breaking Changes & API Cleanup + +1. **Legacy Endpoint Removal**: The following deprecated endpoints have been removed as part of our API modernization effort: + - `/logs` - Use call artifacts and monitoring instead + - `/workflow/{id}` - Access workflows through the main workflow endpoints + - `/test-suite` and related paths - Replaced by the new evaluation system + - `/knowledge-base` and related paths - Integrated into model configurations + +2. **Knowledge Base Architecture Change**: The `knowledgeBaseId` property has been removed from all model configurations. This affects: + - [`XaiModel`](https://api.vapi.ai/api#:~:text=XaiModel), [`GroqModel`](https://api.vapi.ai/api#:~:text=GroqModel), [`GoogleModel`](https://api.vapi.ai/api#:~:text=GoogleModel) + - [`OpenAIModel`](https://api.vapi.ai/api#:~:text=OpenAIModel), [`AnthropicModel`](https://api.vapi.ai/api#:~:text=AnthropicModel), [`CustomLLMModel`](https://api.vapi.ai/api#:~:text=CustomLLMModel) + - All other model provider configurations + +3. **Transcriber Property Deprecation**: [`AssemblyAITranscriber.wordFinalizationMaxWaitTime`](https://api.vapi.ai/api#:~:text=AssemblyAITranscriber.wordFinalizationMaxWaitTime) and [`FallbackAssemblyAITranscriber.wordFinalizationMaxWaitTime`](https://api.vapi.ai/api#:~:text=FallbackAssemblyAITranscriber.wordFinalizationMaxWaitTime) are now deprecated: + - Use smart endpointing plans for better speech timing control + - More precise conversation flow management + - Enhanced end-of-turn detection capabilities + +4. **Schema Path Cleanup**: Removed numerous unused schema paths from model configurations to simplify the API structure and improve performance. This cleanup affects internal schema references but doesn't impact your existing integrations. + +5. **New v2 API**: We are introducing a new API version v2. These changes are part of our ongoing effort to: + - Simplify the API structure for better developer experience + - Remove redundant and deprecated functionality + - Complete the transition to new evaluation and compliance systems + - Improve API performance and maintainability + +For details on the new features that replace these deprecated endpoints, see our recent changelog entries: +- [Enhanced Authentication & Custom Credentials (Aug 30)](./2025-08-30.mdx) +- [Recording Consent & Compliance Management (Sep 2)](./2025-09-02.mdx) +- [Evaluation System Foundation (Sep 5)](./2025-09-05.mdx) +- [Evaluation Execution & Results Processing (Sep 28)](./2025-09-28.mdx) + + + If you're currently using any of the removed endpoints or properties, you must migrate to the new alternatives before this release. Contact support if you need assistance with migration strategies. + + +## Migration Guide + + + Replace /logs endpoint usage with call artifacts, monitoring plans, and end-of-call reports for comprehensive logging. + + + Migrate from test-suite endpoints to the new evaluation system with mock conversations and comprehensive result tracking. + + + Update model configurations to use the integrated knowledge base system instead of separate knowledgeBaseId references. + + + Replace deprecated transcriber timing properties with smart endpointing plans for better conversation flow control. + + + +## Removed Endpoints +The following endpoints are no longer available: +- `GET /logs` - Use call artifacts instead +- `GET /workflow/{id}` - Use main workflow endpoints +- `GET /test-suite`, `POST /test-suite` - Use [evaluation endpoints](./2025-09-05.mdx) +- `GET /test-suite/{id}`, `PUT /test-suite/{id}`, `DELETE /test-suite/{id}` - Use [evaluation management](./2025-09-28.mdx) +- `POST /test-suite/{testSuiteId}/run` - Use [evaluation runs](./2025-09-28.mdx) +- `GET /knowledge-base`, `POST /knowledge-base` - Integrated into model configurations +- All related nested endpoints and operations + +**See Also:** +- [Authentication System Updates (Aug 30)](./2025-08-30.mdx) - For credential management migration +- [Recording Consent Features (Sep 2)](./2025-09-02.mdx) - For compliance system details +- [Enhanced Transcription (Sep 8)](./2025-09-08.mdx) - For AssemblyAI timing alternatives \ No newline at end of file diff --git a/fern/changelog/2026-03-31.mdx b/fern/changelog/2026-03-31.mdx new file mode 100644 index 000000000..8a94351de --- /dev/null +++ b/fern/changelog/2026-03-31.mdx @@ -0,0 +1,79 @@ +# What's New: October 2025 – March 2026 + +Here's a summary of major items shipped from October 2025 through March 2026. + +--- + +## Platform + +1. **Squads v2**: Visual builder to simplify sophisticated multi-assistant orchestration with seamless handoffs between specialized agents. + +2. **Composer (Alpha)**: Intelligent assistant inside the dashboard that allows you to describe what you need through plain text prompts to help build, adjust, and debug voice agents. + +3. **Simulations (Alpha)**: Voice agent testing feature to build confidence through enabling systematic, AI-powered testing in specific scenarios with evaluation of outcomes. + +4. **Monitoring & Issues**: Automated call quality monitoring with trigger-based issue detection, alerting, and resolution suggestions. + +5. **HIPAA with Data Retention**: New compliance mode with private storage and in-dashboard toggle/purchase flow — available for additional cost. + +6. **Zero Data Retention**: Compliance mode that keeps context data during call as needed to execute tasks and retains no data afterwards. + +7. **Consolidated Logs**: Unified log viewing into a single page. + +8. **Vapi Voices**: 12 new ultra-realistic voices released, optimized for latency and cost with adjustable speed controls exposed. 8 legacy voices deprecated. + +--- + +## New Models & Provider Support + +### Transcriber Models (Speech-to-Text) + +1. **Deepgram Nova-3 Languages**: Added Hebrew, Urdu, Tagalog, and Arabic bilingual support. + +2. **Cartesia Transcriber**: ink-whisper. + +3. **Soniox**: stt-rt-v4. + +### Intelligence Models (LLM) + +1. **GPT-5 Family**: OpenAI's latest intelligence models, including GPT-5, 5-Mini, 5-Nano, 5.1, 5.2, 5.4, 5.4-Mini, 5.4-Nano. + +2. **Claude 4.5–4.6**: Anthropic's latest intelligence models Sonnet 4.5, Opus 4.5, Opus 4.6, Sonnet 4.6. + +3. **Gemini 3 Flash**: Google's latest intelligence models. + +4. **Grok 4 Fast**: Reasoning and non-reasoning variants. + +5. **GPT Realtime Mini**: OpenAI's lightweight realtime model. + +### Voice Models (Text-to-Speech) + +1. **Cartesia**: sonic-3, sonic-3-2026-01-12, sonic-3-2025-10-27. + +2. **WellSaid**: Caruso (new), legacy. + +3. **Inworld**: inworld-tts-1 (REST, original), inworld-tts-1.5-max (WebSocket, \$10/M chars), inworld-tts-1.5-mini (WebSocket, \$5/M chars). + +4. **ElevenLabs Scribe v2**: Latest version of ElevenLabs speech-to-text. + +--- + +## Developer Tools & API + +1. **Structured Outputs Improvements**: Updates to our AI-powered analysis and data extraction tool, including transient structured outputs, audio-based extraction, and regex extraction. + +2. **SIP Request Tool + DTMF over SIP INFO**: Send SIP requests and DTMF tones via SIP INFO messages during calls. + +3. **Variable Passing Between Tool Calls**: Pass output variables from one tool call as input to subsequent tool calls. + +4. **Encrypted Tool Arguments**: Encrypt sensitive tool arguments to protect data in transit. + +5. **Low Confidence Speech Hook**: Hook that triggers when the transcriber returns low-confidence speech results. + +6. **Time Elapsed Hook**: Hook that triggers at specified time intervals during a call. + +7. **assistant.speechStarted Event**: New event fired when the assistant begins speaking. + +8. **MCP Improvements**: Bearer auth, $ref dereferencing, child tool messages/discovery. + +9. **Warm Transfer Improvements**: SIP support, caller ID, context engineering, variable filling. diff --git a/fern/changelog/2026-04-13.mdx b/fern/changelog/2026-04-13.mdx new file mode 100644 index 000000000..16ad57ef3 --- /dev/null +++ b/fern/changelog/2026-04-13.mdx @@ -0,0 +1,6 @@ +# What's New: Week of April 13, 2026 + +1. **Monitoring — GA**: Automated call quality monitoring is now generally available. Detect issues with trigger-based rules, get alerts when something goes wrong, and surface resolution suggestions — all from the dashboard. + + - [Monitoring quickstart](https://docs.vapi.ai/observability/monitoring-quickstart) + - [Announcement blog post](https://blog.vapi.ai/monitoring) diff --git a/fern/changelog/2026-04-20.mdx b/fern/changelog/2026-04-20.mdx new file mode 100644 index 000000000..196e76921 --- /dev/null +++ b/fern/changelog/2026-04-20.mdx @@ -0,0 +1,14 @@ +# What's New: Week of April 20, 2026 + +1. **Logs UX Refresh**: New filter layout plus a round of UX improvements — improved date picker, active row is clearly highlighted across all log views when the flyout is opened, log tables are fully keyboard-accessible, sortable `cost` and `duration` columns, pagination, and more. + +2. **Squads `contextEngineeringPlan` Handoff Type — `previousAssistantMessages`**: Forwards only the conversation history from *before* the current assistant's session. The current assistant's own messages and tool calls are excluded entirely from the handoff payload. See the updated [handoff context configuration docs](https://docs.vapi.ai/security-and-privacy/pci#handoff-context-configuration). + +3. **`assistant.speechStarted` Event — Live Captions & Word-Level Timing (GA)**: A new opt-in message fires as the assistant begins speaking each segment, carrying the full turn text, `turn`, `source` (`model` / `force-say` / `custom-voice`), and optional timing: + - Per-word alignment on **ElevenLabs** + - Cursor-based word-progress on **Minimax** (set `voice.subtitleType: "word"`, with correct CJK handling) + - Text-only fallback on all other providers + + Subscribe by adding `"assistant.speechStarted"` to your assistant's `clientMessages` and/or `serverMessages` — now **GA with no feature flag**. Use it for live captions, karaoke-style highlighting, or any UI that needs to stay in sync with assistant audio. Fully backward-compatible; no existing messages changed. + +4. **Autofallbacks on Transcribers**: Let Vapi pick the best transcriber to fall back to if your primary one fails — even mid-call. Opt in by setting `assistant.transcriber.fallbackPlan.autoFallback.enabled` to `true`. See the updated [transcriber fallback plan docs](https://docs.vapi.ai/customization/transcriber-fallback-plan). diff --git a/fern/changelog/2026-04-27.mdx b/fern/changelog/2026-04-27.mdx new file mode 100644 index 000000000..03a1b3231 --- /dev/null +++ b/fern/changelog/2026-04-27.mdx @@ -0,0 +1,3 @@ +# What's New: Week of April 27, 2026 + +1. **Deepgram Flux — Multilingual Support**: Full support for Deepgram's multilingual Flux model. Multilingual agents can now leverage the same smart turn-taking that powers the English Flux transcriber, making cross-lingual conversations feel more fluid and natural. diff --git a/fern/changelog/2026-05-04.mdx b/fern/changelog/2026-05-04.mdx new file mode 100644 index 000000000..ab51f4ba2 --- /dev/null +++ b/fern/changelog/2026-05-04.mdx @@ -0,0 +1,3 @@ +# What's New: Week of May 4, 2026 + +1. **Soniox — General Availability**: The Soniox transcriber is now rolled out to all customers. Configure it on any assistant via `assistant.transcriber` (provider: `soniox`) for low-latency, multilingual real-time speech-to-text. diff --git a/fern/changelog/2026-05-11.mdx b/fern/changelog/2026-05-11.mdx new file mode 100644 index 000000000..c400a881f --- /dev/null +++ b/fern/changelog/2026-05-11.mdx @@ -0,0 +1,4 @@ +# What's New: Week of May 11, 2026 + +1. **New Assistant Builder Experience**: An updated, streamlined assistant configuration experience, now available to all users. + - UI optimizations for the Phone Numbers page were also made to align its look and interactions with the new experience. diff --git a/fern/changelog/2026-05-18.mdx b/fern/changelog/2026-05-18.mdx new file mode 100644 index 000000000..5af2cafdb --- /dev/null +++ b/fern/changelog/2026-05-18.mdx @@ -0,0 +1,5 @@ +# What's New: Week of May 18, 2026 + +1. **Responsive UI Polish**: A round of UI adjustments to make the app work better across viewport sizes. + +2. **New Composer-Based Onboarding Flow**: A new onboarding experience built on top of the Assistant Builder and powered by Composer is rolling out to select users as part of a phased release. diff --git a/fern/changelog/2026-05-25.mdx b/fern/changelog/2026-05-25.mdx new file mode 100644 index 000000000..38f56ea61 --- /dev/null +++ b/fern/changelog/2026-05-25.mdx @@ -0,0 +1,3 @@ +# What's New: Week of May 25, 2026 + +1. **Dashboard Performance**: Front-end infrastructure improvements for faster page loads and a snappier feel across the dashboard. diff --git a/fern/changelog/2026-06-01.mdx b/fern/changelog/2026-06-01.mdx new file mode 100644 index 000000000..b9374cc0b --- /dev/null +++ b/fern/changelog/2026-06-01.mdx @@ -0,0 +1,12 @@ +# What's New: Week of June 1, 2026 + +1. **xAI Speech-to-Text and Text-to-Speech**: xAI is now available as a transcriber (STT) and voice (TTS) provider for assistants. + +2. **Upgraded Vapi Voices**: A new text-to-speech model powering [Vapi Voices](https://docs.vapi.ai/providers/voice/vapi-voices) makes them sound more authentic, human, and consistent — at ~50% lower cost. + - Existing deployments don't change automatically — opt in by setting `version: 2` on the voice configuration via the API or Dashboard. See [Vapi Voices](https://docs.vapi.ai/providers/voice/vapi-voices) for supported voices and audio samples. + +3. **Pronunciation Dictionaries in the Dashboard**: The Assistants view now supports creating new [pronunciation dictionaries](https://docs.vapi.ai/assistants/pronunciation-dictionaries) directly from the dashboard. + +4. **Phone Number Fixes**: Improvements to phone number creation and listing. + - The Phone Numbers list no longer breaks on rows with no number or SIP URI. + - Creating a phone number now validates its Vapi identifier up front. diff --git a/fern/changelog/2026-06-15.mdx b/fern/changelog/2026-06-15.mdx new file mode 100644 index 000000000..91bef9e15 --- /dev/null +++ b/fern/changelog/2026-06-15.mdx @@ -0,0 +1,17 @@ +# What's New: Week of June 15, 2026 + +1. **Claude Haiku (Global)**: Now available as a model through [Amazon Bedrock](https://docs.vapi.ai/providers/model/anthropic-bedrock) for assistants. + +2. **Pronunciation Dictionary Management in Voice Config**: [Pronunciation dictionaries](https://docs.vapi.ai/assistants/pronunciation-dictionaries) configured via the API can now be viewed and managed directly in an assistant's voice settings in the dashboard. + - Stale dictionary references are flagged when a voice changes to a model that cannot apply them. + +3. **Rotating Tool Messages**: You can now configure multiple [message variants](https://docs.vapi.ai/tools/custom-tools) for a tool, and the assistant picks one at random so longer calls feel less repetitive. + +4. **Dynamic Variables in Test Calls**: A dialog lets you set [dynamic variable](https://docs.vapi.ai/assistants/dynamic-variables) values before starting a test call from the dashboard. + +5. **Concurrency and Rate Limits in Organization Settings**: Your [call concurrency](https://docs.vapi.ai/calls/call-concurrency) cap and API request rate limit now appear as read-only fields in Organization Settings. + +6. **Fixes and Improvements**: + - Cartesia voice overrides in squads now apply correctly instead of falling back to a hard-coded default. + - Duplicate tools sharing the same `function.name` are de-duplicated during model streaming, preventing duplicate tool calls. + - The call concurrency chart in analytics now renders correctly. diff --git a/fern/changelog/2026-06-22.mdx b/fern/changelog/2026-06-22.mdx new file mode 100644 index 000000000..e190610fd --- /dev/null +++ b/fern/changelog/2026-06-22.mdx @@ -0,0 +1,9 @@ +# What's New: Week of June 22, 2026 + +1. **Gemini 3.5 Flash and 3.1 Flash-Lite**: Google's [Gemini 3.5 Flash and 3.1 Flash-Lite](https://docs.vapi.ai/providers/model/gemini) models are now available for assistants. + +2. **Soniox stt-rt-v5**: A new `stt-rt-v5` real-time speech-to-text model is available for the Soniox transcriber. + +3. **Discord Login Removed**: Discord is no longer offered as a login or signup option. + +4. **Variable Values in Handoff Webhooks**: After an assistant handoff, webhook payloads now include the assistant's configured `variableValues`. diff --git a/fern/changelog/2026-06-29.mdx b/fern/changelog/2026-06-29.mdx new file mode 100644 index 000000000..75cf4c5c3 --- /dev/null +++ b/fern/changelog/2026-06-29.mdx @@ -0,0 +1,12 @@ +# What's New: Week of June 29, 2026 + +1. **OpenAI Realtime v2**: OpenAI's latest [Realtime v2](https://docs.vapi.ai/openai-realtime) model is now available for assistants. + +2. **AI-Generated Tool Failure and Completion Messages**: You can now set `role: 'system'` on request-failed [tool messages](https://docs.vapi.ai/tools/custom-tools), and the dashboard has a new UI for configuring AI-generated messages when tools fail or complete. This gives assistants more natural responses when tools hit errors. + +3. **Call Logs Improvements**: + - Significant latency improvements across both the dashboard and the `/calls` API endpoints. + - The call detail flyout now shows which assistant or squad handled the call, includes a link to the assistant or squad, and indicates which phone number was used. + - In squad or handoff calls, transcript messages now show which assistant said what, making it easier to trace conversation flow. + +4. **MCP Child Tools in Dashboard**: When you connect an [MCP server](https://docs.vapi.ai/sdk/mcp-server), the dashboard tool form now lists all child tools it discovers, so you can see exactly what capabilities your MCP server exposes. diff --git a/fern/changelog/2026-07-13.mdx b/fern/changelog/2026-07-13.mdx new file mode 100644 index 000000000..28285ae50 --- /dev/null +++ b/fern/changelog/2026-07-13.mdx @@ -0,0 +1,9 @@ +# What's New: Week of July 13, 2026 + +1. **Playback Speed for Recordings**: Call recording players now include a playback-speed control. + +2. **Download Every Recording Type**: You can now download every recording a call produced: mono, stereo, separate assistant and customer tracks, video, and packet capture. + +3. **VAD Transitions in Call Logs**: The call log now surfaces voice-activity-detection transitions with a per-phase latency breakdown. + +4. **HIPAA Compliance**: xAI is now HIPAA-compliant across its model, voice, and transcriber. diff --git a/fern/changelog/2026-07-20.mdx b/fern/changelog/2026-07-20.mdx new file mode 100644 index 000000000..056f1c369 --- /dev/null +++ b/fern/changelog/2026-07-20.mdx @@ -0,0 +1,7 @@ +# What's New: Week of July 20, 2026 + +1. **Model Intelligence**: You can now set your assistant's transcriber, llm, and voice models in one click with a [Model Preset](/assistants/model-intelligence/presets) (choose between Balanced, High Intelligence, Ultra Fast, or Cost Saver), and see the latency, cost, and quality metrics for your chosen models so you can compare options and optimize with data. + +2. **Recording Download URLs in the End of Call Report**: The end of call report now includes short-lived presigned download URLs for your [call recordings and logs](/assistants/retrieve-call-artifacts), so you can download them directly. + +3. **End of Call Reports with Zero Data Retention**: End of call reports are now reliably delivered for transient assistants running under Zero Data Retention. diff --git a/fern/changelog/2026-07-27.mdx b/fern/changelog/2026-07-27.mdx new file mode 100644 index 000000000..276bb563a --- /dev/null +++ b/fern/changelog/2026-07-27.mdx @@ -0,0 +1,15 @@ +# What's New: Week of July 27, 2026 + +## New Models + +1. **Anthropic Claude Sonnet 5**: Anthropic's Claude Sonnet 5 is now available as a model for assistants. + +2. **OpenAI GPT-5.5 "Instant"**: OpenAI's [GPT-5.5](/providers/model/openai) (`gpt-5.5` and `chat-latest`) is now available as a model for assistants. + +3. **OpenAI GPT-5.6 Models**: OpenAI's [GPT-5.6](/providers/model/openai) models (`sol`, `terra`, and `luna`) are now available for assistants. + +4. **Inworld TTS-2**: Inworld's [TTS-2](/providers/voice/inworld) voice is now available for assistants. + +## SIP Call Transfers + +1. **SIP Warm Transfer Audio**: Warm [call transfers](/call-forwarding) on SIP calls now play hold audio to the operator and a completion sound (`transferCompleteAudioUrl`) when the transfer connects. diff --git a/fern/changelog/2026-08-03.mdx b/fern/changelog/2026-08-03.mdx new file mode 100644 index 000000000..91302ff94 --- /dev/null +++ b/fern/changelog/2026-08-03.mdx @@ -0,0 +1,5 @@ +# What's New: Week of August 3, 2026 + +1. **Conditional Structured Outputs**: You can now add conditions to a [structured output](/assistants/structured-outputs) so it only generates when the condition is met, and any skipped outputs are surfaced in the assistant preview, call logs, and sessions. + +2. **Deepgram Aura-2 German Voices**: New German voices are now available for [Deepgram's Aura-2](/providers/voice/deepgram) voice. diff --git a/fern/changelog/2026-08-10.mdx b/fern/changelog/2026-08-10.mdx new file mode 100644 index 000000000..b34ce4760 --- /dev/null +++ b/fern/changelog/2026-08-10.mdx @@ -0,0 +1,14 @@ +# What's New: Week of August 10, 2026 + +1. **Simulations**: You can now build [simulation](/observability/simulations-overview) suites and run them against your assistants or squads to test and evaluate their behavior, with detailed results for each run. + +2. **Unified Provider and Model Picker**: The assistant editor now combines provider and model into a single picker for your LLM, voice, and transcriber. + +3. **Chat and Session Log Export**: You can now export selected rows from chat and session logs and use a bulk-actions bar, matching the call logs experience. + +4. **SIP Transfer Improvements**: Blind [call transfers](/call-forwarding) now support a configurable `fallbackPlan`, SIP verb, and dial timeout, and cold-transfer outcomes now appear in call logs. + +5. **Composer Improvements**: [Composer](/composer) is now more capable, reliable, and easier to use when building voice agents. + - Upload files for it to reference, read current Vapi documentation directly, and follow new Vapi-built skills for building assistants, choosing models, managing tools, configuring phone numbers, and debugging calls. + - Longer, multi-step tasks are far more reliable, with mid-task error recovery and progress that survives page refreshes and thread switches. + - Connect Google Calendar from the conversation, clickable resource mentions with copyable IDs, and cleaner, collapsible activity timelines. diff --git a/fern/changelog/2026-08-17.mdx b/fern/changelog/2026-08-17.mdx new file mode 100644 index 000000000..6c03aa84f --- /dev/null +++ b/fern/changelog/2026-08-17.mdx @@ -0,0 +1,7 @@ +# What's New: Week of August 17, 2026 + +1. **Assistant and Tool Versioning**: Edits no longer go live immediately. Work in a draft, publish when you're ready, and every publish creates a named [version snapshot](/assistants/versioning), so you can go back to your history to see what changed or roll back to a previous version as needed. You can also pin a specific tool version to an assistant. + +2. **Call Artifact Upload Webhook**: A new [`call.artifact.upload`](/api-reference/webhooks/server-message) server message fires as each recording, packet capture, and log finishes uploading, and it includes the result for each, so you can process artifacts as they arrive instead of waiting for the end of call report. + +3. **Azure Region Pinning for GPT-5 Models**: You can now pin a GPT-5 model to a specific [Azure](/providers/model/azure-openai) region by adding the region to the model name after a colon (for example `gpt-5:eastus2`), which keeps requests in that region for lower latency and data residency. It uses Vapi's platform Azure credential, so no Bring Your Own Key (BYOK) is needed. diff --git a/fern/changelog/2026-08-24.mdx b/fern/changelog/2026-08-24.mdx new file mode 100644 index 000000000..f60a319be --- /dev/null +++ b/fern/changelog/2026-08-24.mdx @@ -0,0 +1,5 @@ +# What's New: Week of August 24, 2026 + +1. **AssemblyAI Universal 3.5 Pro**: AssemblyAI's [Universal 3.5 Pro](/providers/transcriber/assembly-ai) model is now available as a transcriber for your assistants. + +2. **Websocket Call Type Filter**: You can now filter call logs by Websocket call type. diff --git a/fern/changelog/overview.mdx b/fern/changelog/overview.mdx index 712e15e23..168d27496 100644 --- a/fern/changelog/overview.mdx +++ b/fern/changelog/overview.mdx @@ -1,3 +1,34 @@ --- -slug: changelog +slug: whats-new --- + +
+
+ + + +
+
+
+
\ No newline at end of file diff --git a/fern/chat/non-streaming.mdx b/fern/chat/non-streaming.mdx new file mode 100644 index 000000000..d7085ea8f --- /dev/null +++ b/fern/chat/non-streaming.mdx @@ -0,0 +1,242 @@ +--- +title: Non-streaming chat +subtitle: Build reliable chat integrations with complete response patterns for batch processing and simple UIs +description: Build a non-streaming Vapi chat integration that returns complete responses, maintains conversation context, and supports reliable request-response workflows. +slug: chat/non-streaming +--- + +## Overview + +Build a chat integration that receives complete responses after processing, perfect for batch processing, simple UIs, or when you need the full response before proceeding. Ideal for integrations where real-time display isn't essential. + +**What You'll Build:** +* Simple request-response chat patterns with immediate complete responses +* Context management using `previousChatId` for linked conversations +* Basic integration with predictable response timing + + +For comprehensive context management options including sessions, see **[Session management](/chat/session-management)**. + + +## Prerequisites + +* Completed [Chat quickstart](/chat/quickstart) tutorial +* Understanding of basic HTTP requests and JSON handling +* Familiarity with JavaScript/TypeScript promises or async/await + +## Scenario + +We'll build a help desk system for "TechFlow" that processes support messages through text chat and maintains conversation history using `previousChatId`. + +--- + +## 1. Basic Non-Streaming Implementation + + + + Start with a basic non-streaming chat implementation: + + ```bash title="Basic Non-Streaming Request" + curl -X POST https://api.vapi.ai/chat \ + -H "Authorization: Bearer YOUR_API_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "assistantId": "your-assistant-id", + "input": "I need help resetting my password" + }' + ``` + + + Non-streaming responses come back as complete JSON objects: + + ```json title="Complete Chat Response" + { + "id": "chat_123456", + "orgId": "org_789012", + "assistantId": "assistant_345678", + "name": "Password Reset Help", + "sessionId": "session_901234", + "messages": [ + { + "role": "user", + "content": "I need help resetting my password" + } + ], + "output": [ + { + "role": "assistant", + "content": "I can help you reset your password. First, let me verify your account information..." + } + ], + "createdAt": "2024-01-15T09:30:00Z", + "updatedAt": "2024-01-15T09:30:01Z" + } + ``` + + + Create a reusable function for non-streaming chat: + + ```typescript title="non-streaming-chat.ts" + async function sendChatMessage( + message: string, + previousChatId?: string + ): Promise<{ chatId: string; response: string }> { + const response = await fetch('https://api.vapi.ai/chat', { + method: 'POST', + headers: { + 'Authorization': 'Bearer YOUR_API_KEY', + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + assistantId: 'your-assistant-id', + input: message, + ...(previousChatId && { previousChatId }) + }) + }); + + const chat = await response.json(); + return { + chatId: chat.id, + response: chat.output[0].content + }; + } + ``` + + + +--- + +## 2. Context Management with previousChatId + + + + Use `previousChatId` to maintain context across multiple chats: + + ```typescript title="conversation-chain.ts" + async function createConversation() { + let lastChatId: string | undefined; + + async function sendMessage(input: string): Promise { + const response = await fetch('https://api.vapi.ai/chat', { + method: 'POST', + headers: { + 'Authorization': 'Bearer YOUR_API_KEY', + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + assistantId: 'your-assistant-id', + input: input, + ...(lastChatId && { previousChatId: lastChatId }) + }) + }); + + const chat = await response.json(); + lastChatId = chat.id; + return chat.output[0].content; + } + + return { sendMessage }; + } + + // Usage + const conversation = await createConversation(); + + const response1 = await conversation.sendMessage("Hello, I'm Alice"); + console.log(response1); + + const response2 = await conversation.sendMessage("What's my name?"); + console.log(response2); // Should remember "Alice" + ``` + + + +--- + +## 3. Custom Assistant Configuration + + + + Instead of pre-created assistants, define configuration per request: + + ```bash title="Custom Assistant Request" + curl -X POST https://api.vapi.ai/chat \ + -H "Authorization: Bearer YOUR_API_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "input": "I need help with enterprise features", + "assistant": { + "model": { + "provider": "openai", + "model": "gpt-4o", + "temperature": 0.7, + "messages": [ + { + "role": "system", + "content": "You are a helpful technical support agent specializing in enterprise features." + } + ] + } + } + }' + ``` + + + Build different chat handlers for different types of requests: + + ```typescript title="specialized-handlers.ts" + async function createSpecializedChat(systemPrompt: string) { + return async function(userInput: string): Promise { + const response = await fetch('https://api.vapi.ai/chat', { + method: 'POST', + headers: { + 'Authorization': 'Bearer YOUR_API_KEY', + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + input: userInput, + assistant: { + model: { + provider: 'openai', + model: 'gpt-4o', + temperature: 0.3, + messages: [{ role: 'system', content: systemPrompt }] + } + } + }) + }); + + const chat = await response.json(); + return chat.output[0].content; + }; + } + + const technicalSupport = await createSpecializedChat( + "You are a technical support specialist. Ask clarifying questions and provide step-by-step troubleshooting." + ); + + const billingSupport = await createSpecializedChat( + "You are a billing support specialist. Be precise about billing terms and always verify account information." + ); + + // Usage + const techResponse = await technicalSupport("My API requests are returning 500 errors"); + const billingResponse = await billingSupport("I was charged twice this month"); + ``` + + + +--- + +## Next Steps + +Enhance your non-streaming chat system further: + +* **[Add streaming capabilities](/chat/streaming)** - Upgrade to real-time responses for better UX +* **[OpenAI compatibility](/chat/openai-compatibility)** - Use familiar OpenAI SDK patterns +* **[Integrate tools](/tools)** - Enable your assistant to call external APIs and databases +* **[Session management](/chat/session-management)** - Learn about advanced context management with sessions +* **[Add voice capabilities](/calls/outbound-calling)** - Extend your text chat to voice interactions + + +Need help? Chat with the team on our [Discord](https://discord.com/invite/pUFNcf2WmH) or mention us on [X/Twitter](https://x.com/Vapi_AI). + diff --git a/fern/chat/openai-compatibility.mdx b/fern/chat/openai-compatibility.mdx new file mode 100644 index 000000000..b2d026fe8 --- /dev/null +++ b/fern/chat/openai-compatibility.mdx @@ -0,0 +1,540 @@ +--- +title: OpenAI compatibility +subtitle: Seamlessly migrate existing OpenAI integrations to Vapi with zero code changes +description: Use Vapi through OpenAI-compatible chat interfaces, migrate existing integrations, and support streaming, non-streaming, and common JavaScript frameworks. +slug: chat/openai-compatibility +--- + +## Overview + +Migrate your existing OpenAI chat applications to Vapi without changing a single line of code. Perfect for teams already using OpenAI SDKs, third-party tools expecting OpenAI API format, or developers who want to leverage existing OpenAI workflows. + +**What You'll Build:** +* Drop-in replacement for OpenAI chat endpoints using Vapi assistants +* Migration path from OpenAI to Vapi with existing codebases +* Integration with popular frameworks like LangChain and Vercel AI SDK +* Production-ready server implementations with both streaming and non-streaming + +## Prerequisites + +* Completed [Chat quickstart](/chat/quickstart) tutorial +* Existing OpenAI integration or familiarity with OpenAI SDK + +## Scenario + +We'll migrate "TechFlow's" existing OpenAI-powered customer support chat to use Vapi assistants, maintaining all existing functionality while gaining access to Vapi's advanced features like custom voices and tools. + +--- + +## 1. Quick Migration Test + + + + If you don't already have it, install the OpenAI SDK: + + + ```bash title="npm" + npm install openai + ``` + + ```bash title="yarn" + yarn add openai + ``` + + ```bash title="pnpm" + pnpm add openai + ``` + + ```bash title="bun" + bun add openai + ``` + + + + Use your existing OpenAI code with minimal changes: + + ```bash title="Test OpenAI Compatibility" + curl -X POST https://api.vapi.ai/chat/responses \ + -H "Authorization: Bearer YOUR_VAPI_API_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "model": "gpt-4o", + "input": "Hello, I need help with my account", + "stream": false, + "assistantId": "your-assistant-id" + }' + ``` + + + The response follows OpenAI's structure with Vapi enhancements: + + ```json title="OpenAI-Compatible Response" + { + "id": "response_abc123", + "object": "chat.response", + "created": 1642678392, + "model": "gpt-4o", + "output": [ + { + "role": "assistant", + "content": [ + { + "type": "text", + "text": "Hello! I'd be happy to help with your account. What specific issue are you experiencing?" + } + ] + } + ], + "usage": { + "prompt_tokens": 12, + "completion_tokens": 23, + "total_tokens": 35 + } + } + ``` + + + +--- + +## 2. Migrate Existing OpenAI Code + + + + Change only the base URL and API key in your existing code: + + ```typescript title="Before (OpenAI)" + import OpenAI from 'openai'; + + const openai = new OpenAI({ + apiKey: 'your-openai-api-key' + }); + + const response = await openai.chat.completions.create({ + model: 'gpt-4o', + messages: [{ role: 'user', content: 'Hello!' }], + stream: true + }); + ``` + + ### With Vapi (No Code Changes) + + ```typescript title="After (Vapi)" + import OpenAI from 'openai'; + + const openai = new OpenAI({ + apiKey: 'YOUR_VAPI_API_KEY', + baseURL: 'https://api.vapi.ai/chat', + }); + + const response = await openai.chat.completions.create({ + model: 'gpt-4o', + messages: [{ role: 'user', content: 'Hello!' }], + stream: true + }); + ``` + + + Change `chat.completions.create` to `responses.create` and add `assistantId`: + + ```typescript title="Before (OpenAI Chat Completions)" + const response = await openai.chat.completions.create({ + model: 'gpt-4o', + messages: [ + { role: 'user', content: 'What is the capital of France?' } + ], + stream: false + }); + + console.log(response.choices[0].message.content); + ``` + + ```typescript title="After (Vapi Compatibility)" + const response = await openai.responses.create({ + model: 'gpt-4o', + input: 'What is the capital of France?', + stream: false, + assistantId: 'your-assistant-id' + }); + + console.log(response.output[0].content[0].text); + ``` + + + Run your updated code to verify the migration works: + + ```typescript title="migration-test.ts" + import OpenAI from 'openai'; + + const openai = new OpenAI({ + apiKey: 'YOUR_VAPI_API_KEY', + baseURL: 'https://api.vapi.ai/chat' + }); + + async function testMigration() { + try { + const response = await openai.responses.create({ + model: 'gpt-4o', + input: 'Hello, can you help me troubleshoot an API issue?', + stream: false, + assistantId: 'your-assistant-id' + }); + + console.log('Migration successful!'); + console.log('Response:', response.output[0].content[0].text); + } catch (error) { + console.error('Migration test failed:', error); + } + } + + testMigration(); + ``` + + + +--- + +## 3. Implement Streaming with OpenAI SDK + + + + Update your streaming code to use Vapi's streaming format: + + ```bash title="Streaming via curl" + curl -X POST https://api.vapi.ai/chat/responses \ + -H "Authorization: Bearer YOUR_VAPI_API_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "model": "gpt-4o", + "input": "Explain how machine learning works in detail", + "stream": true, + "assistantId": "your-assistant-id" + }' + ``` + + + Adapt your existing streaming implementation: + + ```typescript title="streaming-migration.ts" + async function streamWithVapi(userInput: string): Promise { + const stream = await openai.responses.create({ + model: 'gpt-4o', + input: userInput, + stream: true, + assistantId: 'your-assistant-id' + }); + + let fullResponse = ''; + + const reader = stream.body?.getReader(); + if (!reader) return fullResponse; + + const decoder = new TextDecoder(); + + while (true) { + const { done, value } = await reader.read(); + if (done) break; + + const chunk = decoder.decode(value); + + // Parse and process SSE events + const lines = chunk.split('\n').filter(line => line.trim()); + for (const line of lines) { + if (line.startsWith('data: ')) { + try { + const event = JSON.parse(line.slice(6)); + if (event.path && event.delta) { + process.stdout.write(event.delta); + fullResponse += event.delta; + } + } catch (e) { + console.error('Invalid JSON line:', line); + continue; + } + } + } + } + + console.log('\n\nComplete response received.'); + return fullResponse; + } + + streamWithVapi('Write a detailed explanation of REST APIs'); + ``` + + + Implement context management using Vapi's approach: + + ```typescript title="context-management.ts" + function createContextualChatSession(apiKey: string, assistantId: string) { + const openai = new OpenAI({ + apiKey: apiKey, + baseURL: 'https://api.vapi.ai/chat' + }); + let lastChatId: string | null = null; + + async function sendMessage(input: string, stream: boolean = false) { + const requestParams = { + model: 'gpt-4o', + input: input, + stream: stream, + assistantId: assistantId, + ...(lastChatId && { previousChatId: lastChatId }) + }; + + const response = await openai.responses.create(requestParams); + + if (!stream) { + lastChatId = response.id; + return response.output[0].content[0].text; + } + + return response; + } + + return { sendMessage }; + } + + // Usage example + const session = createContextualChatSession('YOUR_VAPI_API_KEY', 'your-assistant-id'); + + const response1 = await session.sendMessage("My name is Sarah and I'm having login issues"); + console.log('Response 1:', response1); + + const response2 = await session.sendMessage("What was my name again?"); + console.log('Response 2:', response2); // Should remember "Sarah" + ``` + + + +--- + +## 4. Framework Integrations + + + + Use Vapi with LangChain's OpenAI integration: + + ```typescript title="langchain-integration.ts" + import { ChatOpenAI } from "langchain/chat_models/openai"; + import { HumanMessage } from "langchain/schema"; + + const chat = new ChatOpenAI({ + openAIApiKey: "YOUR_VAPI_API_KEY", + configuration: { + baseURL: "https://api.vapi.ai/chat" + }, + modelName: "gpt-4o", + streaming: false + }); + + async function chatWithVapi(message: string, assistantId: string): Promise { + const response = await fetch('https://api.vapi.ai/chat/responses', { + method: 'POST', + headers: { + 'Authorization': `Bearer YOUR_VAPI_API_KEY`, + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + model: 'gpt-4o', + input: message, + assistantId: assistantId, + stream: false + }) + }); + + const data = await response.json(); + return data.output[0].content[0].text; + } + + // Usage + const response = await chatWithVapi( + "What are the best practices for API design?", + "your-assistant-id" + ); + console.log(response); + ``` + + + Use Vapi with Vercel's AI SDK: + + ```typescript title="vercel-ai-integration.ts" + import { openai } from '@ai-sdk/openai'; + import { generateText, streamText } from 'ai'; + + const vapiOpenAI = openai({ + apiKey: 'YOUR_VAPI_API_KEY', + baseURL: 'https://api.vapi.ai/chat' + }); + + // Non-streaming text generation + async function generateWithVapi(prompt: string, assistantId: string): Promise { + const response = await fetch('https://api.vapi.ai/chat/responses', { + method: 'POST', + headers: { + 'Authorization': `Bearer YOUR_VAPI_API_KEY`, + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + model: 'gpt-4o', + input: prompt, + assistantId: assistantId, + stream: false + }) + }); + + const data = await response.json(); + return data.output[0].content[0].text; + } + + // Streaming implementation + async function streamWithVapi(prompt: string, assistantId: string): Promise { + const response = await fetch('https://api.vapi.ai/chat/responses', { + method: 'POST', + headers: { + 'Authorization': `Bearer YOUR_VAPI_API_KEY`, + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + model: 'gpt-4o', + input: prompt, + assistantId: assistantId, + stream: true + }) + }); + + const reader = response.body?.getReader(); + if (!reader) return; + + const decoder = new TextDecoder(); + + while (true) { + const { done, value } = await reader.read(); + if (done) break; + + const chunk = decoder.decode(value); + + // Parse and process SSE events + const lines = chunk.split('\n').filter(line => line.trim()); + for (const line of lines) { + if (line.startsWith('data: ')) { + try { + const event = JSON.parse(line.slice(6)); + if (event.path && event.delta) { + process.stdout.write(event.delta); + } + } catch (e) { + console.error('Invalid JSON line:', line); + continue; + } + } + } + } + } + + // Usage examples + const text = await generateWithVapi( + "Explain the benefits of microservices architecture", + "your-assistant-id" + ); + console.log(text); + ``` + + + Build a simple server that exposes Vapi through OpenAI-compatible endpoints: + + ```typescript title="simple-server.ts" + import express from 'express'; + + const app = express(); + app.use(express.json()); + + app.post('/v1/chat/completions', async (req, res) => { + const { messages, model, stream = false, assistant_id } = req.body; + + if (!assistant_id) { + return res.status(400).json({ + error: 'assistant_id is required for Vapi compatibility' + }); + } + + const lastMessage = messages[messages.length - 1]; + const input = lastMessage.content; + + const response = await fetch('https://api.vapi.ai/chat', { + method: 'POST', + headers: { + 'Authorization': `Bearer ${process.env.VAPI_API_KEY}`, + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + assistantId: assistant_id, + input: input, + stream: stream + }) + }); + + if (stream) { + res.setHeader('Content-Type', 'text/event-stream'); + res.setHeader('Cache-Control', 'no-cache'); + res.setHeader('Connection', 'keep-alive'); + + const reader = response.body?.getReader(); + if (!reader) { + return res.status(500).json({ error: 'Failed to get stream reader' }); + } + + const decoder = new TextDecoder(); + + while (true) { + const { done, value } = await reader.read(); + if (done) { + res.write('data: [DONE]\n\n'); + res.end(); + break; + } + + const chunk = decoder.decode(value); + res.write(chunk); + } + } else { + const chat = await response.json(); + const openaiResponse = { + id: chat.id, + object: 'chat.completion', + created: Math.floor(Date.now() / 1000), + model: model || 'gpt-4o', + choices: [{ + index: 0, + message: { + role: 'assistant', + content: chat.output[0].content + }, + finish_reason: 'stop' + }] + }; + res.json(openaiResponse); + } + }); + + app.listen(3000, () => { + console.log('Vapi-OpenAI compatibility server running on port 3000'); + }); + ``` + + + +--- + +## Next Steps + +Enhance your migrated system: + +* **[Explore Vapi-specific features](/chat/quickstart)** - Leverage advanced assistant capabilities +* **[Add voice capabilities](/calls/outbound-calling)** - Extend beyond text to voice interactions +* **[Integrate tools](/tools/custom-tools)** - Give your assistant access to external APIs +* **[Optimize for streaming](/chat/streaming)** - Improve real-time user experience + + +Need help? Chat with the team on our [Discord](https://discord.com/invite/pUFNcf2WmH) or mention us on [X/Twitter](https://x.com/Vapi_AI). + diff --git a/fern/chat/quickstart.mdx b/fern/chat/quickstart.mdx new file mode 100644 index 000000000..76537ef01 --- /dev/null +++ b/fern/chat/quickstart.mdx @@ -0,0 +1,376 @@ +--- +title: Chat quickstart +subtitle: Build your first text-based conversation with a Vapi assistant in 5 minutes +description: "Create a text chat with a Vapi assistant, send messages through the Chat API, continue conversations, pass variables, and integrate with TypeScript apps." +slug: chat/quickstart +--- + +## Overview + +Build a customer service chat bot that can handle text-based conversations through your application. Perfect for adding AI chat to websites, mobile apps, or messaging platforms. + +**What You'll Build:** +* A working chat integration that responds to user messages +* Context-aware conversations that remember previous messages +* Both one-shot and multi-turn conversation patterns + +**Agent Capabilities:** +* Instant text responses without voice processing +* Maintains conversation context across multiple messages +* Compatible with existing OpenAI workflows + +## Prerequisites + +* A [Vapi account](https://dashboard.vapi.ai/) +* An existing assistant or willingness to create one +* Basic knowledge of making API requests +* For a pay-as-you-go subscription, the billing setup described in [Troubleshooting](#troubleshooting) + +## Scenario + +We'll create a customer support chat for "TechFlow", a software company that wants to handle common questions via text chat before escalating to human agents. + +--- + +## 1. Get Your API Credentials + + + + Follow the [Vapi API key guide](/security-and-privacy/api-keys) to create, view, or copy a private key. Use this key to authenticate server-side chat requests. + + + Keep this key secure - never expose it in client-side code. + + + + +--- + +## 2. Create or Select an Assistant + + + + In your Vapi dashboard, click `Assistants` in the left sidebar. + + + - Click `Create Assistant` if you need a new one + - Select `Blank Template` as your starting point + - Name it `TechFlow Support` + - Set the first message to: `Hello! I'm here to help with TechFlow questions. What can I assist you with today?` + + + Update the system prompt to: + + ```txt title="System Prompt" maxLines=8 + You are a helpful customer support agent for TechFlow, a software company. + + Your role: + - Answer common questions about our products + - Help troubleshoot basic issues + - Escalate complex problems to human agents + + Keep responses concise and helpful. Always maintain a friendly, professional tone. + ``` + + + After publishing, copy the Assistant ID from the URL or assistant details. You'll need this for API calls. + + + +--- + +## 3. Send Your First Chat Message + + + + Replace `YOUR_API_KEY` and `your-assistant-id` with your actual values: + + ```bash title="First Chat Request" + curl -X POST https://api.vapi.ai/chat \ + -H "Authorization: Bearer YOUR_API_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "assistantId": "your-assistant-id", + "input": "Hi, I need help with my TechFlow account" + }' + ``` + + + You should receive a JSON response like: + + ```json title="Chat Response" + { + "id": "chat_abc123", + "assistantId": "your-assistant-id", + "messages": [ + { + "role": "user", + "content": "Hi, I need help with my TechFlow account" + } + ], + "output": [ + { + "role": "assistant", + "content": "I'd be happy to help with your TechFlow account! What specific issue are you experiencing?" + } + ], + "createdAt": "2024-01-15T09:30:00Z", + "updatedAt": "2024-01-15T09:30:00Z" + } + ``` + + + +--- + +## 4. Build a Multi-Turn Conversation + + + + Use the `previousChatId` from the first response to maintain context: + + ```bash title="Follow-up Message" + curl -X POST https://api.vapi.ai/chat \ + -H "Authorization: Bearer YOUR_API_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "assistantId": "your-assistant-id", + "previousChatId": "chat_abc123", + "input": "I forgot my password and can't log in" + }' + ``` + + + Send another message to verify the assistant remembers the conversation: + + ```bash title="Context Test" + curl -X POST https://api.vapi.ai/chat \ + -H "Authorization: Bearer YOUR_API_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "assistantId": "your-assistant-id", + "previousChatId": "chat_abc123", + "input": "What was my original question?" + }' + ``` + + + +--- + +## 5. Pass Dynamic Variables + + + + In your assistant's system prompt, you can reference dynamic variables using `{{variableName}}` syntax: + + ```txt title="System Prompt with Variables" + You are a helpful customer support agent for {{companyName}}. + + Your role: + - Answer questions about {{companyName}}'s products + - Help customers with their {{serviceType}} needs + - Escalate to human agents when needed + + Current customer tier: {{customerTier}} + ``` + + + Use `assistantOverrides.variableValues` to pass dynamic data: + + ```bash title="Chat Request with Variables" + curl -X POST https://api.vapi.ai/chat \ + -H "Authorization: Bearer YOUR_API_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "assistantId": "your-assistant-id", + "input": "I need help with my account", + "assistantOverrides": { + "variableValues": { + "companyName": "TechFlow Solutions", + "serviceType": "software", + "customerTier": "Premium" + } + } + }' + ``` + + + +--- + +## 6. Integrate with TypeScript + + + + Here's a TypeScript function you can use in your application: + + ```typescript title="chat.ts" + interface ChatMessage { + role: 'user' | 'assistant'; + content: string; + } + + interface ChatApiResponse { + id: string; + assistantId: string; + messages: ChatMessage[]; + output: ChatMessage[]; + createdAt: string; + updatedAt: string; + orgId?: string; + sessionId?: string; + name?: string; + } + + interface ChatResponse { + chatId: string; + response: string; + fullData: ChatApiResponse; + } + + async function sendChatMessage( + message: string, + previousChatId?: string + ): Promise { + const response = await fetch('https://api.vapi.ai/chat', { + method: 'POST', + headers: { + 'Authorization': 'Bearer YOUR_API_KEY', + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + assistantId: 'your-assistant-id', + input: message, + ...(previousChatId && { previousChatId }) + }) + }); + + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + + const chat: ChatApiResponse = await response.json(); + return { + chatId: chat.id, + response: chat.output[0].content, + fullData: chat + }; + } + + // Usage example + const firstMessage = await sendChatMessage("Hello, I need help"); + console.log(firstMessage.response); + + const followUp = await sendChatMessage("Tell me more", firstMessage.chatId); + console.log(followUp.response); + ``` + + + Run your TypeScript code to verify the chat integration works correctly. + + + +--- + + + +## 7. Test Your Chat Bot + + + + Try these test cases to ensure your chat bot works correctly: + + ```bash title="Test Case 1: General Question" + curl -X POST https://api.vapi.ai/chat \ + -H "Authorization: Bearer YOUR_API_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "assistantId": "your-assistant-id", + "input": "What are your business hours?" + }' + ``` + + ```bash title="Test Case 2: Technical Issue" + curl -X POST https://api.vapi.ai/chat \ + -H "Authorization: Bearer YOUR_API_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "assistantId": "your-assistant-id", + "input": "My app keeps crashing when I try to export data" + }' + ``` + + + Send follow-up messages using `previousChatId` to ensure context is maintained. + + + +## Troubleshooting + +The Chat API returns HTTP `402` when the pay-as-you-go organization does not meet a billing requirement. Use the message to identify the required action. + +| Message | What it means | What to do | +| --- | --- | --- | +| `Add a payment method to use chat. Pay-as-you-go orgs require a card on file.` | The organization does not have a saved payment method. | [Add a payment method](/billing/manage-billing-and-credits). | +| `Purchase credits to use chat. New pay-as-you-go orgs require a completed payment.` | The pay-as-you-go subscription is less than 30 days old and the organization has no completed payment. | [Buy credits](/billing/manage-billing-and-credits) or complete another purchase. Adding a card does not count as a payment. | + +## Frequently asked questions + + + + Every pay-as-you-go organization needs a saved payment method. During the subscription's first 30 days, the organization must also have completed a payment. Enterprise and agency plans do not have these requirements. + + + + No. The purchase requirement applies only to chat. + + + + No. Adding a card authorizes future charges but does not complete a payment. To unblock chat during the first 30 days, [buy credits](/billing/manage-billing-and-credits) or complete another purchase. + + + + No. One completed payment permanently satisfies the requirement for the organization. The payment does not need to be recent or recurring. + + + + The completed-payment requirement ends when the pay-as-you-go subscription reaches 30 days old. The organization still needs a saved payment method to use chat. + + + + Chat access usually returns within one minute after the payment settles. If chat remains blocked, wait one minute, refresh the Dashboard, and try again. + + + +## Limitations + + +**Current chat functionality limitations:** +- Server webhook events (status updates, end-of-call reports, etc.) are not supported + + +## Webhook Support + + +The chat API supports the following webhook events through server messaging: +- **`chat.created`** - Triggered when a new chat conversation is initiated +- **`chat.deleted`** - Triggered when a chat conversation is deleted + +To receive these webhooks, go to your Assistant page in the Dashboard and navigate to "Server Messaging" and select the events you want to receive. + +These webhooks are useful for tracking conversation analytics, maintaining conversation history in your own database, and triggering follow-up actions. + + +## Next Steps + +Take your chat bot to the next level: + +* **[Streaming responses](/chat/streaming)** - Add real-time typing indicators and progressive responses +* **[Non-streaming responses](/chat/non-streaming)** - Learn about sessions and complex conversation flows +* **[Session management](/chat/session-management)** - Learn advanced context management with sessions and previousChatId +* **[OpenAI compatibility](/chat/openai-compatibility)** - Integrate with existing OpenAI workflows + + +Need help? Chat with the team on our [Discord](https://discord.com/invite/pUFNcf2WmH) or mention us on [X/Twitter](https://x.com/Vapi_AI). + diff --git a/fern/chat/session-management.mdx b/fern/chat/session-management.mdx new file mode 100644 index 000000000..1175f4f07 --- /dev/null +++ b/fern/chat/session-management.mdx @@ -0,0 +1,266 @@ +--- +title: Session management +subtitle: Maintain conversation context using previousChatId vs sessionId +description: Manage Vapi chat context with previousChatId or sessionId, understand when to use each method, and build persistent multi-turn conversations safely at scale. +slug: chat/session-management +--- + +## Overview + +Vapi provides two approaches for maintaining conversation context across multiple chat interactions. + +**Two Context Management Methods:** +* **`previousChatId`** - Links individual chats in sequence +* **`sessionId`** - Groups multiple chats under a persistent session + + +`previousChatId` and `sessionId` are **mutually exclusive**. You cannot use both in the same request. + + +## Prerequisites + +* Completed [Chat quickstart](/chat/quickstart) tutorial +* Basic understanding of chat requests and responses + +--- + +## Method 1: Using previousChatId + +Link chats together by referencing the ID of the previous chat. + + + + ```bash title="Initial Chat" + curl -X POST https://api.vapi.ai/chat \ + -H "Authorization: Bearer YOUR_API_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "assistantId": "your-assistant-id", + "input": "Hello, my name is Sarah" + }' + ``` + + + ```json title="Response" + { + "id": "chat_abc123", + "output": [{"role": "assistant", "content": "Hello Sarah!"}] + } + ``` + + + ```bash title="Follow-up Chat" + curl -X POST https://api.vapi.ai/chat \ + -H "Authorization: Bearer YOUR_API_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "assistantId": "your-assistant-id", + "previousChatId": "chat_abc123", + "input": "What was my name again?" + }' + ``` + + + +Here's a TypeScript implementation of the conversation chain: + +```typescript title="conversation-chain.ts" +function createConversationChain() { + let lastChatId: string | null = null; + + return async function sendMessage(assistantId: string, input: string) { + const requestBody = { + assistantId, + input, + ...(lastChatId && { previousChatId: lastChatId }) + }; + + const response = await fetch('https://api.vapi.ai/chat', { + method: 'POST', + headers: { + 'Authorization': `Bearer ${process.env.VAPI_API_KEY}`, + 'Content-Type': 'application/json' + }, + body: JSON.stringify(requestBody) + }); + + const chat = await response.json(); + lastChatId = chat.id; + + return chat.output[0].content; + }; +} + +// Usage +const sendMessage = createConversationChain(); +await sendMessage("asst_123", "Hi, I'm Alice"); +await sendMessage("asst_123", "What's my name?"); // Remembers Alice +``` + +--- + +## Method 2: Using sessionId + +Create a persistent session that groups multiple chats. + + + + ```bash title="Create Session" + curl -X POST https://api.vapi.ai/session \ + -H "Authorization: Bearer YOUR_API_KEY" \ + -H "Content-Type: application/json" \ + -d '{"assistantId": "your-assistant-id"}' + ``` + + + ```json title="Session Response" + { + "id": "session_xyz789", + "assistantId": "your-assistant-id" + } + ``` + + + ```bash title="First Chat in Session" + curl -X POST https://api.vapi.ai/chat \ + -H "Authorization: Bearer YOUR_API_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "sessionId": "session_xyz789", + "input": "Hello, I need help with billing" + }' + ``` + + + + +- Sessions expire automatically after 24 hours by default. After expiration, you'll need to create a new session to continue conversations. +- Web chat widget and SMS conversations automatically manage session creation and expiration. You don't need to manually create or manage sessions when using these channels. + + +Here's a TypeScript implementation of the session manager: + +```typescript title="session-manager.ts" +async function createSession(assistantId: string) { + const response = await fetch('https://api.vapi.ai/session', { + method: 'POST', + headers: { + 'Authorization': `Bearer ${process.env.VAPI_API_KEY}`, + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ assistantId }) + }); + + const session = await response.json(); + + return function sendMessage(input: string) { + return fetch('https://api.vapi.ai/chat', { + method: 'POST', + headers: { + 'Authorization': `Bearer ${process.env.VAPI_API_KEY}`, + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ sessionId: session.id, input }) + }) + .then(response => response.json()) + .then(chat => chat.output[0].content); + }; +} + +// Usage +const sendMessage = await createSession("asst_123"); +await sendMessage("I need help with my account"); +await sendMessage("What was my first question?"); // Remembers context +``` + +--- + +## When to use each approach + +Use `previousChatId` when: +* Dealing with simple back-and-forth conversations +* Looking for a minimal setup + +Use `sessionId` when: +* Building complex multi-step workflows +* Long-running conversations +* Error resilience needed + + +Sessions are tied to one assistant. You cannot specify `assistantId` when using `sessionId`. + + +--- + +## Multi-Assistant Workflows + +For workflows with multiple assistants, create separate sessions for each assistant. + +```typescript title="multi-assistant-workflow.ts" +function createMultiAssistantWorkflow() { + const sessions = new Map(); + + return async function sendToAssistant(assistantId: string, input: string) { + let sessionId = sessions.get(assistantId); + + if (!sessionId) { + const response = await fetch('https://api.vapi.ai/session', { + method: 'POST', + headers: { + 'Authorization': `Bearer ${process.env.VAPI_API_KEY}`, + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ assistantId }) + }); + + const session = await response.json(); + sessionId = session.id; + sessions.set(assistantId, sessionId); + } + + const response = await fetch('https://api.vapi.ai/chat', { + method: 'POST', + headers: { + 'Authorization': `Bearer ${process.env.VAPI_API_KEY}`, + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ sessionId, input }) + }); + + const chat = await response.json(); + return chat.output[0].content; + }; +} + +// Usage +const sendToAssistant = createMultiAssistantWorkflow(); +await sendToAssistant("support_agent", "I have a billing issue"); +await sendToAssistant("billing_agent", "Can you help with this?"); +``` + +--- + +## Webhook Support + + +Sessions support the following webhook events through server messaging: +- **`session.created`** - Triggered when a new session is created +- **`session.updated`** - Triggered when a session is updated +- **`session.deleted`** - Triggered when a session is deleted + +To receive these webhooks, go to your Assistant page in the Dashboard and navigate to "Server Messaging" and select the events you want to receive. + +These webhooks are useful for tracking session lifecycle, managing session state in your own database, and triggering workflows based on session changes. + + +--- + +## Next Steps + +* **[Streaming responses](/chat/streaming)** - Add real-time responses to session-managed chats +* **[OpenAI compatibility](/chat/openai-compatibility)** - Use familiar OpenAI patterns with sessions +* **[Custom tools](/tools/custom-tools)** - Give assistants access to external APIs within sessions + + +Need help? Chat with the team on our [Discord](https://discord.com/invite/pUFNcf2WmH) or mention us on [X/Twitter](https://x.com/Vapi_AI). + diff --git a/fern/chat/sms-chat.mdx b/fern/chat/sms-chat.mdx new file mode 100644 index 000000000..05dfc937c --- /dev/null +++ b/fern/chat/sms-chat.mdx @@ -0,0 +1,116 @@ +--- +title: SMS chat +subtitle: Enable text-based conversations with assistants via SMS messaging +description: Connect a 10DLC-approved Twilio number to a Vapi assistant, receive customer-initiated SMS messages, and maintain context through managed chat sessions. +slug: chat/sms-chat +--- + +## Overview + +Let customers chat with your Vapi assistants through SMS text messages. Perfect for businesses that want to provide AI support through familiar messaging channels. + +**What You'll Enable:** +* Text-based conversations through SMS +* Automatic session management for each customer +* Context-aware responses across message exchanges + + +SMS chat requires a **10DLC-approved Twilio number**. Only customers can initiate conversations - assistants cannot send the first message. + + +## Prerequisites + +* A [Vapi account](https://dashboard.vapi.ai/) with an existing assistant +* A **10DLC-approved Twilio phone number** (required for assistant responses) +* Basic understanding of phone number management + +--- + +## Setup Steps + + + + Bring your approved Twilio number into Vapi so we can manage SMS messaging. + + + SMS is **enabled by default** when importing Twilio numbers. + + + See: [Import number from Twilio](/phone-numbers/import-twilio) and [Inbound SMS setup](/phone-numbers/inbound-sms) + + + Assign the assistant that will handle SMS conversations for this number. + + When customers text your number, they'll automatically start a chat session with this assistant. + + + Send a text message to your phone number to verify the assistant responds correctly. + + + + +View all SMS conversations in the [Session Logs](https://dashboard.vapi.ai/logs/session) page of your dashboard. Each SMS conversation creates a session where you can see the full message history and conversation flow. + + +--- + +## How It Works + +When a customer texts your number: + +1. **Session Creation**: Vapi automatically creates a chat session for the customer +2. **Context Management**: All messages maintain conversation context within the session +3. **Response Delivery**: Assistant responses are sent back as SMS messages +4. **Session Expiry**: Sessions expire after 24 hours of inactivity, then create fresh sessions for new conversations + +```mermaid +sequenceDiagram + participant Customer + participant Twilio + participant Vapi + participant Assistant + + Customer->>Twilio: "Hi, I need help" + Twilio->>Vapi: SMS webhook + Vapi->>Vapi: Create/find session + Vapi->>Assistant: Process message + Assistant->>Vapi: Generate response + Vapi->>Twilio: Send SMS response + Twilio->>Customer: "Hello! How can I help?" +``` + +--- + +## Session Management + +SMS conversations use automatic session management: + +* **New customers**: Get a fresh session on first text +* **Returning customers**: Continue existing session if under 24 hours +* **Session expiry**: After 24 hours, new session created automatically +* **Context preservation**: Full conversation history maintained within session + +--- + +## Limitations + + +**Current SMS chat limitations:** +- **10DLC requirement**: Only 10DLC-approved Twilio numbers support assistant responses +- **Customer-initiated**: Assistants cannot send the first message to customers +- **Twilio only**: Other SMS providers are not currently supported + + +--- + +## Next Steps + +Enhance your SMS chat implementation: + +* **[Chat API](/chat/quickstart)** - Understand the underlying chat technology +* **[Session management](/chat/session-management)** - Learn how sessions work in detail +* **[Assistant configuration](/assistants/quickstart)** - Optimize your assistant for text conversations + + +For the best SMS experience, configure your assistant with concise responses and clear conversation flows. SMS users expect quick, direct answers. + diff --git a/fern/chat/streaming.mdx b/fern/chat/streaming.mdx new file mode 100644 index 000000000..6e4cca4f1 --- /dev/null +++ b/fern/chat/streaming.mdx @@ -0,0 +1,222 @@ +--- +title: Streaming chat +subtitle: Build real-time chat experiences with token-by-token responses like ChatGPT +description: Build a streaming Vapi chat integration with server-sent events, display tokens as they arrive, and maintain context across real-time app conversations. +slug: chat/streaming +--- + +## Overview + +Build a real-time chat interface that displays responses as they're generated, creating an engaging user experience similar to ChatGPT. Perfect for interactive applications where users expect immediate visual feedback. + +**What You'll Build:** +* Real-time streaming chat interface with progressive text display +* Context management across multiple messages +* Basic TypeScript implementation ready for production use + +## Prerequisites + +* Completed [Chat quickstart](/chat/quickstart) tutorial +* Basic knowledge of TypeScript/JavaScript and async/await + +## Scenario + +We'll enhance the TechFlow support chat from the quickstart to provide real-time streaming responses. Users will see text appear progressively as the AI generates it. + +--- + +## 1. Enable Streaming in Your Requests + + + + Modify your chat request to enable streaming by adding `"stream": true`: + + ```bash title="Streaming Chat Request" + curl -X POST https://api.vapi.ai/chat \ + -H "Authorization: Bearer YOUR_API_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "assistantId": "your-assistant-id", + "input": "Explain how to set up API authentication in detail", + "stream": true + }' + ``` + + + Instead of a single JSON response, you'll receive Server-Sent Events (SSE): + + ```typescript title="SSE Event Format" + // Example SSE events received: + data: {"id":"stream_123","path":"chat.output[0].content","delta":"Hello"} + data: {"id":"stream_123","path":"chat.output[0].content","delta":" there!"} + data: {"id":"stream_123","path":"chat.output[0].content","delta":" How can"} + data: {"id":"stream_123","path":"chat.output[0].content","delta":" I help?"} + + // TypeScript interface for SSE events: + interface SSEEvent { + id: string; + path: string; + delta: string; + } + ``` + + + +--- + +## 2. Basic TypeScript Streaming Implementation + + + + Here's a basic streaming implementation: + + ```typescript title="streaming-chat.ts" + async function streamChatMessage( + message: string, + previousChatId?: string + ): Promise { + const response = await fetch('https://api.vapi.ai/chat', { + method: 'POST', + headers: { + 'Authorization': 'Bearer YOUR_API_KEY', + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + assistantId: 'your-assistant-id', + input: message, + stream: true, + ...(previousChatId && { previousChatId }) + }) + }); + + const reader = response.body?.getReader(); + if (!reader) throw new Error('No reader available'); + + const decoder = new TextDecoder(); + let fullResponse = ''; + + while (true) { + const { done, value } = await reader.read(); + if (done) break; + + const chunk = decoder.decode(value); + const lines = chunk.split('\n').filter(line => line.trim()); + + for (const line of lines) { + if (line.startsWith('data: ')) { + const data = JSON.parse(line.slice(6)); + if (data.path && data.delta) { + fullResponse += data.delta; + process.stdout.write(data.delta); + } + } + } + } + + return fullResponse; + } + ``` + + + Try it out: + + ```typescript title="Test Streaming" + const response = await streamChatMessage("Explain API rate limiting in detail"); + console.log('\nComplete response:', response); + ``` + + + +--- + +## 3. Streaming with Context Management + + + + Maintain context across multiple streaming messages: + + ```typescript title="context-streaming.ts" + async function createStreamingConversation() { + let lastChatId: string | undefined; + + async function sendMessage(input: string): Promise { + const response = await fetch('https://api.vapi.ai/chat', { + method: 'POST', + headers: { + 'Authorization': 'Bearer YOUR_API_KEY', + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + assistantId: 'your-assistant-id', + input: input, + stream: true, + ...(lastChatId && { previousChatId: lastChatId }) + }) + }); + + const reader = response.body?.getReader(); + if (!reader) throw new Error('No reader available'); + + const decoder = new TextDecoder(); + let fullContent = ''; + let currentChatId: string | undefined; + + while (true) { + const { done, value } = await reader.read(); + if (done) break; + + const chunk = decoder.decode(value); + const lines = chunk.split('\n').filter(line => line.trim()); + + for (const line of lines) { + if (line.startsWith('data: ')) { + const event = JSON.parse(line.slice(6)); + + if (event.id && !currentChatId) { + currentChatId = event.id; + } + + if (event.path && event.delta) { + fullContent += event.delta; + process.stdout.write(event.delta); + } + } + } + } + + if (currentChatId) { + lastChatId = currentChatId; + } + + return fullContent; + } + + return { sendMessage }; + } + ``` + + + ```typescript title="Test Context" + const conversation = await createStreamingConversation(); + + await conversation.sendMessage("My name is Alice"); + console.log('\n---'); + await conversation.sendMessage("What's my name?"); // Should remember Alice + ``` + + + +--- + +## Next Steps + +Enhance your streaming chat further: + +* **[OpenAI compatibility](/chat/openai-compatibility)** - Use OpenAI SDK for streaming with familiar syntax +* **[Non-streaming patterns](/chat/non-streaming)** - Learn about sessions and complex conversation management +* **[Session management](/chat/session-management)** - Learn about context management with sessions and previousChatId in streaming +* **[Add tools](/tools)** - Enable your assistant to call external APIs while streaming + + +Need help? Chat with the team on our [Discord](https://discord.com/invite/pUFNcf2WmH) or mention us on [X/Twitter](https://x.com/Vapi_AI). + diff --git a/fern/chat/variable-substitution.mdx b/fern/chat/variable-substitution.mdx new file mode 100644 index 000000000..54553663b --- /dev/null +++ b/fern/chat/variable-substitution.mdx @@ -0,0 +1,172 @@ +--- +title: Variable substitution in sessions +subtitle: Learn how template variables behave with sessions and chats +description: Use variable substitution in Vapi chat sessions, understand when values are resolved, and choose safe patterns for updating personalized conversation context. +slug: chat/variable-substitution +--- + +## Overview + +When using sessions with the Chat API, understanding how variable substitution works is essential for building dynamic, personalized conversations. + +**Key concept:** Variables are substituted at session creation time and "baked into" the stored assistant configuration. Template placeholders like `{{name}}` are replaced with actual values and no longer exist in the session. + + +Vapi uses [LiquidJS](https://liquidjs.com/) for variable substitution. The `{{ }}` syntax follows Liquid template language conventions, giving you access to filters, conditionals, and other Liquid features beyond simple variable replacement. + + +--- + +## How variable substitution works + +### At session creation + +When you create a session with `assistantOverrides.variableValues`, the system: + +1. Takes your assistant's template variables (e.g., `"Hello {{name}} from {{company}}"`) +2. Substitutes all `{{ }}` placeholders using LiquidJS +3. Stores the **pre-substituted assistant** in the session +4. Saves the original variable values in `session.metadata.variableValues` for reference + +```bash title="Create session with variables" +curl -X POST https://api.vapi.ai/session \ + -H "Authorization: Bearer $VAPI_API_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "assistantId": "79f3cae3-5e47-4d8c-a1b2-9f8e7d6c5b4a", + "assistantOverrides": { + "variableValues": { + "name": "John", + "company": "Acme Corp" + } + } + }' +``` + +If your assistant's system prompt was `"You are a helpful assistant for {{name}} at {{company}}"`, the session stores: `"You are a helpful assistant for John at Acme Corp"`. + +### At chat creation + +When you send a chat request with a `sessionId`: + +1. The system loads the session's pre-substituted assistant +2. Any `variableValues` in the chat request are processed, but **there are no `{{ }}` placeholders left** to substitute +3. New variable values have **no effect** on already-substituted text + +--- + +## Behavior examples + +### Variables persist across chats + +Once you set variables at session creation, they persist for all chats in that session: + +```bash title="Chat using the session" +curl -X POST https://api.vapi.ai/chat \ + -H "Authorization: Bearer $VAPI_API_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "sessionId": "6b4c494f-c22c-4bce-84fa-a7a86942c7d3", + "input": "What is my name and company?" + }' +``` + +The assistant will respond with the values set at session creation (John, Acme Corp). + +### New variableValues don't override session values + + +Passing new `variableValues` in a chat request **will not** change the session's pre-substituted assistant. The template placeholders no longer exist. + + +```bash title="This will NOT change the assistant's context" +curl -X POST https://api.vapi.ai/chat \ + -H "Authorization: Bearer $VAPI_API_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "sessionId": "6b4c494f-c22c-4bce-84fa-a7a86942c7d3", + "input": "What is my name and company?", + "assistantOverrides": { + "variableValues": { + "name": "Jane", + "company": "Wayne Enterprises" + } + } + }' +``` + +The assistant still responds with "John" and "Acme Corp" because the original templates were already replaced. + +### Provide fresh templates to use new values + +To use different variable values mid-session, provide a new template with `{{ }}` placeholders along with the new values: + +```bash title="Override with fresh template" +curl -X POST https://api.vapi.ai/chat \ + -H "Authorization: Bearer $VAPI_API_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "sessionId": "6b4c494f-c22c-4bce-84fa-a7a86942c7d3", + "input": "What is my name and company?", + "assistantOverrides": { + "model": { + "provider": "openai", + "model": "gpt-4.1", + "systemPrompt": "You are a helpful assistant for {{name}} at {{company}}. Be very formal." + }, + "variableValues": { + "name": "Jane", + "company": "Wayne Enterprises" + } + } + }' +``` + +Now the assistant responds with "Jane" and "Wayne Enterprises" because fresh template placeholders were provided. + +--- + +## Quick reference + +| Scenario | Variables applied? | Why | +|----------|-------------------|-----| +| Session creation with `variableValues` | ✅ Yes | Templates exist, substitution happens | +| Chat with just `sessionId` | ✅ Session values persist | Pre-substituted assistant is used | +| Chat with `sessionId` + new `variableValues` | ❌ No effect | No `{{ }}` placeholders left to substitute | +| Chat with `sessionId` + new template with `{{ }}` + new `variableValues` | ✅ New values applied | Fresh templates provided | + +--- + +## Best practices + +### For consistent variables across a session + +Pass `assistantOverrides.variableValues` once when creating the session. Subsequent chat requests only need the `sessionId` and `input`. + +### For different variables per conversation + +Choose one of these approaches: + + + + Pass the full assistant configuration in each chat request. This gives you complete control over variables per request. + + + Include a new system prompt (or other text field) with `{{ }}` placeholders plus new `variableValues` in your chat request. + + + Create a new session for each unique variable context. This keeps conversations cleanly separated. + + + +--- + +## Next steps + +- **[Session management](/chat/session-management)** - Learn about `previousChatId` vs `sessionId` approaches +- **[Variables](/assistants/dynamic-variables)** - Configure dynamic variables in your assistant +- **[Streaming responses](/chat/streaming)** - Add real-time responses to your chats + + +Need help? Chat with the team on our [Discord](https://discord.com/invite/pUFNcf2WmH) or mention us on [X/Twitter](https://x.com/Vapi_AI). + diff --git a/fern/chat/web-widget.mdx b/fern/chat/web-widget.mdx new file mode 100644 index 000000000..4bf010646 --- /dev/null +++ b/fern/chat/web-widget.mdx @@ -0,0 +1,474 @@ +--- +title: Web widget +subtitle: Add AI chat and voice capabilities to any website with a simple embeddable widget +description: "Add Vapi's web widget to a website for voice and text conversations, configure its appearance and behavior, and meet pay-as-you-go chat access requirements." +slug: chat/web-widget +--- + +## Overview + +Add a complete AI chat and voice interface to your website with a single line of code. The Vapi Web Widget provides a customizable, floating chat interface that supports both text chat and voice conversations. + +**What You'll Build:** +* Embeddable chat widget with voice and text capabilities +* Customizable themes, colors, and positioning +* Real-time conversations with context management +* Cross-platform compatibility with minimal setup + +**Widget Features:** +* **Voice Mode** - Full voice conversations with transcription +* **Chat Mode** - Text-based conversations like ChatGPT +* **Custom Styling** - Match your website's design + + +View the complete source code and examples on [GitHub](https://github.com/VapiAI/client-sdk-react). + + +## Prerequisites + +* A [Vapi account](https://dashboard.vapi.ai/) with a [public API key](/security-and-privacy/api-keys) +* An existing assistant or willingness to create one +* A website where you want to embed the widget + +## Scenario + +We'll add a customer support widget to "TechFlow's" website that allows visitors to get help through both voice and text conversations. + +--- + +## 1. Get Your Public API Key + + + + Follow the [Vapi API key guide](/security-and-privacy/api-keys) to create, view, or copy a public key. + + + Unlike private keys, public keys are safe to expose in your website code. + + + + Navigate to `Assistants` in the left sidebar and copy the ID of the assistant you want to use. + + + +--- + +## 2. Install the Widget + + + + Add the widget script to your HTML page: + + ```html title="index.html" + + + + Your Website + + + + + + + + + + + ``` + + + Install the React package and use it as a component: + + + ```bash title="npm" + npm install @vapi-ai/client-sdk-react + ``` + + ```bash title="yarn" + yarn add @vapi-ai/client-sdk-react + ``` + + ```bash title="pnpm" + pnpm add @vapi-ai/client-sdk-react + ``` + + + ```tsx title="App.tsx" + import { VapiWidget } from '@vapi-ai/client-sdk-react'; + + function App() { + return ( +
+ {/* Your app content */} + + +
+ ); + } + ``` +
+
+ +--- + +## 3. Configure Widget Modes + + + + The widget supports two interaction modes: + + **Voice Mode** - Voice-only conversations + ```html + + ``` + + **Chat Mode** - Text-only conversations + ```html + + ``` + + + + Open your website and click the floating widget button to test the integration. + + + +--- + +## 4. Customize Appearance + + + + Customize the widget to match your website's design: + + ```html title="Custom Styling" + + ``` + + + Set custom text for better user experience: + + ```html title="Custom Labels" + + ``` + + + +--- + +## 5. Handle Events and Callbacks + + + + Handle widget events to integrate with your application: + + ```html title="Event Handling" + + ``` + + + Handle events in React components: + + ```tsx title="React Events" + import { VapiWidget } from '@vapi-ai/client-sdk-react'; + + function App() { + const handleCallStart = () => { + console.log('Voice call started'); + // Update state, track analytics, etc. + }; + + const handleCallEnd = () => { + console.log('Voice call ended'); + // Update state, save conversation, etc. + }; + + const handleMessage = (message: any) => { + console.log('Message received:', message); + // Process message, update state, etc. + }; + + const handleError = (error: Error) => { + console.error('Widget error:', error); + // Handle errors, show fallback UI, etc. + }; + + return ( + + ); + } + ``` + + + +--- + +## 6. Advanced Configuration + + + + Configure the assistant directly without pre-creating it: + + + The `assistant` configuration is only supported in **voice mode**. For chat mode, use `assistant-id` with optional `assistant-overrides`. + + + ```html title="Inline Assistant Configuration" + + ``` + + + Modify existing assistant behavior with overrides: + + ```html title="Assistant Overrides" + + ``` + + + Implement consent requirements for compliance: + + ```html title="Consent Management" + + ``` + + + +--- + +## 7. Production Considerations + + + + Consider these optimizations for production: + + ```html title="Performance Optimizations" + + ``` + + + Implement proper error handling: + + ```javascript title="Error Handling" + document.addEventListener('DOMContentLoaded', function() { + const widget = document.querySelector('vapi-widget'); + + widget.addEventListener('error', function(event) { + const error = event.detail; + + // Log error for debugging + console.error('Widget error:', error); + + // Show user-friendly message + if (error.message.includes('microphone')) { + alert('Please allow microphone access to use voice features.'); + } else if (error.message.includes('network')) { + alert('Connection error. Please check your internet connection.'); + } else { + alert('Something went wrong. Please try again.'); + } + }); + }); + ``` + + + +--- + +## Configuration Reference + +### Required Props + +| Prop | Type | Description | +|------|------|-------------| +| `public-key` | string | Your Vapi public API key | + +### Assistant Configuration + +| Prop | Type | Description | +|------|------|-------------| +| `assistant-id` | string | ID of your Vapi assistant | +| `assistant` | object | Full assistant configuration (JSON string) - **Voice mode only** | +| `assistant-overrides` | object | Override existing assistant settings (JSON string) | + + +You must provide either `assistant-id`, `assistant`, or both `assistant-id` and `assistant-overrides`. The `assistant` prop is only supported in voice mode. + + +### Appearance Options + +| Prop | Type | Default | Description | +|------|------|---------|-------------| +| `mode` | `voice` \| `chat` | `chat` | Widget interaction mode | +| `theme` | `light` \| `dark` | `light` | Color theme | +| `position` | `bottom-right` \| `bottom-left` \| `top-right` \| `top-left` | `bottom-right` | Screen position | +| `size` | `tiny` \| `compact` \| `full` | `full` | Widget size | +| `radius` | `none` \| `small` \| `medium` \| `large` | `medium` | Border radius | + +### Styling Options + +| Prop | Type | Default | Description | +|------|------|---------|-------------| +| `base-color` | string | - | Main background color | +| `accent-color` | string | `#14B8A6` | Primary accent color | +| `button-base-color` | string | `#000000` | Floating button background | +| `button-accent-color` | string | `#FFFFFF` | Floating button text/icon color | + +### Text Customization + +| Prop | Type | Default | Description | +|------|------|---------|-------------| +| `main-label` | string | `Talk with AI` | Widget header text | +| `start-button-text` | string | `Start` | Voice call start button text | +| `end-button-text` | string | `End Call` | Voice call end button text | +| `empty-chat-message` | string | - | Message when chat is empty | +| `empty-voice-message` | string | - | Message when voice mode is empty | + +### Advanced Options + +| Prop | Type | Default | Description | +|------|------|---------|-------------| +| `require-consent` | boolean | `false` | Show consent form before first use | +| `terms-content` | string | - | Custom consent form text | +| `local-storage-key` | string | `vapi_widget_consent` | Key for storing consent | +| `show-transcript` | boolean | `true` | Show/hide voice transcript | + +## Browser Support + +* Chrome/Edge 79+ +* Firefox 86+ +* Safari 14.1+ +* Mobile browsers with WebRTC support + +## Requirements + +* Microphone access for voice mode +* HTTPS required in production +* Vapi account and [API key](/security-and-privacy/api-keys) + +## Next Steps + +Enhance your widget integration: + +* **[Chat API](/chat/quickstart)** - Build custom chat interfaces using the API directly +* **[Voice calls](/calls/outbound-calling)** - Add programmatic voice calling capabilities +* **[Custom tools](/tools/custom-tools)** - Give your assistant access to external APIs +* **[Assistant customization](/assistants)** - Fine-tune your assistant's behavior + + +The widget automatically handles microphone permissions, audio processing, and cross-browser compatibility. For custom implementations, consider using the [Web SDK](/quickstart/web) directly. + + + +Need help? Chat with the team on our [Discord](https://discord.com/invite/pUFNcf2WmH) or mention us on [X/Twitter](https://x.com/Vapi_AI). + diff --git a/fern/cli/authentication.mdx b/fern/cli/authentication.mdx new file mode 100644 index 000000000..327cc60a3 --- /dev/null +++ b/fern/cli/authentication.mdx @@ -0,0 +1,463 @@ +--- +title: Authentication management +description: Manage multiple Vapi accounts and environments with the CLI +slug: cli/auth +--- + +## Overview + +The Vapi CLI supports sophisticated authentication management, allowing you to work with multiple accounts, organizations, and environments seamlessly. This is perfect for developers who work across different teams, manage client accounts, or need to switch between production and staging environments. + +**In this guide, you'll learn to:** +- Authenticate with your Vapi account +- Manage multiple accounts simultaneously +- Switch between organizations and environments +- Configure API keys and tokens + +## Quick start + + + + Authenticate with your primary account: + ```bash + vapi login + ``` + This opens your browser for secure OAuth authentication. + + + + View your authentication status: + ```bash + vapi auth status + ``` + + + + Add additional accounts without logging out: + ```bash + vapi auth login + ``` + + + + Switch between authenticated accounts: + ```bash + vapi auth switch production + ``` + + + +## Authentication methods + +### OAuth login (recommended) + +The default authentication method uses OAuth for maximum security: + +```bash +vapi login +# Opens browser for authentication +# Securely stores tokens locally +``` + +Benefits: +- No manual API key handling +- Automatic token refresh +- Secure credential storage +- Organization access management + +### API key authentication + +For CI/CD or scripting, use API keys: + +```bash +# Via environment variable +export VAPI_API_KEY=your-api-key +vapi assistant list + +# Via command flag +vapi assistant list --api-key your-api-key +``` + +### Configuration file + +Store API keys in configuration: + +```yaml +# ~/.vapi-cli.yaml +api_key: your-api-key +base_url: https://api.vapi.ai # Optional custom endpoint +``` + +## Multi-account management + +### Understanding accounts + +Each authenticated account includes: +- **User identity** - Your email and user ID +- **Organization** - The Vapi organization you belong to +- **API access** - Permissions and API keys +- **Environment** - Production, staging, or custom + +### Viewing accounts + +List all authenticated accounts: + +```bash +vapi auth status +``` + +Output: +``` +🔐 Vapi Authentication Status + +Active Account: + ✓ Email: john@company.com + ✓ Organization: Acme Corp (org_abc123) + ✓ Environment: Production + ✓ API Key: sk-prod_****efgh + +Other Accounts: + • jane@agency.com - ClientCo (org_xyz789) [staging] + • john@personal.com - Personal (org_def456) [production] + +Total accounts: 3 +``` + +### Adding accounts + +Add accounts without affecting existing ones: + +```bash +# Add another account +vapi auth login + +# You'll be prompted to: +# 1. Open browser for authentication +# 2. Choose an account alias (e.g., "staging", "client-a") +# 3. Confirm organization access +``` + +### Switching accounts + +Switch between accounts instantly: + +```bash +# Switch by alias +vapi auth switch staging + +# Switch by email +vapi auth switch jane@agency.com + +# Interactive selection +vapi auth switch +# Shows menu of available accounts +``` + +### Account aliases + +Assign meaningful aliases to accounts: + +```bash +# During login +vapi auth login --alias production + +# Update existing +vapi auth alias john@company.com production + +# Use aliases +vapi auth switch production +``` + +## Common workflows + +### Development vs production + + + + ```bash + # Development work + vapi auth switch dev + vapi assistant create --name "Test Assistant" + + # Production deployment + vapi auth switch prod + vapi assistant create --name "Customer Support" + ``` + + + + ```bash + # Client A work + vapi auth switch client-a + vapi phone list + + # Client B work + vapi auth switch client-b + vapi assistant list + ``` + + + + ```bash + # Personal development + vapi auth switch personal + vapi init + + # Team project + vapi auth switch team + vapi assistant list + ``` + + + +### Account information + +Get detailed information about current account: + +```bash +vapi auth whoami +``` + +Output: +```json +{ + "user": { + "id": "user_abc123", + "email": "john@company.com", + "name": "John Doe" + }, + "organization": { + "id": "org_abc123", + "name": "Acme Corp", + "plan": "enterprise" + }, + "permissions": [ + "assistants:read", + "assistants:write", + "calls:create", + "billing:view" + ] +} +``` + +### Token management + +View and manage API tokens: + +```bash +# View current token (masked) +vapi auth token + +# Show full token (careful!) +vapi auth token --show + +# Refresh token +vapi auth refresh +``` + +## Security best practices + +### Credential storage + +The CLI stores credentials securely: + +- **macOS**: Keychain +- **Linux**: Secret Service API / keyring +- **Windows**: Credential Manager + +### Environment isolation + +Keep environments separate: + +```bash +# Never mix environments +vapi auth switch prod +vapi assistant list # Production assistants + +vapi auth switch dev +vapi assistant list # Development assistants +``` + +### CI/CD integration + +For automated workflows: + +```yaml +# GitHub Actions example +env: + VAPI_API_KEY: ${{ secrets.VAPI_PROD_KEY }} + +steps: + - name: Deploy Assistant + run: | + vapi assistant create --file assistant.json +``` + +### Revoking access + +Remove accounts when no longer needed: + +```bash +# Logout from current account +vapi auth logout + +# Logout from specific account +vapi auth logout jane@agency.com + +# Logout from all accounts +vapi auth logout --all +``` + +## Advanced features + +### Custom API endpoints + +For on-premise or custom deployments: + +```bash +# Login to custom endpoint +vapi login --base-url https://vapi.company.internal + +# Or configure in file +echo "base_url: https://vapi.company.internal" >> ~/.vapi-cli.yaml +``` + +### Service accounts + +For server applications: + +```bash +# Create service account in dashboard +# Then configure: +export VAPI_API_KEY=service_account_key +export VAPI_ORG_ID=org_abc123 +``` + +### Proxy configuration + +For corporate environments: + +```bash +# HTTP proxy +export HTTP_PROXY=http://proxy.company.com:8080 +export HTTPS_PROXY=http://proxy.company.com:8080 + +# SOCKS proxy +export ALL_PROXY=socks5://proxy.company.com:1080 +``` + +## Troubleshooting + + + + Configure default browser: + + ```bash + # macOS + export BROWSER="Google Chrome" + + # Linux + export BROWSER=firefox + + # Windows + set BROWSER=chrome + ``` + + + + If you see authentication errors: + + ```bash + # Refresh current token + vapi auth refresh + + # Or re-login + vapi login + ``` + + + + For credential storage problems: + + ```bash + # macOS: Reset keychain access + security unlock-keychain + + # Linux: Install keyring + sudo apt-get install gnome-keyring + + # Use file storage instead + vapi config set storage file + ``` + + + + If you can't access organization resources: + + 1. Verify organization membership in dashboard + 2. Check account permissions + 3. Re-authenticate: + ```bash + vapi auth logout + vapi login + ``` + + + +## Best practices + +### Account naming + +Use clear, consistent aliases: + +```bash +# Good aliases +vapi auth login --alias prod-acme +vapi auth login --alias dev-personal +vapi auth login --alias staging-client + +# Avoid unclear aliases +vapi auth login --alias test1 +vapi auth login --alias new +``` + +### Regular maintenance + +Keep your authentication clean: + +```bash +# Monthly review +vapi auth status + +# Remove unused accounts +vapi auth logout old-client@example.com + +# Update tokens +vapi auth refresh --all +``` + +### Team documentation + +Document account structure for your team: + +```markdown +## Vapi Accounts + +- `prod`: Production (org_abc123) +- `staging`: Staging environment (org_abc124) +- `dev`: Shared development (org_abc125) + +To switch: `vapi auth switch ` +``` + +## Next steps + +With authentication configured: + +- **[Create assistants](/quickstart/phone):** Build voice assistants +- **[Initialize projects](/cli/init):** Add Vapi to your codebase +- **[Test webhooks](/cli/webhook):** Debug locally with any account + +--- + +**Security tip:** Always use OAuth login for interactive use and API keys only for automation. Never commit API keys to version control! \ No newline at end of file diff --git a/fern/cli/mcp-integration.mdx b/fern/cli/mcp-integration.mdx new file mode 100644 index 000000000..7d767647f --- /dev/null +++ b/fern/cli/mcp-integration.mdx @@ -0,0 +1,394 @@ +--- +title: MCP integration +description: Turn your IDE into a Vapi expert with Model Context Protocol +slug: cli/mcp +--- + +## Overview + +The Model Context Protocol (MCP) integration transforms your IDE's AI assistant into a Vapi expert. Once configured, your IDE gains complete, accurate knowledge of Vapi's APIs, features, and best practices - eliminating AI hallucinations and outdated information. + +**In this guide, you'll learn to:** +- Set up MCP in supported IDEs +- Understand what knowledge is provided +- Use your enhanced IDE effectively +- Troubleshoot common issues + +## Quick start + +Run the setup command to auto-configure all supported IDEs: + +```bash +vapi mcp setup +``` + +Or configure a specific IDE: + +```bash +vapi mcp setup cursor # For Cursor +vapi mcp setup windsurf # For Windsurf +vapi mcp setup vscode # For VSCode with Copilot +``` + +## What is MCP? + +Model Context Protocol is a standard that allows AI assistants to access structured knowledge and tools. When you set up MCP for Vapi: + +- Your IDE's AI gains access to complete Vapi documentation +- Code suggestions become accurate and up-to-date +- Examples use real, working Vapi patterns +- API hallucinations are eliminated + +## Supported IDEs + + + + AI-first code editor with deep MCP integration + + **Setup:** Creates `.cursor/mcp.json` + + + Codeium's AI-powered IDE + + **Setup:** Creates `.windsurf/mcp.json` + + + With GitHub Copilot extension + + **Setup:** Configures Copilot settings + + + +## How it works + +### What gets configured + +The MCP setup creates configuration files that connect your IDE to the Vapi MCP server: + + + + **File:** `.cursor/mcp.json` + ```json + { + "servers": { + "vapi-docs": { + "command": "npx", + "args": ["@vapi-ai/mcp-server"] + } + } + } + ``` + + + **File:** `.windsurf/mcp.json` + ```json + { + "servers": { + "vapi-docs": { + "command": "npx", + "args": ["@vapi-ai/mcp-server"] + } + } + } + ``` + + + **Settings:** Updates workspace settings + ```json + { + "github.copilot.advanced": { + "mcp.servers": { + "vapi-docs": { + "command": "npx", + "args": ["@vapi-ai/mcp-server"] + } + } + } + } + ``` + + + +### What knowledge is provided + +Your IDE gains access to: + +- **Complete API Reference** - Every endpoint, parameter, and response +- **Code Examples** - Working samples for all features +- **Integration Guides** - Step-by-step implementation patterns +- **Best Practices** - Recommended approaches and patterns +- **Latest Features** - Always up-to-date with new releases +- **Troubleshooting** - Common issues and solutions + +## Using your enhanced IDE + +### Example prompts + +Once MCP is configured, try these prompts in your IDE: + + + + **Prompt:** "How do I create a voice assistant with Vapi?" + + Your IDE will provide accurate code like: + ```typescript + import { VapiClient } from "@vapi-ai/server-sdk"; + + const client = new VapiClient({ token: process.env.VAPI_API_KEY }); + + const assistant = await client.assistants.create({ + name: "Customer Support", + model: { + provider: "openai", + model: "gpt-4", + systemPrompt: "You are a helpful customer support agent..." + }, + voice: { + provider: "11labs", + voiceId: "rachel" + } + }); + ``` + + + + **Prompt:** "Show me how to handle Vapi webhooks" + + Get complete webhook examples: + ```typescript + app.post('/webhook', async (req, res) => { + const { type, call, assistant } = req.body; + + switch (type) { + case 'call-started': + console.log(`Call ${call.id} started`); + break; + case 'speech-update': + console.log(`User said: ${req.body.transcript}`); + break; + case 'function-call': + // Handle tool calls + const { functionName, parameters } = req.body.functionCall; + const result = await handleFunction(functionName, parameters); + res.json({ result }); + return; + } + + res.status(200).send(); + }); + ``` + + + + **Prompt:** "How do I set up call recording with custom storage?" + + Get detailed implementation: + ```typescript + const assistant = await client.assistants.create({ + name: "Recorded Assistant", + recordingEnabled: true, + artifactPlan: { + recordingEnabled: true, + videoRecordingEnabled: false, + recordingPath: "s3://my-bucket/recordings/{call_id}" + }, + credentialIds: ["aws-s3-credential-id"] + }); + ``` + + + +### Best practices + + + + Ask detailed questions about Vapi features: + - ✅ "How do I transfer calls to a human agent in Vapi?" + - ❌ "How do I transfer calls?" + + + + Ask for working code samples: + - "Show me a complete example of..." + - "Generate a working implementation of..." + + + + Specify SDK versions when needed: + - "Using @vapi-ai/web v2.0, how do I..." + - "What's the latest way to..." + + + +## Configuration options + +### Check status + +View current MCP configuration: + +```bash +vapi mcp status +``` + +Output: +``` +MCP Configuration Status: +✓ Cursor: Configured (.cursor/mcp.json) +✗ Windsurf: Not configured +✓ VSCode: Configured (workspace settings) + +Vapi MCP Server: v1.2.3 (latest) +``` + +### Update server + +Keep the MCP server updated: + +```bash +# Update to latest version +npm update -g @vapi-ai/mcp-server + +# Or reinstall +npm install -g @vapi-ai/mcp-server@latest +``` + +### Remove configuration + +Remove MCP configuration: + +```bash +# Remove from all IDEs +vapi mcp remove + +# Remove from specific IDE +vapi mcp remove cursor +``` + +## How MCP tools work + +The Vapi MCP server provides these tools to your IDE: + + + + Semantic search across all Vapi docs + + **Example:** "How to handle voicemail detection" + + + Retrieve code samples for any feature + + **Example:** "WebSocket connection example" + + + Get detailed API endpoint information + + **Example:** "POST /assistant parameters" + + + Step-by-step guides for complex features + + **Example:** "Custom tool implementation guide" + + + +## Troubleshooting + + + + If your IDE isn't using the MCP knowledge: + + 1. **Restart your IDE** after configuration + 2. **Check the logs** in your IDE's output panel + 3. **Verify npm is accessible** from your IDE + 4. **Ensure MCP server is installed** globally + + ```bash + # Verify installation + npm list -g @vapi-ai/mcp-server + ``` + + + + For permission issues: + + ```bash + # Install with proper permissions + sudo npm install -g @vapi-ai/mcp-server + + # Or use a Node version manager + nvm use 18 + npm install -g @vapi-ai/mcp-server + ``` + + + + If you're getting old API information: + + 1. Update the MCP server: + ```bash + npm update -g @vapi-ai/mcp-server + ``` + + 2. Clear your IDE's cache + 3. Restart the IDE + + + + For different projects needing different configs: + + - MCP configuration is per-workspace + - Run `vapi mcp setup` in each project + - Configuration won't conflict between projects + + + +## Advanced usage + +### Custom MCP configuration + +Modify the generated MCP configuration for advanced needs: + +```json +{ + "servers": { + "vapi-docs": { + "command": "npx", + "args": ["@vapi-ai/mcp-server"], + "env": { + "VAPI_MCP_LOG_LEVEL": "debug" + } + } + } +} +``` + +### Using with teams + +Share MCP configuration with your team: + +1. **Commit the config files** (`.cursor/mcp.json`, etc.) +2. **Document the setup** in your README +3. **Include in onboarding** for new developers + +Example README section: +```markdown +## Development Setup + +This project uses Vapi MCP for enhanced IDE support: + +1. Install Vapi CLI: `curl -sSL https://vapi.ai/install.sh | bash` +2. Set up MCP: `vapi mcp setup` +3. Restart your IDE +``` + +## Next steps + +Now that MCP is configured: + +- **[Create assistants](/quickstart/phone):** Build your first voice AI +- **[Test webhooks locally](/cli/webhook):** Debug webhooks with tunneling services +- **[Manage resources](/cli#common-commands):** Use CLI commands + +--- + +**Pro tip:** After setting up MCP, try asking your IDE to "Create a complete Vapi voice assistant with error handling and logging" - watch it generate production-ready code with all the right patterns! diff --git a/fern/cli/overview.mdx b/fern/cli/overview.mdx new file mode 100644 index 000000000..e6250cab1 --- /dev/null +++ b/fern/cli/overview.mdx @@ -0,0 +1,253 @@ +--- +title: Vapi CLI +description: Command-line interface for building voice AI applications faster +slug: cli +--- + +## Overview + +The Vapi CLI is the official command-line interface that brings world-class developer experience to your terminal and IDE. Build, test, and deploy voice AI applications without leaving your development environment. + +**In this guide, you'll learn to:** +- Install and authenticate with the Vapi CLI +- Initialize Vapi in existing projects +- Manage assistants, phone numbers, and calls from your terminal +- Forward webhooks to your local development server +- Turn your IDE into a Vapi expert with MCP integration + +## Installation + +Install the Vapi CLI in seconds with our automated scripts: + + + + ```bash + curl -sSL https://vapi.ai/install.sh | bash + ``` + + + ```powershell + iex ((New-Object System.Net.WebClient).DownloadString('https://vapi.ai/install.ps1')) + ``` + + + ```bash + docker run -it ghcr.io/vapiai/cli:latest --help + ``` + + + +## Quick start + + + + Connect your Vapi account: + ```bash + vapi login + ``` + This opens your browser for secure OAuth authentication. + + + + Add Vapi to an existing project: + ```bash + vapi init + ``` + The CLI auto-detects your tech stack and sets up everything you need. + + + + Build a voice assistant: + ```bash + vapi assistant create + ``` + Follow the interactive prompts to configure your assistant. + + + +## Key features + +### 🚀 Project integration + +Drop Vapi into any existing codebase with intelligent auto-detection: + +```bash +vapi init +# Detected: Next.js application +# ✓ Installed @vapi-ai/web SDK +# ✓ Generated components/VapiButton.tsx +# ✓ Created pages/api/vapi/webhook.ts +# ✓ Added environment template +``` + +Supports React, Vue, Next.js, Python, Go, Flutter, React Native, and dozens more frameworks. + +### 🤖 MCP integration + +Turn your IDE into a Vapi expert with Model Context Protocol: + +```bash +vapi mcp setup +``` + +Your IDE's AI assistant (Cursor, Windsurf, VSCode) gains complete, accurate knowledge of Vapi's APIs and best practices. No more hallucinated code or outdated examples. + +### 🔗 Local webhook testing + +Forward webhooks to your local server for debugging: + +```bash +# Terminal 1: Create tunnel (e.g., with ngrok) +ngrok http 4242 + +# Terminal 2: Forward webhooks +vapi listen --forward-to localhost:3000/webhook +``` + + +**Important:** `vapi listen` is a local forwarder only - it does NOT provide a public URL. You need a separate tunneling service (like ngrok) to expose the CLI's port to the internet. Update your webhook URLs in Vapi to use the tunnel's public URL. + + +### 🔐 Multi-account management + +Switch between organizations and environments seamlessly: + +```bash +# List all authenticated accounts +vapi auth status + +# Switch between accounts +vapi auth switch production + +# Add another account +vapi auth login +``` + +### 📱 Complete feature parity + +Everything you can do in the dashboard, now in your terminal: + +- **Assistants**: Create, update, list, and delete voice assistants +- **Phone numbers**: Purchase, configure, and manage phone numbers +- **Calls**: Make outbound calls and view call history +- **Campaigns**: Create and manage AI phone campaigns at scale +- **Tools**: Configure custom functions and integrations +- **Webhooks**: Set up and test event delivery +- **Logs**: View system logs, call logs, and debug issues + +## Common commands + + + + ```bash + # List all assistants + vapi assistant list + + # Create a new assistant + vapi assistant create + + # Get assistant details + vapi assistant get + + # Update an assistant + vapi assistant update + + # Delete an assistant + vapi assistant delete + ``` + + + + ```bash + # List your phone numbers + vapi phone list + + # Purchase a new number + vapi phone create + + # Update number configuration + vapi phone update + + # Release a number + vapi phone delete + ``` + + + + ```bash + # List recent calls + vapi call list + + # Make an outbound call + vapi call create + + # Get call details + vapi call get + + # End an active call + vapi call end + ``` + + + + ```bash + # View system logs + vapi logs list + + # View call-specific logs + vapi logs calls + + # View error logs + vapi logs errors + + # View webhook logs + vapi logs webhooks + ``` + + + +## Configuration + +The CLI stores configuration in `~/.vapi-cli.yaml`. You can also use environment variables: + +```bash +# Set API key via environment +export VAPI_API_KEY=your-api-key + +# View current configuration +vapi config get + +# Update configuration +vapi config set + +# Manage analytics preferences +vapi config analytics disable +``` + +## Auto-updates + +The CLI automatically checks for updates and notifies you when new versions are available: + +```bash +# Check for updates manually +vapi update check + +# Update to latest version +vapi update +``` + +## Next steps + +Now that you have the Vapi CLI installed: + +- **[Initialize a project](/cli/init):** Add Vapi to your existing codebase +- **[Set up MCP](/cli/mcp):** Enhance your IDE with Vapi intelligence +- **[Test webhooks locally](/cli/webhook):** Debug webhooks with tunneling services +- **[Manage authentication](/cli/auth):** Work with multiple accounts + +--- + +**Resources:** +- [GitHub Repository](https://github.com/VapiAI/cli) +- [Report Issues](https://github.com/VapiAI/cli/issues) +- [Discord Community](https://discord.gg/vapi) \ No newline at end of file diff --git a/fern/cli/project-integration.mdx b/fern/cli/project-integration.mdx new file mode 100644 index 000000000..18fa02f17 --- /dev/null +++ b/fern/cli/project-integration.mdx @@ -0,0 +1,351 @@ +--- +title: Project integration +description: Initialize Vapi in your existing projects with intelligent auto-detection +slug: cli/init +--- + +## Overview + +The `vapi init` command intelligently integrates Vapi into your existing codebase. It automatically detects your framework, installs the appropriate SDK, and generates production-ready code examples tailored to your project structure. + +**In this guide, you'll learn to:** +- Initialize Vapi in any project +- Understand what files are generated +- Customize the initialization process +- Work with different frameworks + +## Quick start + +Navigate to your project directory and run: + +```bash +cd my-project +vapi init +``` + +The CLI will: +1. Detect your project type and framework +2. Install the appropriate Vapi SDK +3. Generate example components and API routes +4. Create environment configuration templates +5. Provide next steps specific to your setup + +## How it works + +### Framework detection + +The CLI analyzes your project structure to identify: +- **Package files**: `package.json`, `requirements.txt`, `go.mod`, etc. +- **Configuration files**: Framework-specific configs +- **Project structure**: Directory patterns and file extensions +- **Dependencies**: Installed packages and libraries + +### What gets generated + +Based on your framework, the CLI generates: + + + + ```bash + vapi init + # Detected: Next.js application + ``` + + **Generated files:** + - `components/VapiButton.tsx` - Voice call button component + - `pages/api/vapi/webhook.ts` - Webhook handler endpoint + - `lib/vapi-client.ts` - Vapi client setup + - `.env.example` - Environment variables template + + **Installed packages:** + - `@vapi-ai/web` - Web SDK for browser integration + - `@vapi-ai/server-sdk` - Server SDK for webhooks + + + + ```bash + vapi init + # Detected: Python application + ``` + + **Generated files:** + - `vapi_example.py` - Basic assistant example + - `webhook_handler.py` - Flask/FastAPI webhook handler + - `requirements.txt` - Updated with Vapi SDK + - `.env.example` - Environment variables template + + **Installed packages:** + - `vapi-server-sdk` - Python server SDK + + + + ```bash + vapi init + # Detected: Node.js application + ``` + + **Generated files:** + - `vapi-example.js` - Basic usage example + - `webhook-server.js` - Express webhook handler + - `.env.example` - Environment variables template + + **Installed packages:** + - `@vapi-ai/server-sdk` - TypeScript/JavaScript SDK + + + +## Supported frameworks + +### Frontend frameworks + + + + - Create React App + - Vite + - Custom webpack + + + - Vue 3 + - Nuxt.js + - Vite + + + - Angular 12+ + - Ionic + + + - App Router + - Pages Router + - API Routes + + + - SvelteKit + - Vite + + + - HTML/CSS/JS + - Webpack + - Parcel + + + +### Mobile frameworks + + + + - Expo + - Bare workflow + + + - iOS & Android + - Web support + + + +### Backend frameworks + + + + - Express + - Fastify + - Koa + + + - Django + - FastAPI + - Flask + + + - Gin + - Echo + - Fiber + + + - Rails + - Sinatra + + + - Spring Boot + - Quarkus + + + - ASP.NET Core + - Blazor + + + +## Advanced options + +### Specify target directory + +Initialize in a specific directory: + +```bash +vapi init /path/to/project +``` + +### Skip SDK installation + +Generate only example files without installing packages: + +```bash +vapi init --skip-install +``` + +### Force framework + +Override auto-detection: + +```bash +vapi init --framework react +vapi init --framework python +``` + +### Custom templates + +Use your own templates: + +```bash +vapi init --template @myorg/vapi-templates +``` + +## Environment setup + +After initialization, configure your environment: + + + + ```bash + cp .env.example .env + ``` + + + + Follow the [Vapi API key guide](/security-and-privacy/api-keys) to create, view, or copy an API key: + ```bash + VAPI_API_KEY=your-api-key-here + ``` + + + + For local development: + ```bash + VAPI_WEBHOOK_URL=https://your-domain.com/api/vapi/webhook + ``` + + + +## Common patterns + +### Adding to monorepos + +For monorepos, run init in the specific package: + +```bash +cd packages/web-app +vapi init + +cd ../api-server +vapi init +``` + +### CI/CD integration + +Add to your build process: + +```yaml +# GitHub Actions example +- name: Setup Vapi + run: | + curl -sSL https://vapi.ai/install.sh | bash + vapi init --skip-install +``` + +### Docker environments + +Include in your Dockerfile: + +```dockerfile +# Install Vapi CLI +RUN curl -sSL https://vapi.ai/install.sh | bash + +# Initialize project +RUN vapi init --skip-install +``` + +## Troubleshooting + + + + If the CLI can't detect your framework: + + 1. Ensure you're in the project root + 2. Check for required config files + 3. Use `--framework` flag to specify manually + + ```bash + vapi init --framework react + ``` + + + + For permission issues during SDK installation: + + ```bash + # npm projects + sudo npm install + + # Python projects + pip install --user vapi-server-sdk + ``` + + + + If files already exist, the CLI will: + + 1. Ask for confirmation before overwriting + 2. Create backup files (`.backup` extension) + 3. Show a diff of changes + + Use `--force` to skip confirmations: + ```bash + vapi init --force + ``` + + + +## Next steps + +After initializing your project: + +- **[Test locally](/cli/webhook):** Use `vapi listen` to test webhooks +- **[Create assistants](/quickstart/phone):** Build your first voice assistant +- **[Set up MCP](/cli/mcp):** Enhance your IDE with Vapi intelligence + +--- + +**Example output:** + +```bash +$ vapi init +🔍 Analyzing project... +✓ Detected: Next.js 14 application + +📦 Installing dependencies... +✓ Installed @vapi-ai/web@latest +✓ Installed @vapi-ai/server-sdk@latest + +📝 Generating files... +✓ Created components/VapiButton.tsx +✓ Created app/api/vapi/webhook/route.ts +✓ Created lib/vapi-client.ts +✓ Created .env.example + +🎉 Vapi initialized successfully! + +Next steps: +1. Copy .env.example to .env +2. Add your VAPI_API_KEY +3. Run: npm run dev +4. Test the voice button at http://localhost:3000 +``` diff --git a/fern/cli/webhook-testing.mdx b/fern/cli/webhook-testing.mdx new file mode 100644 index 000000000..a578b0c6a --- /dev/null +++ b/fern/cli/webhook-testing.mdx @@ -0,0 +1,548 @@ +--- +title: Local webhook testing +description: Forward webhooks to your local development server with vapi listen +slug: cli/webhook +--- + +## Overview + +The `vapi listen` command provides a local webhook forwarding service that receives events and forwards them to your local development server. This helps you debug webhook integrations during development. + +**Important:** `vapi listen` does NOT provide a public URL or tunnel. You'll need to use a separate tunneling solution like ngrok to expose your local server to the internet. + +**In this guide, you'll learn to:** +- Set up local webhook forwarding with a tunneling service +- Debug webhook events in real-time +- Configure advanced forwarding options +- Handle different webhook types + + +**No automatic tunneling:** The `vapi listen` command is a local forwarder only. It does not create a public URL or tunnel to the internet. You must use a separate tunneling service (like ngrok) and configure your Vapi webhook URLs manually. + + +## Quick start + + + + Use a tunneling service like ngrok to create a public URL: + ```bash + # Example with ngrok + ngrok http 4242 # 4242 is the default port for vapi listen + ``` + + Note the public URL provided by your tunneling service (e.g., `https://abc123.ngrok.io`) + + + + ```bash + vapi listen --forward-to localhost:3000/webhook + ``` + + This starts a local server on port 4242 that forwards to your application + + + + Go to your Vapi Dashboard and update your webhook URLs to point to your tunnel URL: + - Assistant webhook URL: `https://abc123.ngrok.io` + - Phone number webhook URL: `https://abc123.ngrok.io` + - Or any other webhook configuration + + + + Trigger webhook events (make calls, etc.) and see them forwarded through the tunnel to your local server + + + +## How it works + + +**Current implementation:** The `vapi listen` command acts as a local webhook forwarder only. It receives webhook events on a local port (default 4242) and forwards them to your specified endpoint. To receive events from Vapi, you must: + +1. Use a tunneling service (ngrok, localtunnel, etc.) to expose port 4242 to the internet +2. Configure your Vapi webhook URLs to point to the tunnel URL +3. The flow is: Vapi → Your tunnel URL → vapi listen (port 4242) → Your local server + + + + + The CLI starts a webhook forwarder on port 4242 (configurable) + + + + Your tunneling service creates a public URL that routes to port 4242 + + + + Update your Vapi webhook URL to point to the tunnel's public URL + + + + Webhook events flow: Vapi → Tunnel → CLI forwarder → Your local endpoint + + + + Events are displayed in your terminal for debugging + + + +## Basic usage + +### Standard forwarding + +Forward to your local development server: + +```bash +# Forward to localhost:3000/webhook +vapi listen --forward-to localhost:3000/webhook + +# Short form +vapi listen -f localhost:3000/webhook +``` + +### Custom port + +Use a different port for the webhook listener: + +```bash +# Listen on port 8080 instead of default 4242 +vapi listen --forward-to localhost:3000/webhook --port 8080 + +# Remember to update your tunnel to use port 8080 +ngrok http 8080 +``` + +### Skip TLS verification + +For development with self-signed certificates: + +```bash +vapi listen --forward-to https://localhost:3000/webhook --skip-verify +``` + + +Only use `--skip-verify` in development. Never in production. + + +## Understanding the output + +When you run `vapi listen`, you'll see: + +```bash +$ vapi listen --forward-to localhost:3000/webhook + +🎧 Vapi Webhook Listener +📡 Listening on: http://localhost:4242 +📍 Forwarding to: http://localhost:3000/webhook + +⚠️ To receive Vapi webhooks: + 1. Use a tunneling service (e.g., ngrok http 4242) + 2. Update your Vapi webhook URLs to the tunnel URL + +Waiting for webhook events... + +[2024-01-15 10:30:45] POST / +Event: call-started +Call ID: call_abc123def456 +Status: 200 OK (45ms) + +[2024-01-15 10:30:52] POST / +Event: speech-update +Transcript: "Hello, how can I help you?" +Status: 200 OK (12ms) +``` + +## Webhook event types + +The listener forwards all Vapi webhook events: + + + + - `call-started` - Call initiated + - `call-ended` - Call completed + - `call-failed` - Call encountered an error + + + + - `speech-update` - Real-time transcription + - `transcript` - Final transcription + - `voice-input` - User speaking detected + + + + - `function-call` - Tool/function invoked + - `assistant-message` - Assistant response + - `conversation-update` - Conversation state change + + + + - `error` - Error occurred + - `recording-ready` - Call recording available + - `analysis-ready` - Call analysis complete + + + +## Advanced configuration + +### Headers and authentication + +The listener adds helpful headers to forwarded requests: + +```http +X-Forwarded-For: vapi-webhook-listener +X-Original-Host: +X-Webhook-Event: call-started +X-Webhook-Timestamp: 1705331445 +``` + +Your server receives the exact webhook payload from Vapi with these additional headers for debugging. + +### Setting up with different tunneling services + + + + ```bash + # Terminal 1: Start ngrok tunnel + ngrok http 4242 + + # Terminal 2: Start vapi listener + vapi listen --forward-to localhost:3000/webhook + + # Use the ngrok URL in Vapi Dashboard + ``` + + + + ```bash + # Terminal 1: Install and start localtunnel + npm install -g localtunnel + lt --port 4242 + + # Terminal 2: Start vapi listener + vapi listen --forward-to localhost:3000/webhook + + # Use the localtunnel URL in Vapi Dashboard + ``` + + + + ```bash + # Terminal 1: Start cloudflare tunnel + cloudflared tunnel --url http://localhost:4242 + + # Terminal 2: Start vapi listener + vapi listen --forward-to localhost:3000/webhook + + # Use the cloudflare URL in Vapi Dashboard + ``` + + + + +**Pro tip:** Some tunneling services offer static URLs (like ngrok with a paid plan), which means you won't need to update your Vapi webhook configuration every time you restart development. + + +### Filtering events + +Filter specific event types (coming soon): + +```bash +# Only forward call events +vapi listen --forward-to localhost:3000 --filter "call-*" + +# Multiple filters +vapi listen --forward-to localhost:3000 --filter "call-started,call-ended" +``` + +### Response handling + +The listener expects standard HTTP responses: + +- **200-299**: Success, event processed +- **400-499**: Client error, event rejected +- **500-599**: Server error, will retry + +## Development workflow + +### Typical setup + + + + ```bash + # In terminal 1 + npm run dev # Your app on localhost:3000 + ``` + + + + ```bash + # In terminal 2 + ngrok http 4242 # Creates public URL for the CLI listener + # Note the public URL (e.g., https://abc123.ngrok.io) + ``` + + + + ```bash + # In terminal 3 + vapi listen --forward-to localhost:3000/api/vapi/webhook + ``` + + + + Update your Vapi webhook URLs to point to the ngrok URL from step 2 + + + + Use the Vapi dashboard or API to trigger webhooks + + + + See events in the CLI terminal and debug your handler + + + + +**Data flow:** Vapi sends webhooks → Ngrok tunnel (public URL) → vapi listen (port 4242) → Your local server (port 3000) + + +### Example webhook handler + + +```typescript title="Node.js/Express" +app.post('/api/vapi/webhook', async (req, res) => { + const { type, call, timestamp } = req.body; + + console.log(`Webhook received: ${type} at ${timestamp}`); + + switch (type) { + case 'call-started': + console.log(`Call ${call.id} started with ${call.customer.number}`); + break; + + case 'speech-update': + console.log(`User said: ${req.body.transcript}`); + break; + + case 'function-call': + const { functionName, parameters } = req.body.functionCall; + console.log(`Function called: ${functionName}`, parameters); + + // Return function result + const result = await processFunction(functionName, parameters); + return res.json({ result }); + + case 'call-ended': + console.log(`Call ended. Duration: ${call.duration}s`); + break; + } + + res.status(200).send(); +}); +``` + +```python title="Python/FastAPI" +from fastapi import FastAPI, Request +from datetime import datetime + +app = FastAPI() + +@app.post("/api/vapi/webhook") +async def handle_webhook(request: Request): + data = await request.json() + event_type = data.get("type") + call = data.get("call", {}) + timestamp = data.get("timestamp") + + print(f"Webhook received: {event_type} at {timestamp}") + + if event_type == "call-started": + print(f"Call {call.get('id')} started") + + elif event_type == "speech-update": + print(f"User said: {data.get('transcript')}") + + elif event_type == "function-call": + function_call = data.get("functionCall", {}) + function_name = function_call.get("functionName") + parameters = function_call.get("parameters") + + # Process function and return result + result = await process_function(function_name, parameters) + return {"result": result} + + elif event_type == "call-ended": + print(f"Call ended. Duration: {call.get('duration')}s") + + return {"status": "ok"} +``` + +```go title="Go/Gin" +func handleWebhook(c *gin.Context) { + var data map[string]interface{} + if err := c.ShouldBindJSON(&data); err != nil { + c.JSON(400, gin.H{"error": err.Error()}) + return + } + + eventType := data["type"].(string) + fmt.Printf("Webhook received: %s\n", eventType) + + switch eventType { + case "call-started": + call := data["call"].(map[string]interface{}) + fmt.Printf("Call %s started\n", call["id"]) + + case "speech-update": + fmt.Printf("User said: %s\n", data["transcript"]) + + case "function-call": + functionCall := data["functionCall"].(map[string]interface{}) + result := processFunction( + functionCall["functionName"].(string), + functionCall["parameters"], + ) + c.JSON(200, gin.H{"result": result}) + return + + case "call-ended": + fmt.Println("Call ended") + } + + c.JSON(200, gin.H{"status": "ok"}) +} +``` + + +## Testing scenarios + +### Simulating errors + +Test error handling in your webhook: + +```bash +# Your handler returns 500 +vapi listen --forward-to localhost:3000/webhook-error + +# Output shows: +# Status: 500 Internal Server Error (23ms) +# Response: {"error": "Database connection failed"} +``` + +### Load testing + +Test with multiple concurrent calls: + +```bash +# Terminal 1: Start listener +vapi listen --forward-to localhost:3000/webhook + +# Terminal 2: Trigger multiple calls via API +for i in {1..10}; do + vapi call create --to "+1234567890" & +done +``` + +### Debugging specific calls + +Filter logs by call ID: + +```bash +# Coming soon +vapi listen --forward-to localhost:3000 --call-id call_abc123 +``` + +## Security considerations + + +The `vapi listen` command is designed for development only. In production, use proper webhook endpoints with authentication. + + +### Best practices + +1. **Never expose sensitive data** in console logs +2. **Validate webhook signatures** in production +3. **Use HTTPS** for production endpoints +4. **Implement proper error handling** +5. **Set up monitoring** for production webhooks + +### Production webhook setup + +For production, configure webhooks in the Vapi dashboard: + +```typescript +// Production webhook with signature verification +app.post('/webhook', verifyVapiSignature, async (req, res) => { + // Your production handler +}); +``` + +## Troubleshooting + + + + If you see "connection refused": + + 1. **Verify your server is running** on the specified port + 2. **Check the endpoint path** matches your route + 3. **Ensure no firewall** is blocking local connections + + ```bash + # Test your endpoint directly + curl -X POST http://localhost:3000/webhook -d '{}' + ``` + + + + For timeout issues: + + 1. **Check response time** - Vapi expects < 10s response + 2. **Avoid blocking operations** in webhook handlers + 3. **Use async processing** for heavy operations + + ```typescript + // Good: Quick response + app.post('/webhook', async (req, res) => { + // Queue for processing + await queue.add('process-webhook', req.body); + res.status(200).send(); + }); + ``` + + + + If events aren't appearing: + + 1. **Check CLI authentication** - `vapi auth whoami` + 2. **Verify account access** to the resources + 3. **Ensure events are enabled** in assistant config + + ```bash + # Re-authenticate if needed + vapi login + ``` + + + + For HTTPS endpoints: + + ```bash + # Development only - skip certificate verification + vapi listen --forward-to https://localhost:3000 --skip-verify + + # Or use HTTP for local development + vapi listen --forward-to http://localhost:3000 + ``` + + + +## Next steps + +Now that you can test webhooks locally: + +- **[Build webhook handlers](/server-url/events):** Learn about all webhook events +- **[Implement tools](/tools/custom-tools):** Add custom functionality +- **[Set up production webhooks](/server-url):** Deploy to production + +--- + +**Pro tip:** Keep `vapi listen` running while developing - you'll see all events in real-time and can iterate quickly on your webhook handlers without deployment delays! \ No newline at end of file diff --git a/fern/community/expert-directory.mdx b/fern/community/expert-directory.mdx index 2183134c0..4f06ac7c5 100644 --- a/fern/community/expert-directory.mdx +++ b/fern/community/expert-directory.mdx @@ -5,11 +5,34 @@ slug: community/expert-directory --- -Want to maximize your Voice AI? Vapi, a certified consultant, specializes in building Voice AI bots. +Need help building, deploying, or scaling voice agents with Vapi? -Whether you need help deciding what to automate or assistance in building it, Vapi Experts have proven their expertise by supporting users and creating valuable video content for the community. Find the right fit here. +This directory lists certified partners and agencies with proven experience on our platform. They can assist with everything from identifying automation use cases to complex development and integration projects. + +These partners have demonstrated their expertise through successful Vapi implementations and contributions to the developer community. Find the right technical partner for your project below.
+ + +
+

Qonvo

+

Qonvo is the best way to stop wasting your time on the phone for repetitive tasks and low-value added inbound requests. Allow your self to better invest your time thanks custom-build Vocal AI agents.

+
+
+

Flowzen

- Our agency offers Voice AI solutions using VAPI, in English and Spanish, + Our agency offers Voice AI solutions using Vapi, in English and Spanish, integrated with platforms like GoHighLevel, Airtable, and Make.com.

@@ -401,7 +424,7 @@ Whether you need help deciding what to automate or assistance in building it, Va />

NukyLabs.AI

-

All Services for VAPI.ai Automation

+

All Services for Vapi.ai Automation

@@ -520,13 +543,13 @@ Whether you need help deciding what to automate or assistance in building it, Va

Value Added Tech

Top-notch automation company. We specialise in Make.com (Silver partner), - multiple CRMs and VAPI. + multiple CRMs and Vapi.

-

Strinq

+

Saidwell

- Strinq develops custom voice AI solutions for enterprises, offering bespoke software and high-quality human voice models. + Saidwell develops custom voice AI solutions for enterprises, offering bespoke software and high-quality human voice models.

diff --git a/fern/community/knowledgebase.mdx b/fern/community/knowledgebase.mdx index 35a80c02b..4cbab936a 100644 --- a/fern/community/knowledgebase.mdx +++ b/fern/community/knowledgebase.mdx @@ -43,25 +43,62 @@ curl --location 'https://api.vapi.ai/file' \ ### **Step 2: Create a Knowledge Base** -Use the ID of the uploaded file to create a Knowledge Base. Currently we support [trieve](https://trieve.ai) as a provider. +Use the ID of the uploaded file to create a Knowledge Base along with the KB configurations. + +1. Provider: [trieve](https://trieve.ai) ```bash -curl --location 'https://api.vapi.ai/knowledge-base' \ +curl --location 'http://localhost:3001/knowledge-base' \ --header 'Content-Type: text/plain' \ --header 'Authorization: Bearer ' \ --data '{ - "name": "knowledge-base-test", + "name": "v2", "provider": "trieve", - "vectorStoreSearchPlan": { - "scoreThreshold": 0.1, - "searchType": "hybrid" + "searchPlan": { + "searchType": "semantic", + "topK": 3, + "removeStopWords": true, + "scoreThreshold": 0.7 }, - "vectorStoreCreatePlan": { - "fileIds": [""] + "createPlan": { + "type": "create", + "chunkPlans": [ + { + "fileIds": ["", ""], + "websites": ["", ""], + "targetSplitsPerChunk": 50, + "splitDelimiters": [".!?\n"], + "rebalanceChunks": true + } + ] } }' ``` +#### Configuration Options + +##### Search Plan Options + +- **searchType** (required): The search method used for finding relevant chunks. Available options: + - `fulltext`: Traditional text search + - `semantic`: Semantic similarity search + - `hybrid`: Combines fulltext and semantic search + - `bm25`: BM25 ranking algorithm +- **topK** (optional): Number of top chunks to return. Default varies by implementation +- **removeStopWords** (optional): When true, removes common stop words from the search query. Default: `false` +- **scoreThreshold** (optional): Filters out chunks based on their similarity score: + - For cosine distance: Excludes chunks below the threshold + - For Manhattan Distance, Euclidean Distance, and Dot Product: Excludes chunks above the threshold + - Set to 0 or omit for no threshold + +##### Chunk Plan Options + +- **fileIds** (optional): Array of file IDs to include in the vector store +- **websites** (optional): Array of website URLs to crawl and include in the vector store +- **targetSplitsPerChunk** (optional): Number of splits per chunk. Default: `20` +- **splitDelimiters** (optional): Array of delimiters used to split text before chunking. Default: `[".!?\n"]` +- **rebalanceChunks** (optional): When true, evenly distributes remainder splits across chunks. For example, 66 splits with `targetSplitsPerChunk: 20` will create 3 chunks with 22 splits each. Default: `true` + ### **Step 3: Create an Assistant** Create a new assistant in Vapi and, on the right sidebar menu. Add the Knowledge Base to your assistant via the PATCH endpoint. Also make sure you customize your assistant's system prompt to utilize the Knowledge Base for responding to user queries. diff --git a/fern/community/myvapi.mdx b/fern/community/myvapi.mdx index 9080728ca..0cd20d3db 100644 --- a/fern/community/myvapi.mdx +++ b/fern/community/myvapi.mdx @@ -4,7 +4,7 @@ slug: community/myvapi --- -Here is the updated MyVapi User Guide, including the customer endpoints and noting that MyVapi uses 27 out of the 33 available VAPI APIs: +Here is the updated MyVapi User Guide, including the customer endpoints and noting that MyVapi uses 27 out of the 33 available Vapi APIs: # MyVapi User Guide Welcome to MyVapi! This guide will help you get started with using MyVapi, your custom GPT, to enhance your productivity and streamline your tasks. Follow the steps below to make the most out of this powerful tool. @@ -22,7 +22,7 @@ Welcome to MyVapi! This guide will help you get started with using MyVapi, your ## Introduction to MyVapi ### What is MyVapi? -MyVapi is a custom GPT designed to allow users to manage their Vapi accounts with ease. While the Vapi Dashboard provides limited functionality and using PostMan can be cumbersome, MyVapi offers a streamlined solution to interact with the Vapi API directly. This eliminates the back-and-forth usually associated with manual API interactions and JSON validation, making the process more efficient and user-friendly. The reason MyVapi was created is to help users understand the power of using VAPI's API. MyVapi uses 27 out of the 33 available VAPI APIs. +MyVapi is a custom GPT designed to allow users to manage their Vapi accounts with ease. While the Vapi Dashboard provides limited functionality and using PostMan can be cumbersome, MyVapi offers a streamlined solution to interact with the Vapi API directly. This eliminates the back-and-forth usually associated with manual API interactions and JSON validation, making the process more efficient and user-friendly. The reason MyVapi was created is to help users understand the power of using Vapi's API. MyVapi uses 27 out of the 33 available Vapi APIs. ### Key Features - **Full API Access:** Leverage the full power of the Vapi API without the limitations of the Dashboard. diff --git a/fern/composer.mdx b/fern/composer.mdx new file mode 100644 index 000000000..5b7105d5c --- /dev/null +++ b/fern/composer.mdx @@ -0,0 +1,286 @@ +--- +title: Composer +subtitle: Build and configure voice AI agents through natural conversation +slug: composer +--- + + +Composer is currently in **Alpha**. Features and behavior may change as we iterate based on user feedback. + + +## Overview + +Composer is Vapi's intelligent assistant that helps you build and configure voice AI agents through natural conversation. Instead of manually configuring settings and writing prompts, describe what you want to build and Composer handles the technical setup. + +Composer understands voice agent architecture and Vapi's capabilities. It can create agents, configure phone numbers, set up integrations, troubleshoot issues, and answer questions about Vapi features. + +**Why use Composer:** + +- **Faster development** — Build agents in minutes instead of hours by describing your use case +- **Best practices built in** — Composer applies Vapi best practices automatically +- **Lower barrier to entry** — No need to learn every API parameter or configuration option +- **Troubleshooting support** — Composer can diagnose issues and suggest fixes + +## Get started + + + + Log into your [Vapi dashboard](https://dashboard.vapi.ai) and click the **Composer** option in the navigation, or use the chat widget. + + + Tell Composer what you need in plain language. The more context you provide, the better the result. + + **Effective prompts:** + - "Help me build a restaurant reservation agent" + - "I need to set up a phone number for my agent" + - "Create an agent that can answer questions about my business" + - "My agent isn't transferring calls correctly, can you help?" + + + Composer asks follow-up questions to understand your requirements, then takes action to build and configure your agent. + + + Test the agent Composer creates, then request adjustments as needed. Building the right agent is an iterative process. + + + +## What Composer can do + +### Capabilities + +- Create and configure assistants +- Set up phone numbers +- Configure integrations and webhooks +- Update agent prompts and settings +- Troubleshoot technical issues +- Answer questions about Vapi features +- Recommend best practices for your use case + +### Limitations + +- **Cannot delete resources** — Composer cannot delete assistants, tools, phone numbers, or any other resources. This is an intentional safety measure. Use the dashboard sidebar to delete resources manually. +- **Cannot access external systems** — Composer operates within Vapi and cannot reach your CRM, database, or other third-party systems directly. +- **Cannot make business logic decisions** — You provide the domain knowledge; Composer handles the technical configuration. +- **Cannot test your agent** — You need to test the agent yourself and provide feedback. +- **Cannot deploy to production automatically** — You control when and how changes go live. + +## Common use cases + + + + **What you say:** + + > "I want to build an agent for my dental office that can schedule appointments and answer common questions about our services." + + **What Composer does:** + 1. Asks about your specific requirements (hours, services, appointment types) + 2. Creates an agent with an appropriate system prompt + 3. Configures necessary tools (calendar integration, knowledge base) + 4. Sets up phone number configuration + 5. Provides testing guidance + + **Your part:** + - Answer Composer's questions about your business + - Provide specific details (office hours, services offered, etc.) + - Test the agent and provide feedback + + **Example conversation:** + + ```txt title="Sample conversation" + You: "I want to build an agent for my dental office that can schedule + appointments and answer common questions." + + Composer: "I'd be happy to help you build a dental office agent! Let me + ask a few questions: + + 1. What are your office hours? + 2. What types of appointments do you offer? + 3. Do you want the agent to book directly or collect information + for your staff to follow up? + 4. What are the most common questions patients ask?" + + You: "Office hours are Mon-Fri 9am-5pm. We do cleanings, exams, and + consultations. The agent should collect appointment requests and our + staff will confirm. Common questions are about insurance, parking, + and first-visit procedures." + + Composer: "I've created your dental office agent. It's configured to: + - Collect appointment requests during business hours + - Answer questions about insurance, parking, and first visits + - Escalate to staff when needed + + Would you like me to set up a phone number for testing?" + ``` + + + + **What you say:** + + > "I need to connect a phone number to my agent." + + **What Composer does:** + 1. Asks if you want to purchase a new number or import an existing one + 2. Helps you select an area code or region + 3. Configures the number to work with your agent + 4. Provides the phone number for testing + + + If you need a specific area code for local presence, mention it upfront. If you're porting an existing number, have your account details from your current provider ready. + + + + + **What you say:** + + > "My agent keeps dropping calls when trying to transfer." + + **What Composer does:** + 1. Asks diagnostic questions (when does it happen, what number, etc.) + 2. Checks your agent configuration + 3. Identifies the issue (incorrect transfer format, missing permissions, etc.) + 4. Fixes the configuration or guides you through the fix + + **Common issues Composer can help with:** + - Call transfers not working + - Agent not responding correctly to specific inputs + - Phone number routing problems + - Integration failures (calendar, CRM, etc.) + - Voice quality or latency issues + - Prompt behavior not matching expectations + + + + **What you say:** + + > "I want my agent to check availability in our calendar before booking appointments." + + **What Composer does:** + 1. Explains integration options (API webhooks, direct integrations) + 2. Helps configure the integration endpoint + 3. Sets up the agent to call your API with the right parameters + 4. Provides example requests/responses for testing + + **Your part:** + - Provide your API endpoint URL + - Share authentication details (API keys, etc.) + - Describe the expected request/response format + - Test the integration with real scenarios + + **Popular integrations:** Google Calendar, Calendly, Salesforce, HubSpot, booking systems, knowledge bases, and custom APIs. + + + +## Safety features + +Composer includes safeguards to prevent accidental or irreversible changes to your account. + +### No deletion capability + +Composer **cannot delete any resources** — assistants, tools, phone numbers, squads, files, or anything else. This is a deliberate safety measure, not a limitation. + +If you ask Composer to delete something, it directs you to do it yourself: + +```txt title="Deletion request example" +You: "Delete my old test assistant" + +Composer: "I'm not able to delete resources to prevent accidental data loss. +You can delete it yourself from the dashboard — use the sidebar on the left, +go to Assistants, select the one you want to remove, and delete it from there." +``` + + +Unlike creating or updating a resource (which can be undone or re-done), deletion is permanent. Requiring manual confirmation through the dashboard UI prevents accidental loss of important configurations. + + +### Approval required for updates + +When Composer modifies an existing resource (like updating an assistant's prompt, changing a voice setting, or editing a tool configuration), it pauses and asks for your explicit approval first. + +**How the approval flow works:** + + + + Composer shows you a summary of the update it wants to make. + + + The chat interface displays **Approve** and **Deny** buttons. Click **Approve** to proceed or **Deny** to cancel. + + + If approved, Composer makes the update and confirms. If denied, no changes are made. + + + +```txt title="Approval flow example" +You: "Change my agent's voice to sound more energetic" + +Composer: [Proposes update] +→ UI shows: "Update Resource — Updating voice settings on assistant xyz" + [Approve] [Deny] + +You: [Clicks Approve] + +Composer: "Done! I've updated the voice settings. Test it out and let me +know if you'd like to adjust further." +``` + +**Key details about approvals:** + +- **Tokens expire after 10 minutes** — if you don't respond in time, Composer needs to re-propose the change +- **Each approval is specific** — approval tokens are cryptographically bound to the exact change being made; multiple updates each require individual approval +- **Read operations don't require approval** — Composer can freely read and list your resources without permission +- **Creating new resources doesn't require approval** — new assistants, tools, and other resources are additive and non-destructive + +## Tips for best results + +### Be specific about your use case + +Provide context about your industry, audience, and requirements upfront. + +```txt title="Compare prompt quality" +Less effective: "I need an agent" + +More effective: "I need an agent for my e-commerce store that can track +orders, answer product questions, and handle returns" +``` + +### Iterate in stages + +Build a basic working agent first, then layer on advanced features: + +1. **Phase 1** — Basic conversation flow +2. **Phase 2** — Add integrations (calendar, CRM, knowledge base) +3. **Phase 3** — Add advanced features (custom voices, complex routing) + +### Handle one task at a time + +Keep conversations focused on a single objective for best results. + +```txt title="Compare task scoping" +Less effective: "Set up my phone number, fix the transfer issue, add +Spanish support, and integrate with my CRM" + +More effective: "First, let's set up my phone number" +[Complete that task] +"Great! Now can you help me fix the transfer issue?" +``` + +### Ask Composer to explain + +If you're unsure about Vapi features or want to learn the API, ask directly: + +- "What's the best way to handle voicemail?" +- "Should I use function calling or server URL for my integration?" +- "Can you show me the API call you're making to create this agent?" + + +Ask Composer for the full configuration of an agent it builds. Save it in version control to use as a template for similar agents. + + +## Next steps + +Now that you know how Composer works: + +- **[Assistants quickstart](/assistants/quickstart):** Learn the fundamentals of building voice agents manually +- **[Prompting guide](/prompting-guide):** Write effective system prompts for your agents +- **[Tools overview](/tools):** Understand the tools and integrations available to your agents +- **[Phone numbers](/free-telephony):** Set up phone numbers for your agents diff --git a/fern/custom.js b/fern/custom.js new file mode 100644 index 000000000..6434797a4 --- /dev/null +++ b/fern/custom.js @@ -0,0 +1,224 @@ +const WIDGET_TAG = 'vapi-voice-agent-widget'; +const ENABLE_VOICE_WIDGET = false; // Feature flag to enable/disable the floating voice widget +const isLocalhost = window.location.hostname === 'localhost' || window.location.hostname === '127.0.0.1'; +const WIDGET_SCRIPT_URL = isLocalhost + ? 'http://localhost:9001/widget.js' + : 'https://docs-widget.vercel.app/widget.js'; + +const HOCKEYSTACK_API_KEY = '96e358f635f3f5ea7fda26023b10da'; +const REO_CLIENT_ID = '0dc28e3fda800b9'; + +function injectVapiWidget() { + console.log('[custom.js] injectVapiWidget called'); + if (document.querySelector(WIDGET_TAG)) { + console.log('[custom.js] Widget already present in DOM'); + return; + } + + const script = document.createElement('script'); + script.src = WIDGET_SCRIPT_URL; + script.async = true; + script.onload = () => { + console.log('[custom.js] Widget script loaded'); + // Create the web component after the script loads + const widget = document.createElement(WIDGET_TAG); + const apiKey = '6d46661c-2dce-4032-b62d-64c151a14e0d'; + widget.setAttribute('apiKey', apiKey); + widget.style.position = 'fixed'; + widget.style.bottom = '0'; + widget.style.right = '0'; + widget.style.zIndex = '9999'; + document.body.appendChild(widget); + console.log('[custom.js] Widget element appended to DOM'); + }; + document.body.appendChild(script); + console.log('[custom.js] Widget script appended to DOM'); +} + +function initializeHockeyStack() { + if (isLocalhost) { + console.log('[custom.js] Skipping HockeyStack on localhost'); + return; + } + + var hsscript = document.createElement("script"); + hsscript.id = "wphs"; + hsscript.src = "https://cdn.jsdelivr.net/npm/hockeystack@latest/hockeystack.min.js"; + hsscript.async = 1; + hsscript.dataset.apikey = HOCKEYSTACK_API_KEY; + hsscript.dataset.cookieless = 1; + hsscript.dataset.autoIdentify = 1; + + document.getElementsByTagName('head')[0].append(hsscript); +} + +function initializeReo() { + if (isLocalhost) { + console.log('[custom.js] Skipping Reo on localhost'); + return; + } + + var reoScript = document.createElement("script"); + reoScript.type = "text/javascript"; + reoScript.src = "https://static.reo.dev/" + REO_CLIENT_ID + "/reo.js"; + reoScript.defer = true; + reoScript.onload = function() { + if (typeof Reo !== 'undefined') { + Reo.init({ clientID: REO_CLIENT_ID }); + } + }; + document.head.appendChild(reoScript); +} + +function configurePostHog() { + if (isLocalhost) { + console.log('[custom.js] Skipping PostHog configuration on localhost'); + return; + } + + // Wait for PostHog to be initialized by Fern + const checkPostHog = setInterval(() => { + if (typeof window.posthog !== 'undefined') { + clearInterval(checkPostHog); + + // Configure cross-domain tracking + window.posthog.set_config({ + cross_subdomain_cookie: true, + cross_domain: '.vapi.ai', + persistence: 'localStorage+cookie' + }); + + } + }, 100); + +} + +function initializeHubSpot() { + + if (isLocalhost) { + console.log('[custom.js] Skipping HubSpot configuration on localhost'); + return; + } + + var hubSpotScript = document.createElement("script"); + hubSpotScript.type = "text/javascript"; + hubSpotScript.id = "hs-script-loader"; + hubSpotScript.src = "https://js-na2.hs-scripts.com/244349038.js"; + hubSpotScript.async = true; + hubSpotScript.defer = true; + document.getElementsByTagName('head')[0].appendChild(hubSpotScript); +} + +function initializeSubscribeForm() { + // Fern's MDX renderer strips JSX event handlers (onSubmit, onClick), so the + // form's validation and submission logic must be attached from plain JS. + // Without this, the form falls through to a native HTML POST that silently + // redirects back to the same page with no user feedback. + + var form = document.querySelector('form.subscribe-form'); + if (!form) { + return; + } + + // Avoid attaching the handler twice on SPA navigations + if (form.dataset.enhanced === 'true') { + return; + } + form.dataset.enhanced = 'true'; + + form.addEventListener('submit', function (e) { + e.preventDefault(); + + var emailInput = form.querySelector('input[name="email"]'); + var submitBtn = form.querySelector('button[type="submit"]'); + var messageDiv = form.querySelector('.subscribe-form-message'); + + if (!emailInput || !submitBtn) { + return; + } + + var email = emailInput.value.trim(); + var emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; + + if (!emailPattern.test(email)) { + if (messageDiv) { + messageDiv.textContent = 'Please enter a valid email address.'; + messageDiv.className = 'subscribe-form-message error'; + messageDiv.style.display = 'block'; + } + return; + } + + // Hide any previous message and disable the button while submitting + if (messageDiv) { + messageDiv.style.display = 'none'; + } + submitBtn.disabled = true; + var originalText = submitBtn.textContent; + submitBtn.textContent = 'Submitting...'; + + var formAction = form.getAttribute('action'); + var formData = new FormData(); + formData.append('email', email); + + fetch(formAction, { + method: 'POST', + body: formData, + redirect: 'manual', + }) + .then(function (response) { + // Customer.io returns 302 on success which becomes an opaque redirect + // with redirect:'manual'. Both 302 and opaque (type 0) indicate success. + if (response.ok || response.status === 302 || response.status === 0 || response.type === 'opaqueredirect') { + if (messageDiv) { + messageDiv.textContent = 'Thanks for subscribing! You will receive product updates at ' + email + '.'; + messageDiv.className = 'subscribe-form-message success'; + messageDiv.style.display = 'block'; + } + emailInput.value = ''; + } else { + throw new Error('Unexpected response: ' + response.status); + } + }) + .catch(function () { + if (messageDiv) { + messageDiv.textContent = 'Something went wrong. Please try again.'; + messageDiv.className = 'subscribe-form-message error'; + messageDiv.style.display = 'block'; + } + }) + .finally(function () { + submitBtn.disabled = false; + submitBtn.textContent = originalText; + }); + }); +} + +function initializeAll() { + initializeHockeyStack(); + initializeReo(); + initializeHubSpot(); + configurePostHog(); + initializeSubscribeForm(); + if (ENABLE_VOICE_WIDGET) { + injectVapiWidget(); + } +} + +// Fern uses client-side routing, so the form may appear after the initial page +// load. Re-attach the handler whenever the DOM changes on the whats-new page. +var subscribeFormObserver = new MutationObserver(function () { + if (window.location.pathname.indexOf('whats-new') !== -1) { + initializeSubscribeForm(); + } +}); + +if (document.readyState === 'loading') { + document.addEventListener('DOMContentLoaded', function () { + initializeAll(); + subscribeFormObserver.observe(document.body, { childList: true, subtree: true }); + }); +} else { + initializeAll(); + subscribeFormObserver.observe(document.body, { childList: true, subtree: true }); +} \ No newline at end of file diff --git a/fern/custom.spec.js b/fern/custom.spec.js new file mode 100644 index 000000000..8b4860837 --- /dev/null +++ b/fern/custom.spec.js @@ -0,0 +1,155 @@ +/** + * Standalone tests for the subscribe form logic in custom.js. + * + * These tests validate the initializeSubscribeForm() function by extracting + * its logic and running it against a mock DOM. No external dependencies + * required -- run with: node fern/custom.spec.js + * + * The function under test is extracted here rather than imported because + * custom.js is a browser script that reads window.location at parse time. + */ + +'use strict'; + +let passed = 0; +let failed = 0; + +function assert(condition, message) { + if (condition) { + passed++; + console.log(' PASS: ' + message); + } else { + failed++; + console.error(' FAIL: ' + message); + } +} + +function assertEqual(actual, expected, message) { + if (actual === expected) { + passed++; + console.log(' PASS: ' + message); + } else { + failed++; + console.error(' FAIL: ' + message + ' (expected ' + JSON.stringify(expected) + ', got ' + JSON.stringify(actual) + ')'); + } +} + +// --------------------------------------------------------------------------- +// Extracted logic from initializeSubscribeForm (the core of the fix) +// --------------------------------------------------------------------------- + +function emailValidate(email) { + var emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; + return emailPattern.test(email); +} + +// --------------------------------------------------------------------------- +// Tests +// --------------------------------------------------------------------------- + +console.log('\n--- Email validation ---'); + +assert(emailValidate('user@example.com'), 'accepts standard email'); +assert(emailValidate('user+tag@domain.co.uk'), 'accepts email with plus and subdomain'); +assert(emailValidate('a@b.c'), 'accepts minimal valid email'); +assert(!emailValidate(''), 'rejects empty string'); +assert(!emailValidate('not-an-email'), 'rejects string without @'); +assert(!emailValidate('user@'), 'rejects email missing domain'); +assert(!emailValidate('@domain.com'), 'rejects email missing local part'); +assert(!emailValidate('user @domain.com'), 'rejects email with space'); +assert(!emailValidate('user@domain'), 'rejects email without TLD dot'); + +console.log('\n--- MDX structure validation ---'); + +var fs = require('fs'); +var path = require('path'); + +var mdxPath = path.join(__dirname, 'changelog', 'overview.mdx'); +var mdxContent = fs.readFileSync(mdxPath, 'utf-8'); + +assert(mdxContent.indexOf('class="subscribe-form"') !== -1 || mdxContent.indexOf('className="subscribe-form"') !== -1, + 'MDX contains form with subscribe-form class'); +assert(mdxContent.indexOf('customerioforms.com') !== -1, + 'MDX contains Customer.io form action URL'); +assert(mdxContent.indexOf('name="email"') !== -1, + 'MDX contains email input with correct name attribute'); +assert(mdxContent.indexOf('type="submit"') !== -1, + 'MDX contains submit button'); +assert(mdxContent.indexOf('subscribe-form-message') !== -1, + 'MDX contains message div for feedback'); +assert(mdxContent.indexOf('subscribe-form-input') !== -1, + 'MDX uses CSS class for input styling'); +assert(mdxContent.indexOf('subscribe-form-button') !== -1, + 'MDX uses CSS class for button styling'); + +// Verify the broken onSubmit handler is removed +assert(mdxContent.indexOf('onSubmit') === -1, + 'MDX does not contain onSubmit handler (Fern strips JSX event handlers)'); +assert(mdxContent.indexOf('onClick') === -1, + 'MDX does not contain onClick handler (Fern strips JSX event handlers)'); + +console.log('\n--- custom.js structure validation ---'); + +var customJsPath = path.join(__dirname, 'custom.js'); +var customJsContent = fs.readFileSync(customJsPath, 'utf-8'); + +assert(customJsContent.indexOf('initializeSubscribeForm') !== -1, + 'custom.js contains initializeSubscribeForm function'); +assert(customJsContent.indexOf('addEventListener') !== -1 && customJsContent.indexOf("'submit'") !== -1, + 'custom.js attaches submit event listener'); +assert(customJsContent.indexOf('e.preventDefault()') !== -1, + 'custom.js prevents default form submission'); +assert(customJsContent.indexOf("redirect: 'manual'") !== -1, + 'custom.js uses fetch with redirect:manual to handle 302'); +assert(customJsContent.indexOf('opaqueredirect') !== -1, + 'custom.js checks for opaqueredirect response type'); +assert(customJsContent.indexOf('subscribe-form-message') !== -1, + 'custom.js updates the message div'); +assert(customJsContent.indexOf('Thanks for subscribing') !== -1, + 'custom.js shows success message'); +assert(customJsContent.indexOf('Something went wrong') !== -1, + 'custom.js shows error message on failure'); +assert(customJsContent.indexOf("dataset.enhanced === 'true'") !== -1, + 'custom.js guards against duplicate handler attachment'); +assert(customJsContent.indexOf('MutationObserver') !== -1, + 'custom.js uses MutationObserver for SPA route changes'); +assert(customJsContent.indexOf('Submitting...') !== -1, + 'custom.js shows loading state on button'); + +console.log('\n--- CSS validation ---'); + +var cssPath = path.join(__dirname, 'assets', 'styles.css'); +var cssContent = fs.readFileSync(cssPath, 'utf-8'); + +assert(cssContent.indexOf('.subscribe-form-input') !== -1, + 'CSS contains subscribe-form-input styles'); +assert(cssContent.indexOf('.subscribe-form-button') !== -1, + 'CSS contains subscribe-form-button styles'); +assert(cssContent.indexOf('.subscribe-form-message.success') !== -1, + 'CSS contains success message styles'); +assert(cssContent.indexOf('.subscribe-form-message.error') !== -1, + 'CSS contains error message styles'); +assert(cssContent.indexOf('.subscribe-form-input:focus') !== -1, + 'CSS contains focus styles for input'); +assert(cssContent.indexOf('.subscribe-form-button:hover') !== -1, + 'CSS contains hover styles for button'); +assert(cssContent.indexOf('.subscribe-form-button:disabled') !== -1, + 'CSS contains disabled styles for button'); +assert(cssContent.indexOf(':is(.dark) .subscribe-form-input') !== -1, + 'CSS contains dark mode styles for input'); +assert(cssContent.indexOf(':is(.dark) .subscribe-form-button') !== -1, + 'CSS contains dark mode styles for button'); +assert(cssContent.indexOf('.subscribe-form-row') !== -1, + 'CSS contains flex row layout for form'); + +// --------------------------------------------------------------------------- +// Summary +// --------------------------------------------------------------------------- + +console.log('\n--- Results ---'); +console.log('Passed: ' + passed); +console.log('Failed: ' + failed); + +if (failed > 0) { + process.exit(1); +} diff --git a/fern/customization/bring-your-own-vectors/trieve.mdx b/fern/customization/bring-your-own-vectors/trieve.mdx deleted file mode 100644 index 9987d265c..000000000 --- a/fern/customization/bring-your-own-vectors/trieve.mdx +++ /dev/null @@ -1,59 +0,0 @@ ---- -title: Bring your own chunks/vectors from Trieve -subtitle: Use existing chunks/vectors from [Trieve](https://trieve.ai) -slug: customization/bring-your-own-vectors/trieve ---- - -Vapi supports Trieve as a knowledgebase provider, allowing you to leverage your existing document embeddings and chunks. While Vapi maintains its own storage of documents and vectors, you can seamlessly integrate with your Trieve datasets. - -## Use Cases - -### Existing Knowledge Base Migration - -If you've already invested time in building and organizing your knowledge base in Trieve, you can continue using those vectors without having to reprocess your documents. This is particularly useful for: - -- Large document collections that took significant time to process -- Carefully curated and cleaned datasets -- Custom-chunked documents with specific segmentation rules - -### Parallel Systems - -You might want to use both Trieve's native interface and Vapi simultaneously: - -- Use Trieve's UI for content management and organization -- Leverage Vapi's chat interface and API capabilities -- Maintain consistency across both platforms - -## Integration Steps - -1. **Configure Trieve Credentials** - - - Navigate to the credentials page in your [Vapi dashboard](https://dashboard.vapi.ai/keys) - - Add your Trieve API key for authentication from [Trieve](https://dashboard.trieve.ai/org/keys) - -2. **Create a New Knowledge Base** - - - When setting up a new knowledge base, provide: - - Your Trieve datasetId as the vectorStoreProviderId - - Appropriate search configuration parameters - - Vapi will then connect to your existing Trieve vectors - - Example configuration: - - ```json - { - "name": "byok-test", - "provider": "trieve", - "vectorStoreSearchPlan": { - "scoreThreshold": 0.2, - "searchType": "semantic" - }, - "vectorStoreProviderId": "" - } - ``` - -## Best Practices - -- Ensure your Trieve API key has appropriate permissions -- Keep track of which datasetIds correspond to which knowledge bases -- Monitor vector synchronization to ensure consistency diff --git a/fern/customization/custom-keywords.mdx b/fern/customization/custom-keywords.mdx index 95e1450ed..0fb5e0a0f 100644 --- a/fern/customization/custom-keywords.mdx +++ b/fern/customization/custom-keywords.mdx @@ -1,11 +1,13 @@ --- -title: Custom Keywords -subtitle: Enhanced transcription accuracy guide +title: Keywords and keyterm prompting +subtitle: Boost STT accuracy for domain words and phrases slug: customization/custom-keywords --- -VAPI allows you to improve the accuracy of your transcriptions by leveraging Deepgram's keyword boosting feature. This is particularly useful when dealing with specialized terminology or uncommon proper nouns. By providing specific keywords to the Deepgram model, you can enhance transcription quality directly through VAPI. +Vapi allows you to improve the accuracy of your transcriptions by leveraging keyword boosting and keyterm prompting. This is particularly useful when dealing with specialized terminology or uncommon proper nouns. Both [Deepgram](#deepgram-keywords-and-keyterm-prompting) and [AssemblyAI](#assemblyai-keyterms-prompting) transcribers support this through Vapi. + +## Deepgram keywords and keyterm prompting ### Why Use Keyword Boosting? @@ -18,21 +20,25 @@ Keyword boosting is beneficial for: ### Important Notes - Keywords should be uncommon words or proper nouns not frequently recognized by the model. -- Custom model training is the most effective way to ensure accurate keyword recognition. -- For more than 50 keywords, consider custom model training by contacting Deepgram. +- Use single words for `keywords` (no spaces or punctuation). For multi-word phrases, use `keyterm` instead. +- Custom model training is the most effective way to ensure accurate keyword recognition when you need extensive vocabulary coverage. + +### Model support -## Enabling Keyword Boosting in VAPI +- Keywords is available on Deepgram Nova-2, Nova-1, Enhanced, and Base speech-to-text models. +- For Nova-3 models, use Keyterm Prompting instead of Keywords. -### API Call Integration +### Enabling Keyword Boosting in Vapi -To enable keyword boosting, you need to add a `keywords` parameter to your VAPI assistant's transcriber section. This parameter should include the keywords and their respective intensifiers. +#### API Call Integration + +To enable keyword boosting, add the `keywords` parameter to your assistant's `transcriber` configuration when using the Deepgram provider. You can also supply `keyterm` to boost recall for phrases. ### Example of POST Request -To create an assistant with keyword boosting enabled, you can make the following POST request to VAPI: +To create an assistant with keyword boosting enabled, you can make the following POST request to Vapi: ```bash -bashCopy code curl \ --request POST \ --header 'Authorization: Bearer ' \ @@ -40,27 +46,33 @@ curl \ --data '{ "name": "Emma", "model": { - "model": "gpt-4o", - "provider": "openai" + "model": "gpt-4o", + "provider": "openai" }, "voice": { - "voiceId": "emma", - "provider": "azure" + "voiceId": "emma", + "provider": "azure" }, "transcriber": { - "provider": "deepgram", - "model": "nova-2", - "language": "bg", - "smartFormat": true, - "keywords": [ - "snuffleupagus:1" - ] + "provider": "deepgram", + "model": "nova-2", + "language": "en", + "smartFormat": true, + "keywords": [ + "snuffleupagus:5", + "systrom", + "krieger" + ], + "keyterm": [ + "order number", + "account ID", + "PCI compliance" + ] }, "firstMessage": "Hi, I am Emma, what is your name?", "firstMessageMode": "assistant-speaks-first" }' \ https://api.vapi.ai/assistant - ``` In this configuration: @@ -68,28 +80,85 @@ In this configuration: - **name**: The name of the assistant. - **model**: Specifies the model and provider for the assistant's conversational capabilities. - **voice**: Specifies the voice and provider for the assistant's speech. -- **transcriber**: Specifies Deepgram as the transcription provider, along with the model, language, smart formatting, and keywords for boosting. +- **transcriber**: Specifies Deepgram as the transcription provider, along with the model, language, smart formatting, and both `keywords` (single words) and `keyterm` (phrases) for boosting. - **firstMessage**: The initial message the assistant will speak. - **firstMessageMode**: Specifies that the assistant speaks first. -### Intensifiers +### Format and intensifiers -Intensifiers are exponential factors that boost or suppress the likelihood of the specified keyword being recognized. The default intensifier is `1`. Higher values increase the likelihood, while `0` is equivalent to not specifying a keyword. +The `keywords` array accepts single-word tokens consisting of letters and digits, with an optional integer intensifier after a colon: + +- Accepted forms: `apple`, `apple:3`, `apple:-2` +- Not accepted: `order number` (use `keyterm`), `hello-world`, `foo_bar`, `rate:1.5` (decimals are not supported by this schema) + +Intensifiers are exponential factors that boost or suppress the likelihood of the specified keyword being recognized. The default intensifier is `1`. Higher values increase the likelihood, while `0` is equivalent to not specifying a keyword. Negative values suppress recognition. - **Boosting Example:** `keywords=snuffleupagus:5` - **Suppressing Example:** `keywords=kansas:-10` -### Best Practices for Keyword Boosting +### Keyterm prompting (phrases) + +Deepgram's Keyterm Prompting improves Keyword Recall Rate (KRR) for important keyterms or phrases. Use `keyterm` for multi‑word phrases you want the model to detect more reliably. Unlike `keywords`, keyterms are specified as plain strings without intensifiers. + +Example: `"keyterm": ["account number", "confirmation code", "HIPAA compliance"]` -1. **Send Uncommon Keywords:** Focus on keywords not successfully transcribed by the model. -2. **Send Keywords Once:** Avoid repeating keywords. -3. **Use Individual Keywords:** Prefer individual terms over phrases. -4. **Use Proper Spelling:** Spell proper nouns as you want them to appear in transcripts. -5. **Moderate Intensifiers:** Start with small increments to avoid false positives. -6. **Custom Model Training:** For extensive vocabulary needs, consider custom model training. +### Best Practices for Keyword and Keyterm Boosting + +1. **Start small:** Begin without any boosting; add keywords/keyterms only where needed. +2. **Send uncommon words:** Focus on proper nouns or domain terms the model often misses. +3. **Use `keywords` for single words; `keyterm` for phrases:** Avoid spaces in `keywords`. +4. **Avoid duplicates:** Send each keyword once; duplicates don't improve results. +5. **Moderate intensifiers:** Use minimal integer boosts to reduce false positives; increase cautiously. +6. **Correct spelling/casing:** Provide the spelling and capitalization you want in transcripts. +7. **Consider custom models:** For extensive vocabularies, consider custom model training with Deepgram. ### Additional Resources -For more detailed information on Deepgram's keyword boosting feature, refer to the Deepgram Keyword Boosting Documentation. +For more details, see: + +- Deepgram Keywords: [developers.deepgram.com/docs/keywords](https://developers.deepgram.com/docs/keywords) +- Deepgram Keyterm Prompting: [developers.deepgram.com/docs/keyterm](https://developers.deepgram.com/docs/keyterm) +- API reference: Deepgram transcriber `keywords` and `keyterm` in the [API reference](https://api.vapi.ai/api#:~:text=DeepgramTranscriber) + +By following these guidelines, you can effectively utilize Deepgram's keyword boosting feature within your Vapi assistant, ensuring enhanced transcription accuracy for specialized terminology and uncommon proper nouns. + +## AssemblyAI keyterms prompting + +AssemblyAI's Universal-Streaming keyterms prompting boosts recognition of domain-specific words and phrases. Add the `keytermsPrompt` parameter to your assistant's `transcriber` configuration when using the `assembly-ai` provider. + +- Up to 100 keyterms per session, each up to 50 characters. +- Keyterms can be single words or multi-word phrases — no intensifiers needed. +- Supported with the `universal-streaming-english` and `universal-3-5-pro` speech models. Not supported with `universal-streaming-multilingual`. +- Keyterms prompting adds $0.04/hour to transcription cost on `universal-streaming-english`. + +### Example + +```bash +curl \ + --request POST \ + --header 'Authorization: Bearer ' \ + --header 'Content-Type: application/json' \ + --data '{ + "name": "Emma", + "model": { + "model": "gpt-4o", + "provider": "openai" + }, + "transcriber": { + "provider": "assembly-ai", + "speechModel": "universal-streaming-english", + "keytermsPrompt": [ + "order number", + "account ID", + "PCI compliance" + ] + }, + "firstMessage": "Hi, I am Emma, what is your name?" + }' \ + https://api.vapi.ai/assistant +``` + +### Additional resources -By following these guidelines, you can effectively utilize Deepgram's keyword boosting feature within your VAPI assistant, ensuring enhanced transcription accuracy for specialized terminology and uncommon proper nouns. \ No newline at end of file +- AssemblyAI Keyterms Prompting: [AssemblyAI's prompting and keyterms guide](https://www.assemblyai.com/docs/streaming/prompting-and-keyterms) +- API reference: [`AssemblyAITranscriber` fields](/api-reference/assistants/create#request.body.transcriber.AssemblyAITranscriber) diff --git a/fern/customization/custom-llm/tool-calling-integration.mdx b/fern/customization/custom-llm/tool-calling-integration.mdx new file mode 100644 index 000000000..252343feb --- /dev/null +++ b/fern/customization/custom-llm/tool-calling-integration.mdx @@ -0,0 +1,426 @@ +--- +title: Custom LLM Tool Calling Integration +slug: customization/tool-calling-integration +--- +## What Is a Custom LLM and Why Use It? + +A **Custom LLM** is more than just a text generator—it’s a conversational assistant that can call external functions, trigger processes, and handle special logic, all while chatting with your users. Think of it as your smart helper that not only answers questions but also takes actions. + +**Why use a Custom LLM?** +- **Enhanced Functionality:** It mixes natural language responses with actionable functions. +- **Flexibility:** You can combine built-in functions, attach external tools via Vapi, or even add custom endpoints. +- **Dynamic Interactions:** The assistant can return structured instructions—like transferring a call or running a custom process—when needed. +- **Seamless Integration:** Vapi lets you plug these custom endpoints into your assistant quickly and easily. + +--- + +## Setting Up Your Custom LLM for Response Generation + +Before adding tool calls, let’s start with the basics: setting up your Custom LLM to simply generate conversation responses. In this mode, your LLM receives conversation details, asks the model for a reply, and streams that text back. + +### How It Works +- **Request Reception:** Your endpoint (e.g., `/chat/completions`) gets a payload with the model, messages, temperature, and (optionally) tools. +- **Content Generation:** The code builds an OpenAI API request that includes the conversation context. +- **Response Streaming:** The generated reply is sent back as Server-Sent Events (SSE). + +### Sample Code Snippet + +```typescript +app.post("/chat/completions", async (req: Request, res: Response) => { + // Log the incoming request. + logEvent("Request received at /chat/completions", req.body); + const payload = req.body; + + // Prepare the API request to OpenAI. + const requestArgs: any = { + model: payload.model, + messages: payload.messages, + temperature: payload.temperature ?? 1.0, + stream: true, + tools: payload.tools || [], + tool_choice: "auto", + }; + + // Optionally merge in native tool definitions. + const modelTools = payload.tools || []; + requestArgs.tools = [...modelTools, ...ourTools]; + + logEvent("Calling OpenAI API for content generation"); + const openAIResponse = await openai.chat.completions.create(requestArgs); + logEvent("OpenAI API call successful. Streaming response."); + + // Set up streaming headers. + res.setHeader("Content-Type", "text/event-stream"); + res.setHeader("Cache-Control", "no-cache"); + res.setHeader("Connection", "keep-alive"); + + // Stream the response chunks back. + for await (const chunk of openAIResponse as unknown as AsyncIterable) { + res.write(`data: ${JSON.stringify(chunk)}\n\n`); + } + res.write("data: [DONE]\n\n"); + res.end(); +}); +``` + +### Attaching Custom LLM Without Tools to an Existing Assistant in Vapi + +If you just want response generation (without tool calls), update your Vapi model with a PATCH request like this: + +```bash +curl -X PATCH https://api.vapi.ai/assistant/insert-your-assistant-id-here \ + -H "Authorization: Bearer insert-your-private-key-here" \ + -H "Content-Type: application/json" \ + -d '{ + "model": { + "provider": "custom-llm", + "model": "gpt-4o", + "url": "https://custom-llm-url/chat/completions", + "messages": [ + { + "role": "system", + "content": "[TASK] Ask the user if they want to transfer the call; if not, continue the conversation." + } + ] + }, + "transcriber": { + "provider": "azure", + "language": "en-CA" + } +}' +``` + +--- + +## Adding Tools Calling with Your Custom LLM + +Now that you’ve got response generation working, let’s expand your assistant’s abilities. Your Custom LLM can trigger external actions in three different ways. + +### a. Native LLM Tools + +These tools are built right into your LLM integration. For example, a native function like `get_payment_link` can return a payment URL. + +**How It Works:** +1. **Detection:** The LLM’s streaming response includes a tool call for `get_payment_link`. +2. **Execution:** The integration parses the arguments and calls the native function. +3. **Response:** The result is packaged into a follow-up API call and streamed back. + +**Code Snippet:** + +```typescript +// Variables to accumulate tool call information. +let argumentsStr = ""; +let toolCallInfo: { name?: string; id?: string } | null = null; + +// Process streaming chunks. +for await (const chunk of openAIResponse as unknown as AsyncIterable) { + const choice = chunk.choices && chunk.choices[0]; + const delta = choice?.delta || {}; + const toolCalls = delta.tool_calls; + + if (toolCalls && toolCalls.length > 0) { + for (const toolCall of toolCalls) { + const func = toolCall.function; + if (func && func.name) { + toolCallInfo = { name: func.name, id: toolCall.id }; + } + if (func && func.arguments) { + argumentsStr += func.arguments; + } + } + } + + const finishReason = choice?.finish_reason; + if (finishReason === "tool_calls" && toolCallInfo) { + let parsedArgs = {}; + try { + parsedArgs = JSON.parse(argumentsStr); + } catch (err) { + console.error("Failed to parse arguments:", err); + } + if (tool_functions[toolCallInfo.name!]) { + const result = await tool_functions[toolCallInfo.name!](parsedArgs); + const functionMessage = { + role: "function", + name: toolCallInfo.name, + content: JSON.stringify(result) + }; + + const followUpResponse = await openai.chat.completions.create({ + model: requestArgs.model, + messages: [...requestArgs.messages, functionMessage], + temperature: requestArgs.temperature, + stream: true, + tools: requestArgs.tools, + tool_choice: "auto" + }); + + for await (const followUpChunk of followUpResponse) { + res.write(`data: ${JSON.stringify(followUpChunk)}\n\n`); + } + argumentsStr = ""; + toolCallInfo = null; + continue; + } + } + res.write(`data: ${JSON.stringify(chunk)}\n\n`); +} +``` + +### b. Vapi-Attached Tools + +These tools come pre-attached via your Vapi configuration. For example, the `transferCall` tool: + +**How It Works:** +1. **Detection:** When a tool call for `transferCall` appears with a destination in the payload, the function isn’t executed. +2. **Response:** The integration immediately sends a function call payload with the destination back to Vapi. + +**Code Snippet:** + +```typescript +if (functionName === "transferCall" && payload.destination) { + const functionCallPayload = { + function_call: { + name: "transferCall", + arguments: { + destination: payload.destination, + }, + }, + }; + logEvent("Special handling for transferCall", { functionCallPayload }); + res.write(`data: ${JSON.stringify(functionCallPayload)}\n\n`); + // Skip further processing for this chunk. + continue; +} +``` + +### c. Custom Tools + +Custom tools are unique to your application and are handled by a dedicated endpoint. For example, a custom function named `processOrder`. + +**How It Works:** +1. **Dedicated Endpoint:** Requests for custom tools go to `/chat/completions/custom-tool`. +2. **Detection:** The payload includes a tool call list. If the function name is `"processOrder"`, a hardcoded result is returned. +3. **Response:** A JSON response is sent back with the result. + +**Code Snippet (Custom Endpoint):** + +```typescript +app.post("/chat/completions/custom-tool", async (req: Request, res: Response) => { + logEvent("Received request at /chat/completions/custom-tool", req.body); + // Expect the payload to have a "message" with a "toolCallList" array. + const vapiPayload = req.body.message; + + // Process tool call. + for (const toolCall of vapiPayload.toolCallList) { + if (toolCall.function?.name === "processOrder") { + const hardcodedResult = "CustomTool processOrder With CustomLLM Always Works"; + logEvent("Returning hardcoded result for 'processOrder'", { toolCallId: toolCall.id }); + return res.json({ + results: [ + { + toolCallId: toolCall.id, + result: hardcodedResult, + }, + ], + }); + } + } +}); +``` + +--- + +## Testing Tool Calling with cURL + +Once your endpoints are set up, try testing them with these cURL commands. + +### a. Native Tool Calling (`get_payment_link`) + +```bash +curl -X POST https://custom-llm-url/chat/completions \ + -H "Content-Type: application/json" \ + -d '{ + "model": "gpt-4o", + "messages": [ + {"role": "user", "content": "I need a payment link."} + ], + "temperature": 0.7, + "tools": [ + { + "type": "function", + "function": { + "name": "get_payment_link", + "description": "Get a payment link", + "parameters": {} + } + } + ] + }' +``` + +*Expected Response:* +Streaming chunks eventually include the result (e.g., a payment link) returned by the native tool function. + +### b. Vapi-Attached Tool Calling (`transferCall`) + +```bash +curl -X POST https://custom-llm-url/chat/completions \ + -H "Content-Type: application/json" \ + -d '{ + "model": "gpt-4o", + "messages": [ + {"role": "user", "content": "Please transfer my call."} + ], + "temperature": 0.7, + "tools": [ + { + "type": "function", + "function": { + "name": "transferCall", + "description": "Transfer call to a specified destination", + "parameters": {} + } + } + ], + "destination": "555-1234" + }' +``` + +*Expected Response:* +Immediately returns a function call payload that instructs Vapi to transfer the call to the specified destination. + +### c. Custom Tool Calling (`processOrder`) + +```bash +curl -X POST https://custom-llm-url/chat/completions/custom-tool \ + -H "Content-Type: application/json" \ + -d '{ + "message": { + "toolCallList": [ + { + "id": "12345", + "function": { + "name": "processOrder", + "arguments": { + "param": "value" + } + } + } + ] + } + }' +``` + +*Expected Response:* +```json +{ + "results": [ + { + "toolCallId": "12345", + "result": "CustomTools With CustomLLM Always Works" + } + ] +} +``` + +--- + +## Integrating Tools with Vapi + +After testing locally, integrate your Custom LLM with Vapi. Choose the configuration that fits your needs. + +### a. Without Tools (Response Generation Only) + +```bash +curl -X PATCH https://api.vapi.ai/assistant/insert-your-assistant-id-here \ + -H "Authorization: Bearer insert-your-private-key-here" \ + -H "Content-Type: application/json" \ + -d '{ + "model": { + "provider": "custom-llm", + "model": "gpt-4o", + "url": "https://custom-llm-url/chat/completions", + "messages": [ + { + "role": "system", + "content": "[TASK] Ask the user if they want to transfer the call; if not, continue chatting." + } + ] + }, + "transcriber": { + "provider": "azure", + "language": "en-CA" + } +}' +``` + +### b. With Tools (Including `transferCall` and `processOrder`) + +```bash +curl -X PATCH https://api.vapi.ai/assistant/insert-your-assistant-id-here \ + -H "Authorization: Bearer insert-your-private-key-here" \ + -H "Content-Type: application/json" \ + -d '{ + "model": { + "provider": "custom-llm", + "model": "gpt-4o", + "url": "https://custom-llm-url/chat/completions", + "messages": [ + { + "role": "system", + "content": "[TASK] Ask the user if they want to transfer the call; if they agree, trigger the transferCall tool; if not, continue the conversation. Also, if the user asks about the custom function processOrder, trigger that tool." + } + ], + "tools": [ + { + "type": "transferCall", + "destinations": [ + { + "type": "number", + "number": "+xxxxxx", + "numberE164CheckEnabled": false, + "message": "Transferring Call To Customer Service Department" + } + ] + }, + { + "type": "function", + "async": false, + "function": { + "name": "processOrder", + "description": "it's a custom tool function named processOrder according to vapi.ai custom tools guide" + }, + "server": { + "url": "https://custom-llm-url/chat/completions/custom-tool" + } + } + ] + }, + "transcriber": { + "provider": "azure", + "language": "en-CA" + } +}' +``` + +--- + +## Conclusion + +A Custom LLM turns a basic conversational assistant into an interactive helper that can: +- **Generate everyday language responses,** +- **Call native tools** (like fetching a payment link), +- **Use Vapi-attached tools** (like transferring a call), and +- **Leverage custom tools** (like processing orders). + +By building each layer step by step and testing with cURL, you can fine-tune your integration before rolling it out in production. + +--- + +## Complete Code + +For your convenience, you can find the complete source code for this Custom LLM integration here: + +**[Custom LLM with Vapi Integration – Complete Code](https://codesandbox.io/p/devbox/gfwztp)** +``` diff --git a/fern/customization/custom-llm/using-your-server.mdx b/fern/customization/custom-llm/using-your-server.mdx index fecbcac73..65e25a5cf 100644 --- a/fern/customization/custom-llm/using-your-server.mdx +++ b/fern/customization/custom-llm/using-your-server.mdx @@ -4,11 +4,11 @@ slug: customization/custom-llm/using-your-server --- -This guide provides a comprehensive walkthrough on integrating Vapi with OpenAI's gpt-3.5-turbo-instruct model using a custom LLM configuration. We'll leverage Ngrok to expose a local development environment for testing and demonstrate the communication flow between Vapi and your LLM. +This guide provides a comprehensive walkthrough on integrating Vapi with OpenAI's gpt-4.1-mini model using a custom LLM configuration. We'll leverage Ngrok to expose a local development environment for testing and demonstrate the communication flow between Vapi and your LLM. ## Prerequisites - **Vapi Account**: Access to the Vapi Dashboard for configuration. -- **OpenAI API Key**: With access to the gpt-3.5-turbo-instruct model. +- **OpenAI API Key**: With access to the gpt-4.1-mini model. - **Python Environment**: Set up with the OpenAI library (`pip install openai`). - **Ngrok**: For exposing your local server to the internet. - **Code Reference**: Familiarize yourself with the `/openai-sse/chat/completions` endpoint function in the provided Github repository: [Server-Side Example Python Flask](https://github.com/VapiAI/server-side-example-python-flask/blob/main/app/api/custom_llm.py). @@ -31,7 +31,7 @@ def chat_completions(): # ... response = openai.ChatCompletion.create( - model="gpt-3.5-turbo-instruct", + model="gpt-4.1-mini", messages=[ {"role": "system", "content": "You are a helpful assistant."}, # ... (Add messages from conversation history and current prompt) @@ -58,11 +58,48 @@ Log in to your Vapi account and navigate to the "Model" section. Choose the "Custom LLM" option to set up the integration. **3. Enter Ngrok URL:** -Paste the public URL generated by ngrok (e.g., https://your-unique-id.ngrok.io) into the endpoint field. This will be the URL Vapi uses to communicate with your local server. +Paste the public URL generated by ngrok (for example, `https://your-unique-id.ngrok.io`) into the endpoint field. This will be the URL Vapi uses to communicate with your local server. **4. Test the Connection:** Send a test message through the Vapi interface to ensure it reaches your local server and receives a response from the OpenAI API. Verify that the response is displayed correctly in Vapi. +## Authentication (Optional) + +For production deployments, you can secure your custom LLM endpoint using authentication. This ensures only authorized requests from Vapi can access your LLM server. + +![Custom LLM authentication configuration](../../static/images/server-url/authentication/custom-llm.png) + +### Configuration Options + +Vapi supports two authentication methods for custom LLMs: + +1. **API Key**: Simple authentication where Vapi includes a static API key in request headers. Your server validates this key to authorize requests. + +2. **OAuth2 Credentials**: More secure authentication using OAuth2 client credentials flow with automatic token refresh. + +### API Key Authentication + +When using API Key authentication: +- Vapi sends your API key in the Authorization header to your custom LLM endpoint +- Your server validates the API key before processing the request +- Simple to implement and suitable for basic security requirements + +### OAuth2 Authentication + +When configuring OAuth2 in the Vapi dashboard: + +1. **OAuth2 URL**: Enter your OAuth2 token endpoint (e.g., `https://your-server.com/oauth/token`) +2. **OAuth2 Client ID**: Your OAuth2 client identifier +3. **OAuth2 Client Secret**: Your OAuth2 client secret + +### How OAuth2 Works + +1. Vapi requests an access token from your OAuth2 endpoint using client credentials +2. Your server validates the credentials and returns an access token +3. Vapi includes the token in the Authorization header for LLM requests +4. Your server validates the token before processing requests +5. Tokens automatically refresh when they expire + ## Step 3: Understanding the Communication Flow **1. Vapi Sends POST Request:** When a user interacts with your Vapi application, Vapi sends a POST request containing conversation context and metadata to the configured endpoint (your ngrok URL). @@ -74,7 +111,7 @@ Your Python script receives the POST request and the chat_completions function i The script parses the JSON data, extracts relevant information (prompt, conversation history), and builds the prompt for the OpenAI API call. **4. Call to OpenAI API:** -The constructed prompt is sent to the gpt-3.5-turbo-instruct model using the openai.ChatCompletion.create method. +The constructed prompt is sent to the gpt-4.1-mini model using the openai.ChatCompletion.create method. **5. Receive and Format Response:** The response from OpenAI, containing the generated text, is received and formatted according to Vapi's expected structure. @@ -85,7 +122,7 @@ The formatted response is sent back to Vapi as a JSON object. **7. Vapi Displays Response:** Vapi receives the response and displays the generated text within the conversation interface to the user. -By following these detailed steps and understanding the communication flow, you can successfully connect Vapi to OpenAI's gpt-3.5-turbo-instruct model and create powerful conversational experiences within your Vapi applications. The provided code example and reference serve as a starting point for you to build and customize your integration based on your specific needs. +By following these detailed steps and understanding the communication flow, you can successfully connect Vapi to OpenAI's gpt-4.1-mini model and create powerful conversational experiences within your Vapi applications. The provided code example and reference serve as a starting point for you to build and customize your integration based on your specific needs. **Video Tutorial:** + +**Boards allow you to:** + +- Add and configure insights (bar charts, line charts, pie charts, text metrics) +- Apply global time range filters and granularity settings +- Build queries visually with field selectors and filter builders +- Create calculated metrics using formulas +- Drag, resize, and position widgets on a responsive grid + +### When to use Boards + +Boards are ideal for: + +- **Sales tracking** - Monitor call volume, conversion rates, and booking metrics +- **Support metrics** - Track resolution times, issue categories, and customer satisfaction +- **Cost monitoring** - Analyze spending patterns, cost per call, and budget tracking +- **Performance analysis** - Measure assistant performance, call quality, and efficiency + +## What you'll build + +A Sales Performance Dashboard that displays: + +- Total calls and bookings for today +- Call volume trends over the past 30 days +- Bookings by assistant +- Call outcomes distribution +- Booking conversion rate (calculated metric) + +## Prerequisites + + + + Account with Boards access enabled + + + Existing call data helps create meaningful visualizations + + + + + Boards are accessible through the Vapi Dashboard at + [dashboard.vapi.ai](https://dashboard.vapi.ai) + + +## Step 1: Access Boards + +Navigate to the Boards feature in your dashboard. + +1. Log into your Vapi Dashboard at [dashboard.vapi.ai](https://dashboard.vapi.ai) +2. Click **Boards** in the left sidebar (under the "Reporting" or "Analytics" section) +3. Your board will be automatically created on first visit + + + Your board is created automatically when you first access the Boards page. + You'll see an empty 6-column grid layout where you can add insights. + + +## Step 2: Add your first insights + +Start with key performance indicators that show single important numbers. + + + + 1. Click **Add Widget** or the **+** button + 2. Select **Text** widget type + 3. Configure the insight: + - **Name**: "Total Calls Today" + - **Data Source**: Select "Calls" + - **Metric**: Choose "Count" + - **Field**: Select "Call ID" + - **Time Range**: Set to "Last 24 hours" + 4. Click **Preview** to see the result + 5. Click **Add to Board** + 6. Drag the insight to your desired position + 7. Resize if needed by dragging the bottom-right corner + + + The number updates in real-time. Hover over the insight to see additional details. + + + + + Repeat the process for a second insight: + + 1. Click **Add Widget** → **Text** + 2. Configure: + - **Name**: "Total Bookings Today" + - **Data Source**: Calls + - **Metric**: Count of Call ID + - **Time Range**: Last 24 hours + 3. Add a filter to count only successful bookings: + - Click **Add Filter** + - **Field**: Status + - **Operator**: equals (=) + - **Value**: "ended" + 4. Click **Add to Board** + 5. Position it next to your first insight + + + +## Step 3: Create visualizations + +Add charts to visualize trends and patterns in your data. + + + + Create a bar chart showing calls by assistant: + + 1. Click **Add Widget** + 2. Select **Bar Chart** + 3. Configure: + - **Name**: "Calls by Assistant" + - **Data Source**: Calls + - **Metric**: Count of Call ID + - **Group By**: Select "Assistant" from dropdown + - **Time Range**: Last 7 days + - **Group By Time**: Day + 4. Click **Preview** to see bars showing calls per assistant per day + 5. Customize appearance (optional): + - **X-axis Label**: "Date" + - **Y-axis Label**: "Number of Calls" + - **Colors**: Choose color scheme + 6. Click **Add to Board** + + +{" "} + + + Track call volume over time: 1. Click **Add Widget** 2. Select **Line Chart** + 3. Configure: - **Name**: "Call Volume Trend" - **Data Source**: Calls - + **Metric**: Count of Call ID - **Time Range**: Last 30 days - **Group By + Time**: Day 4. Optional - Add multiple lines: - Click **Add Another Metric** - + Configure second metric (e.g., "Average Duration") 5. Click **Add to Board** + + Line charts are ideal for showing trends over time. Use them to identify + patterns and anomalies. + + + + + Show distribution of call outcomes: + + 1. Click **Add Widget** + 2. Select **Pie Chart** + 3. Configure: + - **Name**: "Calls by Status" + - **Data Source**: Calls + - **Metric**: Count of Call ID + - **Group By**: Select "Status" + - **Time Range**: Last 7 days + 4. Click **Add to Board** + + + Pie charts don't have time series grouping. They show distribution across categories only. + + + + +## Step 4: Apply filters to insights + +Filter data to focus on specific segments or conditions. + + + + Open any insight's settings and add filters: + + 1. Click the **⚙️ (settings)** icon on any insight + 2. Click **Add Filter** button + 3. Configure first filter: + - **Field**: Select "Status" from dropdown + - **Operator**: Choose "equals" (=) + - **Value**: Type or select "ended" + 4. Click **Add Another Filter** for multiple conditions + 5. Example second filter: + - **Field**: Cost + - **Operator**: Greater than (>) + - **Value**: 0.50 + 6. Click **Save** + + **Common filter patterns:** + - Filter by assistant: `Assistant ID =