Open-source, dockerized reference implementation to manage Exotel WhatsApp Business APIs with a REST backend and admin UI.
Disclaimer: This is an unofficial community project and is not affiliated with, endorsed by, or maintained by Exotel.
Built with Codex app and love from Bengaluru.
- REST API for auth, credential management, messaging, templates, onboarding links, and webhooks.
- React admin UI for day-to-day operations (send tests, manage templates, view webhooks).
- Queue-based sending with BullMQ + Redis; Prometheus metrics and health endpoints.
- Docker-first: dev and prod compose files, multi-stage Dockerfiles for API and UI.
- API: Node.js + TypeScript (Express), Prisma + PostgreSQL, Redis + BullMQ for queues
- UI: React + Vite single-page app
- Infra: Docker / docker-compose, optional Caddy reverse proxy
- Node.js 20+
- npm
- Docker and Docker Compose
- Access to Exotel WhatsApp Business API credentials (api_key, api_token, subdomain, sid)
npm install
npm -w apps/api run prisma:generate
npm -w apps/api run prisma:migrate -- --name init
npm -w apps/api run prisma:seed
docker compose -f docker-compose.dev.yml up --buildAccess:
- API at http://localhost:4000
- UI at http://localhost:5173
- Seed login: admin@example.com / changeme
Use one of these commands to create the default admin user (admin@example.com / changeme):
Local npm run:
npm -w apps/api run prisma:seedDocker (dev compose):
docker compose -f docker-compose.dev.yml run --rm api npm run prisma:seedIf the user already exists, the seed is safe to run again.
Copy apps/api/.env.example to .env in the same folder and set:
DATABASE_URL(e.g.,postgresql://postgres:postgres@db:5432/exotel_whatsapp)REDIS_URLJWT_SECRETEXOTEL_REGION(e.g.,api.exotel.comorapi.in.exotel.com)EXOTEL_WEBHOOK_SECRET(optional, enables HMAC validation for incoming webhooks)
Use the UI (Credentials page) or call POST /api/v1/credentials with label, apiKey, apiToken, subdomain, sid, region. All messaging/template/onboarding calls use these credentials. For template APIs against Exotel, also provide wabaId per request.
docker compose -f docker-compose.prod.yml build
docker compose -f docker-compose.prod.yml up -d- API exposed on port 4000
- UI exposed on port 8080 via reverse proxy (Caddy)
- Source files:
docs/index.html,docs/coverage.html,docs/openapi.yaml,docs/styles.css,docs/app.js,docs/CNAME - Deployment workflow:
.github/workflows/pages.yml - Live URL:
https://vinodspattar.in/Exotel-WhatsApp/ - Coverage matrix URL:
https://vinodspattar.in/Exotel-WhatsApp/coverage.html - Static OpenAPI URL:
https://vinodspattar.in/Exotel-WhatsApp/openapi.yaml - In repository settings, set Pages source to
GitHub Actionsonce.
POST /api/v1/auth/login– email/password loginPOST /api/v1/auth/refreshGET/POST /api/v1/credentialsGET /api/v1/messages,GET /api/v1/messages/:id,POST /api/v1/messages(single or bulk),POST /api/v1/messages/:id/cancelGET /api/v1/templates(local cache) orGET /api/v1/templates?remote=true&credentialId=...&wabaId=...for live Exotel list;POST /api/v1/templates;PUT /api/v1/templates/:id;DELETE /api/v1/templates;POST /api/v1/templates/upload-sampleGET /api/v1/onboarding-links,POST /api/v1/onboarding-links,GET /api/v1/onboarding-links/validate?token=...POST /api/v1/webhooks/exotel,GET /api/v1/webhooks/logs- Health:
/healthz,/readyz, metrics at/metrics - OpenAPI:
/docs/openapi.yaml(file atapps/api/openapi.yml)
- Messaging API (developer.exotel.com/api/whatsapp): supports canonical Exotel payload (
whatsapp.messages[]) with strict E.164 validation,custom_data,status_callback, and bulk sends up to 100 messages; status available via stored message record and webhook ingestion. - Template Management API (developer.exotel.com/api/whatsapp-template-management-apis): supports list/create/update/delete with required
waba_idand sample media upload (/api/v1/templates/upload-sample). - Onboarding API (developer.exotel.com/api/whatsapp-onboarding-apis): supports link generation (up to 50 per request) and token validation (
/api/v1/onboarding-links/validate).
- Queue
send-messages(BullMQ) sends outbound messages via Exotel. - Run with
node dist/worker.js(already wired in compose).
apps/api– Express API, Prisma schema, queue worker, Dockerfileapps/ui– React + Vite admin UI, Dockerfiledocker-compose.dev.yml– dev stackdocker-compose.prod.yml– prod stack + Caddydeploy/Caddyfile– reverse proxy config
- Placeholder vitest setup. Add unit tests for Exotel client, auth, queue handlers, and integration tests with Testcontainers.
- Template, onboarding, and message sends are forwarded to Exotel; failures are returned as API errors and persisted in message/audit state.
- Redis is recommended; without it, queue/rate-limit features will not work.
- Fork and clone, then create a feature branch (
git checkout -b feature/xyz). - Keep changes lint-clean:
npm run lint; add tests where possible (npm run test). - Ensure Prisma schema changes include migrations and regenerate client.
- Submit PRs with a brief summary, testing notes, and screenshots for UI changes.
- Respect the seed credentials; avoid committing real Exotel secrets.
MIT (see package.json).