Skip to main content

Architecture

System Overview

Virsyn Voice AI follows a serverless architecture with Supabase as the backend platform. Edge Functions handle all business logic, orchestrating between Ultravox (voice AI) and Telnyx (telephony).

┌─────────────┐     ┌──────────────────────┐     ┌─────────────┐
│ Frontend │────▶│ Supabase Edge │────▶│ Ultravox │
│ (Client) │ │ Functions (Deno/TS) │ │ Voice AI │
└─────────────┘ └──────────┬───────────┘ └─────────────┘

┌──────────┴───────────┐
│ │
┌─────▼─────┐ ┌───────▼──────┐
│ Supabase │ │ Telnyx │
│ PostgreSQL │ │ Telephony │
└────────────┘ └──────────────┘

Components

Supabase Backend

  • PostgreSQL database stores all application data: agencies, users, agent mappings, phone numbers, call records, and encrypted credentials
  • Row Level Security (RLS) enforces agency-scoped data isolation
  • RPC functions handle encryption/decryption of API keys (encrypt_api_key, decrypt_api_key)
  • Edge Functions (Deno/TypeScript) implement all API endpoints

Ultravox Integration

Ultravox provides the AI voice engine. The integration covers:

  • Agent creation with system prompts, voice selection, and tool configuration
  • Call management including recordings and transcripts
  • Webhook events for real-time call status updates (call.started, call.joined, call.ended)
  • Voice catalog with language-specific voice options
  • Tool definitions for agent capabilities during calls

Telnyx Integration

Telnyx provides telephony infrastructure:

  • Phone number search and purchase across countries, area codes, and number types
  • Call Control Applications that route inbound calls to Ultravox
  • Outbound Voice Profiles for outbound call origination
  • SIP credential import into Ultravox for call bridging

Database

The PostgreSQL database contains 17 tables organized by domain. See the Database Reference for full schema details.

GroupTablesPurpose
Coreagencies, users, clientsMulti-tenant identity and organization
Agentsagent_mappings, agency_tools, ultravox_voicesAI agent configuration and resources
Phone Numbersagency_phone_numbersTelnyx phone number inventory
Callscalls, call_stats_daily, call_batchesCall records, analytics, and batch operations
Campaignscampaigns, campaign_contactsOutbound campaign management
Queueswebhook_queue, enrichment_queueAsync processing pipelines
Synchistorical_sync_jobsHistorical data backfill

The schema uses 14 custom enums for type safety (e.g., user_role, call_direction, phone_number_status) and database triggers to automate the enrichment pipeline -- when a call ends, a trigger queues transcript fetching, and when the transcript completes, another trigger queues AI analysis.

Data Flow

Inbound Call Flow

  1. Caller dials a Telnyx phone number
  2. Telnyx routes the call via the Call Control Application
  3. Ultravox receives the call and activates the assigned agent
  4. Ultravox sends webhook events (call.started, call.ended) to Virsyn
  5. Virsyn queues and processes webhook events asynchronously
  6. Call data is enriched with transcripts and AI analysis

Provisioning Flow

  1. User saves Ultravox API key (encrypted at rest)
  2. User saves Telnyx credentials (API key, public key, account SID -- all encrypted)
  3. provision-telephony creates a Telnyx Call Control Application and Outbound Voice Profile
  4. Telnyx SIP credentials are imported into Ultravox
  5. Phone numbers can then be purchased and assigned to agents

Queue-Based Processing

Several operations use asynchronous queue processing:

QueuePurposeTrigger
Webhook queueProcess Ultravox call eventswebhook-ingest enqueues, process-webhook-queue dequeues (cron)
Enrichment queueFetch transcripts, run AI analysisCompleted calls enqueued, process-enrichment-queue dequeues (cron)
Historical syncBackfill past call datastart-historical-sync initiates, process-historical-sync runs in batches

Security Model

Authentication

  • User-facing endpoints require Supabase JWT Bearer tokens
  • Cron/internal endpoints use service-role authentication
  • Webhook ingestion uses URL-path secrets (/webhook-ingest/{agency_id}/{secret})

Authorization

  • Role-based access: agency_owner, agency_admin, agency_member
  • All data queries are scoped to the user's agency_id
  • Destructive operations (delete, release) require owner/admin roles

Credential Storage

  • API keys for Ultravox and Telnyx are encrypted via Supabase RPC before storage
  • Decryption happens at runtime only when the key is needed for an API call
  • Webhook secrets are generated per-agency for event verification