Install
openclaw skills install @britrik/elevenlabs-twilio-memory-bridgeFastAPI personalization webhook that adds persistent caller memory and dynamic context injection to ElevenLabs Conversational AI agents on Twilio. No audio proxying, file-based persistence, OpenClaw compatible.
openclaw skills install @britrik/elevenlabs-twilio-memory-bridgePersonalization webhook service for ElevenLabs + Twilio voice agents with persistent caller memory.
When a call arrives on your Twilio number, ElevenLabs' native integration triggers this webhook. The bridge looks up the caller's history, loads long-term memory facts and daily context notes, combines them with a customizable soul/personality template, and returns everything as a system prompt override so your agent greets each caller with full context.
./data/, zero external dependencies| Endpoint | Method | Purpose |
|---|---|---|
/webhook/personalize | POST | ElevenLabs calls this on inbound call |
/webhook/post-call | POST | Optional post-call cleanup |
/api/memory/{phone_hash} | POST | Add long-term fact about a caller |
/api/notes | POST | Add global or caller-scoped context note |
/health | GET | Health check |
pip install -r requirements.txt.env.example to .env, fill in secretshttps://your-domain/webhook/personalize in ElevenLabs settingsuvicorn app:app --host 0.0.0.0 --port 8000ELEVENLABS_API_KEY — scoped ElevenLabs keyELEVENLABS_AGENT_ID — your agent IDOPENCLAW_API_BASE_URL — your OpenClaw instance URLPUBLIC_BASE_URL — publicly reachable URL of this serviceADMIN_API_KEY — secret for admin endpoint authPHONE_HASH_SALT — salt for phone number hashing. Generate with openssl rand -base64 32. Changing this invalidates all existing caller data.WEBHOOK_SECRET — shared secret for HMAC webhook verification. Must be set in production.| Variable | Default | Purpose |
|---|---|---|
DATA_ENCRYPTION_KEY | (unset) | Fernet key for encrypting memories and notes at rest. Generate with python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())". When unset, data is stored as plain JSON. |
SOUL_TEMPLATE_PATH | ./soul_template.md | Path to personality template file |
DATA_DIR | ./data | Directory for JSON persistence |
ALLOWED_ORIGINS | (unset) | Comma-separated CORS origins |
HOST | 0.0.0.0 | Bind address for uvicorn |
PORT | 8000 | Listen port |
LOG_LEVEL | INFO | Python logging level |
PHONE_HASH_SALT as the key before storage. Changing the salt invalidates existing caller data.DATA_ENCRYPTION_KEY is set. Data is stored as plain JSON when the key is not configured.WEBHOOK_SECRET is required in production. Webhooks are rejected when the secret is not set (fail-closed)./api/memory, /api/notes) are limited to 30 requests per minute. Webhook endpoints are limited to 60 per minute.fcntl) to prevent race conditions under concurrent access.DATA_DIR) is created with 0o700 permissions. JSON files are written with 0o600.v1.2.0 introduces breaking security changes:
PHONE_HASH_SALT is now required — Previously, phone numbers were hashed with unsalted SHA-256. Now HMAC-SHA256 with a salt is required. Existing caller data will be unreachable after upgrading because the hash keys change. You must accept data loss and start fresh (v1.2.0 uses a different hashing algorithm).
WEBHOOK_SECRET is now required — Previously optional for development. Now mandatory in all environments. Webhooks without a valid secret are rejected.
DATA_ENCRYPTION_KEY is optional but recommended — When set, all new memories and notes are encrypted at rest. Existing unencrypted data remains readable.
openssl rand -base64 32openssl rand -hex 32python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())".envALLOWED_ORIGINS now defaults to disabledWEBHOOK_SECRET