# Post-Booking Outreach — Message Leads Who Book via Calendly

> Recipe that ties together pieces already documented separately (`platform-features.md` §8/§11,
> `workflows.md`) into one end-to-end flow: **a lead books a call → the agent/system messages them
> automatically** (reminder before the call, or a confirmation right after booking).
>
> First real ask: Tati Goldman (Health Coach), 2026-06-19 — "how do I make the agent write to the
> people who book through Calendly?" Sibling pattern to IG→WhatsApp capture (same workflow→template
> mechanism, gated on a different property).

---

## The two pieces

```
(A) TRACK THE BOOKING                         (B) MESSAGE THE BOOKER
Calendly link carries the contact id          workflow fires on the booking signal
agent always sends that link                  → FOLLOW_UP / SCHEDULE_REMINDER / CUSTOM_NOTIFICATION
booking → Schedules row + property flips  ──►  → channel WhatsApp (template if outside 24h)
```

You wire **(A)** once per client, then **(B)** is one workflow.

---

## Part A — Track the booking (Calendly)

Requires **Calendly Pro**. Connect it in **Integrations**, then make the booking attributable to a
specific contact:

- Append `?utm_term=[[CONTACT_ID]]` to the scheduling link.
  Example: `https://calendly.com/<user>/30min?utm_term=[[CONTACT_ID]]`
- The agent must send **that** link whenever it invites the lead to book. `[[CONTACT_ID]]` is
  substituted at send time, so Ninjō knows which contact booked.
- The booking lands in the **Schedules** table (source = Calendly) and the booking signal is exposed
  as a custom property — typically `call_booked = true`. Confirm the exact key per client before
  gating on it (it is not the same label for everyone).

> Alternative sources that produce the same `Schedules` row + property: agent-booked, Google
> Calendar, GoHighLevel. The Part B workflow is source-agnostic — it only watches the property /
> schedule.

---

## Part B — Message the booker (Workflow)

Pick by **when** you want to reach them:

| Goal | Workflow type | Key settings | Channel |
|------|---------------|--------------|---------|
| Message the moment they book | `FOLLOW_UP` (or `CUSTOM_NOTIFICATION` if it's a fixed canned message) | condition `call_booked = true`, `onlyRunOnce = true` | WhatsApp / WhatsApp Template |
| Remind them before the call | `SCHEDULE_REMINDER` | `minutesBeforeScheduleTime: 1440` (24h before) | WhatsApp / WhatsApp Template |

`SCHEDULE_REMINDER` reads the booked datetime from the `Schedules` row, so it needs no property
condition — it fires relative to the appointment automatically.

---

## ⚠️ The WhatsApp 24-hour window (the gotcha that breaks this)

WhatsApp only allows **free-form** outbound inside **24h** of the lead's last inbound message.
A booking reminder for a call that's days away — or any "message first" outreach — falls **outside**
that window, so it MUST go out as a **pre-approved Meta template** (`WHATSAPP_TEMPLATE` channel),
not plain text. A free-text workflow will silently fail to deliver.

Practical consequence for the client:
- Get **one short reminder/confirmation template approved in Meta** (status APPROVED).
- Point the workflow's destination at `WHATSAPP_TEMPLATE` with that template.
- If the conversation is still inside 24h (e.g. they booked seconds ago while chatting), a plain
  WhatsApp message is fine — but defaulting to a template is the safe choice.

This is the **same mechanism** as the IG→WhatsApp capture playbook (property-gated workflow →
approved template). The only difference is the trigger: `call_booked` instead of `phone_shared`.

---

## Prerequisites checklist

- [ ] Calendly Pro connected in Integrations
- [ ] Scheduling link carries `?utm_term=[[CONTACT_ID]]` and the agent sends that exact link
- [ ] Booking signal property confirmed for this client (key name + that it actually flips on booking)
- [ ] WhatsApp Business number (WABA) connected and assigned to an agent — see "Connect WhatsApp"
- [ ] If messaging outside 24h: a reminder/confirmation template APPROVED in Meta
- [ ] Workflow `enabled = true` with the right condition / `minutesBeforeScheduleTime`

---

## Connect WhatsApp (companion answer)

WhatsApp is a Meta connected account (same family as Instagram/Facebook):

1. Needs a **WhatsApp Business number (WABA)** — a number *not* tied to a personal WhatsApp,
   registered through Meta's WhatsApp Business API (embedded signup in the Meta connection flow).
   Requires a Meta Business account.
2. Once connected it appears as a **sub-account**; assign it to the agent that should own WhatsApp
   conversations (per-agent account selection).
3. Remember the 24h window above — proactive/first outbound = approved templates only.

---

## How to actually execute it — MCP vs platform UI vs DB-direct

The flow splits into a **connection/approval half** (inherently OAuth + human-review flows, never MCP)
and an **automation half** (MCP-shaped, but scope-gated). Be explicit with the client about who does what.

### Connection / approval — platform UI or Meta only (the client does these; needs their credentials)

| Step | Where | Why not MCP |
|------|-------|-------------|
| Connect the WhatsApp number (WABA) | Platform → Connected Accounts (Meta embedded signup) | OAuth/browser onboarding. MCP only **wires an already-connected** account to an agent — it can't onboard a new number. Once connected, `list_influencer_connected_accounts` surfaces its id → `set_connected_account` (`list_connected_accounts` is agent-scoped, empty for a fresh agent). |
| Connect Calendly Pro | Platform → Integrations | OAuth/browser. **No Calendly MCP tool exists.** |
| Create + submit the WhatsApp reminder/confirmation template | Meta Business Manager → wait for APPROVED | Template authoring + Meta review. Not MCP, not even Ninjō. |

### Automation — MCP tools exist…

- Prompt edit (send the link with `?utm_term=[[CONTACT_ID]]`) → `update_prompt` / `deploy_agent_sdk`
- `call_booked` property → `upsert_custom_property` *(often skippable — see below)*
- Workflow → notification → destination → `upsert_workflow`, `upsert_custom_notification`,
  `upsert_notification_destination`

### …but two caveats override "just use MCP"

1. **Gateway scope.** The cortex-gateway MCP is scoped to **our (Lolo's) workspace, not the client's**
   (same trap as the IG→WhatsApp playbook; `mcp-tool-reference.md` notes IAM errors on the prod gateway).
   For a **client's** agent, do the automation **DB-direct** (the IG→WhatsApp script pattern). MCP only
   applies to agents inside our own workspace.
2. **No MCP tool registers a WhatsApp *template definition*** (`whatsapp_template_definitions` — the row
   the Go sender reads). `upsert_notification_destination` can *select* a template, but seeding the
   definition is currently DB-direct.

### Simplifier — `SCHEDULE_REMINDER` needs no property

`SCHEDULE_REMINDER` reads the booked datetime straight from the **Schedules** table, so for the
"remind them before the call" case you **don't need `call_booked` at all** — just the Calendly
connection + the workflow + the approved template. The property only matters for "message them the
instant they book."

### Division of labor (template for the client conversation)

- **Client:** connect WhatsApp (WABA), connect Calendly Pro, create + submit the WhatsApp template.
- **Us:** the booking property + webhook, the workflow→notification→destination chain, point the
  destination at the approved template.

> **Correction to the "MCP scope → DB-direct" caveat above.** The whole automation half can be done
> in the **Studio UI via impersonation** (the official Scribe runs as *"Impersonating: <creator>"*), so
> **DB-direct is only a fallback**, not the default, for a client's agent. The MCP-scope limit still
> means *MCP* can't reach the client's account — but the UI (impersonated) can. See the UI walkthrough
> below.

---

## Platform UI walkthrough (Studio, impersonated) — step by step

Derived from the official Scribe guides (`ninjo-prompts/platform/knowledge-base/scribe-guides/`:
`ConnectWhatsAppBusinessNumbertoninjo`, `CalendlyIntegrationGuide`, `CreateandCustomizeaFollow-UpWorkflow`).
Kept in Spanish since these are relayed to creators.

### A) Conectar WhatsApp — `Página del influencer → WhatsApp Business`

1. Página del influencer → tarjeta **WhatsApp Business** → **+ Add number**.
2. **Continuar** → iniciar sesión con una **cuenta de Facebook existente** (las nuevas no acceden a
   Business Manager).
3. **Empezar** → seleccionar/crear el **Portfolio empresarial** (nombre, web, país) → **Siguiente**.
4. Elegir **"Conecta tu aplicación de WhatsApp Business existente"** → **Siguiente**.
5. Ingresar el **número de WhatsApp Business** (país + número) → **Siguiente**.
6. **Escanear el QR** con ese WhatsApp → elegir **zona horaria** → **Siguiente** → **Confirmar** →
   **Finalizar**.
7. A los segundos queda **Verified: Yes, Connected**. Da 250 convos business-initiated/24h + ilimitadas
   customer-initiated. El número no puede estar en un WhatsApp personal; requiere Meta Business.

### B) Trackear reservas de Calendly — `Automations → Webhooks` (setea propiedad booleana)

Mejor que el `utm_term` link: un webhook `invitee.created` prende una propiedad booleana en cada reserva.

1. En **Calendly (Pro)** → **Integrations & apps → API and webhooks → Personal access tokens →
   Get a token now → Continue → Create token**. Copiar el token.
2. En Ninjō → **Contact Properties → View Properties → + New Property** → Tipo **Yes/No (boolean)**,
   nombre ej. **`Calendly agendado`** → **Create property**.
3. **Automations → Webhooks → + New Webhook**: Name `calendly`; **Platform → Calendly**;
   **Event Type → invitee.created**; **Custom Properties →** `Calendly agendado`; **Static Value =**
   `true`. Copiar la **Webhook URL**.
4. **"View Webhooks Configured in Calendly"** → pegar el **token de Calendly** →
   **"Add Ninjo Webhook to Calendly"** → **Close** → **Create**.

→ Cada reserva setea `Calendly agendado = true` en el contacto. *(Property booleana = consistente con la
preferencia de propiedades booleanas.)*

### C) Escribirle al que agendó — `Automations → Workflows → New Workflow`

1. **Automations → Workflows → New Workflow**.
2. **Type → Follow-up** (o **Schedule Reminder** para "X hs antes de la call" — lee el datetime de la
   tabla Schedules, no necesita property).
3. Nombre + descripción; **Channels → WhatsApp**; elegir **Agente**.
4. **Send after** (ej. 30 min / horas tras el último mensaje).
5. **Response Type → Static Text Message** (fijo) o **AI Generated** (Prompt + Model Config JSON, ej.
   `{"model":"gpt-5-mini","verbosity":"low","reasoning_effort":"minimal"}`).
6. **Property conditions → `Calendly agendado` EQUALS `true`** ← esto lo limita a quienes agendaron.
7. Activar **Track task state** → **Create**.
8. Probar sin esperar al scheduler: **Messages → abrir conversación → Test Follow-up → elegir workflow →
   Ejecutar Test** (muestra "Mensaje generado" + "Tarea completada").

### El único límite que sobrevive — ventana de 24h

El test screen lo dice literal: *"Cannot send free messages after 24 hours… Use the template button."*
Si el WhatsApp sale **+24h** después del último inbound del lead (ej. recordatorio días antes de la call),
**debe** ser un **template aprobado de Meta** (Custom Notification → WhatsApp Template destination — el
mecanismo de `ig-to-wa`), no texto libre. Dentro de las 24h, el Follow-up de arriba alcanza.

---

## Related

- `workflows.md` — FOLLOW_UP / SCHEDULE_REMINDER / CUSTOM_NOTIFICATION types, conditions, channels
- `platform-features.md` §8 (Calendly tool), §10 (notifications/templates), §11 (Schedules), §12
  (connected Meta accounts)
- IG→WhatsApp capture playbook (sibling: workflow→template gated on `phone_shared`)
