diff --git a/fern/assistants/structured-outputs-quickstart.mdx b/fern/assistants/structured-outputs-quickstart.mdx index f5d0e1886..45cbd54ea 100644 --- a/fern/assistants/structured-outputs-quickstart.mdx +++ b/fern/assistants/structured-outputs-quickstart.mdx @@ -10,22 +10,38 @@ This quickstart guide will help you set up structured outputs to automatically e ### What are structured outputs? -Structured outputs are AI-powered data extraction templates that automatically capture and organize information from conversations. They work by: +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. **Listening to conversations** - As your assistant talks with customers, structured outputs analyze the conversation in real-time -2. **Extracting key information** - Based on your defined schema, they identify and extract relevant data points like names, emails, preferences, and issues -3. **Validating and formatting** - The extracted data is validated against your schema rules and formatted into clean, structured JSON -4. **Delivering results** - The structured data is available immediately after the call ends via API or webhooks +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: -- **During the call** - Data is extracted in real-time as the conversation happens -- **After call completion** - Final validation and formatting occurs when the call ends +- **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 @@ -45,79 +61,88 @@ A customer support assistant that automatically extracts: Sign up at [dashboard.vapi.ai](https://dashboard.vapi.ai) - Get your API key from the Dashboard settings + Get your API key from **API Keys** on sidebar ## Step 1: Create your structured output -You can create structured outputs using either the Dashboard UI or the API. - -### Option A: Using the Dashboard (Recommended for beginners) +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 "AI" (for automatic extraction) - 3. **Description**: Add "Extract support ticket information from customer calls" - - - - Use the visual schema builder or paste this JSON directly: - ```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": { + + + + + 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": { - "description": {"type": "string", "description": "Issue description"}, - "category": { - "type": "string", - "enum": ["billing", "technical", "general", "complaint"], - "description": "Issue category" + "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"] }, - "priority": { - "type": "string", - "enum": ["low", "medium", "high", "urgent"], - "description": "Priority level" + "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": ["description", "category"] + "required": ["customer", "issue"] } - }, - "required": ["customer", "issue"] - } - ``` - - - - 1. Click **Create Structured Output** - 2. Copy the generated ID from the details page - 3. You'll use this ID to link to your assistant - - - -### Option B: Using the API - -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. Click **Create Structured Output** + 2. In the structured output dialog, you can directly attach it to an assistant or workflow + 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" \ @@ -191,356 +216,364 @@ curl -X POST https://api.vapi.ai/structured-output \ } }' ``` - -```javascript title="Node.js" -const response = await fetch('https://api.vapi.ai/structured-output', { - method: 'POST', - headers: { - 'Authorization': `Bearer ${process.env.VAPI_API_KEY}`, - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ - 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" - } + + + + ```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" }, - required: ["name"] + email: { + type: "string", + format: "email", + description: "Customer email address" + }, + phone: { + type: "string", + description: "Customer phone number" + } }, - 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: ["name"] + }, + issue: { + type: "object", + properties: { + description: { + type: "string", + description: "Description of the customer issue" }, - required: ["description", "category"] + category: { + type: "string", + enum: ["billing", "technical", "general", "complaint"], + description: "Issue category" + }, + priority: { + type: "string", + enum: ["low", "medium", "high", "urgent"], + description: "Issue priority level" + } }, - 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: ["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"] - } - }) + } + }, + required: ["customer", "issue"] + } }); -const structuredOutput = await response.json(); console.log('Created structured output:', structuredOutput.id); // Save this ID - you'll need it in the next step ``` + -```python title="Python" -import requests + + ```python +from vapi import Vapi import os -response = requests.post( - 'https://api.vapi.ai/structured-output', - headers={ - 'Authorization': f'Bearer {os.environ["VAPI_API_KEY"]}', - 'Content-Type': 'application/json' - }, - json={ - "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" - } +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" }, - "required": ["name"] + "phone": { + "type": "string", + "description": "Customer phone number" + } }, - "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": ["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" }, - "required": ["description", "category"] + "priority": { + "type": "string", + "enum": ["low", "medium", "high", "urgent"], + "description": "Issue priority level" + } }, - "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": ["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"] - } + } + }, + "required": ["customer", "issue"] } ) -structured_output = response.json() -print(f'Created structured output: {structured_output["id"]}') +print(f'Created structured output: {structured_output.id}') # Save this ID - you'll need it in the next step ``` - + + - -Save the returned `id` from the response - you'll need it to link to your assistant. - + +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 an assistant with structured outputs +## Step 2: Create and test a call -Now create an assistant that uses your structured output: +Now test your structured output by making a call. - -```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", - "firstMessage": "Hello! I'\''m here to help you with your support request. Can you please tell me your name and describe the issue you'\''re experiencing?", - "model": { - "provider": "openai", - "model": "gpt-4-turbo-preview", - "messages": [ - { - "role": "system", - "content": "You are a helpful customer support agent. Gather the customer'\''s information and understand their issue. Be empathetic and professional." - } - ] - }, - "voice": { - "provider": "vapi", - "voiceId": "jennifer" - }, - "artifactPlan": { - "structuredOutputIds": ["YOUR_STRUCTURED_OUTPUT_ID_HERE"] - } - }' -``` + +**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 -```javascript title="Node.js" -const assistant = await fetch('https://api.vapi.ai/assistant', { - method: 'POST', - headers: { - 'Authorization': `Bearer ${process.env.VAPI_API_KEY}`, - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ - name: "Customer Support Agent", - firstMessage: "Hello! I'm here to help you with your support request. Can you please tell me your name and describe the issue you're experiencing?", - model: { - provider: "openai", - model: "gpt-4-turbo-preview", - messages: [ - { - role: "system", - content: "You are a helpful customer support agent. Gather the customer's information and understand their issue. Be empathetic and professional." - } - ] - }, - voice: { - provider: "vapi", - voiceId: "jennifer" - }, - artifactPlan: { - structuredOutputIds: [structuredOutput.id] // Use the ID from step 1 - } - }) -}).then(res => res.json()); +You can create an assistant via the Dashboard or API, then use its ID in the examples below. + -console.log('Created assistant:', assistant.id); + + + + + 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 title="Python" -assistant_response = requests.post( - 'https://api.vapi.ai/assistant', - headers={ - 'Authorization': f'Bearer {os.environ["VAPI_API_KEY"]}', - 'Content-Type': 'application/json' - }, - json={ - "name": "Customer Support Agent", - "firstMessage": "Hello! I'm here to help you with your support request. Can you please tell me your name and describe the issue you're experiencing?", - "model": { - "provider": "openai", - "model": "gpt-4-turbo-preview", - "messages": [ - { - "role": "system", - "content": "You are a helpful customer support agent. Gather the customer's information and understand their issue. Be empathetic and professional." - } - ] - }, - "voice": { - "provider": "vapi", - "voiceId": "jennifer" - }, - "artifactPlan": { - "structuredOutputIds": [structured_output["id"]] # Use the ID from step 1 - } - } -) + + ```python +from vapi import Vapi +import os -assistant = assistant_response.json() -print(f'Created assistant: {assistant["id"]}') -``` - +vapi = Vapi(token=os.environ.get("VAPI_API_KEY")) -## Step 3: Test with a phone call +# 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" +) -Make a test call to your assistant: +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 title="cURL" + + ```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_HERE", - "customer": { - "number": "+1234567890" - } + "assistantId": "your-assistant-id", + "type": "webCall" }' -``` -```javascript title="Node.js" -const call = await fetch('https://api.vapi.ai/call', { - method: 'POST', - headers: { - 'Authorization': `Bearer ${process.env.VAPI_API_KEY}`, - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ - assistantId: assistant.id, - customer: { - number: "+1234567890" // Replace with your phone number - } - }) -}).then(res => res.json()); - -console.log('Call initiated:', call.id); -``` - -```python title="Python" -call_response = requests.post( - 'https://api.vapi.ai/call', - headers={ - 'Authorization': f'Bearer {os.environ["VAPI_API_KEY"]}', - 'Content-Type': 'application/json' - }, - json={ - "assistantId": assistant["id"], - "customer": { - "number": "+1234567890" # Replace with your phone number - } - } -) - -call = call_response.json() -print(f'Call initiated: {call["id"]}') +# 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 4: Retrieve extracted data +## Step 3: Retrieve extracted data After the call ends, retrieve the extracted information: - -```bash title="cURL" -curl -X GET "https://api.vapi.ai/call/YOUR_CALL_ID_HERE" \ - -H "Authorization: Bearer $VAPI_API_KEY" -``` + + + + + 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! }); -```javascript title="Node.js" // Wait a few seconds after call ends for processing setTimeout(async () => { - const callData = await fetch(`https://api.vapi.ai/call/${call.id}`, { - headers: { - 'Authorization': `Bearer ${process.env.VAPI_API_KEY}` - } - }).then(res => res.json()); + const callData = await vapi.calls.get(call.id); const outputs = callData.artifact?.structuredOutputs; @@ -552,32 +585,41 @@ setTimeout(async () => { } }, 5000); ``` + -```python title="Python" + + ```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 = requests.get( - f'https://api.vapi.ai/call/{call["id"]}', - headers={ - 'Authorization': f'Bearer {os.environ["VAPI_API_KEY"]}' - } -).json() +call_data = vapi.calls.get(call.id) -outputs = call_data.get('artifact', {}).get('structuredOutputs', {}) +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 -You should see extracted data like this: +The extracted data (the `result` field from the API response) will look like this: ```json { @@ -599,103 +641,9 @@ You should see extracted data like this: } ``` -## Step 5: Set up webhook (optional) - -To automatically receive extracted data when calls end, set up a webhook: - - -```javascript title="Express.js webhook handler" -const express = require('express'); -const app = express(); - -app.use(express.json()); - -app.post('/vapi/webhook', (req, res) => { - const { type, call } = req.body; - - if (type === 'call.ended') { - const outputs = call.artifact?.structuredOutputs; - - if (outputs) { - Object.entries(outputs).forEach(([outputId, data]) => { - if (data.result) { - // Process the extracted support ticket - console.log('New support ticket:', data.result); - - // Example: Create ticket in your system - createSupportTicket({ - customer: data.result.customer, - issue: data.result.issue, - priority: data.result.issue.priority, - followUp: data.result.followUp - }); - } - }); - } - } - - res.status(200).send('OK'); -}); - -function createSupportTicket(ticketData) { - // Your ticket creation logic here - console.log('Creating ticket in system:', ticketData); -} - -app.listen(3000, () => { - console.log('Webhook server running on port 3000'); -}); -``` - -```python title="Flask webhook handler" -from flask import Flask, request, jsonify - -app = Flask(__name__) - -@app.route('/vapi/webhook', methods=['POST']) -def vapi_webhook(): - data = request.json - - if data.get('type') == 'call.ended': - call = data.get('call', {}) - outputs = call.get('artifact', {}).get('structuredOutputs', {}) - - for output_id, output_data in outputs.items(): - if output_data.get('result'): - # Process the extracted support ticket - print('New support ticket:', output_data['result']) - - # Example: Create ticket in your system - create_support_ticket({ - 'customer': output_data['result']['customer'], - 'issue': output_data['result']['issue'], - 'priority': output_data['result']['issue']['priority'], - 'followUp': output_data['result']['followUp'] - }) - - return jsonify({'status': 'ok'}), 200 - -def create_support_ticket(ticket_data): - # Your ticket creation logic here - print('Creating ticket in system:', ticket_data) - -if __name__ == '__main__': - app.run(port=3000) -``` - - -Then update your assistant with the webhook URL: - -```bash -curl -X PATCH "https://api.vapi.ai/assistant/YOUR_ASSISTANT_ID" \ - -H "Authorization: Bearer $VAPI_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{ - "server": { - "url": "https://your-domain.com/vapi/webhook" - } - }' -``` + +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. + ## Next steps @@ -737,6 +685,49 @@ You can attach multiple structured outputs to extract different types of data: 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: diff --git a/fern/calls/websocket-transport.mdx b/fern/calls/websocket-transport.mdx index 115849fd1..7ac27279a 100644 --- a/fern/calls/websocket-transport.mdx +++ b/fern/calls/websocket-transport.mdx @@ -196,10 +196,12 @@ function hangupCall() { ## Ending the Call -To gracefully end the WebSocket 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: "hangup" }); +sendControlMessage({ type: "end-call" }); socket.close(); ```