Meta WhatsApp Business Cloud API — Onboarding fuer Salon-Bots

Setup-Anleitung + harte Stolperer aus dem Aufbau des Friseur-im-Sueden-Bots (proj-2026-014). Gilt fuer jeden Salon-Kunden — pro Kunde eigenes Business-Portfolio anlegen (saubere Trennung der WhatsApp-Phone-Numbers).

1. Account-Topologie (wichtig zu verstehen)

Meta hat vier Ebenen die du im Kopf halten musst:

Meta-User-Account (deiner / Marvin Kuehlmann)
 └── Business Portfolio (z.B. "Friseur im Sueden", id=660776766919106)
      ├── WhatsApp Business Account / WABA (id=889608426871476)
      │    └── Phone Number (id=1170948102758111, display +1 555 973 8821)
      └── Meta-Developer-App (id=988192143605811, name "agentic-friseur-bot")
           ├── WhatsApp-Produkt aktiviert
           └── Webhook-Konfiguration (URL + Verify-Token + abonnierte Fields)

App-WABA-Verknuepfung ist KEIN Auto. Eine App in Portfolio X kann nicht automatisch eine WABA in Portfolio Y sprechen. Plus die App muss explizit als Subscriber zur WABA hinzugefuegt werden (POST /<waba>/subscribed_apps).

2. Pflicht-Schritte fuer Outbound (Bot kann antworten)

In dieser Reihenfolge, sonst Block:

  1. Business-Portfolio anlegen mit echtem Firmen-Namen (Salon-spezifisch, nicht “Agentic Ventures” mehrfach reusen)
  2. WhatsApp Business Account im Portfolio anlegen
  3. Phone Number anhaengen — Meta gibt eine kostenlose Test-Phone (+1 555 xxx xxxx) oder eigene Nummer per SMS-Code verifizieren
  4. Meta-Developer-App anlegen (Type: Business) und WhatsApp-Produkt aktivieren
  5. Token generieren (temp 24h aus dem App-UI ODER permanent ueber System User in Business Settings)
  6. App als Subscriber zur WABA registrieren — POST /<waba-id>/subscribed_apps (sonst Webhooks gehen nicht)
  7. Webhook konfigurieren in der App-UI: Callback-URL + Verify-Token
  8. Webhook-Fields abonnieren (messages + message_status) — separater Klick nach Verify, wird leicht uebersehen
  9. Eigene Handynummer als Test-Empfaenger verifizieren (Test-Mode-Limit: 5 Empfaenger)
  10. Payment-Method hinzufuegen in Business-Settings → Billing — Pflicht fuer business-initiated Messages (Bot schreibt zuerst), auch im Test-Mode
  11. Business-Verification durchziehen — Pflicht fuer freigeschaltete Outbound bei nicht-Test-Phones und ueberhaupt fuer „can_send_message: AVAILABLE”

3. Stolperer-Cheatsheet

A. 131031 = Business Account locked

Symptom: Outbound send_text returnt wamid, aber Status-Webhook sagt failed mit 131031.

Ursache: WABA hat can_send_message: BLOCKED. Health-Check GET /<waba-id>?fields=health_status zeigt typisch 3 Subprobleme:

  • 141006: Payment-Method fehlt → Billing-UI
  • 141010: Business-Verification fehlt → Verification-Prozess
  • 141005: Commerce-Check failed → Appeal im Account-Quality-Center

Fix: alle drei nacheinander loesen, oder einen schon verifizierten Account nutzen (siehe Friseur-Account-Setup unten).

B. 131047 = Re-engagement message

Symptom: Outbound geht raus, Status failed.

Ursache: 24h-Service-Window nicht aktiv — User hat in den letzten 24h NICHT an deine Phone-Number geschrieben. Bot darf dann nur approved Templates senden, kein Freitext.

Fix: User muss zuerst schreiben (Marketing-/Push-Trigger ausserhalb WhatsApp, z.B. „Speicher unsere Nummer und sag Hi”). ODER: pre-approved Template senden.

C. (#190) Application Secret required bei GET /<app-id>/subscriptions

Ursache: User-Access-Token reicht nicht — Webhook-Subscriptions abfragen braucht App-Access-Token (App-ID + App-Secret).

Fix: entweder in UI pruefen, ODER App-Secret aus App-Settings → Token holen.

D. „Object with ID X does not exist or missing permissions”

Ursache: Token-Scope passt nicht zur abgefragten WABA/Phone. Typisch wenn man Token aus App A nutzt um Werte aus App B abzufragen.

Fix: GET /debug_token?input_token=<token> zeigt granular_scopes.target_ids — pruefen ob die gewuenschte WABA dabei ist. Wenn nicht: anderen Token holen.

E. Webhook angenommen, aber Inbound kommt nicht

Symptom: Webhook-Verify war erfolgreich (Webhook verified in Container-Logs), aber User schreibt und nichts kommt an.

Ursachen — alle pruefen:

  1. App nicht als WABA-Subscriber registriertPOST /<waba-id>/subscribed_apps
  2. Webhook-Fields nicht abonniert → in der App-UI nach „Webhook verified” muss man pro Field auf „Subscribe” klicken
  3. User schreibt an falsche Phone-Number (alte Test-Phone vom alten Setup, nicht die aktuelle)

F. name_status: PENDING_REVIEW der Phone-Number

Symptom: Phone-Number ist CONNECTED aber Display-Name ist PENDING_REVIEW.

Bedeutung: Funktioniert trotzdem fuer Test, aber User sieht in WhatsApp die Nummer + ggf. „Business Account”-Label statt deinen gewuenschten Salon-Namen. Review-Approval kommt von Meta in 1-7 Tagen.

4. Tools fuer Diagnose (Graph API)

# Token-Scope pruefen
curl -sS -H "Authorization: Bearer $TOKEN" \
  "https://graph.facebook.com/v23.0/debug_token?input_token=$TOKEN" | jq
 
# WABA-Health (Outbound erlaubt?)
curl -sS -H "Authorization: Bearer $TOKEN" \
  "https://graph.facebook.com/v23.0/<waba-id>?fields=name,health_status,business_verification_status,on_behalf_of_business_info" | jq
 
# Phone-Number-Status
curl -sS -H "Authorization: Bearer $TOKEN" \
  "https://graph.facebook.com/v23.0/<phone-id>?fields=status,verified_name,display_phone_number,quality_rating,name_status,code_verification_status" | jq
 
# WABA-Subscribed-Apps (welche Apps duerfen Webhooks empfangen)
curl -sS -H "Authorization: Bearer $TOKEN" \
  "https://graph.facebook.com/v23.0/<waba-id>/subscribed_apps" | jq
 
# App als WABA-Subscriber hinzufuegen
curl -sS -X POST -H "Authorization: Bearer $TOKEN" \
  "https://graph.facebook.com/v23.0/<waba-id>/subscribed_apps" | jq

5. Empfohlener Setup-Pfad pro Salon-Kunde

  1. Eigenes Business-Portfolio im Namen des Salons (z.B. „Friseur im Sueden”), nicht „Agentic Ventures” — Owner kann Marvin sein, aber Portfolio bleibt Salon-Asset
  2. WABA + Phone-Number im Portfolio
  3. Meta-App (eine pro Salon — saubere Webhook-Isolation)
  4. Hosted-MCP in av-production per Pattern mcp-hosting-fargate-tunnel — eine Tunnel pro Salon, separates DNS (mcp-whatsapp-<salon>.agenticventures.de)
  5. Payment-Method hinterlegen (Marvin’s Karte bis Salon eigene hat)
  6. Business-Verification mit Salon-Handelsregister-Eintrag (Salon-Inhaber liefert)
  7. Templates (Bestaetigung + Erinnerung) bei Meta einreichen, Approval 1-3 Tage
  8. Webhook + Subscribe Fields in der App
  9. Test mit Marvin’s Handy als Test-Empfaenger vor Live

6. Cost-Modell (pro Salon, Meta-Seite)

  • Service-Window-Replies (User schrieb innerhalb 24h zuerst): kostenlos
  • Utility-Templates (Bestaetigung, Erinnerung): ~0.03-0.05 € pro Nachricht (DE)
  • Marketing-Templates: ~0.12 € pro Nachricht (DE)
  • Authentication: ~0.046 € pro Nachricht
  • Plus Infrastruktur (siehe mcp-hosting-fargate-tunnel): ~13 €/Monat Fargate-Container + ~10 €/Monat Cal.com Teams

→ Salon mit ~30 Buchungen/Woche: ~10-15 €/Monat WhatsApp + ~25 €/Monat Infra, gut innerhalb der 149 €/Mo-Pricing-Hypothese.