JSPM

  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 171
  • Score
    100M100P100Q87334F
  • License MIT

Open-source voice AI SDK — connect any AI agent to real phone calls in 4 lines of code

Package Exports

  • getpatter

Readme

Patter TypeScript SDK

Connect AI agents to phone numbers with 4 lines of code

npm MIT License TypeScript 5+

QuickstartFeaturesConfigurationVoice ModesAPI ReferenceContributing


Patter is the open-source SDK that gives your AI agent a phone number. Point it at any function that returns a string, and Patter handles the rest: telephony, speech-to-text, text-to-speech, and real-time audio streaming. You build the agent — we connect it to the phone.

Quickstart

npm install getpatter
import { Patter } from "getpatter";

const phone = new Patter({
  twilioSid: "AC...", twilioToken: "...",
  openaiKey: "sk-...",
  phoneNumber: "+1...",
});

const agent = phone.agent({
  systemPrompt: "You are a friendly customer service agent for Acme Corp.",
  voice: "alloy",
  firstMessage: "Hello! Thanks for calling. How can I help?",
});

await phone.serve({ agent, port: 8000 });

Features

Feature Method Example
Inbound calls phone.serve(agent) Answer calls as an AI
Outbound calls + AMD phone.call(to, machineDetection) Place calls with voicemail detection
Tool calling (webhooks) agent(tools=[...]) Agent calls external APIs mid-conversation
Custom STT + TTS agent(provider="pipeline") Bring your own voice providers
Dynamic variables agent(variables={...}) Personalize prompts per caller
Custom LLM (any model) serve(onMessage=handler) Claude, Mistral, LLaMA, etc.
Call recording serve(recording=true) Record all calls
Call transfer transfer_call (auto-injected) Transfer to a human
Voicemail drop call(voicemailMessage="...") Play message on voicemail

Configuration

Environment Variables

Variable Required Description
OPENAI_API_KEY Yes (Realtime mode) OpenAI API key with Realtime access
TWILIO_ACCOUNT_SID Yes Twilio account SID
TWILIO_AUTH_TOKEN Yes Twilio auth token
TWILIO_PHONE_NUMBER Yes Your Twilio phone number (E.164)
DEEPGRAM_API_KEY Pipeline mode Deepgram STT key
ELEVENLABS_API_KEY Pipeline mode ElevenLabs TTS key
ANTHROPIC_API_KEY Custom LLM For bringing your own model
WEBHOOK_URL No Public URL (auto-tunneled via Cloudflare if omitted)
cp .env.example .env
# Edit .env with your API keys

Telnyx: Telnyx is a fully supported telephony provider alternative to Twilio. Both carriers receive equal support for DTMF, transfer, recording, and metrics.

Voice Modes

Mode Latency Quality Best For
OpenAI Realtime Lowest High Fluid, low-latency conversations
Deepgram + ElevenLabs Low High Independent control over STT and TTS
ElevenLabs ConvAI Low High ElevenLabs-managed conversation flow

API Reference

Patter Constructor

new Patter({
  twilioSid: string;
  twilioToken: string;
  openaiKey: string;
  phoneNumber: string;
  webhookUrl?: string;  // Optional; auto-tunneled via Cloudflare if omitted
})
Parameter Type Description
twilioSid string Twilio account SID
twilioToken string Twilio auth token
openaiKey string OpenAI API key
phoneNumber string Your Twilio phone number (E.164 format)
webhookUrl string Public URL for Twilio webhooks (optional)

phone.agent() Method

phone.agent({
  systemPrompt: string;
  voice?: string;
  firstMessage?: string;
  variables?: Record<string, string>;
  tools?: Array<{name, description, parameters, webhookUrl}>;
})
Parameter Type Description
systemPrompt string Prompt with optional {variable} placeholders
voice string TTS voice name (e.g., "alloy", "echo", "fable")
firstMessage string Opening message (supports {variable} placeholders)
variables Record<string, string> Values substituted into prompts
tools Array Tool definitions: {name, description, parameters, webhookUrl}

phone.serve() Method

await phone.serve({
  agent: Agent;
  port?: number;
  dashboard?: boolean;
  recording?: boolean;
  onCallStart?: (data: CallData) => Promise<void>;
  onCallEnd?: (data: CallData) => Promise<void>;
  onTranscript?: (data: TranscriptData) => Promise<void>;
})
Parameter Type Description
agent Agent Agent configuration to use for calls
port number Port to listen on (default: 8000)
dashboard boolean Enable the built-in monitoring dashboard
recording boolean Enable call recording via the telephony provider
onCallStart (data) => Promise<void> Called when a call connects; receives data.caller, data.callId
onCallEnd (data) => Promise<void> Called when a call ends; receives data.history, data.transcript, data.duration
onTranscript (data) => Promise<void> Called on each transcript turn; receives data.role, data.text, data.history

phone.call() Method

await phone.call({
  to: string;
  firstMessage?: string;
  machineDetection?: boolean;
  voicemailMessage?: string;
})
Parameter Type Description
to string Destination phone number (E.164 format)
firstMessage string Opening message for the outbound call
machineDetection boolean Enable answering machine detection
voicemailMessage string Message to play when voicemail is detected

Static Provider Helpers

Patter.deepgram(options: { apiKey: string; language?: string }) -> STT
Patter.elevenlabs(options: { apiKey: string; voice?: string }) -> TTS
Patter.openaiTts(options: { apiKey: string; voice?: string }) -> TTS
Patter.whisper(options: { apiKey: string; language?: string }) -> STT

Examples

Inbound Calls (AI answers the phone)

import { Patter, IncomingMessage } from "getpatter";

const phone = new Patter({
  twilioSid: "AC...", twilioToken: "...",
  openaiKey: "sk-...",
  phoneNumber: "+1...",
});

async function agent(msg: IncomingMessage): Promise<string> {
  if (msg.text.toLowerCase().includes("hours")) {
    return "We're open Monday through Friday, 9 to 5.";
  }
  return "How can I help you today?";
}

await phone.serve({
  agent: phone.agent({
    systemPrompt: "You are a helpful customer service agent.",
    firstMessage: "Hello! How can I help?",
  }),
  port: 8000,
  onCallStart: (data) => console.log(`Call from ${data.caller}`),
  onCallEnd: (data) => console.log("Call ended"),
});

Outbound Calls (AI calls someone)

import { Patter } from "getpatter";

const phone = new Patter({
  twilioSid: "AC...", twilioToken: "...",
  openaiKey: "sk-...",
  phoneNumber: "+1...",
});

const agentConfig = phone.agent({
  systemPrompt: "You are making reminder calls.",
  firstMessage: "Hi, this is an automated reminder from Acme Corp.",
});

await phone.serve({ agent: agentConfig, port: 8000 });
await phone.call({
  to: "+14155551234",
  firstMessage: "Hi, just checking in.",
});

Tool Calling (Agent calls external APIs)

const agent = phone.agent({
  systemPrompt: "You are a booking assistant. Check availability before confirming.",
  tools: [{
    name: "check_availability",
    description: "Check appointment availability for a given date",
    parameters: {
      type: "object",
      properties: {
        date: { type: "string", description: "ISO date, e.g. 2025-06-15" },
      },
      required: ["date"],
    },
    webhookUrl: "https://api.example.com/availability",
  }],
});

Custom Voice (Deepgram STT + ElevenLabs TTS)

const phone = new Patter({
  twilioSid: "AC...", twilioToken: "...",
  openaiKey: "sk-...",
  phoneNumber: "+1...",
});

const agent = phone.agent({
  systemPrompt: "You are a helpful voice assistant.",
  voice: "aria",
});

// Use custom STT and TTS in pipeline mode
await phone.serve({
  agent,
  port: 8000,
  stt: Patter.deepgram({ apiKey: "dg_...", language: "en" }),
  tts: Patter.elevenlabs({ apiKey: "el_...", voice: "aria" }),
});

Call Recording

await phone.serve({
  agent,
  port: 8000,
  recording: true,  // Records all inbound and outbound calls
});

Dynamic Variables in Prompts

const agent = phone.agent({
  systemPrompt: "You are helping {customer_name}, account #{account_id}.",
  firstMessage: "Hi {customer_name}! How can I help you today?",
  variables: {
    customer_name: "Jane",
    account_id: "A-789",
  },
});

Contributing

Pull requests are welcome.

cd sdk-ts && npm install && npm test

Please open an issue before submitting large changes so we can discuss the approach first.

License

MIT — see LICENSE.