S275 Handoff — Register Twilio WhatsApp Notification Template
Documentation for Sessions
S275 Handoff: Register Twilio WhatsApp Notification Template
Why this matters
Every WhatsApp message Vitto sends outside the 24-hour session window (proactive alerts, daily digests, escalations, system notifications) was failing with Twilio error 63016. The code fix is done (S275.1) — the gateway now checks the session window and routes to a pre-approved template. But the template doesn't exist yet. Until it's registered and the env var is set, all outside-window WhatsApp messages are silently skipped.
This is different from the existing invite template (TWILIO_WHATSAPP_INVITE_CONTENT_SID) which is specific to space invitations. This new template is a generic notification template used by all Vitto outbound messaging.
What you need to do
Step 1: Create the template in Twilio Content Builder
- Log in to Twilio Console → https://console.twilio.com
- Navigate to Messaging → Content Editor (or go directly to Content API templates)
- Click Create New → choose Text template type
- Configure:
- Friendly name:
vitto_notification_v1 - Language:
en - Category: Utility (NOT marketing — utility templates have faster approval and higher delivery rates)
- Body: see template copy below
- Friendly name:
Step 2: Template copy
The template needs 2 variables — keep it generic since this serves ALL notification types (alerts, digests, reminders, escalations):
{{1}}: {{2}}
Reply to this message to continue the conversation.
| Variable | Purpose | Example values |
|---|---|---|
{{1}} |
Notification title / category | Daily Digest, System Alert, Reminder, Escalation |
{{2}} |
Message summary (truncated to fit) | 3 unresolved critical alerts, task success rate 94% |
Alternative body options (pick whichever feels best, but keep {{1}} and {{2}} in order):
Option A (minimal):
{{1}}: {{2}}
Reply to continue.
Option B (branded):
Vitto — {{1}}
{{2}}
Reply to this message to continue the conversation.
Option C (with CTA):
{{1}}
{{2}}
Reply here or open the dashboard to take action.
Important: Once Meta approves the template, the body text is locked. Pick wording you're comfortable with long-term. The "Reply to continue" line is strategic — it re-opens the 24h session window so subsequent messages can be freeform.
Step 3: Submit for Meta approval
After creating the template in Twilio, it gets submitted to Meta for review. Typical turnaround:
- Utility templates: Usually approved within minutes to a few hours
- Marketing templates: Can take 24-48 hours
You'll see the status in the Content Editor: pending → approved or rejected.
If rejected, Meta usually gives a reason. Common issues:
- Template looks like marketing (use "Utility" category)
- Variable-only body (add some static text around the variables)
- Missing opt-out language (not usually required for utility)
Step 4: Get the Content SID
Once approved, Twilio assigns a Content SID — it starts with HX followed by 32 hex characters:
HXxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Copy this value.
Step 5: Set the environment variable
Add to all environments where backend-vitto-api runs:
TWILIO_WHATSAPP_NOTIFICATION_TEMPLATE_SID=HXxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Where to set it:
- Railway:
backend-vitto-apiservice → Variables - Local dev:
.env.localin the monorepo root - Any other deployment: wherever
TWILIO_ACCOUNT_SIDis already set
Step 6: Verify
After setting the env var and redeploying:
- Wait for a proactive notification or daily digest to fire (or trigger one manually)
- Check
backend-vitto-apilogs — you should see template sends instead of the 63016 warning - The Twilio Console → Messaging → Logs should show successful outbound template messages
Context: What the code does now (S275.1)
The sending flow for WhatsApp messages is:
Any caller (proactive, digest, adapter)
→ sendResponse({ channelType: 'whatsapp', ... })
→ sendWhatsAppViaChannel()
→ checks session window (24h since user's last message)
→ IF within window: send freeform text ✅
→ IF outside window:
1. Use per-message fallbackContentSid (if provided)
2. Use TWILIO_WHATSAPP_NOTIFICATION_TEMPLATE_SID (platform default) ← NEW
3. Skip send + log warning (if no template configured) ← NEW
Additionally:
sendWhatsAppQuickReply()— returnsfalseearly when outside window (callers fall back tosendResponse)WhatsAppChannelAdapter.render()— skips rich rendering when outside window (falls back throughsendResponse)
Files changed in S275.1
| File | What changed |
|---|---|
libs/libs-api/messaging-core/src/lib/messaging-core.constants.ts |
Added notificationTemplateSid key |
libs/libs-api/messaging-core/src/lib/services/twilio.service.ts |
Added getNotificationTemplateSid() getter |
APIs/backend-vitto-api/src/app/connectivity/channel-gateway.service.ts |
3-tier template fallback in sendWhatsAppViaChannel(), session window guard in sendWhatsAppQuickReply() |
APIs/backend-vitto-api/src/app/engine/adapters/whatsapp-channel.adapter.ts |
Session window guard in render() |
Existing template reference
There's already an invite-specific template documented at docs/english/integrations/whatsapp-space-invitation-template.md with env var TWILIO_WHATSAPP_INVITE_CONTENT_SID. That one is separate — it serves space invitations only and has 5 variables (space name, role, code, URL, inviter). The notification template we're creating here is a different, generic template for all other outbound messaging.
Twilio account info
The Twilio credentials are in .env.local / Railway. Key details:
- Mode:
TWILIO_WHATSAPP_MODE=production - Production number: value in
TWILIO_NUMBER(the+1607...number) - Account SID: value in
TWILIO_ACCOUNT_SID(starts withAC) - The template must be registered under this same account and this same WhatsApp sender number
Checklist
- Log into Twilio Console
- Create Content Template (text, utility category, 2 variables)
- Submit for Meta approval
- Wait for approval (check status)
- Copy Content SID (
HX...) - Set
TWILIO_WHATSAPP_NOTIFICATION_TEMPLATE_SIDin Railway (backend-vitto-api) - Set
TWILIO_WHATSAPP_NOTIFICATION_TEMPLATE_SIDin.env.local - Redeploy backend-vitto-api
- Verify: trigger a notification, confirm no 63016 in logs