diff --git a/fern/assistants/structured-outputs-examples.mdx b/fern/assistants/structured-outputs-examples.mdx
new file mode 100644
index 000000000..26560fc24
--- /dev/null
+++ b/fern/assistants/structured-outputs-examples.mdx
@@ -0,0 +1,1233 @@
+---
+title: Structured outputs examples
+subtitle: Real-world examples and templates for common use cases
+slug: assistants/structured-outputs-examples
+---
+
+## Overview
+
+This page provides production-ready examples of structured outputs for common business scenarios. Each example includes the complete schema, configuration, and integration code.
+
+## Healthcare appointment booking
+
+Extract patient information and appointment preferences from healthcare calls.
+
+
+```json title="Schema"
+{
+ "name": "Healthcare Appointment",
+ "type": "ai",
+ "description": "Extract patient and appointment information for medical scheduling",
+ "schema": {
+ "type": "object",
+ "properties": {
+ "patient": {
+ "type": "object",
+ "properties": {
+ "firstName": {
+ "type": "string",
+ "description": "Patient's first name"
+ },
+ "lastName": {
+ "type": "string",
+ "description": "Patient's last name"
+ },
+ "dateOfBirth": {
+ "type": "string",
+ "format": "date",
+ "description": "Patient's date of birth (YYYY-MM-DD)"
+ },
+ "phoneNumber": {
+ "type": "string",
+ "pattern": "^\\+?[1-9]\\d{1,14}$",
+ "description": "Patient's contact number"
+ },
+ "insuranceProvider": {
+ "type": "string",
+ "description": "Insurance provider name"
+ },
+ "memberID": {
+ "type": "string",
+ "description": "Insurance member ID"
+ }
+ },
+ "required": ["firstName", "lastName", "phoneNumber"]
+ },
+ "appointment": {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": ["new-patient", "follow-up", "annual-checkup", "urgent-care", "specialist"],
+ "description": "Type of appointment"
+ },
+ "department": {
+ "type": "string",
+ "enum": ["general", "cardiology", "dermatology", "orthopedics", "pediatrics", "obgyn"],
+ "description": "Medical department"
+ },
+ "preferredDates": {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "format": "date"
+ },
+ "maxItems": 3,
+ "description": "Up to 3 preferred appointment dates"
+ },
+ "preferredTimeSlot": {
+ "type": "string",
+ "enum": ["morning", "afternoon", "evening", "any"],
+ "description": "Preferred time of day"
+ },
+ "symptoms": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "description": "List of symptoms or reasons for visit"
+ },
+ "urgency": {
+ "type": "string",
+ "enum": ["routine", "soon", "urgent"],
+ "description": "How urgent is the appointment"
+ }
+ },
+ "required": ["type", "department", "urgency"]
+ },
+ "additionalNotes": {
+ "type": "string",
+ "description": "Any additional notes or special requirements"
+ }
+ },
+ "required": ["patient", "appointment"]
+ }
+}
+```
+
+```json title="Example Output"
+{
+ "patient": {
+ "firstName": "Sarah",
+ "lastName": "Johnson",
+ "dateOfBirth": "1985-03-15",
+ "phoneNumber": "+14155551234",
+ "insuranceProvider": "Blue Cross Blue Shield",
+ "memberID": "BCB123456789"
+ },
+ "appointment": {
+ "type": "follow-up",
+ "department": "cardiology",
+ "preferredDates": ["2024-01-15", "2024-01-16", "2024-01-17"],
+ "preferredTimeSlot": "morning",
+ "symptoms": ["chest pain", "shortness of breath"],
+ "urgency": "urgent"
+ },
+ "additionalNotes": "Patient prefers female doctor if available"
+}
+```
+
+
+## E-commerce order processing
+
+Capture order details, shipping information, and payment preferences.
+
+
+```json title="Schema"
+{
+ "name": "E-commerce Order",
+ "type": "ai",
+ "description": "Extract complete order information from sales calls",
+ "schema": {
+ "type": "object",
+ "properties": {
+ "customer": {
+ "type": "object",
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "Customer full name"
+ },
+ "email": {
+ "type": "string",
+ "format": "email",
+ "description": "Customer email for order confirmation"
+ },
+ "phone": {
+ "type": "string",
+ "description": "Contact number"
+ },
+ "loyaltyNumber": {
+ "type": "string",
+ "description": "Loyalty program member number if mentioned"
+ }
+ },
+ "required": ["name", "email"]
+ },
+ "items": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "productName": {
+ "type": "string",
+ "description": "Name or description of the product"
+ },
+ "sku": {
+ "type": "string",
+ "description": "Product SKU if mentioned"
+ },
+ "quantity": {
+ "type": "integer",
+ "minimum": 1,
+ "description": "Quantity ordered"
+ },
+ "size": {
+ "type": "string",
+ "enum": ["XS", "S", "M", "L", "XL", "XXL", "custom"],
+ "description": "Size if applicable"
+ },
+ "color": {
+ "type": "string",
+ "description": "Color preference"
+ },
+ "customization": {
+ "type": "string",
+ "description": "Any customization requests"
+ }
+ },
+ "required": ["productName", "quantity"]
+ },
+ "minItems": 1,
+ "description": "List of items being ordered"
+ },
+ "shipping": {
+ "type": "object",
+ "properties": {
+ "method": {
+ "type": "string",
+ "enum": ["standard", "express", "overnight", "pickup"],
+ "description": "Shipping method"
+ },
+ "address": {
+ "type": "object",
+ "properties": {
+ "street": {
+ "type": "string"
+ },
+ "apartment": {
+ "type": "string",
+ "description": "Apartment or suite number"
+ },
+ "city": {
+ "type": "string"
+ },
+ "state": {
+ "type": "string",
+ "pattern": "^[A-Z]{2}$"
+ },
+ "zipCode": {
+ "type": "string",
+ "pattern": "^\\d{5}(-\\d{4})?$"
+ },
+ "country": {
+ "type": "string",
+ "default": "USA"
+ }
+ },
+ "required": ["street", "city", "state", "zipCode"]
+ },
+ "instructions": {
+ "type": "string",
+ "description": "Special delivery instructions"
+ },
+ "giftWrap": {
+ "type": "boolean",
+ "description": "Whether gift wrapping was requested"
+ },
+ "giftMessage": {
+ "type": "string",
+ "description": "Gift message if applicable"
+ }
+ },
+ "required": ["method", "address"]
+ },
+ "payment": {
+ "type": "object",
+ "properties": {
+ "method": {
+ "type": "string",
+ "enum": ["credit_card", "debit_card", "paypal", "apple_pay", "google_pay", "invoice"],
+ "description": "Payment method"
+ },
+ "cardLastFour": {
+ "type": "string",
+ "pattern": "^\\d{4}$",
+ "description": "Last 4 digits of card if provided"
+ },
+ "billingAddressSameAsShipping": {
+ "type": "boolean",
+ "description": "Whether billing address is same as shipping"
+ }
+ },
+ "required": ["method"]
+ },
+ "promotions": {
+ "type": "object",
+ "properties": {
+ "promoCode": {
+ "type": "string",
+ "description": "Promotional code mentioned"
+ },
+ "referralSource": {
+ "type": "string",
+ "description": "How customer heard about us"
+ }
+ }
+ },
+ "specialRequests": {
+ "type": "string",
+ "description": "Any special requests or notes"
+ }
+ },
+ "required": ["customer", "items", "shipping"]
+ }
+}
+```
+
+```json title="Example Output"
+{
+ "customer": {
+ "name": "Michael Chen",
+ "email": "michael.chen@example.com",
+ "phone": "+14155552468",
+ "loyaltyNumber": "LOYAL123456"
+ },
+ "items": [
+ {
+ "productName": "Wireless Headphones XL",
+ "quantity": 1,
+ "size": null,
+ "color": "Black",
+ "price": 149.99
+ },
+ {
+ "productName": "USB-C Cable 6ft",
+ "quantity": 2,
+ "size": null,
+ "color": null,
+ "price": 19.99
+ }
+ ],
+ "shipping": {
+ "address": {
+ "street": "123 Market Street",
+ "city": "San Francisco",
+ "state": "CA",
+ "zip": "94102",
+ "country": "USA"
+ },
+ "method": "express",
+ "priority": "standard",
+ "giftWrap": false
+ },
+ "payment": {
+ "method": "credit-card",
+ "lastFourDigits": "4242"
+ },
+ "promotions": {
+ "promoCode": "SAVE20",
+ "giftWrap": false
+ },
+ "specialInstructions": "Please leave package with doorman"
+}
+```
+
+
+## Real estate lead qualification
+
+Qualify real estate leads and capture property preferences.
+
+
+```json title="Schema"
+{
+ "name": "Real Estate Lead",
+ "type": "ai",
+ "description": "Qualify real estate leads and extract property preferences",
+ "schema": {
+ "type": "object",
+ "properties": {
+ "contact": {
+ "type": "object",
+ "properties": {
+ "firstName": {
+ "type": "string"
+ },
+ "lastName": {
+ "type": "string"
+ },
+ "email": {
+ "type": "string",
+ "format": "email"
+ },
+ "phone": {
+ "type": "string"
+ },
+ "preferredContactMethod": {
+ "type": "string",
+ "enum": ["phone", "email", "text", "any"]
+ },
+ "bestTimeToContact": {
+ "type": "string",
+ "enum": ["morning", "afternoon", "evening", "weekends", "any"]
+ }
+ },
+ "required": ["firstName", "phone"]
+ },
+ "propertySearch": {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": ["buy", "rent", "sell", "invest"]
+ },
+ "propertyType": {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "enum": ["single-family", "condo", "townhouse", "multi-family", "commercial", "land"]
+ }
+ },
+ "locations": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "area": {
+ "type": "string",
+ "description": "Neighborhood, city, or region"
+ },
+ "schools": {
+ "type": "boolean",
+ "description": "Important to be near good schools"
+ },
+ "commute": {
+ "type": "string",
+ "description": "Commute requirements mentioned"
+ }
+ }
+ }
+ },
+ "budget": {
+ "type": "object",
+ "properties": {
+ "min": {
+ "type": "number",
+ "minimum": 0
+ },
+ "max": {
+ "type": "number"
+ },
+ "preApproved": {
+ "type": "boolean",
+ "description": "Whether they have mortgage pre-approval"
+ }
+ }
+ },
+ "features": {
+ "type": "object",
+ "properties": {
+ "bedrooms": {
+ "type": "integer",
+ "minimum": 0
+ },
+ "bathrooms": {
+ "type": "number",
+ "minimum": 0
+ },
+ "squareFeet": {
+ "type": "integer",
+ "minimum": 0
+ },
+ "garage": {
+ "type": "boolean"
+ },
+ "pool": {
+ "type": "boolean"
+ },
+ "yard": {
+ "type": "boolean"
+ },
+ "mustHaves": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "description": "List of must-have features"
+ },
+ "dealBreakers": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "description": "List of deal-breakers"
+ }
+ }
+ }
+ },
+ "required": ["type", "propertyType", "budget"]
+ },
+ "timeline": {
+ "type": "object",
+ "properties": {
+ "urgency": {
+ "type": "string",
+ "enum": ["immediate", "1-3months", "3-6months", "6-12months", "browsing"]
+ },
+ "moveInDate": {
+ "type": "string",
+ "format": "date",
+ "description": "Target move-in date if mentioned"
+ },
+ "reason": {
+ "type": "string",
+ "description": "Reason for moving/buying"
+ }
+ }
+ },
+ "currentSituation": {
+ "type": "object",
+ "properties": {
+ "currentlyOwns": {
+ "type": "boolean",
+ "description": "Whether they currently own property"
+ },
+ "needToSell": {
+ "type": "boolean",
+ "description": "Need to sell before buying"
+ },
+ "firstTimeBuyer": {
+ "type": "boolean"
+ }
+ }
+ },
+ "leadScore": {
+ "type": "object",
+ "properties": {
+ "motivation": {
+ "type": "string",
+ "enum": ["high", "medium", "low"],
+ "description": "Buyer/seller motivation level"
+ },
+ "qualified": {
+ "type": "boolean",
+ "description": "Whether lead seems qualified"
+ },
+ "followUpPriority": {
+ "type": "string",
+ "enum": ["hot", "warm", "cold"],
+ "description": "Follow-up priority"
+ }
+ }
+ }
+ },
+ "required": ["contact", "propertySearch", "timeline"]
+ }
+}
+```
+
+```json title="Example Output"
+{
+ "contact": {
+ "name": "Jennifer Martinez",
+ "email": "jmartinez@example.com",
+ "phone": "+14085551234",
+ "preferredContactMethod": "email"
+ },
+ "propertySearch": {
+ "propertyType": "single-family",
+ "locations": [
+ {
+ "area": "Palo Alto",
+ "importance": "high"
+ },
+ {
+ "area": "Mountain View",
+ "importance": "medium"
+ }
+ ],
+ "budget": {
+ "min": 1500000,
+ "max": 2200000,
+ "preApproved": true
+ },
+ "features": {
+ "bedrooms": 4,
+ "bathrooms": 3,
+ "squareFeet": 2500,
+ "mustHaves": ["garage", "backyard", "good schools"],
+ "niceToHaves": ["pool", "home office"]
+ }
+ },
+ "timeline": {
+ "urgency": "3-6-months",
+ "moveInDate": "2024-06-01",
+ "reasonForMove": "job relocation"
+ },
+ "currentSituation": {
+ "currentlyOwns": false,
+ "renting": true,
+ "firstTimeBuyer": false,
+ "needToSell": false
+ },
+ "leadScore": {
+ "motivation": "high",
+ "financialReadiness": "qualified",
+ "decisionTimeframe": "actively-looking",
+ "followUpPriority": "warm"
+ }
+}
+```
+
+
+## Insurance claim intake
+
+Capture insurance claim details and incident information.
+
+
+```json title="Schema"
+{
+ "name": "Insurance Claim",
+ "type": "ai",
+ "description": "Extract insurance claim information and incident details",
+ "schema": {
+ "type": "object",
+ "properties": {
+ "policyholder": {
+ "type": "object",
+ "properties": {
+ "name": {
+ "type": "string"
+ },
+ "policyNumber": {
+ "type": "string",
+ "description": "Insurance policy number"
+ },
+ "dateOfBirth": {
+ "type": "string",
+ "format": "date"
+ },
+ "contactPhone": {
+ "type": "string"
+ },
+ "email": {
+ "type": "string",
+ "format": "email"
+ }
+ },
+ "required": ["name", "policyNumber"]
+ },
+ "incident": {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": ["auto", "property", "theft", "injury", "liability", "other"]
+ },
+ "date": {
+ "type": "string",
+ "format": "date",
+ "description": "Date of incident"
+ },
+ "time": {
+ "type": "string",
+ "format": "time",
+ "description": "Approximate time of incident"
+ },
+ "location": {
+ "type": "object",
+ "properties": {
+ "address": {
+ "type": "string"
+ },
+ "city": {
+ "type": "string"
+ },
+ "state": {
+ "type": "string"
+ },
+ "zipCode": {
+ "type": "string"
+ }
+ }
+ },
+ "description": {
+ "type": "string",
+ "description": "Detailed description of what happened"
+ },
+ "policeReportFiled": {
+ "type": "boolean"
+ },
+ "policeReportNumber": {
+ "type": "string",
+ "description": "Police report number if available"
+ }
+ },
+ "required": ["type", "date", "description"]
+ },
+ "damages": {
+ "type": "object",
+ "properties": {
+ "propertyDamage": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "item": {
+ "type": "string",
+ "description": "Damaged item or property"
+ },
+ "estimatedValue": {
+ "type": "number",
+ "description": "Estimated value or repair cost"
+ },
+ "description": {
+ "type": "string",
+ "description": "Description of damage"
+ }
+ }
+ }
+ },
+ "injuries": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "person": {
+ "type": "string",
+ "description": "Injured person's name"
+ },
+ "relationship": {
+ "type": "string",
+ "enum": ["self", "family", "passenger", "pedestrian", "other-driver", "other"],
+ "description": "Relationship to policyholder"
+ },
+ "injuryDescription": {
+ "type": "string"
+ },
+ "medicalTreatment": {
+ "type": "boolean",
+ "description": "Whether medical treatment was received"
+ },
+ "hospital": {
+ "type": "string",
+ "description": "Hospital or clinic name if treated"
+ }
+ }
+ }
+ },
+ "estimatedTotalLoss": {
+ "type": "number",
+ "description": "Total estimated loss amount"
+ }
+ }
+ },
+ "otherParties": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "name": {
+ "type": "string"
+ },
+ "role": {
+ "type": "string",
+ "enum": ["other-driver", "witness", "property-owner", "passenger"],
+ "description": "Role in incident"
+ },
+ "contactInfo": {
+ "type": "string",
+ "description": "Phone or email"
+ },
+ "insuranceCompany": {
+ "type": "string",
+ "description": "Their insurance company if known"
+ },
+ "policyNumber": {
+ "type": "string",
+ "description": "Their policy number if known"
+ }
+ }
+ }
+ },
+ "documentation": {
+ "type": "object",
+ "properties": {
+ "photosAvailable": {
+ "type": "boolean"
+ },
+ "receiptsAvailable": {
+ "type": "boolean"
+ },
+ "witnessStatements": {
+ "type": "boolean"
+ }
+ }
+ },
+ "urgency": {
+ "type": "string",
+ "enum": ["emergency", "urgent", "standard"],
+ "description": "Claim urgency level"
+ }
+ },
+ "required": ["policyholder", "incident"]
+ }
+}
+```
+
+```json title="Example Output"
+{
+ "policyholder": {
+ "name": "Robert Thompson",
+ "policyNumber": "POL-2024-789456",
+ "dateOfBirth": "1975-08-22",
+ "email": "rthompson@example.com",
+ "phone": "+15105551234"
+ },
+ "incident": {
+ "type": "auto",
+ "date": "2024-01-10",
+ "time": "14:30",
+ "location": {
+ "street": "Highway 101 North",
+ "city": "San Jose",
+ "state": "CA",
+ "zip": "95110"
+ },
+ "description": "Rear-ended at traffic light, other driver at fault",
+ "policeReportNumber": "SJ-2024-001234",
+ "otherPartyInvolved": true
+ },
+ "damages": {
+ "vehicleDamage": {
+ "description": "Rear bumper and trunk damage",
+ "driveable": true,
+ "airbagDeployed": false
+ },
+ "injuries": [
+ {
+ "person": "policyholder",
+ "type": "whiplash",
+ "medicalTreatment": true,
+ "hospital": "Valley Medical Center"
+ }
+ ],
+ "estimatedTotalLoss": 8500,
+ "propertyDamage": null
+ },
+ "witnesses": [
+ {
+ "name": "Maria Garcia",
+ "phone": "+14085559876",
+ "statement": "Saw the other car hit from behind at red light"
+ }
+ ],
+ "urgency": "standard",
+ "additionalInfo": "Other driver admitted fault, have dashcam footage available"
+}
+```
+
+
+## Financial services application
+
+Process loan or credit applications with financial information.
+
+
+```json title="Schema"
+{
+ "name": "Financial Application",
+ "type": "ai",
+ "description": "Extract loan or credit application information",
+ "schema": {
+ "type": "object",
+ "properties": {
+ "applicant": {
+ "type": "object",
+ "properties": {
+ "personalInfo": {
+ "type": "object",
+ "properties": {
+ "firstName": {
+ "type": "string"
+ },
+ "lastName": {
+ "type": "string"
+ },
+ "ssn": {
+ "type": "string",
+ "pattern": "^\\d{3}-\\d{2}-\\d{4}$",
+ "description": "Social Security Number (XXX-XX-XXXX)"
+ },
+ "dateOfBirth": {
+ "type": "string",
+ "format": "date"
+ },
+ "email": {
+ "type": "string",
+ "format": "email"
+ },
+ "phone": {
+ "type": "string"
+ },
+ "currentAddress": {
+ "type": "object",
+ "properties": {
+ "street": {
+ "type": "string"
+ },
+ "city": {
+ "type": "string"
+ },
+ "state": {
+ "type": "string"
+ },
+ "zipCode": {
+ "type": "string"
+ },
+ "yearsAtAddress": {
+ "type": "number"
+ },
+ "rentOrOwn": {
+ "type": "string",
+ "enum": ["rent", "own", "other"]
+ }
+ }
+ }
+ },
+ "required": ["firstName", "lastName", "dateOfBirth"]
+ },
+ "employment": {
+ "type": "object",
+ "properties": {
+ "status": {
+ "type": "string",
+ "enum": ["employed", "self-employed", "unemployed", "retired", "student"]
+ },
+ "employer": {
+ "type": "string",
+ "description": "Employer name"
+ },
+ "position": {
+ "type": "string",
+ "description": "Job title"
+ },
+ "yearsEmployed": {
+ "type": "number"
+ },
+ "annualIncome": {
+ "type": "number",
+ "minimum": 0,
+ "description": "Annual gross income"
+ },
+ "otherIncome": {
+ "type": "number",
+ "description": "Other income sources"
+ },
+ "incomeVerifiable": {
+ "type": "boolean",
+ "description": "Can provide income verification"
+ }
+ },
+ "required": ["status", "annualIncome"]
+ },
+ "financial": {
+ "type": "object",
+ "properties": {
+ "creditScore": {
+ "type": "integer",
+ "minimum": 300,
+ "maximum": 850,
+ "description": "Self-reported credit score"
+ },
+ "monthlyDebt": {
+ "type": "number",
+ "description": "Total monthly debt payments"
+ },
+ "bankruptcyHistory": {
+ "type": "boolean",
+ "description": "Any bankruptcy in past 7 years"
+ },
+ "existingAccounts": {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "enum": ["checking", "savings", "credit-card", "mortgage", "auto-loan", "student-loan"]
+ },
+ "description": "Existing accounts with institution"
+ }
+ }
+ }
+ }
+ },
+ "loanDetails": {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": ["personal", "auto", "mortgage", "home-equity", "business", "student"],
+ "description": "Type of loan"
+ },
+ "amount": {
+ "type": "number",
+ "minimum": 0,
+ "description": "Requested loan amount"
+ },
+ "purpose": {
+ "type": "string",
+ "description": "Purpose of the loan"
+ },
+ "term": {
+ "type": "integer",
+ "description": "Desired loan term in months"
+ },
+ "collateral": {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": ["vehicle", "property", "savings", "none"],
+ "description": "Type of collateral"
+ },
+ "value": {
+ "type": "number",
+ "description": "Estimated value of collateral"
+ },
+ "description": {
+ "type": "string",
+ "description": "Description of collateral"
+ }
+ }
+ }
+ },
+ "required": ["type", "amount", "purpose"]
+ },
+ "coApplicant": {
+ "type": "object",
+ "properties": {
+ "hasCoApplicant": {
+ "type": "boolean"
+ },
+ "relationship": {
+ "type": "string",
+ "enum": ["spouse", "partner", "family", "business-partner", "other"]
+ },
+ "name": {
+ "type": "string"
+ },
+ "income": {
+ "type": "number"
+ }
+ }
+ },
+ "preferences": {
+ "type": "object",
+ "properties": {
+ "preferredRate": {
+ "type": "string",
+ "enum": ["fixed", "variable", "no-preference"]
+ },
+ "automaticPayment": {
+ "type": "boolean",
+ "description": "Interested in automatic payment"
+ },
+ "paperless": {
+ "type": "boolean",
+ "description": "Prefers paperless statements"
+ }
+ }
+ }
+ },
+ "required": ["applicant", "loanDetails"]
+ }
+}
+```
+
+```json title="Example Output"
+{
+ "applicant": {
+ "personalInfo": {
+ "firstName": "David",
+ "lastName": "Kim",
+ "dateOfBirth": "1988-11-15",
+ "ssn": "***-**-6789",
+ "email": "dkim@example.com",
+ "phone": "+12065551234",
+ "currentAddress": {
+ "street": "456 Pine Street",
+ "city": "Seattle",
+ "state": "WA",
+ "zip": "98101",
+ "yearsAtAddress": 3
+ }
+ },
+ "employment": {
+ "status": "full-time",
+ "employerName": "Tech Corp",
+ "jobTitle": "Senior Engineer",
+ "yearsEmployed": 5,
+ "annualIncome": 150000,
+ "otherIncome": 12000,
+ "incomeVerifiable": true
+ },
+ "financial": {
+ "creditScore": 750,
+ "monthlyDebt": 2500,
+ "bankruptcyHistory": false,
+ "existingAccounts": ["checking", "savings", "credit-card"],
+ "accountNumbers": ["****1234", "****5678"]
+ }
+ },
+ "loanDetails": {
+ "type": "mortgage",
+ "amount": 450000,
+ "term": 30,
+ "purpose": "home-purchase",
+ "propertyAddress": {
+ "street": "789 Oak Avenue",
+ "city": "Bellevue",
+ "state": "WA",
+ "zip": "98004"
+ },
+ "propertyValue": 550000,
+ "downPayment": 100000,
+ "collateral": {
+ "type": "real-estate",
+ "value": 550000,
+ "description": "Single family home"
+ }
+ },
+ "coApplicant": {
+ "hasCoApplicant": true,
+ "relationship": "spouse",
+ "name": "Sarah Kim",
+ "income": 85000
+ },
+ "preferences": {
+ "preferredRate": "fixed",
+ "preferredPaymentDate": 1,
+ "autopayInterest": true
+ },
+ "additionalInfo": "Looking to close within 45 days, have pre-approval from another lender"
+}
+```
+
+
+## Best practices for complex schemas
+
+
+
+ Break complex schemas into reusable object definitions for maintainability
+
+
+
+ Start with essential fields as required, make detailed fields optional
+
+
+
+ Add descriptions to every field to help AI understand context
+
+
+
+ Use constraints for data quality but avoid being too restrictive
+
+
+
+## Testing recommendations
+
+### Test scenarios
+
+Always test your structured outputs with these scenarios:
+
+1. **Complete information** - All fields mentioned clearly
+2. **Partial information** - Some required fields missing
+3. **Ambiguous data** - Unclear or conflicting information
+4. **Edge cases** - Boundary values, special characters
+5. **Real conversations** - Actual call recordings or transcripts
+
+### Monitoring checklist
+
+Track these metrics for production deployments:
+
+- Extraction success rate per field
+- Average extraction time
+- Token usage and costs
+- Schema validation failures
+- Most commonly missing fields
+
+## Output data structure
+
+### Webhook payload format
+
+When structured outputs are extracted, they're delivered in this format:
+
+```json
+{
+ "type": "call.ended",
+ "call": {
+ "id": "call_abc123",
+ "artifact": {
+ "structuredOutputs": {
+ "550e8400-e29b-41d4-a716-446655440001": {
+ "name": "Customer Support Ticket",
+ "result": {
+ "customer": {
+ "name": "John Smith",
+ "email": "john@example.com"
+ },
+ "issue": {
+ "description": "Login issues",
+ "priority": "high"
+ }
+ }
+ },
+ "550e8400-e29b-41d4-a716-446655440002": {
+ "name": "Satisfaction Score",
+ "result": {
+ "score": 8,
+ "feedback": "Very helpful agent"
+ }
+ }
+ }
+ }
+ }
+}
+```
+
+### API response format
+
+When retrieving call data via API:
+
+```json
+{
+ "id": "call_abc123",
+ "status": "ended",
+ "endedAt": "2024-01-10T15:30:00Z",
+ "artifact": {
+ "structuredOutputs": {
+ "outputId1": {
+ "name": "Output Name",
+ "result": {
+ // Your extracted data here
+ }
+ }
+ }
+ }
+}
+```
+
+## Related resources
+
+- [Structured outputs overview](/assistants/structured-outputs) - Main documentation
+- [Quickstart guide](/assistants/structured-outputs-quickstart) - Get started quickly
+- [API reference](/api-reference#structured-output) - Complete API documentation
+- [JSON Schema specification](https://json-schema.org/) - JSON Schema standard
\ No newline at end of file
diff --git a/fern/assistants/structured-outputs-quickstart.mdx b/fern/assistants/structured-outputs-quickstart.mdx
new file mode 100644
index 000000000..30ae147d1
--- /dev/null
+++ b/fern/assistants/structured-outputs-quickstart.mdx
@@ -0,0 +1,804 @@
+---
+title: Structured outputs quickstart
+subtitle: Get started with structured data extraction in 5 minutes
+slug: assistants/structured-outputs-quickstart
+---
+
+## Overview
+
+This quickstart guide will help you set up structured outputs to automatically extract customer information from phone calls. In just a few minutes, you'll create a structured output, link it to an assistant, and test data extraction.
+
+### What are structured outputs?
+
+Structured outputs are AI-powered data extraction templates that automatically capture and organize information from conversations. 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
+
+### 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
+- **Available via** - Call artifacts in the API response or webhook events
+
+### Why use structured outputs?
+
+- **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 your API key from the Dashboard settings
+
+
+
+## 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)
+
+
+
+ 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": {
+ "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"]
+ }
+ },
+ "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/).
+
+
+```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"]
+ }
+ }'
+```
+
+```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"
+ }
+ },
+ 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"]
+ }
+ })
+});
+
+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
+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"
+ }
+ },
+ "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"]
+ }
+ }
+)
+
+structured_output = response.json()
+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.
+
+
+## Step 2: Create an assistant with structured outputs
+
+Now create an assistant that uses your structured output:
+
+
+```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"]
+ }
+ }'
+```
+
+```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());
+
+console.log('Created assistant:', assistant.id);
+```
+
+```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
+ }
+ }
+)
+
+assistant = assistant_response.json()
+print(f'Created assistant: {assistant["id"]}')
+```
+
+
+## Step 3: Test with a phone call
+
+Make a test call to your assistant:
+
+
+```bash title="cURL"
+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"
+ }
+ }'
+```
+
+```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"]}')
+```
+
+
+
+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
+
+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"
+```
+
+```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 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 title="Python"
+import time
+import json
+
+# 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()
+
+outputs = call_data.get('artifact', {}).get('structuredOutputs', {})
+
+for output_id, data in outputs.items():
+ print('Extracted Support Ticket:')
+ print(json.dumps(data['result'], indent=2))
+```
+
+
+### Expected output
+
+You should see extracted data 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"
+ }
+}
+```
+
+## 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"
+ }
+ }'
+```
+
+## 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.
+
+### Conditional extraction
+
+Use conditional logic in your schema to handle different scenarios:
+
+```json
+{
+ "if": {
+ "properties": {
+ "requestType": {"const": "appointment"}
+ }
+ },
+ "then": {
+ "required": ["preferredDate", "preferredTime"]
+ }
+}
+```
+
+### 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)
\ No newline at end of file
diff --git a/fern/assistants/structured-outputs.mdx b/fern/assistants/structured-outputs.mdx
new file mode 100644
index 000000000..b7a53ea8e
--- /dev/null
+++ b/fern/assistants/structured-outputs.mdx
@@ -0,0 +1,787 @@
+---
+title: Structured outputs
+subtitle: Extract structured data from conversations using AI-powered analysis
+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 or workflows
+
+
+ Data is automatically extracted after each call and stored in call artifacts
+
+
+
+## Quick start
+
+### Create a structured output
+
+
+```typescript title="TypeScript (Server SDK)"
+import { Vapi } from '@vapi-ai/server-sdk';
+
+const vapi = new Vapi({ apiKey: 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)"
+from vapi_python import Vapi
+
+vapi = Vapi(api_key=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 { type, call } = req.body;
+
+ if (type === 'call.ended') {
+ const outputs = call.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"]
+ }
+}
+```
+
+## Custom models
+
+Configure which AI model performs the extraction:
+
+
+```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-turbo-preview",
+ temperature: 0.1,
+ messages: [
+ {
+ role: "system",
+ content: "You are an expert at analyzing customer sentiment. Be precise and consistent."
+ },
+ {
+ role: "user",
+ content: "Analyze 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-turbo-preview",
+ "temperature": 0.1,
+ "messages": [
+ {
+ "role": "system",
+ "content": "You are an expert at analyzing customer sentiment. Be precise and consistent."
+ },
+ {
+ "role": "user",
+ "content": "Analyze the sentiment of this conversation:\n{{transcript}}"
+ }
+ ]
+ }
+)
+```
+
+
+### Available variables
+
+Use these variables in custom prompts:
+
+- `{{transcript}}` - Full conversation transcript
+- `{{messages}}` - Conversation messages array
+- `{{callEndedReason}}` - How the call ended
+- `{{structuredOutput.name}}` - Output name
+- `{{structuredOutput.description}}` - Output description
+- `{{structuredOutput.schema}}` - Schema definition
+
+## API reference
+
+
+
+### Create structured output
+
+
+ Display name for the structured output (max 40 characters)
+
+
+
+ Must be set to "ai"
+
+
+
+ Description of what data to extract
+
+
+
+ JSON Schema defining the structure of data to extract
+
+
+
+ Array of assistant IDs to link this output to
+
+
+
+ Custom model configuration for extraction
+
+
+### Update structured output
+
+
+
+
+To update the top level schema type after creation, you must include `?schemaOverride=true` as a query parameter in the URL
+
+
+### List structured outputs
+
+
+
+Query parameters:
+- `page` - Page number (default: 1)
+- `limit` - Results per page (default: 20, max: 100)
+
+### 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**: GPT-4 for complex schemas, GPT-3.5 for simple 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
+
+## HIPAA compliance
+
+
+**Important for HIPAA-enabled organizations:**
+
+If your organization has HIPAA compliance enabled (`hipaaEnabled: true`), structured outputs are **disabled by default** to protect PHI (Protected Health Information).
+
+To use structured outputs with HIPAA compliance:
+- Contact the Vapi team to enable structured outputs
+- Ensure you understand the implications for PHI handling
+- Follow all HIPAA compliance best practices when extracting sensitive health data
+
+
+## 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/docs.yml b/fern/docs.yml
index 9692fae99..d1ae8ee03 100644
--- a/fern/docs.yml
+++ b/fern/docs.yml
@@ -213,6 +213,16 @@ navigation:
- page: Trieve integration
path: knowledge-base/integrating-with-trieve.mdx
icon: fa-light fa-brain
+ - section: Structured outputs
+ icon: fa-light fa-database
+ path: assistants/structured-outputs.mdx
+ contents:
+ - page: Quickstart
+ path: assistants/structured-outputs-quickstart.mdx
+ icon: fa-light fa-rocket
+ - page: Examples
+ path: assistants/structured-outputs-examples.mdx
+ icon: fa-light fa-code
- page: Custom keywords
path: customization/custom-keywords.mdx
icon: fa-light fa-bullseye