channelkit 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (237) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +829 -0
  3. package/config.example.yaml +37 -0
  4. package/dist/api/middleware/auth.d.ts +14 -0
  5. package/dist/api/middleware/auth.d.ts.map +1 -0
  6. package/dist/api/middleware/auth.js +130 -0
  7. package/dist/api/middleware/auth.js.map +1 -0
  8. package/dist/api/routes/config.d.ts +4 -0
  9. package/dist/api/routes/config.d.ts.map +1 -0
  10. package/dist/api/routes/config.js +794 -0
  11. package/dist/api/routes/config.js.map +1 -0
  12. package/dist/api/routes/dashboard.d.ts +4 -0
  13. package/dist/api/routes/dashboard.d.ts.map +1 -0
  14. package/dist/api/routes/dashboard.js +89 -0
  15. package/dist/api/routes/dashboard.js.map +1 -0
  16. package/dist/api/routes/inbound.d.ts +4 -0
  17. package/dist/api/routes/inbound.d.ts.map +1 -0
  18. package/dist/api/routes/inbound.js +293 -0
  19. package/dist/api/routes/inbound.js.map +1 -0
  20. package/dist/api/routes/logs.d.ts +4 -0
  21. package/dist/api/routes/logs.d.ts.map +1 -0
  22. package/dist/api/routes/logs.js +49 -0
  23. package/dist/api/routes/logs.js.map +1 -0
  24. package/dist/api/routes/mcp.d.ts +4 -0
  25. package/dist/api/routes/mcp.d.ts.map +1 -0
  26. package/dist/api/routes/mcp.js +100 -0
  27. package/dist/api/routes/mcp.js.map +1 -0
  28. package/dist/api/routes/restart.d.ts +4 -0
  29. package/dist/api/routes/restart.d.ts.map +1 -0
  30. package/dist/api/routes/restart.js +11 -0
  31. package/dist/api/routes/restart.js.map +1 -0
  32. package/dist/api/routes/send.d.ts +4 -0
  33. package/dist/api/routes/send.d.ts.map +1 -0
  34. package/dist/api/routes/send.js +66 -0
  35. package/dist/api/routes/send.js.map +1 -0
  36. package/dist/api/routes/settings.d.ts +4 -0
  37. package/dist/api/routes/settings.d.ts.map +1 -0
  38. package/dist/api/routes/settings.js +133 -0
  39. package/dist/api/routes/settings.js.map +1 -0
  40. package/dist/api/routes/tunnel.d.ts +4 -0
  41. package/dist/api/routes/tunnel.d.ts.map +1 -0
  42. package/dist/api/routes/tunnel.js +209 -0
  43. package/dist/api/routes/tunnel.js.map +1 -0
  44. package/dist/api/routes/twilio.d.ts +4 -0
  45. package/dist/api/routes/twilio.d.ts.map +1 -0
  46. package/dist/api/routes/twilio.js +138 -0
  47. package/dist/api/routes/twilio.js.map +1 -0
  48. package/dist/api/routes/update.d.ts +4 -0
  49. package/dist/api/routes/update.d.ts.map +1 -0
  50. package/dist/api/routes/update.js +42 -0
  51. package/dist/api/routes/update.js.map +1 -0
  52. package/dist/api/server.d.ts +52 -0
  53. package/dist/api/server.d.ts.map +1 -0
  54. package/dist/api/server.js +415 -0
  55. package/dist/api/server.js.map +1 -0
  56. package/dist/api/types.d.ts +61 -0
  57. package/dist/api/types.d.ts.map +1 -0
  58. package/dist/api/types.js +3 -0
  59. package/dist/api/types.js.map +1 -0
  60. package/dist/channels/base.d.ts +15 -0
  61. package/dist/channels/base.d.ts.map +1 -0
  62. package/dist/channels/base.js +20 -0
  63. package/dist/channels/base.js.map +1 -0
  64. package/dist/channels/email/gmail.d.ts +36 -0
  65. package/dist/channels/email/gmail.d.ts.map +1 -0
  66. package/dist/channels/email/gmail.js +351 -0
  67. package/dist/channels/email/gmail.js.map +1 -0
  68. package/dist/channels/email/index.d.ts +3 -0
  69. package/dist/channels/email/index.d.ts.map +1 -0
  70. package/dist/channels/email/index.js +8 -0
  71. package/dist/channels/email/index.js.map +1 -0
  72. package/dist/channels/email/resend.d.ts +29 -0
  73. package/dist/channels/email/resend.d.ts.map +1 -0
  74. package/dist/channels/email/resend.js +155 -0
  75. package/dist/channels/email/resend.js.map +1 -0
  76. package/dist/channels/endpoint/index.d.ts +21 -0
  77. package/dist/channels/endpoint/index.d.ts.map +1 -0
  78. package/dist/channels/endpoint/index.js +80 -0
  79. package/dist/channels/endpoint/index.js.map +1 -0
  80. package/dist/channels/sms/index.d.ts +37 -0
  81. package/dist/channels/sms/index.d.ts.map +1 -0
  82. package/dist/channels/sms/index.js +163 -0
  83. package/dist/channels/sms/index.js.map +1 -0
  84. package/dist/channels/telegram/index.d.ts +24 -0
  85. package/dist/channels/telegram/index.d.ts.map +1 -0
  86. package/dist/channels/telegram/index.js +231 -0
  87. package/dist/channels/telegram/index.js.map +1 -0
  88. package/dist/channels/voice/index.d.ts +62 -0
  89. package/dist/channels/voice/index.d.ts.map +1 -0
  90. package/dist/channels/voice/index.js +286 -0
  91. package/dist/channels/voice/index.js.map +1 -0
  92. package/dist/channels/whatsapp/index.d.ts +31 -0
  93. package/dist/channels/whatsapp/index.d.ts.map +1 -0
  94. package/dist/channels/whatsapp/index.js +383 -0
  95. package/dist/channels/whatsapp/index.js.map +1 -0
  96. package/dist/cli/commands/demo.d.ts +4 -0
  97. package/dist/cli/commands/demo.d.ts.map +1 -0
  98. package/dist/cli/commands/demo.js +55 -0
  99. package/dist/cli/commands/demo.js.map +1 -0
  100. package/dist/cli/commands/init.d.ts +2 -0
  101. package/dist/cli/commands/init.d.ts.map +1 -0
  102. package/dist/cli/commands/init.js +254 -0
  103. package/dist/cli/commands/init.js.map +1 -0
  104. package/dist/cli/commands/install-skill.d.ts +4 -0
  105. package/dist/cli/commands/install-skill.d.ts.map +1 -0
  106. package/dist/cli/commands/install-skill.js +60 -0
  107. package/dist/cli/commands/install-skill.js.map +1 -0
  108. package/dist/cli/commands/send.d.ts +5 -0
  109. package/dist/cli/commands/send.d.ts.map +1 -0
  110. package/dist/cli/commands/send.js +46 -0
  111. package/dist/cli/commands/send.js.map +1 -0
  112. package/dist/cli/commands/start.d.ts +5 -0
  113. package/dist/cli/commands/start.d.ts.map +1 -0
  114. package/dist/cli/commands/start.js +129 -0
  115. package/dist/cli/commands/start.js.map +1 -0
  116. package/dist/cli/helpers.d.ts +26 -0
  117. package/dist/cli/helpers.d.ts.map +1 -0
  118. package/dist/cli/helpers.js +120 -0
  119. package/dist/cli/helpers.js.map +1 -0
  120. package/dist/cli/index.d.ts +3 -0
  121. package/dist/cli/index.d.ts.map +1 -0
  122. package/dist/cli/index.js +282 -0
  123. package/dist/cli/index.js.map +1 -0
  124. package/dist/cli/wizards/channel.d.ts +4 -0
  125. package/dist/cli/wizards/channel.d.ts.map +1 -0
  126. package/dist/cli/wizards/channel.js +285 -0
  127. package/dist/cli/wizards/channel.js.map +1 -0
  128. package/dist/cli/wizards/provision.d.ts +4 -0
  129. package/dist/cli/wizards/provision.d.ts.map +1 -0
  130. package/dist/cli/wizards/provision.js +213 -0
  131. package/dist/cli/wizards/provision.js.map +1 -0
  132. package/dist/cli/wizards/service.d.ts +5 -0
  133. package/dist/cli/wizards/service.d.ts.map +1 -0
  134. package/dist/cli/wizards/service.js +212 -0
  135. package/dist/cli/wizards/service.js.map +1 -0
  136. package/dist/cli.d.ts +3 -0
  137. package/dist/cli.d.ts.map +1 -0
  138. package/dist/cli.js +6 -0
  139. package/dist/cli.js.map +1 -0
  140. package/dist/config/parser.d.ts +6 -0
  141. package/dist/config/parser.d.ts.map +1 -0
  142. package/dist/config/parser.js +37 -0
  143. package/dist/config/parser.js.map +1 -0
  144. package/dist/config/types.d.ts +170 -0
  145. package/dist/config/types.d.ts.map +1 -0
  146. package/dist/config/types.js +3 -0
  147. package/dist/config/types.js.map +1 -0
  148. package/dist/core/apiServer.d.ts +2 -0
  149. package/dist/core/apiServer.d.ts.map +1 -0
  150. package/dist/core/apiServer.js +7 -0
  151. package/dist/core/apiServer.js.map +1 -0
  152. package/dist/core/groupStore.d.ts +19 -0
  153. package/dist/core/groupStore.d.ts.map +1 -0
  154. package/dist/core/groupStore.js +48 -0
  155. package/dist/core/groupStore.js.map +1 -0
  156. package/dist/core/logger.d.ts +42 -0
  157. package/dist/core/logger.d.ts.map +1 -0
  158. package/dist/core/logger.js +142 -0
  159. package/dist/core/logger.js.map +1 -0
  160. package/dist/core/messageHandler.d.ts +15 -0
  161. package/dist/core/messageHandler.d.ts.map +1 -0
  162. package/dist/core/messageHandler.js +309 -0
  163. package/dist/core/messageHandler.js.map +1 -0
  164. package/dist/core/restart.d.ts +3 -0
  165. package/dist/core/restart.d.ts.map +1 -0
  166. package/dist/core/restart.js +35 -0
  167. package/dist/core/restart.js.map +1 -0
  168. package/dist/core/router.d.ts +56 -0
  169. package/dist/core/router.d.ts.map +1 -0
  170. package/dist/core/router.js +168 -0
  171. package/dist/core/router.js.map +1 -0
  172. package/dist/core/tunnel.d.ts +16 -0
  173. package/dist/core/tunnel.d.ts.map +1 -0
  174. package/dist/core/tunnel.js +99 -0
  175. package/dist/core/tunnel.js.map +1 -0
  176. package/dist/core/types.d.ts +54 -0
  177. package/dist/core/types.d.ts.map +1 -0
  178. package/dist/core/types.js +3 -0
  179. package/dist/core/types.js.map +1 -0
  180. package/dist/core/updater.d.ts +44 -0
  181. package/dist/core/updater.d.ts.map +1 -0
  182. package/dist/core/updater.js +264 -0
  183. package/dist/core/updater.js.map +1 -0
  184. package/dist/core/webhook.d.ts +26 -0
  185. package/dist/core/webhook.d.ts.map +1 -0
  186. package/dist/core/webhook.js +224 -0
  187. package/dist/core/webhook.js.map +1 -0
  188. package/dist/dashboard/assets/browser-D_-rzKir.js +8 -0
  189. package/dist/dashboard/assets/index-CNa084vI.js +88 -0
  190. package/dist/dashboard/assets/index-CRvIEyjF.css +1 -0
  191. package/dist/dashboard/index.html +17 -0
  192. package/dist/index.d.ts +22 -0
  193. package/dist/index.d.ts.map +1 -0
  194. package/dist/index.js +551 -0
  195. package/dist/index.js.map +1 -0
  196. package/dist/mcp/index.d.ts +3 -0
  197. package/dist/mcp/index.d.ts.map +1 -0
  198. package/dist/mcp/index.js +6 -0
  199. package/dist/mcp/index.js.map +1 -0
  200. package/dist/mcp/server.d.ts +45 -0
  201. package/dist/mcp/server.d.ts.map +1 -0
  202. package/dist/mcp/server.js +197 -0
  203. package/dist/mcp/server.js.map +1 -0
  204. package/dist/mcp/tools.d.ts +16 -0
  205. package/dist/mcp/tools.d.ts.map +1 -0
  206. package/dist/mcp/tools.js +502 -0
  207. package/dist/mcp/tools.js.map +1 -0
  208. package/dist/media/formatter.d.ts +12 -0
  209. package/dist/media/formatter.d.ts.map +1 -0
  210. package/dist/media/formatter.js +147 -0
  211. package/dist/media/formatter.js.map +1 -0
  212. package/dist/media/processor.d.ts +33 -0
  213. package/dist/media/processor.d.ts.map +1 -0
  214. package/dist/media/processor.js +145 -0
  215. package/dist/media/processor.js.map +1 -0
  216. package/dist/media/stt.d.ts +16 -0
  217. package/dist/media/stt.d.ts.map +1 -0
  218. package/dist/media/stt.js +298 -0
  219. package/dist/media/stt.js.map +1 -0
  220. package/dist/media/tts.d.ts +19 -0
  221. package/dist/media/tts.d.ts.map +1 -0
  222. package/dist/media/tts.js +135 -0
  223. package/dist/media/tts.js.map +1 -0
  224. package/dist/onboarding/index.d.ts +28 -0
  225. package/dist/onboarding/index.d.ts.map +1 -0
  226. package/dist/onboarding/index.js +144 -0
  227. package/dist/onboarding/index.js.map +1 -0
  228. package/dist/paths.d.ts +9 -0
  229. package/dist/paths.d.ts.map +1 -0
  230. package/dist/paths.js +14 -0
  231. package/dist/paths.js.map +1 -0
  232. package/dist/provisioning/twilio.d.ts +51 -0
  233. package/dist/provisioning/twilio.d.ts.map +1 -0
  234. package/dist/provisioning/twilio.js +175 -0
  235. package/dist/provisioning/twilio.js.map +1 -0
  236. package/echo-server.js +163 -0
  237. package/package.json +79 -0
package/README.md ADDED
@@ -0,0 +1,829 @@
1
+ # ChannelKit
2
+
3
+ A self-hosted messaging gateway that connects chat channels (WhatsApp, Telegram, Email) to any application via webhooks.
4
+
5
+ Think **nginx, but for chat.**
6
+
7
+ ```
8
+ 📱 WhatsApp ──┐
9
+ 💬 Telegram ──┤──→ ChannelKit ──→ Your App (webhook)
10
+ 📧 Email ──┘ (unified JSON)
11
+ ```
12
+
13
+ Your app receives every message in a **unified JSON format**, regardless of source channel. Respond with text or media, and ChannelKit routes it back through the originating channel.
14
+
15
+ ## Features
16
+
17
+ - **WhatsApp** (Baileys, optional) — QR code linking, magic codes + auto-created groups for multi-service
18
+ - **Telegram** (grammY) — bot token setup, slash commands for multi-service
19
+ - **Email** — Gmail (OAuth2 + polling) and Resend (API + polling/webhook)
20
+ - **Services model** — single or multiple services per channel, each with its own webhook
21
+ - **SMS** (Twilio) — inbound/outbound SMS via polling or webhooks
22
+ - **Voice** (Twilio) — inbound voice calls with STT, webhook, and TTS/Say responses
23
+ - **Speech-to-Text** — automatic transcription of voice messages (Google, Whisper, Deepgram)
24
+ - **Text-to-Speech** — voice responses when your webhook returns `voice: true` (Google, ElevenLabs, OpenAI)
25
+ - **Auto language detection** — STT supports multiple languages with automatic detection
26
+ - **AI formatting** — transform incoming messages with AI (OpenAI, Anthropic, Google) before forwarding to your webhook
27
+ - **MCP server** — Model Context Protocol server lets AI assistants manage channels, services, and send messages
28
+ - **Web dashboard** — SQLite-backed logs with real-time WebSocket updates
29
+ - **Async messaging API** — `replyUrl` in every webhook payload for sending messages anytime
30
+ - **Onboarding flow** — magic codes (WhatsApp) and slash commands (Telegram) for user self-service
31
+ - **Echo server** — included test server for quick experimentation
32
+
33
+ ## Quick Start
34
+
35
+ ```bash
36
+ npm install -g @dirbalak/channelkit
37
+ channelkit
38
+ ```
39
+
40
+ > **Upgrading?** If you previously installed ChannelKit without the `-g` flag (global), you should uninstall it first and reinstall globally. A local install won't put `channelkit` on your PATH, so the CLI command won't be available system-wide:
41
+ >
42
+ > ```bash
43
+ > npm uninstall @dirbalak/channelkit # remove the local install
44
+ > npm install -g @dirbalak/channelkit # reinstall globally
45
+ > ```
46
+
47
+ On first run, ChannelKit will ask how you'd like to set up:
48
+
49
+ - **Dashboard** — creates a minimal config, starts the server, and opens the dashboard in your browser. You'll get an API secret to log in and configure everything from the UI.
50
+ - **CLI wizard** — step-by-step terminal setup: pick a channel, enter credentials, set a webhook URL, and start.
51
+
52
+ All configuration is stored in `~/.channelkit/` (config, auth sessions, logs).
53
+
54
+ ### Running
55
+
56
+ ```bash
57
+ channelkit # start (opens dashboard automatically)
58
+ channelkit start -c /path/to.yaml # use a custom config file
59
+ channelkit start --tunnel # start with a public URL (Cloudflare tunnel)
60
+ ```
61
+
62
+ ### Public URL (Cloudflare Tunnel)
63
+
64
+ ChannelKit can expose your local instance to the internet using a [Cloudflare Tunnel](https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/). This is required for features like inbound webhooks (Resend, Twilio) and voice calls, which need a publicly reachable URL.
65
+
66
+ #### Quick tunnel (no setup needed)
67
+
68
+ Just run:
69
+
70
+ ```bash
71
+ channelkit start --tunnel
72
+ ```
73
+
74
+ This creates a temporary public URL via [trycloudflare.com](https://trycloudflare.com) — no Cloudflare account or installation required. The URL changes each time you restart.
75
+
76
+ > **Note:** You can also start and stop the tunnel from the dashboard at any time.
77
+
78
+ #### Fixed URL (requires setup)
79
+
80
+ If you need a stable URL that doesn't change between restarts, follow the steps below to set up a named Cloudflare Tunnel.
81
+
82
+ ##### 1. Install cloudflared
83
+
84
+ ```bash
85
+ # macOS
86
+ brew install cloudflared
87
+
88
+ # Linux (Debian/Ubuntu)
89
+ curl -L https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.deb -o cloudflared.deb
90
+ sudo dpkg -i cloudflared.deb
91
+
92
+ # Windows
93
+ winget install Cloudflare.cloudflared
94
+ ```
95
+
96
+ ##### 2. Authenticate with Cloudflare
97
+
98
+ ```bash
99
+ cloudflared tunnel login
100
+ ```
101
+
102
+ This opens your browser to authorize `cloudflared` with your Cloudflare account. You need a domain managed by Cloudflare.
103
+
104
+ ##### 3. Create a tunnel
105
+
106
+ ```bash
107
+ cloudflared tunnel create channelkit
108
+ ```
109
+
110
+ This generates a tunnel ID and a credentials file. Note the tunnel ID — you'll need it next.
111
+
112
+ ##### 4. Route DNS to the tunnel
113
+
114
+ ```bash
115
+ cloudflared tunnel route dns channelkit ck.yourdomain.com
116
+ ```
117
+
118
+ Replace `ck.yourdomain.com` with the subdomain you want to use. This creates a CNAME record pointing to the tunnel.
119
+
120
+ ##### 5. Configure ChannelKit
121
+
122
+ Add the tunnel section to your `config.yaml`:
123
+
124
+ ```yaml
125
+ tunnel:
126
+ provider: cloudflared
127
+ token: <your-tunnel-token> # from the credentials file or Cloudflare dashboard
128
+ public_url: https://ck.yourdomain.com
129
+ auto_start: true # start the tunnel automatically with ChannelKit
130
+ expose_dashboard: true # expose the dashboard through the tunnel
131
+ ```
132
+
133
+ To get the tunnel token, you can either:
134
+ - Copy it from the Cloudflare Zero Trust dashboard under **Networks → Tunnels → your tunnel → Configure**
135
+ - Or use the credentials JSON file generated by `cloudflared tunnel create`
136
+
137
+ ##### 6. Start ChannelKit with the tunnel
138
+
139
+ ```bash
140
+ channelkit start --tunnel
141
+ ```
142
+
143
+ ChannelKit will start `cloudflared` automatically and route traffic through your public URL. You can verify it's working by visiting `https://ck.yourdomain.com` in your browser.
144
+
145
+ > **Tip:** If you set `auto_start: true` in the tunnel config, you don't need the `--tunnel` flag — the tunnel starts automatically with `channelkit start`.
146
+
147
+ ## CLI Commands
148
+
149
+ ```bash
150
+ channelkit # start (auto-runs init on first run)
151
+ channelkit init # interactive setup wizard
152
+ channelkit start [-c path] # start the gateway
153
+
154
+ channelkit channel add # add a new channel interactively
155
+ channelkit channel list # list configured channels
156
+ channelkit channel remove <name> # remove a channel
157
+
158
+ channelkit service add # add a new service interactively
159
+ channelkit service list # list configured services
160
+ channelkit service remove <name> # remove a service
161
+
162
+ channelkit install-skill # install Claude Code skill
163
+ ```
164
+
165
+ ## Services & Multi-Service
166
+
167
+ ChannelKit can route messages from a single channel to multiple backend services.
168
+
169
+ ### Add a service
170
+
171
+ ```bash
172
+ channelkit service add
173
+ # → Service name: Expenses
174
+ # → Webhook: http://localhost:3000/expenses
175
+ # → Enable STT? Enable TTS?
176
+ # → ✅ Added!
177
+ ```
178
+
179
+ ### WhatsApp: Magic Codes + Groups
180
+
181
+ When a channel has multiple services, WhatsApp uses magic codes and auto-created groups:
182
+
183
+ 1. User sends "EXPENSES" to your WhatsApp number (or clicks a `wa.me` link)
184
+ 2. ChannelKit creates a group "Expenses - \<User Name\>"
185
+ 3. All messages in that group route to the service's webhook
186
+
187
+ ### Telegram: Slash Commands
188
+
189
+ For Telegram multi-service, each service gets a slash command:
190
+
191
+ 1. User sends `/expenses` in the bot chat
192
+ 2. Subsequent messages route to the Expenses service webhook
193
+
194
+ ## Speech-to-Text (STT)
195
+
196
+ Automatically transcribe voice messages before forwarding to your webhook. Configure per-service:
197
+
198
+ ```yaml
199
+ services:
200
+ myapp:
201
+ channel: whatsapp
202
+ webhook: http://localhost:3000
203
+ stt:
204
+ provider: google # google | whisper | deepgram
205
+ language: he-IL # primary language
206
+ alternative_languages: # auto-detect from these + primary
207
+ - en-US
208
+ - ar-IL
209
+ ```
210
+
211
+ **API keys via environment variables:**
212
+
213
+ - Google: `GOOGLE_STT_API_KEY` or `GOOGLE_API_KEY`
214
+ - Whisper (OpenAI): `OPENAI_STT_API_KEY` or `OPENAI_API_KEY`
215
+ - Deepgram: `DEEPGRAM_STT_API_KEY` or `DEEPGRAM_API_KEY`
216
+
217
+ ## Text-to-Speech (TTS)
218
+
219
+ When your webhook returns `{ "text": "Hello", "voice": true }`, ChannelKit synthesizes audio and sends a voice message. Configure per-service:
220
+
221
+ ```yaml
222
+ services:
223
+ myapp:
224
+ channel: whatsapp
225
+ webhook: http://localhost:3000
226
+ tts:
227
+ provider: elevenlabs # google | elevenlabs | openai
228
+ voice: 21m00Tcm4TlvDq8ikWAM # optional voice ID
229
+ ```
230
+
231
+ **API keys via environment variables:**
232
+
233
+ - Google: `GOOGLE_TTS_API_KEY` or `GOOGLE_API_KEY`
234
+ - ElevenLabs: `ELEVENLABS_TTS_API_KEY` or `ELEVENLABS_API_KEY`
235
+ - OpenAI: `OPENAI_TTS_API_KEY` or `OPENAI_API_KEY`
236
+
237
+ ## AI Formatting
238
+
239
+ ChannelKit can pass incoming messages through an AI model before forwarding them to your webhook. This enables structured data extraction, translation, classification, and other transformations — all without changing your backend.
240
+
241
+ The processing pipeline is: **STT** (optional) → **AI Format** → **Webhook**
242
+
243
+ ### Configuration
244
+
245
+ ```yaml
246
+ services:
247
+ myapp:
248
+ channel: whatsapp
249
+ webhook: http://localhost:3000
250
+ format:
251
+ provider: openai # openai | anthropic | google
252
+ model: gpt-4o-mini # optional, each provider has a sensible default
253
+ prompt: "Extract the expense amount and category as JSON"
254
+ ```
255
+
256
+ **Supported providers and defaults:**
257
+
258
+ | Provider | Default Model | API Key |
259
+ | --------- | -------------------------- | ------------------- |
260
+ | OpenAI | `gpt-4o-mini` | `OPENAI_API_KEY` |
261
+ | Anthropic | `claude-sonnet-4-20250514` | `ANTHROPIC_API_KEY` |
262
+ | Google | `gemini-2.5-flash` | `GOOGLE_API_KEY` |
263
+
264
+ API keys can be set as environment variables or in `config.yaml`:
265
+
266
+ ```yaml
267
+ settings:
268
+ openai_api_key: "sk-..."
269
+ anthropic_api_key: "sk-ant-..."
270
+ google_api_key: "..."
271
+ ```
272
+
273
+ ### Example
274
+
275
+ With this prompt:
276
+
277
+ ```
278
+ Extract: name, amount, category. Return JSON only.
279
+ ```
280
+
281
+ A message like `"Paid $45 for lunch with Sarah"` becomes:
282
+
283
+ ```json
284
+ { "name": "Sarah", "amount": 45, "category": "lunch" }
285
+ ```
286
+
287
+ Your webhook receives the formatted text. The original text is preserved in the dashboard logs.
288
+
289
+ ## Voice Channel (Twilio)
290
+
291
+ ChannelKit supports inbound voice calls via Twilio. The flow:
292
+
293
+ 1. Caller dials your Twilio number → ChannelKit answers with a greeting
294
+ 2. Caller speaks → recording is captured and transcribed (STT)
295
+ 3. Transcribed text is sent to your webhook
296
+ 4. Your webhook responds with text → ChannelKit speaks it back via TTS or `<Say>`
297
+ 5. In **conversational mode**, the loop repeats; otherwise the call ends
298
+
299
+ ### Setup
300
+
301
+ ```bash
302
+ channelkit channel add # choose Voice (Twilio)
303
+ channelkit service add # configure webhook + voice settings
304
+ ```
305
+
306
+ Voice requires a **public URL** — use `--tunnel` or `--public-url` when starting:
307
+
308
+ ```bash
309
+ channelkit start --public-url https://your-domain.com
310
+ ```
311
+
312
+ ### Voice service config
313
+
314
+ ```yaml
315
+ services:
316
+ support:
317
+ channel: voice
318
+ webhook: "http://localhost:3000/support"
319
+ stt:
320
+ provider: google
321
+ language: en-US
322
+ tts:
323
+ provider: elevenlabs
324
+ voice:
325
+ greeting: "Hello! Please speak after the beep."
326
+ hold_message: "One moment please..."
327
+ language: en-US
328
+ voice_name: Polly.Joanna
329
+ conversational: true
330
+ max_record_seconds: 30
331
+ ```
332
+
333
+ ### TTS Audio Serving
334
+
335
+ When your webhook returns `{ "voice": true }` and TTS is configured, ChannelKit synthesizes audio and plays it to the caller via `<Play>`. Audio clips are cached in memory and served via a one-time URL that expires after 60 seconds.
336
+
337
+ ## Gmail Channel Setup
338
+
339
+ Setting up a Gmail channel requires creating OAuth2 credentials in Google Cloud Console. Here's a step-by-step guide:
340
+
341
+ ### 1. Create a Google Cloud project
342
+
343
+ 1. Go to [Google Cloud Console](https://console.cloud.google.com/)
344
+ 2. Click the project dropdown at the top and select **New Project**
345
+ 3. Enter a name (e.g. "ChannelKit") and click **Create**
346
+
347
+ ### 2. Enable the Gmail API
348
+
349
+ 1. In your project, go to **APIs & Services → Library**
350
+ 2. Search for **Gmail API**
351
+ 3. Click **Gmail API** and then **Enable**
352
+
353
+ ### 3. Configure the OAuth consent screen
354
+
355
+ 1. Go to **APIs & Services → OAuth consent screen**
356
+ 2. Select **External** user type (or **Internal** if using Google Workspace) and click **Create**
357
+ 3. Fill in the required fields:
358
+ - **App name**: e.g. "ChannelKit"
359
+ - **User support email**: your email
360
+ - **Developer contact email**: your email
361
+ 4. Click **Save and Continue**
362
+ 5. On the **Scopes** page, click **Add or Remove Scopes**
363
+ 6. Search for `https://www.googleapis.com/auth/gmail.modify` and check it
364
+ 7. Click **Update** → **Save and Continue**
365
+ 8. On the **Test users** page, click **Add Users** and add the Gmail address you want to connect
366
+ 9. Click **Save and Continue** → **Back to Dashboard**
367
+
368
+ > **Note:** While your app is in "Testing" status, only the test users you added can authorize. This is fine for personal use. To remove the test user limitation, you'd need to publish the app and go through Google's verification process.
369
+
370
+ ### 4. Create OAuth2 credentials
371
+
372
+ 1. Go to **APIs & Services → Credentials**
373
+ 2. Click **Create Credentials → OAuth client ID**
374
+ 3. Select **Desktop app** as the application type
375
+ 4. Enter a name (e.g. "ChannelKit Desktop")
376
+ 5. Click **Create**
377
+ 6. Copy the **Client ID** and **Client Secret**
378
+
379
+ ### 5. Configure the channel
380
+
381
+ Add the Gmail channel via CLI:
382
+
383
+ ```bash
384
+ channelkit channel add
385
+ # → Choose Email → Gmail
386
+ # → Paste your Client ID and Client Secret
387
+ # → Set poll interval (default 30 seconds)
388
+ ```
389
+
390
+ Or add it directly to `config.yaml`:
391
+
392
+ ```yaml
393
+ channels:
394
+ gmail:
395
+ type: email
396
+ provider: gmail
397
+ client_id: "123456789-abc.apps.googleusercontent.com"
398
+ client_secret: "GOCSPX-..."
399
+ poll_interval: 30
400
+ ```
401
+
402
+ ### 6. Authorize
403
+
404
+ When you start ChannelKit, it will automatically open your browser for OAuth authorization. Sign in with the Gmail account you added as a test user, grant access, and the token is saved locally in `~/.channelkit/auth/gmail-<channel-name>.json`.
405
+
406
+ ```bash
407
+ channelkit start
408
+ # → Browser opens → sign in → authorize → done
409
+ ```
410
+
411
+ The refresh token is saved automatically. You won't need to re-authorize unless you revoke access or delete the token file.
412
+
413
+ ## Config
414
+
415
+ Default location: `~/.channelkit/config.yaml`
416
+
417
+ ```yaml
418
+ channels:
419
+ whatsapp:
420
+ type: whatsapp
421
+ number: "+972..."
422
+ telegram:
423
+ type: telegram
424
+ bot_token: "123456:ABC-DEF..."
425
+ gmail:
426
+ type: email
427
+ provider: gmail
428
+ client_id: "..."
429
+ client_secret: "..."
430
+ poll_interval: 30
431
+
432
+ services:
433
+ expenses:
434
+ channel: whatsapp
435
+ webhook: "http://localhost:3000/expenses"
436
+ code: "EXPENSES" # magic code for WhatsApp multi-service
437
+ stt:
438
+ provider: google
439
+ language: he-IL
440
+ tts:
441
+ provider: elevenlabs
442
+ assistant:
443
+ channel: telegram
444
+ webhook: "http://localhost:3000/assistant"
445
+ command: "assistant" # slash command for Telegram multi-service
446
+ ```
447
+
448
+ ## Async Messaging API
449
+
450
+ Every webhook payload includes a `replyUrl` — a callback endpoint your service can use to send messages at any time.
451
+
452
+ ### Webhook payload
453
+
454
+ ```json
455
+ {
456
+ "id": "msg_abc123",
457
+ "channel": "whatsapp",
458
+ "from": "+44123456789",
459
+ "text": "What's my balance?",
460
+ "replyUrl": "http://localhost:4000/api/send/whatsapp/44123456789%40s.whatsapp.net"
461
+ }
462
+ ```
463
+
464
+ ### Sync response (immediate)
465
+
466
+ ```json
467
+ { "text": "Your balance is $42.00" }
468
+ ```
469
+
470
+ ### Async message (anytime)
471
+
472
+ ```bash
473
+ curl -X POST "http://localhost:4000/api/send/whatsapp/44123456789%40s.whatsapp.net" \
474
+ -H "Content-Type: application/json" \
475
+ -d '{"text": "Your invoice was approved! ✅"}'
476
+ ```
477
+
478
+ ### Health check
479
+
480
+ ```
481
+ GET http://localhost:4000/api/health
482
+ → { "status": "ok", "channels": ["whatsapp"] }
483
+ ```
484
+
485
+ ## Web Dashboard
486
+
487
+ ChannelKit includes a built-in web dashboard (enabled by default) that shows:
488
+
489
+ - Real-time message log with WebSocket updates
490
+ - Message details: channel, sender, text, STT transcription, TTS usage
491
+ - Search and filter by channel
492
+ - Stats: total messages, messages by channel, average latency
493
+
494
+ All logs are stored in SQLite (`~/.channelkit/data/logs.db`) with automatic 30-day retention.
495
+
496
+ ## MCP Server
497
+
498
+ ChannelKit includes a [Model Context Protocol](https://modelcontextprotocol.io/) server that lets AI assistants (Claude, etc.) manage your messaging gateway programmatically.
499
+
500
+ ### Configuration
501
+
502
+ ```yaml
503
+ mcp:
504
+ enabled: true
505
+ stdio: true # enable stdio transport (for Claude Desktop)
506
+ secret: "my-token" # optional Bearer token for auth
507
+ ```
508
+
509
+ ### Available tools
510
+
511
+ | Tool | Description |
512
+ | ---------------- | --------------------------------------------------------- |
513
+ | `send_message` | Send a message through any channel |
514
+ | `get_messages` | Retrieve message history with search/filtering |
515
+ | `list_channels` | View all channels and their status |
516
+ | `add_channel` | Add a new channel (WhatsApp, Telegram, Email, SMS, Voice) |
517
+ | `remove_channel` | Remove a channel |
518
+ | `list_services` | View all services |
519
+ | `add_service` | Create a service with STT/TTS/format config |
520
+ | `update_service` | Modify service settings |
521
+ | `remove_service` | Remove a service |
522
+ | `get_status` | Get uptime, stats, version info, update availability |
523
+ | `update` | Update ChannelKit to the latest version |
524
+ | `set_config` | Set config values (e.g., `settings.openai_api_key`) |
525
+
526
+ ### Transports
527
+
528
+ - **Streamable HTTP** — `http://localhost:4000/mcp` (modern clients)
529
+ - **SSE** — `http://localhost:4000/sse` + `/messages` (legacy clients)
530
+ - **Stdio** — for Claude Desktop and local integrations
531
+
532
+ ### Connecting from Claude Desktop
533
+
534
+ Add to your Claude Desktop config (`claude_desktop_config.json`):
535
+
536
+ ```json
537
+ {
538
+ "mcpServers": {
539
+ "channelkit": {
540
+ "command": "channelkit",
541
+ "args": ["start", "--mcp-stdio"]
542
+ }
543
+ }
544
+ }
545
+ ```
546
+
547
+ Or connect to a running instance via HTTP at `http://localhost:4000/mcp`.
548
+
549
+ ## Claude Code Skill
550
+
551
+ ChannelKit ships with a skill file that teaches Claude Code how to set up channels, create services, and integrate messaging into your app using the MCP tools.
552
+
553
+ ```bash
554
+ channelkit install-skill # copies skill to ~/.claude/skills/channelkit/SKILL.md
555
+ ```
556
+
557
+ The installer will also print a short snippet to add to your `~/.claude/CLAUDE.md`. This ensures Claude Code always knows about ChannelKit's built-in features (TTS/STT, MCP tools, etc.) without relying on the skill trigger to fire. Add it to your `~/.claude/CLAUDE.md` (create the file if it doesn't exist):
558
+
559
+ ```markdown
560
+ ## ChannelKit
561
+
562
+ When working with WhatsApp, SMS, Voice, Telegram, or Email messaging:
563
+ - **ChannelKit has built-in TTS/STT.** Never install TTS or STT packages in the app. Configure TTS on the ChannelKit service — the app just returns `{ "text": "..." }` and ChannelKit converts it to audio automatically.
564
+ - **Use ChannelKit MCP tools** (get_status, send_message, add_channel, etc.) — not curl. If MCP tools are not available, ask the user to connect: `claude mcp add --transport http channelkit http://localhost:4000/mcp`
565
+ - **Do not install ChannelKit** unless the user explicitly asks — it's likely already running.
566
+ - Run `/channelkit` to load the full ChannelKit skill with detailed integration docs, MCP tool reference, and setup patterns.
567
+ ```
568
+
569
+ If ChannelKit runs on a different machine (e.g., a server) than Claude Code (your dev laptop), use `--print` to output the skill and transfer it:
570
+
571
+ ```bash
572
+ # On the server
573
+ channelkit install-skill --print > channelkit-skill.md
574
+
575
+ # Copy to your dev machine
576
+ scp server:channelkit-skill.md ~/.claude/skills/channelkit/SKILL.md
577
+ ```
578
+
579
+ ## Webhook API
580
+
581
+ ### Your app receives
582
+
583
+ ```json
584
+ {
585
+ "id": "msg_abc123",
586
+ "channel": "whatsapp",
587
+ "from": "+44123456789",
588
+ "type": "text",
589
+ "text": "What's the temperature?",
590
+ "timestamp": 1708420200,
591
+ "replyUrl": "http://localhost:4000/api/send/whatsapp/..."
592
+ }
593
+ ```
594
+
595
+ For voice messages with STT enabled, `type` is `"audio"` and `text` contains the transcription.
596
+
597
+ ### Your app responds
598
+
599
+ ```json
600
+ { "text": "Kitchen: 23°C 🌡️" }
601
+ ```
602
+
603
+ Or with voice:
604
+
605
+ ```json
606
+ { "text": "Kitchen is 23 degrees", "voice": true }
607
+ ```
608
+
609
+ ## Echo Server
610
+
611
+ A test server is included for quick experimentation:
612
+
613
+ ```bash
614
+ channelkit demo
615
+ ```
616
+
617
+ Runs on port 3000 and echoes back any message it receives.
618
+
619
+ ## Supported Channels
620
+
621
+ | Channel | Status | Multi-Service |
622
+ | ------------------ | ---------- | -------------------- |
623
+ | WhatsApp (Baileys) | ✅ Working | Magic codes + groups |
624
+ | Telegram (grammY) | ✅ Working | Slash commands |
625
+ | Email — Gmail | ✅ Working | — |
626
+ | Email — Resend | ✅ Working | — |
627
+ | SMS (Twilio) | ✅ Working | — |
628
+ | Voice (Twilio) | ✅ Working | — |
629
+
630
+ ## Auto-Start on Reboot
631
+
632
+ To keep ChannelKit running after a system restart, set it up as a system service.
633
+
634
+ ### macOS (launchd)
635
+
636
+ First, find the paths you'll need:
637
+
638
+ ```bash
639
+ which channelkit # e.g. /Users/you/.nvm/versions/node/v22.0.0/bin/channelkit
640
+ which node # e.g. /Users/you/.nvm/versions/node/v22.0.0/bin/node
641
+ dirname $(which node) # e.g. /Users/you/.nvm/versions/node/v22.0.0/bin
642
+ ```
643
+
644
+ Then create a plist file at `~/Library/LaunchAgents/com.channelkit.plist`, replacing all three paths below:
645
+
646
+ ```xml
647
+ <?xml version="1.0" encoding="UTF-8"?>
648
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
649
+ <plist version="1.0">
650
+ <dict>
651
+ <key>Label</key>
652
+ <string>com.channelkit</string>
653
+ <key>EnvironmentVariables</key>
654
+ <dict>
655
+ <key>PATH</key>
656
+ <string>REPLACE_WITH_OUTPUT_OF_DIRNAME_WHICH_NODE:/usr/local/bin:/usr/bin:/bin</string>
657
+ </dict>
658
+ <key>ProgramArguments</key>
659
+ <array>
660
+ <string>REPLACE_WITH_OUTPUT_OF_WHICH_NODE</string>
661
+ <string>REPLACE_WITH_OUTPUT_OF_WHICH_CHANNELKIT</string>
662
+ <string>start</string>
663
+ </array>
664
+ <key>RunAtLoad</key>
665
+ <true/>
666
+ <key>KeepAlive</key>
667
+ <true/>
668
+ <key>StandardOutPath</key>
669
+ <string>/tmp/channelkit.log</string>
670
+ <key>StandardErrorPath</key>
671
+ <string>/tmp/channelkit.err</string>
672
+ </dict>
673
+ </plist>
674
+ ```
675
+
676
+ > **Why these settings?** launchd doesn't load your shell profile (where `nvm`/`fnm`/Homebrew set up `PATH`), so both `node` and `npm` would be missing. The `EnvironmentVariables` block sets `PATH` so child processes (like auto-update) can find `npm`, and `ProgramArguments` calls `node` directly to avoid the `env: node: No such file or directory` error.
677
+
678
+ Load the service:
679
+
680
+ ```bash
681
+ launchctl load ~/Library/LaunchAgents/com.channelkit.plist
682
+ ```
683
+
684
+ To stop and remove:
685
+
686
+ ```bash
687
+ launchctl unload ~/Library/LaunchAgents/com.channelkit.plist
688
+ ```
689
+
690
+ ### Linux (systemd)
691
+
692
+ Find the binary path with `which channelkit`, then create a service file at `/etc/systemd/system/channelkit.service`:
693
+
694
+ ```ini
695
+ [Unit]
696
+ Description=ChannelKit Messaging Gateway
697
+ After=network.target
698
+
699
+ [Service]
700
+ Type=simple
701
+ User=your-username
702
+ ExecStart=REPLACE_WITH_OUTPUT_OF_WHICH_CHANNELKIT start
703
+ Restart=always
704
+ RestartSec=10
705
+ Environment=NODE_ENV=production
706
+
707
+ [Install]
708
+ WantedBy=multi-user.target
709
+ ```
710
+
711
+ Enable and start:
712
+
713
+ ```bash
714
+ sudo systemctl daemon-reload
715
+ sudo systemctl enable channelkit # start on boot
716
+ sudo systemctl start channelkit # start now
717
+ ```
718
+
719
+ Check status and logs:
720
+
721
+ ```bash
722
+ sudo systemctl status channelkit
723
+ journalctl -u channelkit -f # follow logs
724
+ ```
725
+
726
+ ## WhatsApp Setup
727
+
728
+ WhatsApp support requires the `@whiskeysockets/baileys` package, which is an **optional peer dependency** — it is not installed automatically with ChannelKit.
729
+
730
+ > **License notice:** `@whiskeysockets/baileys` depends on `libsignal-node`, which is licensed under **GPL-3.0**. By installing it, you accept the GPL-3.0 terms for that dependency. The ChannelKit core remains MIT-licensed.
731
+
732
+ ### Install Baileys
733
+
734
+ If ChannelKit is installed globally:
735
+
736
+ ```bash
737
+ npm install -g @whiskeysockets/baileys
738
+ ```
739
+
740
+ If running from a project directory:
741
+
742
+ ```bash
743
+ npm install @whiskeysockets/baileys
744
+ ```
745
+
746
+ Without this package, ChannelKit will skip any WhatsApp channels in your config and print a warning. All other channels (Telegram, Email, SMS, Voice, Endpoint) work without it.
747
+
748
+ ### Pair your device
749
+
750
+ Start ChannelKit and scan the QR code with WhatsApp:
751
+
752
+ ```bash
753
+ channelkit start
754
+ ```
755
+
756
+ Open WhatsApp on your phone > Settings > Linked Devices > Link a Device, then scan the QR code shown in the terminal.
757
+
758
+ ### Provision a new number
759
+
760
+ To buy a Twilio number and automatically pair it with WhatsApp:
761
+
762
+ ```bash
763
+ channelkit channel provision
764
+ ```
765
+
766
+ ## Development
767
+
768
+ ```bash
769
+ git clone https://github.com/dirbalak/channelkit.git
770
+ cd channelkit
771
+ npm install
772
+ npm run dev # starts with auto-reload on code changes
773
+ ```
774
+
775
+ ## Security
776
+
777
+ ChannelKit is designed to run on a dedicated server. Follow these guidelines to secure your deployment:
778
+
779
+ ### Required for production
780
+
781
+ - **Set `api_secret`** in your config — this protects all dashboard and API endpoints with Bearer token authentication. It is auto-generated on first run. Without it, anyone with network access can control your instance.
782
+ - **Run behind a reverse proxy** (nginx, Caddy, Traefik) with TLS termination. ChannelKit itself serves HTTP; the proxy handles HTTPS.
783
+ - **Use firewall rules** to restrict port 4000 to localhost if using a reverse proxy, or to trusted IPs only.
784
+
785
+ ### Credentials
786
+
787
+ - **Never commit your config** to version control. Config is stored in `~/.channelkit/` by default, outside your project directory.
788
+ - **Set a strong MCP secret** in Settings if you expose the MCP server externally.
789
+ - **Webhook signature verification** is enabled automatically for Twilio and Resend channels when `auth_token` / `webhook_secret` are configured.
790
+
791
+ ### What's protected
792
+
793
+ | Feature | Protection |
794
+ | ----------------------------- | ----------------------------------------- |
795
+ | Dashboard & admin APIs | `api_secret` Bearer token |
796
+ | WebSocket (real-time updates) | Token validated on connection |
797
+ | `/api/send` endpoint | `api_secret` Bearer token |
798
+ | MCP server | `mcp.secret` Bearer token (external only) |
799
+ | Inbound webhooks (Twilio) | Request signature verification |
800
+ | Inbound webhooks (Resend) | Svix signature verification |
801
+ | Endpoint channels | Optional `X-Channel-Secret` header |
802
+
803
+ ### Additional hardening
804
+
805
+ - Rate limiting is applied to all endpoints (60/min for send, 120/min for inbound, 300/min for dashboard)
806
+ - Security headers (CSP, X-Frame-Options, etc.) are set via `helmet`
807
+ - Webhook URLs are validated against private IP ranges (SSRF protection) — see [Local webhooks](#local-webhooks) to allow localhost/private IPs
808
+ - Channel/service names are restricted to alphanumeric characters, hyphens, and underscores
809
+ - Sensitive fields (API keys, tokens) are masked in API responses
810
+ - Server log broadcasts redact common API key patterns
811
+
812
+ ### Local webhooks
813
+
814
+ By default, ChannelKit blocks webhook requests to `localhost`, `127.0.0.1`, and private IP ranges (`10.x`, `172.16-31.x`, `192.168.x`) as SSRF protection. Cloud metadata endpoints (`169.254.169.254`) are **always** blocked regardless of this setting.
815
+
816
+ If your webhook server runs locally or on a private network, add this to your `config.yaml`:
817
+
818
+ ```yaml
819
+ settings:
820
+ allow_local_webhooks: true
821
+ ```
822
+
823
+ This is common during development or when ChannelKit and your app run on the same machine or local network.
824
+
825
+ ## License
826
+
827
+ MIT — see [LICENSE](LICENSE).
828
+
829
+ WhatsApp integration requires `@whiskeysockets/baileys` (optional peer dependency, GPL-3.0 via `libsignal-node`). Installing it is opt-in and subject to its own license terms.