An AI-run call center on the customer's own number. A whole floor - agents, team leads, and an AI management layer - with nobody to hire, schedule, or pay by the hour. This runbook is for operators.
A Virtual Call-Center staffs five roles, top of the house to the floor. Only the call-facing roles carry a voice; the management layer supervises and reports silently.
| Role | Layer | On the phone? | What it does |
|---|---|---|---|
| Site Manager also Box Manager | Management | No | Owns the whole site. Sets the operating plan and signs the daily report. |
| Operations Manager | Management | No | Guards the service level. Rebalances staffing across shifts to hit SLA. |
| Shift Manager | Management | No | Runs the shift. Opens and closes the floor and keeps the queue healthy. |
| Team Lead | Supervisor | Yes | Runs a pod of agents and takes the escalations agents cannot close. |
| Agent required | Frontline | Yes | Answers the calls, has the conversation, captures what the caller needs. |
A call center is only "up" once it has at least one Agent seat. Every other role is a layer the customer can add or leave off.
Point a center's number VoiceUrl at POST /voice. A live center with an Agent connects the caller to the media bridge (OpenAI Realtime, G.711 mu-law both ways); an unknown number, a closed floor, or a center with no Agent seat gets a brand-neutral spoken message and hangs up.
caller → the customer's number (DID or TFN) → POST /voice
→ <Connect><Stream> to the media bridge
→ an Agent persona greets in its assigned voice, converses,
captures name / callback / reason (capture_message)
→ needs a lead? the agent calls escalate_to_team_lead → the SAME live
call is handed to the Team Lead persona (voice + instructions swap in
place; no human dialed, no dead end)
→ on hangup the call is logged (agent voice, escalated?, seconds, summary)
so the management layer rolls it into a shift report
Call-facing roles pick from a named cast (Aria, Marcus, ...) in three tiers - standard, signature, and studio (most lifelike). The raw speech engine behind each voice is never shown to a customer. The same cast powers the single AI receptionist (VocalizeCloud), so a customer who runs both hears one consistent roster.
Open /console, paste your ADMIN_TOKEN, and Connect.
Pick a call center (or + New), set the number, business name, timezone, and greeting, then staff each role with the seat steppers and give every call-facing role a voice. Save roster writes it. The monthly seat estimate updates live at the bottom.
The live view of the staffed org: the management row, the Team Lead row, and the wall of Agent seats, with the headcount and monthly seat cost. Open the floor takes the center live - it only works once at least one Agent seat is staffed. Close floor stops taking calls without touching the roster.
Everything the console does is on a Bearer ADMIN_TOKEN API. Roster changes take effect immediately.
| Verb | Path | Purpose |
|---|---|---|
GET | /admin/roles | Role catalog (public) |
GET | /admin/voices | Voice catalog, provider stripped (public) |
GET | /admin/centers | List call centers |
GET | /admin/centers/:number | One center + its resolved floor |
PUT | /admin/centers/:number | Create or update a center + roster |
POST | /admin/centers/:number/live | Open or close the floor ({"live":true}) |
GET | /admin/centers/:number/report | Shift report: calls, escalation rate, avg handle time (?since=) |
DELETE | /admin/centers/:number | Remove a center |
GET | /admin/requests | Concierge number requests |
POST | /admin/assist | Console assistant (needs OPENAI_API_KEY) |
curl -X PUT https://<host>/admin/centers/+18885330466 \
-H "authorization: Bearer $ADMIN_TOKEN" -H "content-type: application/json" \
-d '{"businessName":"Northside Support","timezone":"America/Chicago",
"staffing":[
{"roleId":"operations_manager","seats":1},
{"roleId":"team_lead","seats":2,"voiceId":"marcus"},
{"roleId":"agent","seats":8,"voiceId":"aria"}
]}'
The customer's welcome link opens /setup?grant=…, a signed deep link (same HMAC contract as the voice engine, secret CLIENT_GRANT_SECRET). They provide their number, staff the roster, pick voices, and go live without an admin token. Customers who want us to source or port a number file a concierge request there instead.
Each staffed seat carries a flat monthly USD fee. Agents and Team Leads also meter call minutes at their voice's per-minute rate. Everything is in US dollars.
DATABASE_URL. Without it the engine runs an env-only demo center so the console still works.ADMIN_TOKEN (openssl rand -hex 24).CLIENT_GRANT_SECRET (self-serve links), OPENAI_API_KEY (console assistant).GET /healthz touches the call_center table and reports store, role, and voice counts - a live query, not an env flag, so a dead database reads as degraded.