AI Phone Assistant — Twilio + OpenAI Realtime + Cloudflare Workers

Template for deploying an AI voice assistant with Twilio, OpenAI Realtime API, and Cloudflare Workers

View the Project on GitHub jmoore2333/twilio-openai-voice-assistant-cloudflare-template

Cloudflare D1 Setup

Use this path if you want the simplest Cloudflare-native storage option.

The included ./scripts/setup.sh script is the easiest way to get started. It automates the main setup steps described below so you can go from clone to deployed Worker with less manual Wrangler work.

Fastest Path

Run the setup script:

./scripts/setup.sh

It can:

If you prefer to do the steps manually, use the workflow below.

1. Create a D1 database

npx wrangler d1 create voice-assistant-template

Copy the returned database_id.

2. Add the D1 binding to wrangler.toml

Uncomment the [[d1_databases]] block and fill in your values:

[[d1_databases]]
binding = "DB"
database_name = "voice-assistant-template"
database_id = "replace-with-your-d1-database-id"

3. Apply the schema

Create the local development database:

npx wrangler d1 execute voice-assistant-template --local --file=docs/schema-d1.sql

Create the remote database schema:

npx wrangler d1 execute voice-assistant-template --remote --file=docs/schema-d1.sql

4. Configure Worker secrets

wrangler secret put OPENAI_API_KEY
wrangler secret put TWILIO_AUTH_TOKEN
wrangler secret put RESEND_API_KEY

RESEND_API_KEY is optional. If you skip it, email delivery will be disabled.

5. Local development

Copy .dev.vars.example to .dev.vars and set:

6. Deploy

npm run deploy

7. Run a real inbound smoke test

After deploy:

  1. Set your Twilio number to POST https://<your-domain>/voice/incoming
  2. Place one short test call
  3. Run the verification queries in inbound-smoke-test.md

8. Cloudflare Access

If your Worker sits behind Cloudflare Access, create bypass rules for the Twilio-facing paths:

If you turn on the optional outbound starter later, also bypass:

Keep /voice/outbound behind your own authentication. That route is for your app or admin tooling, not for Twilio.

Notes