WorldVC Platform Guides

Everything an operator needs, in one place. Product runbooks are hosted with their engines; module deploy guides live on this page.

VocalizeCloud · voice

Voice engine runbook

Onboard a number, transfer policy, recording, capture delivery, troubleshooting, admin API.

AgentCloud · chat

AI agents operator guide

Tenants, agents, the one-tag embed, token billing, admin API, troubleshooting.

Sales

Client onboarding one-pager

The white-label pitch: keep your number, your domain, your brand. Integration tiers.

Modules

CRM · Meetings · Communications

Deploy each module on Railway and wire it into the platform - sections below.

Deploying a module (common pattern)

CRM, Meetings, and Communications are Next.js modules in the monorepo (apps/*). Each deploys as its own Railway service:

  1. Railway → + Create → GitHub RepoYore-code/VC, branch main.
  2. Leave Root Directory empty (repo root) and add the variable RAILWAY_DOCKERFILE_PATH = apps/<module>/Dockerfile. Module images build from the repo root so the workspace packages resolve - setting Root Directory to the app folder breaks the build.
  3. Rename the service to the module's name.
  4. Variables: add DATABASE_URL via the reference picker (never type ${"{{"}…} by hand). Prefer a separate database (or at least separate schema) per module.
  5. Generate a domain (Next.js listens on 3000) or attach a custom domain (CNAME + TXT, same drill as console/ai).
  6. The Dockerfile runs prisma db push on boot - the schema creates itself. Check /api/health.
Modules share one Postgres server fine, but Prisma manages each module's tables - keep each module in its own database name to avoid collisions (e.g. vc_crm, vc_meetings, vc_comms).

CRM

Contacts, companies, a kanban deal pipeline (Lead → Qualified → Proposal → Won/Lost, created automatically), activity log - and the platform's lead funnel.

Wire phone calls into the pipeline

  1. Deploy CRM (pattern above). Optionally set env CRM_INGEST_SECRET to any random string.
  2. In the voice console, open the number's agent → Lead delivery → Webhook URL = https://<crm-domain>/api/ingest, Webhook secret = the same CRM_INGEST_SECRET.
  3. Save. Every captured call now lands as a Contact + Deal in the first pipeline stage, with the AI summary as the deal context.

The ingest accepts both the voice engine's call.captured envelope and a flat {name, phone, email?, reason?, source} for manual/other sources. Signature: x-vc-signature: sha256=<HMAC-SHA256 of raw body>.

EnvPurpose
DATABASE_URLModule's Postgres.
CRM_INGEST_SECRETOptional; when set, unsigned ingest posts are rejected.

Meetings

Event types, weekly availability, bookings - plus a brand-neutral public booking page per event type at /book/<slug>.

  1. Deploy (pattern above). Open /app → set Availability (per weekday) → create an Event type.
  2. Share https://<meetings-domain>/book/<slug> - or put it behind the client's own subdomain via CNAME.
  3. Bookings appear in /app/bookings; cancel from there.
Times are org/server-local for now - set the container's TZ env to the client's timezone. Per-org timezones are the flagged follow-up.

Communications

A unified inbox for texts AND calls on the same Twilio account the voice engine uses: threads with calls interleaved, a Calls tab (AI-captured leads, transcripts, recording/voicemail playback), per-number AI call answering, click-to-call, and missed-call text-back. One number, two brains: the number's SMS webhook points at comms, its voice webhook at the voice engine.

  1. Deploy (pattern above) with TWILIO_ACCOUNT_SID + TWILIO_AUTH_TOKEN (and PUBLIC_BASE_URL if behind a proxy).
  2. Register the client's number(s) on the Numbers page (exact E.164).
  3. In Twilio, set each number's “A message comes in” webhook to POST https://<comms-domain>/api/twilio/inbound.
  4. Inbound texts thread into the inbox; replies send from the same number.
  5. Calls: toggle AI call answering on a number (needs the voice engine env below) - comms writes the agent config, then asks the engine to repoint the VoiceUrl (the engine is the single writer of Twilio voice config). The Call handling panel sets human transfer (any country - enable it in Twilio Geo Permissions first), the whisper announcement name, and recording. Captures land on the Calls tab via the engine's signed webhook; Sync history backfills.
  6. Click-to-call: the client sets a callback phone in Settings; the Call button rings it first, then bridges to the customer from the business number. Guardrails: known counterparties only, US-only unless CALL_ALLOW_INTL, daily cap, 1h limit. Completed bridges meter to the usage pipe (international legs as bridge-intl at their own wholesale rate).
EnvPurpose
DATABASE_URLModule's Postgres.
TWILIO_ACCOUNT_SID / TWILIO_AUTH_TOKENSend + validate inbound signatures; place bridge calls.
TWILIO_VALIDATEfalse only for local debugging.
VOICE_ENGINE_URL / VOICE_ADMIN_TOKENThe voice engine + its admin token - powers AI answering, Call handling, sync, recording playback.
ONBOARDING_URL / CLIENT_GRANT_SECRETBridge-minute metering into the Welcome Desk usage pipe (signed).
CALL_DAILY_CAP / CALL_ALLOW_INTLClick-to-call guardrails (default 50/day, US-only).
COMMS_EVENTS_URL / COMMS_EVENTS_SECRETOptional: publish comms.message.* / comms.call.* platform events.

Domains cheat-sheet

Any service → any branded domain, the same three steps every time:

  1. Railway service → Settings → Networking → + Custom Domain → enter it.
  2. Add the two records Railway shows to the domain's DNS: a CNAME (name = the subdomain) and a TXT (_railway-verify.<subdomain>).
  3. Wait for the row to go green; TLS issues automatically. ("Train has not arrived" = records not propagated/verified yet.)