Configuration
ThePatter constructor accepts PatterOptions. Pass a carrier instance and a phone number — everything else flows through environment variables unless you override it.
Minimal config
Constructor parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
carrier | Twilio | Telnyx | Yes | — | Telephony carrier instance. Reads credentials from env vars when arguments are omitted. See Carrier. |
phoneNumber | string | Yes | — | Your phone number in E.164 format. |
webhookUrl | string | Conditional | — | Public hostname for webhooks (no protocol prefix, no path). Required unless using tunnel: true in serve(). |
tunnel | CloudflareTunnel | StaticTunnel | boolean | No | — | Tunnel directive. true is shorthand for new CloudflareTunnel(). See Tunneling. |
pricing | Record<string, Partial<ProviderPricing>> | No | — | Override default provider pricing estimates. See Metrics. |
persist | boolean | string | No | true (on, platform default path) | Persist the dashboard’s call history to disk so it survives process restarts. Defaults to ON since 0.6.2 — pass persist: false to keep the prior ephemeral-RAM-only behaviour. See Persistent dashboard history below. |
Webhook URL Format
ThewebhookUrl must be a bare hostname with no protocol prefix or path:
https://{webhookUrl}/webhooks/twilio/voice).
Telnyx: Telnyx is a fully supported alternative to Twilio, with feature parity for DTMF, call transfer, recording, and cost tracking.
Environment variables
Every credential resolves from an env var when the matching argument is omitted. See.env.example in the repo for a complete list.
| Env var | Used by |
|---|---|
TWILIO_ACCOUNT_SID, TWILIO_AUTH_TOKEN | new Twilio() |
TELNYX_API_KEY, TELNYX_CONNECTION_ID, TELNYX_PUBLIC_KEY (optional) | new Telnyx() |
OPENAI_API_KEY | new OpenAIRealtime(), new OpenAITTS(), new WhisperSTT() |
ELEVENLABS_API_KEY, ELEVENLABS_AGENT_ID | new ElevenLabsTTS(), new ElevenLabsConvAI() |
DEEPGRAM_API_KEY | new DeepgramSTT() |
CARTESIA_API_KEY | new CartesiaSTT(), new CartesiaTTS() |
RIME_API_KEY | new RimeTTS() |
LMNT_API_KEY | new LMNTTTS() |
SONIOX_API_KEY | new SonioxSTT() |
ASSEMBLYAI_API_KEY | new AssemblyAISTT() |
Runtime env vars
These tune SDK runtime behaviour (no credential lookup).| Env var | Default | Effect |
|---|---|---|
PATTER_LOG_DIR | unset | Persistent dashboard root (see Persistent dashboard history below). |
PATTER_LOG_RETENTION_DAYS | 30 | Days of disk history to retain. 0 disables cleanup. |
PATTER_LOG_REDACT_PHONE | 1 | Mask phone numbers in metadata.json (last 4 digits). Set to 0 to store full E.164. |
PATTER_DASHBOARD_NOTIFY | enabled | Set to 0, false, no, or off (case-insensitive) to skip the fire-and-forget dashboard ingest POST. Use this when you embed Patter alongside your own Express server on port 8000 to avoid 404 spam in your access log. |
PATTER_BIND_HOST | 127.0.0.1 | Host the embedded server binds to. Set to 0.0.0.0 when running inside a container whose port must be reachable from the host (e.g. docker run -p 8000:8000 — Docker’s port-mapping cannot forward to a 127.0.0.1 listener inside the container). |
PATTER_BIND_HOST defaults to loopback on purpose — exposing the embedded server on 0.0.0.0 outside a containerised deployment puts the dashboard and webhook routes on every interface. Pair PATTER_BIND_HOST=0.0.0.0 with the dashboardToken option on serve() (or skip the dashboard) before going public.PATTER_DASHBOARD_NOTIFY only gates the standalone-dashboard ingest webhook. It does not disable the embedded dashboard you can serve from phone.serve({ dashboard: true }) — that route runs in-process and is unaffected.Examples
OpenAI Realtime on Twilio
OpenAI Realtime on Telnyx
Pipeline mode
Persistent dashboard history
By default the dashboard is an in-memory ring buffer — restart the process and the call list is empty. Passpersist to keep per-call records (metadata.json, transcript.jsonl, events.jsonl) on disk and rebuild the dashboard on the next startup. No external database required.
persist value | Behaviour |
|---|---|
omitted / undefined (default) | Persistence is on. Falls back to PATTER_LOG_DIR when set; otherwise writes under the platform default location. Changed from opt-in to default-on in 0.6.2 so the dashboard’s hydrate path can rebuild call history across process restarts without extra wiring. |
false | Force-off. Disk writes are skipped even when PATTER_LOG_DIR is set. |
true | Write under the platform default location (see below). Equivalent to PATTER_LOG_DIR=auto. |
"<path>" (string) | Write under the supplied path (~ is expanded). Equivalent to PATTER_LOG_DIR=<path>. |
persist is set explicitly the env var is ignored. When persist is undefined, PATTER_LOG_DIR continues to work as a deployment-time override.
Platform default location
| Platform | Default root |
|---|---|
| macOS | ~/Library/Application Support/patter |
| Linux | $XDG_DATA_HOME/patter (falls back to ~/.local/share/patter) |
| Windows | %LOCALAPPDATA%\patter |
Simplest opt-in
Custom path
Env-var override (deployment-time)
Leavepersist unset in code and let ops decide per environment:
Programmatic hydration on startup
phone.serve() calls MetricsStore.hydrate(logRoot) automatically when persistence is enabled, so the dashboard repopulates from disk before the first call lands. You can call it directly if you build the store yourself:
hydrate() is idempotent — callIds already in the store are skipped, and unparseable records are logged at debug level rather than aborting.
Retention
Loading from .env
Telnyx delivers 16 kHz PCM audio natively, so no transcoding is needed. Twilio uses mulaw 8 kHz, which the SDK transcodes automatically.

