Voicebox is a self-serve voice booking widget by APPGAMBiT for Indian businesses. The flow is: configure, embed, and start taking visit bookings from any web page.
| Landing | Setup |
|---|---|
![]() |
![]() |
- SST v4 AWS components
- Vite + React admin/configuration app
- S3 + CloudFront static hosting for the web app and embeddable widget script
- Cognito Hosted UI for signup/login
- API Gateway HTTP API + Lambda for backend APIs
- DynamoDB single-table storage for accounts, widget config, usage, and bookings
- xAI Voice Agent API (Grok realtime) with browser-safe ephemeral tokens
┌──────────────────────────────────────────────┐
│ Voicebox Architecture │
└──────────────────────────────────────────────┘
Tenant admin End user (on customer's site)
│ │
│ HTTPS │ HTTPS
▼ ▼
┌──────────────────────────────────────────────────────────────┐
│ CloudFront (CDN) │
└────────┬────────────────────────────────────┬────────────────┘
│ static (HTML/JS/CSS/embed.js) │ /login redirect
▼ ▼
┌──────────────────────┐ ┌────────────────────────┐
│ S3 (StaticSite) │ │ Cognito Hosted UI │
│ ├─ index.html │ │ + User Pool │
│ ├─ preview.html │ │ (post-confirm Lambda │
│ ├─ assets/*.js,*.css│ │ seeds tenant in DDB) │
│ └─ embed/widget.js │ └───────────┬────────────┘
└──────────────────────┘ │
│ id_token (implicit)
┌──────────────────────────────────┘
│ Authorization: Bearer
▼
┌──────────────────────────────────────────────────────────────┐
│ API Gateway HTTP API │
│ /me /dashboard /calendar /widgets /widgets/{id}/... │
└─────────────────────────────┬────────────────────────────────┘
│ application/json only
▼
┌──────────────┐
│ Lambda │
│ (Node 22) │
└──────┬───────┘
│
▼
┌──────────────┐
│ DynamoDB │
│ single table │
│ pk/sk + GSI1 │
└──────────────┘
── voice audio bypasses our infra entirely ──
End user browser ═══ WebSocket ═══► wss://api.x.ai/v1/realtime
(ephemeral token from POST /widgets/{id}/session)
Boundary
• Static UI + embed script → S3 + CloudFront (no Lambda)
• JSON API + tenant data → API Gateway → Lambda → DynamoDB
• Voice audio bytes → browser ↔ xAI directly
The customer-facing embed script (/embed/voice-booking-widget.js) is served from
the same CloudFront distribution, so 3rd-party sites that paste the snippet pull
it from S3 + CloudFront — no Lambda hop. The Lambda only ever returns
application/json; voice audio never traverses our infrastructure.
cp .env.example .env
# put your real xAI key in .env
npm install
npm run devSST prints the deployed API URL and starts the Vite app in dev mode.
# first deploy — generates the CloudFront URL
npx sst deploy
# read the printed `web` URL, then redeploy with it set
# (this registers it as a Cognito callback so hosted-UI sign-in works)
APP_URL="https://your-xxxxxxx.cloudfront.net" npx sst deployIf you later add a custom domain, set APP_URL to that origin instead.
- New user signs up with Cognito.
- The post-confirmation trigger creates a DynamoDB account on the default free plan.
- Pick a pre-configured template: clinic appointment, salon visit, jewellery store, property site visit, or restaurant table.
- Adjust business name, booking type, location, languages, voice (Female / Male), brand color, weekly availability, and welcome greeting.
- Store the widget config, selected template, and category in DynamoDB under the signed-in tenant.
- Generate an embed snippet and test it in the dashboard preview iframe.
- Paste the snippet into any website.
- Visitor speaks Hindi, English, or Hinglish and books a visit.
Every new Cognito user starts on the free plan:
- 20 voice calls per calendar month
- usage counted when the widget requests an xAI ephemeral voice session
- bookings and widget config stored per tenant in DynamoDB
<script
src="https://YOUR_WEB_DOMAIN/embed/voice-booking-widget.js"
data-api-url="https://YOUR_API_DOMAIN"
data-widget-id="WIDGET_ID"
defer
></script>Add data-preview="1" to mount the widget in test mode (no usage counted, no bookings saved). The dashboard's Setup page uses this via an iframe that loads /preview.html?widgetId=...&apiUrl=....
GET /mereturns the signed-in tenant account and plan.GET /dashboard?start=YYYY-MM-DD&end=YYYY-MM-DDreturns booking/call activity summary for the signed-in tenant. Defaults in the UI to the current month.GET /calendar?start=YYYY-MM-DD&end=YYYY-MM-DDreturns bookings grouped by day for the signed-in tenant.GET /widgetslists the signed-in tenant's widgets.POST /widgetscreates a widget config for the signed-in tenant.GET /widgets/{widgetId}returns public widget config.POST /widgets/{widgetId}/sessioncreates a 5-minute xAI ephemeral token. Pass{ "preview": true }in the body to mint a token without reserving a call against the monthly limit (used by the in-dashboard test panel).GET /widgets/{widgetId}/slotsreturns the next bookable slots computed from the widget's weekly schedule (IST), with a fallback to legacy free-text slots for older widgets.POST /widgets/{widgetId}/calls/{callId}/completestores call duration and transcript, then moves the call from pending to consumed.POST /widgets/{widgetId}/bookingsstores a confirmed visit booking.GET /widgets/{widgetId}/bookingslists recent bookings for the signed-in tenant.
TENANT#{tenantId} / ACCOUNT: plan, monthly call limit, pending calls, consumed calls, total seconds, transcript count.TENANT#{tenantId} / USAGE#{YYYY-MM}: monthly aggregate with reserved, pending, consumed, duration, and transcript counters.WIDGET#{widgetId} / CONFIG: public widget configuration.WIDGET#{widgetId} / CALL#{callId}: pending or consumed voice call with duration and transcript.WIDGET#{widgetId} / BOOKING#{timestamp}#{bookingId}: confirmed booking.
Activity records include activityType for dashboard buckets:
new_bookingcancelled_bookinggeneral_inquiryspam_fake
The current slots endpoint computes availability from each widget's weekly schedule. The next step is to swap the computation for a provider boundary that can sync from external calendars (Google Calendar, Cal.com, Calendly) or vertical systems, while keeping the widget and voice tool contract stable.
- xAI Voice Agent docs — realtime WebSocket API, tools, ephemeral tokens
- xAI API console — get your
XAI_API_KEY - SST v4 docs — components used:
Dynamo,CognitoUserPool,ApiGatewayV2,StaticSite
MIT — see LICENSE.

