railway-backend-index-FIXED
railway-backend-index-FIXED.js is a Fastify-based backend server that orchestrates real-time voice conversations using the OpenAI Realtime API and handles telephony connections via Twilio media streams. It manages user authentication, voice agent configurations, and session persistence, while performing asynchronous contact extraction and conversation summary updates in Supabase. The script serves as the core communication layer between callers, real-time AI logic, and the user management dashboard. For the general repository overview, return to the MeetGabbi Developer Documentation Hub.
Overview
This server integrates several technologies to establish a zero-latency real-time voice assistant:
- Telephony streaming accepts raw PCM audio streams from Twilio call lines over WebSockets and forwards voice output deltas back to the caller
- Real-time AI logic connects to OpenAI Realtime API using WebSockets to provide conversational audio with Voice Activity Detection (VAD) and interrupt handling
- Asynchronous logging persists transcripts, call details, and AI-generated summaries into Supabase without blocking active call streams
- Multi-user isolation isolates configurations and call histories using custom headers or query parameters for dashboard APIs
How it works
The lifecycle of an incoming call flows through the following stages:
- Twilio webhook receives an inbound call at
/incoming-call/:agentId?and queries Supabase for the assigned user and agent configuration - TwiML response instructions tell Twilio to open a WebSocket connection containing metadata to the
/media-stream/:agentId/:userId?server route - OpenAI session handshake initializes a WebSocket connection to
wss://api.openai.com/v1/realtimewith custom settings (voice model, VAD threshold, prompts, and tool configurations) - Bidirectional relay pipes audio payloads between the Twilio stream and the OpenAI socket. If the user begins speaking during assistant output, the server issues a truncate command and clears the Twilio output buffer
- Function calling processes realtime tool outputs like
end_callorsave_contact - Graceful cleanup triggers on connection close, prompting Fastify to update the call record and call
extractContactFromTranscript()asynchronously to extract structured database entries and generate AI summary details
API
HTTP and WebSocket Endpoints
| Endpoint | Method | Description |
|---|---|---|
/ |
GET | Health check endpoint returning uptime and database user statistics |
/health |
GET | System health check reporting uptime and counts of active users and agents |
/health/supabase |
GET | Connectivity verification querying contact records in Supabase |
/health/dns |
GET | DNS resolution check for Supabase endpoint |
/api/phone-numbers |
GET | List assigned phone numbers, agent associations, and call statistics |
/api/assign-agent |
POST | Maps a Twilio phone number to a specific agent configuration |
/api/unassign-agent |
POST | Disconnects the phone number assignment mapping |
/api/update-prompt/:agentId? |
POST/PUT | Modifies the system message prompt, greeting, and speaking order configuration |
/api/current-prompt/:agentId? |
GET | Retrieves active system messages and speaking configurations |
/api/sync-prompt |
POST | Synchronizes prompt modifications directly into memory database config |
/api/update-speaking-order |
POST | Toggles whether the agent or the caller initiates speaking |
/api/agents |
GET/POST | Fetch all agent profiles or create a new agent profile |
/api/agents/:agentId |
GET/PUT | Retrieve details or update config for a specific agent |
/api/calls |
GET | Retrieve list of completed and active calls associated with the user |
/api/calls/:callId |
GET | Fetch details and conversation transcript for a specific call ID |
/api/calls/:callId/transcript |
GET | Retrieve the text transcript of a specific call |
/api/dashboard/stats |
GET | Summary statistics of active calls, agents, and calls per agent |
/api/contacts |
GET | Paginated search of database contacts |
/api/contacts/:contactId |
GET/PUT/DELETE | Retrieve, update, or delete a specific contact profile |
/api/contacts/:contactId/calls |
GET | List historical calls associated with a contact |
/incoming-call/:agentId? |
POST | Webhook triggered by Twilio returning TwiML stream connection details |
/media-stream/:agentId/:userId? |
GET (WS) | WebSocket connection orchestrating media stream and OpenAI socket interaction |
Helper Functions
| Function | Description |
|---|---|
safeSupabaseOperation(operation, operationName, retries) |
Executes a Supabase database query with retry attempts and exponential backoff |
endTwilioCall(callSid, reason) |
Communicates with the Twilio API client to terminate the active call line |
initializeUser(userId) |
Sets up memory placeholders for new user profiles and agent configurations |
getUserAgent(userId, agentId) |
Fetches the active system prompt and profile details for an agent |
updateUserAgent(userId, agentId, updates) |
Applies updates to agent memory structures and updates timestamp |
requireUser(req, reply, next) |
Fastify pre-handler verifying user identity headers |
generateCallId() |
Computes a unique string prefix used to track call events |
calculateConfidence(logprobs) |
Calculates confidence metric for transcriptions |
extractContactFromTranscript(callId, userId, callerNumber) |
Calls OpenAI Completions API to parse contact details from call logs and saves them |
generateCallSummaryForContact(contactId, transcript, extractedInfo, callerNumber, callId) |
Fires request to Supabase edge function to update contact summaries |
createOrUpdateContact(userId, phoneNumber, callId, agentId, metadata) |
Direct insert or update query handler for contact records |
createCallRecord(callId, streamSid, agentId, callerNumber, userId) |
Commits active call metadata locally and database records asynchronously |
updateCallRecord(callId, updates) |
Marks local call logs complete and updates database entries |
saveTranscriptEntry(callId, entry) |
Logs text dialogue increments into memory storage arrays |
calculateDuration(startTime, endTime) |
Formats duration differences into readable string indicators |
reconnectConversationWs(attempt, maxAttempts) |
Preserves active call context and tries to re-establish dropped OpenAI Realtime WebSocket |
Configuration
The server relies on the following environment variables:
| Option | Type | Default | Description |
|---|---|---|---|
PORT |
number |
3000 |
Port on which Fastify listens |
OPENAI_API_KEY |
string |
Required | API key required to establish connection to OpenAI Realtime endpoints |
SUPABASE_URL |
string |
Required | Base connection URL for database operations |
SUPABASE_ANON_KEY |
string |
Required | Public anonymous key used for Supabase Edge Functions |
SUPABASE_SERVICE_ROLE_KEY |
string |
Required | Secret credentials used for elevated DB privileges |
TWILIO_ACCOUNT_SID |
string |
Required | Identifies Twilio account access permissions |
TWILIO_AUTH_TOKEN |
string |
Required | Authorization key for Twilio API actions |
SHOW_TIMING_MATH |
boolean |
false |
Activates verbose logs reporting internal audio latency |
Where skills live
This server configuration maps across the following workspace files:
| Location | Scope |
|---|---|
railway-backend-index-FIXED.js |
Core server implementation containing routes, event handlers, and socket relays |
.env |
Environment configuration container |
Usage
Start the Fastify backend server locally:
node railway-backend-index-FIXED.js
Example request to sync a prompt configuration:
const response = await fetch('http://localhost:3000/api/sync-prompt', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
userId: 'user_12345',
agentId: 'default',
prompt: 'You are a friendly agent helping with appointment scheduling.',
speaksFirst: true,
voice: 'marin'
})
});
const data = await response.json();
console.log(data.success);
Dependencies
fastify— core framework used to listen to HTTP calls and manage API routingws— creates connections to OpenAI WebSocket endpoints and handles standard socket actionsdotenv— parses local file properties into node environment context variables@fastify/formbody— middleware translating form urlencoded inputs from Twilio@fastify/websocket— adds WebSocket routing structures inside Fastify@fastify/cors— controls resource permissions across differing origin requests@supabase/supabase-js— client used to interface with Supabase databasestwilio— telephony client utilized to trigger call state closures
Best practices
- Use safe database wrappers always encapsulate Supabase queries with
safeSupabaseOperationretry logic to ensure server errors do not disconnect live voice streams - Asynchronous workflow processing defer tasks like transcript database syncs and OpenAI contact parsing until after connections close or run them in parallel without awaiting
- Resilient socket management handle potential OpenAI WebSocket dropouts by checking states and initiating
reconnectConversationWswhile preserving state indices - Enforce isolated user scopes require authorization headers or query parameters to ensure caller data and configuration details do not overlap