Skip to main content

Prerequisites

Before you begin, make sure you have:

Python 3.12+

Required for async features and modern syntax

MongoDB

Local or cloud instance for data persistence

OpenAI API Key

With access to Realtime API capabilities

Webhook Secret

From OpenAI for webhook verification
This guide uses uv for package management. You can also use pip or poetry if you prefer.

Installation

1

Clone the Repository

Get the source code and navigate to the project directory:
git clone <repository-url>
cd sonore-phone-agent
2

Create Virtual Environment

Set up an isolated Python environment:
uv venv
source .venv/bin/activate  # On Windows: .venv\Scripts\activate
3

Install Dependencies

Install the project and all required packages:
uv pip install -e .
This installs the dependencies from pyproject.toml:
  • FastAPI - Web framework
  • Pydantic - Data validation
  • httpx - Async HTTP client
  • pymongo - MongoDB driver
  • openai - OpenAI SDK
  • websockets - WebSocket client
  • phonenumbers - Phone number parsing

Configuration

1

Create Environment File

Create a .env file in the project root:
.env
# OpenAI Configuration
OPENAI_API_KEY=sk-proj-...
OPENAI_WEBHOOK_SECRET=whsec_...
WS_SERVER_URL=wss://api.openai.com/v1/realtime?model=gpt-4o-realtime-preview-2024-12-17&

# MongoDB Configuration
MONGODB_URI=mongodb://localhost:27017

# Capacity Management
MAX_CONCURRENT_CALLS=5
MAX_CONCURRENT_CALLS_PER_TENANT=3

# Post-Call Processing
POST_CALL_URI=http://localhost:8001
Never commit your .env file to version control. Add it to .gitignore to keep your secrets safe.
2

Configure MongoDB

Ensure MongoDB is running and accessible:
# If using Docker:
docker run -d -p 27017:27017 --name mongodb mongo:latest

# Or install locally following MongoDB documentation
The system will create the following collections automatically:
  • call_registries - Call metadata and transcripts
  • tenant_configs - Per-tenant configurations
  • prompts - System and greeting prompts
3

Set Up Initial Tenant

Insert a tenant configuration in MongoDB. You can use MongoDB Compass or the CLI:
// Connect to your database
use phone_agent

// Insert tenant config
db.tenant_configs.insertOne({
  tenant_id: "demo-tenant",
  dialed_numbers: ["+1234567890"],
  features: {
    call_transfer_enabled: true,
    transfer_phone_number: "+1987654321"
  },
  created_at: new Date(),
  updated_at: new Date()
})

// Insert greeting prompt
db.prompts.insertOne({
  tenant_id: "demo-tenant",
  prompt_type: "greeting",
  text: "Hello! Thanks for calling. How can I help you today?",
  active: true,
  created_at: new Date()
})

// Insert instruction prompt
db.prompts.insertOne({
  tenant_id: "demo-tenant",
  prompt_type: "instruction",
  text: "You are a helpful customer service assistant. Answer questions politely and offer to transfer to a specialist if needed.",
  active: true,
  created_at: new Date()
})

Running the System

Sonore Phone Agent consists of two FastAPI applications that work together:
1

Start the Call Handler

This service handles incoming webhook events and manages active call sessions:
uvicorn src.apps.calls.main:app --reload --port 8000
You should see:
INFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
INFO:     Started reloader process
INFO:     Started server process
INFO:     Waiting for application startup.
INFO:     Application startup complete.
The --reload flag enables auto-reload on code changes. Remove it in production.
2

Start the Post-Call Processor

In a new terminal, start the post-call processing service:
source .venv/bin/activate  # Activate venv again
uvicorn src.apps.post_call.main:app --reload --port 8001
This service handles:
  • Call transcript processing
  • Summary generation
  • Analytics and metrics
3

Verify Health

Check that both services are running:
# Call handler health check
curl http://localhost:8000/health
# Response: {"status":"ok"}

# Check active calls (should be empty initially)
curl http://localhost:8000/api/v1/calls
# Response: {"calls":[]}

Testing Webhook Flow

To test the complete call flow, you’ll need to expose your local server to the internet for OpenAI webhooks:
1

Set Up Tunnel

Use ngrok or a similar tool to expose your local server:
ngrok http 8000
Copy the HTTPS URL (e.g., https://abc123.ngrok.io)
2

Configure OpenAI Webhook

In your OpenAI dashboard, set the webhook URL to:
https://abc123.ngrok.io/api/v1/openai/webhook
The system will verify the webhook signature on every request:
# From src/apps/calls/api/v1/endpoints/openai_webhook.py:74
event = client.webhooks.unwrap(
    raw_body,
    headers=headers,
    secret=settings.openai_webhook_secret.get_secret_value(),
)
3

Make a Test Call

Call the phone number associated with your tenant configuration. The system will:
  1. Receive webhook - OpenAI sends realtime.call.incoming event
  2. Resolve tenant - Match dialed number to tenant
  3. Check capacity - Verify concurrent call limits
  4. Fetch instructions - Load prompts from MongoDB
  5. Accept call - Send acceptance to OpenAI
  6. Start session - Create WebSocket connection
  7. Handle conversation - Process audio and execute tools
  8. Post-process - Generate transcript and summary
Watch the terminal logs to see each step in real-time. The structured logging shows the complete call lifecycle.

Understanding the Call Flow

Here’s what happens during a typical call:

Monitoring Active Calls

The system provides real-time visibility into call sessions:
# List all active calls
curl http://localhost:8000/api/v1/calls

# Response example:
{
  "calls": [
    {
      "call_id": "call_abc123",
      "status": "running"
    }
  ]
}
# Get live metrics
curl http://localhost:8000/api/v1/metrics/live

# Response example:
{
  "timestamp": "2024-03-02T14:30:00Z",
  "active_calls": 2,
  "total_accepted": 15,
  "total_rejected": 3
}

Next Steps

Architecture Deep Dive

Learn how the components work together

Custom Tools

Build custom tools for your phone agent

Prompt Engineering

Optimize your agent’s conversation flow

Production Deployment

Deploy with Docker and best practices

Troubleshooting

Problem: 401 Unauthorized - Invalid signatureSolution: Verify your OPENAI_WEBHOOK_SECRET in .env matches the secret in your OpenAI dashboard.
Problem: pymongo.errors.ServerSelectionTimeoutErrorSolution:
  • Check MongoDB is running: docker ps or mongosh
  • Verify MONGODB_URI in .env
  • Ensure no firewall blocking port 27017
Problem: Calls are rejected with capacity reasonSolution: Increase limits in .env:
MAX_CONCURRENT_CALLS=10
MAX_CONCURRENT_CALLS_PER_TENANT=5
Problem: Errors in post-call webhookSolution:
  • Verify post-call service is running on port 8001
  • Check POST_CALL_URI in .env
  • Review logs in post-call terminal
Running into issues? Check the Troubleshooting Guide for more detailed solutions, or review the logs with structured event names for debugging.

Build docs developers (and LLMs) love