9. Templates
9.1 Template Send Structure
A template message (WhatsAppTemplateMessageRequestDto) references a Meta-approved template by name and
language, plus zero or more components that fill in the template's variable placeholders:
{
"to": "966501112222",
"templateName": "send_document_invoice",
"languageCode": "ar",
"components": [
{ "type": "body", "parameters": [
{ "type": "text", "text": "Ahmed" },
{ "type": "text", "text": "12500.00" },
{ "type": "text", "text": "INV-2026-00451" }
] }
]
}
Templates, their approved languages, and their variable count/order are all defined and approved on Meta's
side (via the Meta Business Manager) — Shumoul never creates or modifies a template definition through this
integration. Sending a template name Meta hasn't approved for the sender's number, or supplying the wrong
number/type of parameters, results in a Meta-side rejection surfaced through the response's
ErrorCode/ErrorMessage.
9.2 Variables and Components
Component type | Purpose | Notes |
|---|---|---|
body | The template's main text, with {{1}}, {{2}}, … positional placeholders | Parameters supplied in array order |
header | Optional header — text or media (ImageUrl/DocumentUrl/VideoUrl on the parameter) | Media headers reference a public URL, not an uploaded binary — see §3.2 |
button | Optional interactive button (e.g. a URL button reusing an OTP code) | Requires SubType (url/quick_reply) and Index |
WhatsAppTemplateComponentParameterDto.Type defaults to "text"; ImageUrl/DocumentUrl/VideoUrl/
Payload are used for media or button-specific parameter types.
9.3 Approved Templates in Use
| Template (Arabic / English) | Used by | Body parameters |
|---|---|---|
otp_verification_ar / otp_verification_en | WhatsAppOtpMessageService | 1 — the OTP code (plus an optional URL button reusing the code, if WhatsAppTenantOtpIncludeUrlButton is true) |
welcome_activation_ar / welcome_activation_en | WhatsAppActivationMessageService | 2 — customer name, organization name |
{DefaultTemplatePrefix}_{documentType} (default prefix send_document) | CommunicationService/TenantWhatsAppSender (business documents — invoices, quotes, receipts) | Varies by document type — resolved via Data object passed to Send/Document |
Notification Framework per-event templates (AppNotificationTemplate.WhatsAppTemplateName) | MetaWhatsAppProvider (template name/language/params resolved and rendered by NotificationDispatchService before the provider is called) | Defined per template via WhatsAppBodyParams (a JSON array of Scriban expressions) — see the Notification Framework's WhatsApp channel docs |
Template names, languages, and defaults are all configurable per tenant via WhatsAppOperationalSettings
and SaaSNotificationSettings — see §4 Configuration.
9.4 OTP Template
Sent with exactly one body parameter (the OTP code). If WhatsAppTenantOtpIncludeUrlButton is true, a
second button component of SubType: "url" reuses the same code as its Payload. The OTP code is never
logged anywhere in the send pipeline — TenantNotificationLog records only the literal string
"Template:{templateName}" as the message body.
9.5 Activation Template
Sent with two body parameters — customer name and organization name — resolved via
WhatsAppActivationMessageService.SendTenantActivationMessageAsync. Only sent when
WhatsAppOperationalSettings.EnableWhatsAppActivationForFreeSubscriptions allows it for free-tier tenants,
or unconditionally for paid activations.
9.6 Invoice / Business Document Template
Resolved dynamically: {DefaultTemplatePrefix}_{documentType in lowercase} combined with the tenant's
TemplateLanguageStrategy (ByRecipientLanguage by default). The Data object passed to Send/Document
or Send/WhatsApp supplies the values that fill the resolved template's body parameters — the exact mapping
is template-specific and configured per tenant, not hardcoded in the ERP.
9.7 Error Cases
| Cause | Surfaced as |
|---|---|
| Template name not approved for the sender's number/language | Meta error code/message in WhatsAppTemplateMessageResponseDto.ErrorCode/ErrorMessage, or in the Result<Guid>.FailureAsync message for Communication-module sends |
| Wrong number of body parameters | Same as above — Meta rejects the request |
Recipient phone fails normalization (WhatsAppPhoneHelper.TryNormalizePhone returns false) | Dispatch skipped before any Meta call; failure message states the recipient phone is invalid |
Tenant's WhatsApp sending disabled (EnableSending == false) | Result<Guid>.FailureAsync — a configuration failure, not a Meta error |
| 24-hour customer-service window expired (Inbox free-text reply only — does not apply to template sends) | See §6.3 SendReply — templates are exempt from this window by Meta's own rules |
