welldun. offhook

Getting started

Quickstart

Run Offhook on your machine, talk to an agent in your browser, then place a real phone call.

What you need

  • Python 3.13 and uv.
  • Docker, to run Postgres.
  • API keys from Deepgram, Cartesia and Groq. All three have free tiers.
  • For phone calls only: a Plivo account with a number, and a way to expose your machine to the internet, such as ngrok.

1. Install and configure

Terminal
git clone https://github.com/welldunai/offhook.git
cd offhook
uv venv && source .venv/bin/activate
uv pip install -e .
cp .env.example .env

In .env, set DEEPGRAM_API_KEY, CARTESIA_API_KEY, GROQ_API_KEY and a master encryption key, which you can generate with:

Terminal
python -c "import os,base64;print(base64.b64encode(os.urandom(32)).decode())"
# paste the output into .env as MASTER_ENCRYPTION_KEY

2. Start Postgres and create a dev tenant

Terminal
docker compose up -d
alembic upgrade head
python -m app.admin seed-dev --voice-id 05a69c2d-457a-4802-8f91-628cb158b522

seed-dev creates a tenant, stores the provider keys from .env as encrypted connections, creates a demo agent, and prints two values:

  • An API key, shown once. Export it so the examples below work as written: export OFFHOOK_KEY="vk_dev_…"
  • A DEV_AGENT_ID. Add it to .env.

3. Talk to the agent in your browser

Terminal
python run.py

Open http://localhost:8000, allow the microphone and start talking. The playground runs the same pipeline as a phone call over WebRTC, and shows live transcripts and the latency of each stage.

4. Place a phone call

Phone calls need three more things:

  • Carrier keys. Add PLIVO_AUTH_ID, PLIVO_AUTH_TOKEN and PLIVO_FROM_NUMBER to .env before running seed-dev, so the demo agent gets a telephony connection. For Twilio, add a telephony connection through the API instead.
  • A public URL. The carrier calls back into Offhook when the call is answered. Run ngrok http 8000 and set PUBLIC_BASE_URL in .env to the https address it prints.
  • The worker. It dials queued calls and delivers webhooks. Run python -m app.worker in a second terminal.

Restart python run.py so it picks up the new .env, then place the call:

curl -X POST http://localhost:8000/v1/calls \
  -H "Authorization: Bearer $OFFHOOK_KEY" \
  -H "Idempotency-Key: first-call" \
  -H "Content-Type: application/json" \
  -d '{
    "agent_id": "<DEV_AGENT_ID>",
    "to_number": "+14155550123",
    "context": { "patient_name": "Priya", "appointment_time": "Tuesday at 3 PM" }
  }'

5. Get the result

Fetch the call, or subscribe to webhooks to be told when it changes. Once the call ends, it has an outcome, a transcript and a full event log.

curl http://localhost:8000/v1/calls/8f2c4d1e-6b7a-4c2e-9f1d-3a5b7c9e1f20 \
  -H "Authorization: Bearer $OFFHOOK_KEY"

Next steps