Skip to content
AI Voice Agents
AI Voice Agents10 min read0 views

Build a Voice Agent on Railway: One-Click FastAPI Deploy (2026)

Ship a production voice agent in 5 minutes on Railway: FastAPI bridge, OpenAI Realtime, Postgres for sessions, and a one-click template. No Docker knowledge required.

TL;DR — Railway gives you Postgres, a Python service, environment variables, and a public HTTPS URL with two clicks. Drop in a FastAPI WebSocket bridge between Twilio and OpenAI Realtime, push to GitHub, and Railway redeploys on every commit. Total time from git init to live voice agent: under 5 minutes.

What you'll build

A FastAPI service hosted on Railway that:

  • Returns TwiML at /incoming
  • Bridges /media WebSocket to OpenAI Realtime
  • Logs every call to Railway-managed Postgres
  • Auto-deploys on git push

Prerequisites

  1. Railway account (railway login).
  2. GitHub repo.
  3. OPENAI_API_KEY, Twilio number.
  4. Python 3.11.

Architecture

flowchart LR
  C[Caller] --> T[Twilio]
  T -->|HTTP TwiML| RW[Railway FastAPI]
  T -->|wss media| RW
  RW <-->|wss| OAI[OpenAI Realtime]
  RW -->|asyncpg| PG[(Railway Postgres)]
  GH[GitHub repo] -->|push| RW

Step 1 — FastAPI app

```python

app.py

import os, json, base64, asyncio, asyncpg, websockets from fastapi import FastAPI, WebSocket, Request from fastapi.responses import Response

app = FastAPI() pool: asyncpg.Pool

@app.on_event("startup") async def startup(): global pool pool = await asyncpg.create_pool(os.environ["DATABASE_URL"]) async with pool.acquire() as c: await c.execute("""create table if not exists turns ( id serial primary key, call_sid text, role text, text text, ts timestamptz default now())""")

Hear it before you finish reading

Talk to a live CallSphere AI voice agent in your browser — 60 seconds, no signup.

Try Live Demo →

@app.post("/incoming") async def incoming(req: Request): host = req.headers["host"] return Response(content=f"""""", media_type="text/xml")

@app.websocket("/media") async def media(ws: WebSocket): await ws.accept() async with websockets.connect( "wss://api.openai.com/v1/realtime?model=gpt-realtime", additional_headers={"Authorization": f"Bearer {os.environ['OPENAI_API_KEY']}", "OpenAI-Beta": "realtime=v1"} ) as ai: await ai.send(json.dumps({ "type": "session.update", "session": { "instructions": "You are a concise voice agent.", "voice": "marin", "input_audio_format": "g711_ulaw", "output_audio_format": "g711_ulaw", "turn_detection": {"type": "server_vad"} } })) sid = "" async def to_ai(): async for raw in ws.iter_text(): ev = json.loads(raw) nonlocal_sid = ev.get("streamSid") if ev.get("event") == "media": await ai.send(json.dumps({"type": "input_audio_buffer.append", "audio": ev["media"]["payload"]})) async def to_caller(): async for raw in ai: ev = json.loads(raw) if ev["type"] == "response.audio.delta": await ws.send_text(json.dumps({"event": "media", "streamSid": sid, "media": {"payload": ev["delta"]}})) if ev["type"] == "response.done": text = ev["response"]["output"][0]["content"][0]["transcript"] async with pool.acquire() as c: await c.execute("insert into turns(call_sid, role, text) values($1, 'assistant', $2)", sid, text) await asyncio.gather(to_ai(), to_caller()) ```

Step 2 — requirements.txt and railway.toml

``` fastapi==0.115.0 uvicorn[standard]==0.32.0 websockets==13.1 asyncpg==0.30.0 ```

```toml

railway.toml

[build] builder = "NIXPACKS" [deploy] startCommand = "uvicorn app:app --host 0.0.0.0 --port $PORT" restartPolicyType = "ON_FAILURE" ```

Railway's Nixpacks builder detects Python automatically; no Dockerfile needed.

Step 3 — Provision Postgres + service

In Railway dashboard: New Project → Deploy from GitHub repo → pick the FastAPI repo. Add a Postgres plugin from the same project; Railway sets DATABASE_URL automatically.

Step 4 — Set env vars

In the service settings, add OPENAI_API_KEY. Railway redeploys on save.

Still reading? Stop comparing — try CallSphere live.

CallSphere ships complete AI voice agents per industry — 14 tools for healthcare, 10 agents for real estate, 4 specialists for salons. See how it actually handles a call before you book a demo.

Step 5 — Public URL + Twilio webhook

Railway generates https://your-app.up.railway.app. Plug into Twilio → number → Voice Webhook → POST https://your-app.up.railway.app/incoming.

Step 6 — Add observability

Pin the Railway "OpenTelemetry" template, set OTEL_EXPORTER_OTLP_ENDPOINT to a Honeycomb/Tempo URL. Latency per turn shows up in spans automatically with the standard FastAPI OTel instrumentation.

Step 7 — Scale

Bump replicas from 1 to N in the dashboard. Railway puts a load balancer in front; sticky sessions on x-twilio-signature keep call legs pinned.

Pitfalls

  • Cold-start on free hobby plan is ~5s — voice agents will drop. Use Pro ($5/mo + usage) or pin always-on.
  • Twilio retries TwiML POSTs aggressively on slow boots; first request must respond <15s.
  • Postgres pool sizing: Railway's Postgres has a connection cap; tune asyncpg.create_pool(min_size=2, max_size=10).
  • Nixpacks Python version: pin via runtime.txt or PYTHON_VERSION=3.11 env var.
  • No persistent disk on basic plans; logs are ephemeral. Pipe to Logtail/Axiom.

How CallSphere does this in production

CallSphere doesn't run on Railway — we use bare k3s + Postgres on Hetzner for cost predictability at our scale (~$1k/mo infra for 6 verticals). For early-stage builders, Railway is the fastest way to ship a real voice agent with a real database. CallSphere's 37 agents, 90+ tools, 115+ DB tables, 6 verticals run on FastAPI :8084 with the same code patterns shown here. $149/$499/$1499, 14-day trial, 22% affiliate.

FAQ

Q: Railway vs Render vs Fly? Railway: easiest CLI + UI, Postgres bundled. Render: similar, slightly slower deploys. Fly: best for multi-region. Pick Railway for speed.

Q: Can I use a one-click template? Yes — Railway's marketplace has Deploy OpenAI Voice Assistant and Deploy Faster Whisper templates that wire most of this for you.

Q: Latency? Railway runs in us-west and us-east; voice-to-voice ~750ms vs Twilio + OpenAI on East Coast.

Q: Cost at 100k call-min/month? Compute ~$30, Postgres ~$10, OpenAI Realtime ~$30k. Infra is rounding error — pick what's productive.

Q: HIPAA? Railway doesn't sign BAAs as of May 2026. For HIPAA, run on AWS/GCP/Azure with their BAA.

Sources

Share

Try CallSphere AI Voice Agents

See how AI voice agents work for your industry. Live demo available -- no signup required.