Documentation Index
Fetch the complete documentation index at: https://patter-06b046ce-feat-observability-otel-attrs-0-6-1.mintlify.app/llms.txt
Use this file to discover all available pages before exploring further.
Configuration
The Patter class is the main entry point for the SDK. Pass a carrier instance and a phone number — everything else flows through environment variables unless you override it.
Minimal config
from getpatter import Patter, Twilio
phone = Patter(carrier=Twilio(), phone_number="+15550001234") # TWILIO_* from env
The carrier instance reads credentials from environment variables when you don’t pass them explicitly. See Carrier for the full list.
Constructor parameters
| Parameter | Type | Default | Description |
|---|
carrier | Twilio | Telnyx | None | None | Telephony carrier instance. See Carrier. Reads credentials from env vars when arguments are omitted. |
phone_number | str | "" | Your phone number in E.164 format (e.g., "+15550001234"). Required when a carrier is set. |
webhook_url | str | "" | Public hostname of this server, without scheme (e.g., "abc.ngrok.io"). See Tunneling for ways to get one. |
tunnel | CloudflareTunnel | Static | bool | None | None | Tunnel directive. True is shorthand for CloudflareTunnel(). See Tunneling. |
pricing | dict | None | None | Override default provider pricing estimates. See Metrics & Cost Tracking. |
persist | bool | str | None | None | Persist the dashboard’s call history to disk so it survives process restarts. See Persistent dashboard history below. |
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 | Twilio() |
TELNYX_API_KEY, TELNYX_CONNECTION_ID, TELNYX_PUBLIC_KEY (optional) | Telnyx() |
OPENAI_API_KEY | OpenAIRealtime(), OpenAITTS(), WhisperSTT() |
ELEVENLABS_API_KEY, ELEVENLABS_AGENT_ID | ElevenLabsTTS(), ElevenLabsConvAI() |
DEEPGRAM_API_KEY | DeepgramSTT() |
CARTESIA_API_KEY | CartesiaSTT(), CartesiaTTS() |
RIME_API_KEY | RimeTTS() |
LMNT_API_KEY | LMNTTTS() |
SONIOX_API_KEY | SonioxSTT() |
SPEECHMATICS_API_KEY | SpeechmaticsSTT() (Python only) |
ASSEMBLYAI_API_KEY | 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 FastAPI 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 dashboard_token argument 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
from getpatter import Patter, Twilio, OpenAIRealtime
phone = Patter(carrier=Twilio(), phone_number="+15550001234")
agent = phone.agent(
engine=OpenAIRealtime(voice="nova"),
system_prompt="You are a friendly receptionist.",
first_message="Thanks for calling!",
)
OpenAI Realtime on Telnyx
from getpatter import Patter, Telnyx, OpenAIRealtime
phone = Patter(carrier=Telnyx(), phone_number="+15550001234")
agent = phone.agent(
engine=OpenAIRealtime(),
system_prompt="You are a friendly receptionist.",
)
Pipeline mode
from getpatter import Patter, Twilio, DeepgramSTT, ElevenLabsTTS
phone = Patter(carrier=Twilio(), phone_number="+15550001234")
agent = phone.agent(
stt=DeepgramSTT(endpointing_ms=80),
tts=ElevenLabsTTS(voice_id="rachel"),
system_prompt="You are a helpful assistant.",
)
Validation
Local mode enforces the following when telephony credentials are present:
phone_number is required
- Both
account_sid and auth_token are required when using Twilio (either via Twilio(...) kwargs or TWILIO_* env vars)
# Raises ValueError — Twilio credentials missing from env and arguments.
phone = Patter(carrier=Twilio())
# ValueError: Twilio carrier requires account_sid and auth_token.
Persistent dashboard history
By default the dashboard is an in-memory ring buffer — restart the process and the call list is empty. Pass persist= 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 / None (default) | Falls back to the PATTER_LOG_DIR env var. If the env var is also unset, persistence is off — backward-compatible with prior releases. |
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>. |
When persist is set explicitly the env var is ignored. When persist is None, PATTER_LOG_DIR continues to work as a deployment-time override.
| 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
from getpatter import Patter, Twilio, OpenAIRealtime
phone = Patter(
carrier=Twilio(),
phone_number="+15555550100",
persist=True, # platform default location
)
agent = phone.agent(
engine=OpenAIRealtime(),
system_prompt="You are a friendly receptionist.",
)
Custom path
phone = Patter(
carrier=Twilio(),
phone_number="+15555550100",
persist="/var/log/patter", # explicit path; ~ is expanded
)
Env-var override (deployment-time)
Leave persist unset in code and let ops decide per environment:
# Production: keep history under a managed volume
export PATTER_LOG_DIR=/var/log/patter
# Dev: platform default
export PATTER_LOG_DIR=auto
# CI: leave unset → no disk writes
phone = Patter(carrier=Twilio(), phone_number="+15555550100")
# `persist` defaults to None → reads PATTER_LOG_DIR
Programmatic hydration on startup
phone.serve() calls MetricsStore.hydrate(log_root) 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:
from getpatter.dashboard.store import MetricsStore
store = MetricsStore()
restored = store.hydrate("/var/log/patter")
print(f"Restored {restored} calls from disk")
hydrate() is idempotent — call_ids already in the store are skipped, and unparseable records are logged at debug level rather than aborting.
Retention
# Default: 30 days. Old day-directories are swept on ~2% of calls (no daemon).
export PATTER_LOG_RETENTION_DAYS=30
# Keep forever — opt out of automatic cleanup
export PATTER_LOG_RETENTION_DAYS=0
Retention defaults to 30 days and phone numbers in metadata.json are masked by default (last 4 digits) via PATTER_LOG_REDACT_PHONE. If you need to keep call history indefinitely or store full E.164 numbers, set those env vars explicitly — and gate access to the log root, since transcript.jsonl is never redacted and may contain customer PII spoken during the call.
See Call logging for the full layout, schema, and reading patterns.
Loading from .env
import os
from dotenv import load_dotenv
from getpatter import Patter, Twilio, OpenAIRealtime
load_dotenv()
phone = Patter(
carrier=Twilio(), # reads TWILIO_* from env
phone_number=os.environ["PHONE_NUMBER"],
webhook_url=os.environ["WEBHOOK_URL"],
)
agent = phone.agent(
engine=OpenAIRealtime(), # reads OPENAI_API_KEY
system_prompt="You are a helpful assistant.",
)
Never hardcode API keys, tokens, or secrets in your source code. Always use environment variables or a secret manager.