Skip to Content
WhatsApp MCPPlan & Phases0 — Meta Setup

Phase 0 — Prereqs & Meta Setup

Effort: S (mostly waiting on Meta verification)

Goal

Have all external accounts, secrets, DNS, and host baseline ready before any code is written.

Deliverables

Meta side

  • Meta Business Manager account verified (business name, address, tax id).
  • Meta App created at developers.facebook.com (App type: Business).
  • WhatsApp product added to the App.
  • WhatsApp Business Account (WABA) created or linked.
  • v1 phone number added to the WABA and verified (SMS / voice OTP). Note: number verification can take hours; start this first.
  • System User at the Business level with:
    • whatsapp_business_messaging permission on the WABA
    • whatsapp_business_management permission on the WABA
    • Permanent access token generated and copied (do not use temporary 24h tokens).
  • App Secret captured from the App Dashboard → Settings → Basic (for WA_APP_SECRET).
  • Webhook verify token chosen (32 random chars; this becomes WA_WEBHOOK_VERIFY_TOKEN).
  • IDs noted:
    • WA_DEFAULT_PHONE_NUMBER_ID (Meta’s numeric id, not the display number)
    • WA_DEFAULT_WABA_ID

DNS

  • A (and AAAA if applicable) record for wa.<yourdomain> → Ubuntu host public IP.
  • TTL ≤ 300 so cert issuance + future moves are quick.
  • dig wa.<yourdomain> from a third location returns the expected IP.

Ubuntu host baseline (22.04 or 24.04 LTS)

  • Non-root sudo user wamcp.
  • UFW enabled:
    • 22/tcp allowed only from admin source IPs (the owner’s static IPs / VPN).
    • 80/tcp and 443/tcp open to the world (needed for certbot + Meta webhooks + MCP HTTPS).
    • All other inbound denied by default.
  • Docker (Engine + Compose v2) installed; the wamcp user is in the docker group.
  • Base tools: git, curl, make, htop, unattended-upgrades, fail2ban (for sshd).
  • Directories owned by the service user:
    • /var/lib/whatsapp-mcp/media
    • /var/lib/whatsapp-mcp/backups
    • /var/lib/whatsapp-mcp/audit-archive
  • unattended-upgrades configured for security updates.
  • Time sync: chrony or systemd-timesyncd.

Inngest Cloud

  • Inngest Cloud account.
  • New Environment named prod.
  • Event Key and Signing Key copied for the env.
  • (Optional) a second dev Environment for Phase 3 development.

Secret vault decision

  • v1 (Phases 1–6): .env file at /opt/whatsapp-mcp/.env, mode 0600, owned by service user, never committed.
  • Phase 7: migrate to SOPS + age. Decision documented; not implemented yet.

Runbooks (skeletons)

  • docs/operations/phase-0-meta-setup.md — step-by-step with screenshots of the Meta Dashboard click paths.
  • docs/operations/host-bootstrap.md — ansible-style checklist (manual for v1; can be automated later).

Tests

Phase 0 has no automated tests (no code yet). Manual verification only — see Acceptance.

Code documentation

None — no code in this phase. Runbook docs above are the deliverable.

Acceptance

  1. From the Ubuntu host as wamcp:
    curl -s -H "Authorization: Bearer $WA_DEFAULT_ACCESS_TOKEN" \ "https://graph.facebook.com/v23.0/$WA_DEFAULT_WABA_ID?fields=id,name"
    returns 200 with the expected WABA name.
  2. dig +short wa.<yourdomain> from outside the host resolves to the host’s public IP.
  3. ssh wamcp@<host> works from an allowed admin IP; ssh from a non-allowed IP times out.
  4. docker run --rm hello-world works as the wamcp user.
  5. The Inngest Cloud dashboard shows the prod Environment with Event Key + Signing Key visible (still hidden behind reveal, but present).
  6. The three /var/lib/whatsapp-mcp/* dirs exist with correct ownership and mode 0750.

Risks

  • Meta number verification can take hours or fail. Start Phase 0 first; do not block Phase 1 on it (Phase 1 can be built dry against a test number Meta provides automatically in the dashboard).
  • Permanent token is bound to the System User. Losing the System User breaks the token. Document the recovery path in docs/operations/incident-runbook.md (Phase 7).
  • Graph API version pinned at v23.0. Do not use latest. Plan to bump quarterly via the ops/upgrade.md procedure.

Definition of Done

Tick each box as the item is verified. Phase is done when every box including Phase signoff is checked.

Meta side

  • Meta Business Manager account verified.
  • Meta App (Business type) created with WhatsApp product added.
  • WABA created or linked.
  • v1 phone number added to the WABA and verified (OTP).
  • System User created with whatsapp_business_messaging + whatsapp_business_management on the WABA.
  • Permanent access token generated and stored securely.
  • App Secret captured.
  • Webhook verify token chosen (32+ random chars).
  • WA_DEFAULT_PHONE_NUMBER_ID and WA_DEFAULT_WABA_ID recorded.

DNS

  • A (and AAAA if applicable) record for wa.<yourdomain> → host IP.
  • TTL ≤ 300.
  • dig wa.<yourdomain> from a third location returns the expected IP.

Ubuntu host baseline

  • Non-root sudo user wamcp.
  • UFW: 22/tcp restricted to admin IPs, 80/tcp + 443/tcp open, default deny.
  • Docker Engine + Compose v2 installed; wamcp in docker group.
  • Base tools installed (git, curl, make, htop, unattended-upgrades, fail2ban).
  • /var/lib/whatsapp-mcp/{media,backups,audit-archive} exist with correct ownership and mode 0750.
  • unattended-upgrades configured.
  • Time sync (chrony or systemd-timesyncd) running.

Inngest Cloud

  • Account created.
  • prod Environment created.
  • Event Key + Signing Key copied to secure storage.

Runbooks

  • docs/operations/phase-0-meta-setup.md written (with screenshots of Meta dashboard click paths).
  • docs/operations/host-bootstrap.md written.

Acceptance verified

  • curl … /v23.0/$WA_DEFAULT_WABA_ID returns 200 with expected WABA name.
  • dig +short wa.<yourdomain> from outside returns the host IP.
  • SSH from allowed IP works; SSH from non-allowed IP times out.
  • docker run --rm hello-world works as wamcp.
  • Inngest dashboard shows prod env with both keys present.

Phase signoff

  • Phase 0 complete. README.md status table updated to ✅.