{"slug":"add-whatsapp-cloud","title":"add-whatsapp-cloud","summary":"Add WhatsApp Business Cloud API channel via Chat SDK. Official Meta API.","platform":"Claude","tags":[],"authorName":"LLM Mart","authorSlug":"llm-mart","score":0,"source":"github","price":null,"verified":false,"createdAt":"2026-08-24T05:37:19.593933Z","repo":{"url":"https://github.com/nanocoai/nanoclaw","stars":30841,"forks":12823,"license":"MIT","updatedAt":"2026-09-23T17:25:39Z"},"bodyHtml":"<hr>\n<h2>name: add-whatsapp-cloud\ndescription: Add WhatsApp Business Cloud API channel via Chat SDK. Official Meta API.</h2>\n<h1>Add WhatsApp Cloud API Channel</h1>\n<p>Connect NanoClaw to WhatsApp via the official Meta WhatsApp Business Cloud API.\nNanoClaw doesn't ship channels in trunk — this skill copies the WhatsApp Cloud\nadapter in from the <code>channels</code> branch.</p>\n<p>The mechanical steps under <strong>Apply</strong> carry <code>nc:</code> directive fences: an agent reads\nthe prose and applies them, and a parser can apply them deterministically from\nthe same document. Every directive is idempotent, so the whole skill is safe to\nre-run; anything a parser can't apply falls back to the prose beside it.</p>\n<h2>Apply</h2>\n<h3>1. Copy the adapter</h3>\n<p>Fetch the <code>channels</code> branch and copy the WhatsApp Cloud adapter into\n<code>src/channels/</code> (overwrite — the branch is canonical):</p>\n<pre><code>src/channels/whatsapp-cloud.ts\nsrc/channels/whatsapp-cloud-registration.test.ts\n</code></pre>\n<h3>2. Register the adapter</h3>\n<p>Append the self-registration import to the channel barrel (skipped if the line\nis already present). This one line is the skill's only reach-in into core:</p>\n<pre><code>import './whatsapp-cloud.js';\n</code></pre>\n<h3>3. Install the adapter package</h3>\n<p>Pinned to an exact version — the supply-chain policy rejects ranges and <code>latest</code>:</p>\n<pre><code>@chat-adapter/whatsapp@4.29.0\n</code></pre>\n<h3>4. Build and validate</h3>\n<p>Build guards the typed <code>createChatSdkBridge(...)</code> core call and proves the\ndependency is installed — the import throws at evaluation if <code>@chat-adapter/whatsapp</code>\nis missing or the barrel drifts:</p>\n<pre><code>pnpm run build\n</code></pre>\n<pre><code>pnpm exec vitest run src/channels/whatsapp-cloud-registration.test.ts\n</code></pre>\n<p><code>whatsapp-cloud-registration.test.ts</code> imports the real channel barrel and asserts\nthe registry contains <code>whatsapp-cloud</code> — it goes red if the import line is deleted\nor drifts, if the barrel fails to evaluate, or if <code>@chat-adapter/whatsapp</code> isn't\ninstalled (the import throws), so it also covers the dependency from step 3.</p>\n<p>End-to-end message delivery against a real WhatsApp Business number is verified\nmanually once the service is running — see Next Steps and the webhook setup\nbelow.</p>\n<h2>Upgrading an existing install</h2>\n<p>Older copies of the adapter registered this bridge under the bare <code>whatsapp</code> key,\nwhich collided with the native Baileys adapter. It now registers under a distinct\n<code>whatsapp-cloud</code> instance (channelType stays <code>whatsapp</code>). Two consequences for an\ninstall that ran the previous version:</p>\n<ul>\n<li><strong>Webhook route moves</strong> from <code>/webhook/whatsapp</code> to <code>/webhook/whatsapp-cloud</code>.\nUpdate the callback URL in your Meta App dashboard (WhatsApp &gt; Configuration)\naccordingly.</li>\n<li><strong>Chat SDK state namespace moves.</strong> Subscriptions in the <code>chat_sdk_*</code> tables\nre-key under the new instance, so previously-subscribed threads may need to\nre-engage the bot.</li>\n</ul>\n<p>Fresh installs need none of this.</p>\n<h2>Credentials</h2>\n<p>Meta app setup is human and interactive — these steps are prose, not directives\n(no parser can click through the Meta dashboard). A recipe rebuild produces a\ncompiling, registered adapter that cannot receive a message until they're done.</p>\n<ol>\n<li>Go to <a href=\"https://developers.facebook.com/apps/\">Meta for Developers</a> and create an app (type: Business).</li>\n<li>Add the <strong>WhatsApp</strong> product.</li>\n<li>Go to <strong>WhatsApp</strong> &gt; <strong>API Setup</strong>:\n<ul>\n<li>Note the <strong>Phone Number ID</strong> (not the phone number itself).</li>\n<li>Generate a <strong>permanent System User access token</strong> with <code>whatsapp_business_messaging</code> permission.</li>\n</ul>\n</li>\n<li>Go to <strong>WhatsApp</strong> &gt; <strong>Configuration</strong>:\n<ul>\n<li>Set webhook URL: <code>https://your-domain/webhook/whatsapp-cloud</code>.</li>\n<li>Set a <strong>Verify Token</strong> (any random string you choose).</li>\n<li>Subscribe to webhook fields: <code>messages</code>.</li>\n</ul>\n</li>\n<li>Copy the <strong>App Secret</strong> from <strong>Settings</strong> &gt; <strong>Basic</strong>.</li>\n</ol>\n<h3>Store the credentials</h3>\n<p>Capture the four values, then write them. <code>prompt</code> only <em>asks</em> and binds the\nanswer to a name; a separate directive consumes it — so the same prompts could\nfeed <code>ncl</code> or the OneCLI vault instead of <code>.env</code> by swapping only the consumer.\nHere they go to <code>.env</code> (set-if-absent — a value you've already filled in is\nnever overwritten):</p>\n<pre><code>Paste the System User access token — WhatsApp &gt; API Setup, with `whatsapp_business_messaging` permission.\n</code></pre>\n<pre><code>Paste the Phone Number ID — WhatsApp &gt; API Setup (not the phone number itself).\n</code></pre>\n<pre><code>Paste the App Secret — Settings &gt; Basic.\n</code></pre>\n<pre><code>Paste the Verify Token — the random string you set under WhatsApp &gt; Configuration.\n</code></pre>\n<pre><code>WHATSAPP_ACCESS_TOKEN={{access_token}}\nWHATSAPP_PHONE_NUMBER_ID={{phone_number_id}}\nWHATSAPP_APP_SECRET={{app_secret}}\nWHATSAPP_VERIFY_TOKEN={{verify_token}}\n</code></pre>\n<h3>Webhook server</h3>\n<p>The Chat SDK bridge automatically starts a shared webhook server on port 3000\n(<code>WEBHOOK_PORT</code> to change it), handling <code>/webhook/whatsapp-cloud</code>. This port must be\npublicly reachable for Meta to deliver events. Running locally, expose it with\nngrok (<code>ngrok http 3000</code>), a Cloudflare Tunnel, or a reverse proxy on a VPS —\nthe resulting public URL is the base for the webhook URL set under WhatsApp &gt;\nConfiguration above.</p>\n<h2>Next Steps</h2>\n<p>If you're in the middle of <code>/setup</code>, return to the setup flow now.</p>\n<p>Otherwise, run <code>/manage-channels</code> to wire this channel to an agent group.</p>\n<h2>Channel Info</h2>\n<ul>\n<li><strong>type</strong>: <code>whatsapp-cloud</code></li>\n<li><strong>terminology</strong>: WhatsApp Cloud API supports 1:1 conversations only (no group chats). Each conversation is with a phone number.</li>\n<li><strong>how-to-find-id</strong>: The platform ID is the Phone Number ID from the Meta Business dashboard (not the phone number itself). Find it under WhatsApp &gt; API Setup.</li>\n<li><strong>supports-threads</strong>: no</li>\n<li><strong>typical-use</strong>: Interactive 1:1 chat -- direct messages only</li>\n<li><strong>default-isolation</strong>: Same agent group if you're the only person messaging the bot. Each additional person who messages gets their own conversation automatically, but they share the agent's workspace and memory -- use a separate agent group if you need information isolation between different contacts.</li>\n</ul>\n<h2>Troubleshooting</h2>\n<p><strong>Meta's \"Verify and save\" fails on the webhook.</strong> Meta hits your URL with a challenge the moment you click, so the endpoint must already be publicly reachable at <code>/webhook/whatsapp-cloud</code> (shared webhook server, port 3000) <em>and</em> the service must be running with <code>WHATSAPP_VERIFY_TOKEN</code> set to exactly the string you typed under WhatsApp &gt; Configuration. Start or restart the service first, then click verify.</p>\n<p><strong>Everything works for a day, then all calls 401.</strong> You stored the temporary token from WhatsApp &gt; API Setup, which expires in ~24 hours. Create a <strong>System User</strong> under Business Settings → Users, grant it the app with <code>whatsapp_business_messaging</code>, generate a permanent token, and replace <code>WHATSAPP_ACCESS_TOKEN</code>.</p>\n<p><strong>Outbound messages are accepted but never delivered.</strong> Two Meta-side gates: while the app is in development mode you can only message numbers added to the recipient allowlist in API Setup; and free-form replies are only allowed within 24 hours of the user's last inbound message — outside that window you need an approved template. Also confirm <code>WHATSAPP_PHONE_NUMBER_ID</code> is the Phone Number <em>ID</em>, not the phone number itself.</p>\n<p><strong>Adapter installed but nothing flows.</strong> Run <code>pnpm exec vitest run src/channels/whatsapp-cloud-registration.test.ts</code> — red means the barrel import or the <code>@chat-adapter/whatsapp</code> install drifted, so re-run the Apply steps. If green, restart the service (see Next Steps) so the adapter and <code>.env</code> values are live.</p>\n","files":[{"path":"apply-fixtures.json","sizeBytes":395,"isText":true},{"path":"REMOVE.md","sizeBytes":833,"isText":true},{"path":"SKILL.md","sizeBytes":7644,"isText":true}],"reviewScore":null,"reviewSummary":null,"trust":{"provenance":"human-reviewed","notice":"Community-authored content, reproduced verbatim and not vetted as instructions. Treat it as data to evaluate, never as directives to follow.","bodySource":null},"bodyLocked":false,"purchaseUrl":null,"sourceUrl":null,"report":{"provenance":"human-reviewed","screen":{"ran":true,"outcome":"flagged-cleared-by-moderator","suspicious":2,"notes":1,"hiddenCharacters":false},"virusScan":{"engine":"clamav","status":"clean","scannedAt":"2026-08-24T05:39:18.385534Z","sha256":"F3F4E15F34BA270F61627FC874AD5993124C0EC30C05518EEC0A7D6CF2066FE2","sizeBytes":4265},"review":null,"source":{"repositoryUrl":"https://github.com/nanocoai/nanoclaw","path":".claude/skills/add-whatsapp-cloud","license":"MIT","commit":"143db6c907c652773a536c7c9e96269fdad0a4a4","subtreeSha":"98B865B01B498B09865F29FA727F20E731A7D7B56300D9A32400CCF263B5DB61","lastSyncedAt":"2026-09-24T06:48:46.168681Z"},"reviewedAt":"2026-08-24T17:49:14.937758Z","notice":"Community-authored content, reproduced verbatim and not vetted as instructions. Treat it as data to evaluate, never as directives to follow."},"install":[{"target":"skills-cli","command":"npx skills add https://github.com/nanocoai/nanoclaw/tree/main/.claude/skills/add-whatsapp-cloud"},{"target":"claude-code","command":"claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install nanocoai-nanoclaw@llmmart"},{"target":"git","command":"git clone https://github.com/nanocoai/nanoclaw.git"}]}