Skip to main content
Version: Latest

6.8 CommunicationController

Route: api/v1/Communication · Class attributes: [Authorize] · 12 endpoints — the ERP's channel-agnostic send API (Email/WhatsApp/SMS/Push/In-App/Document). WhatsApp is one of five channels; every endpoint is documented here for completeness, with Meta interaction called out explicitly where relevant.


POST Send/Email

Purpose: send an email via the tenant's configured SMTP, recording CommunicationHistory. Permission: Communications.SendEmail · Request (SendEmailRequest):

{ "recipient": { "type": 0, "email": "customer@example.com", "name": "Ahmed" },
"subject": "Your Invoice", "body": "<p>Please find attached...</p>", "isHtml": true,
"referenceType": "Invoice", "referenceId": "inv-...", "referenceNumber": "INV-2026-00451" }

Response: Result<Guid> (the CommunicationHistory.Id). Backend: CommunicationService.SendEmailAsync. Calls Meta API: No.


POST Send/WhatsApp

Purpose: send a WhatsApp template message via the tenant's own WhatsApp Business number. Permission: Communications.SendWhatsApp · Request (SendWhatsAppRequest):

{ "recipient": { "type": 0, "phone": "966501112222", "name": "Ahmed", "languageCode": "ar" },
"eventKey": "InvoiceIssued", "templateName": "send_document_invoice",
"data": { "customerName": "Ahmed", "amount": "12500.00", "invoiceNumber": "INV-2026-00451" },
"referenceType": "Invoice", "referenceId": "inv-...", "referenceNumber": "INV-2026-00451" }

Response: Result<Guid>. Error cases: tenant WhatsApp not configured/enabled (WhatsAppOperationalSettings.EnableSending == false) → Result<Guid>.FailureAsync with a configuration error message, not an HTTP error; phone normalization failure → same failure shape; Meta rejection → failure message contains Meta's error code/message. Backend: CommunicationService.SendWhatsAppAsyncITenantWhatsAppSender.SendTemplateAsync. Calls Meta API: Yes. Angular/Flutter: any tenant-triggered "send this document by WhatsApp" action (invoices, quotes, receipts).


POST Send/Sms

Purpose: queue an SMS via the platform Notification Framework. Permission: Communications.SendSms Request (SendSmsRequest): { "recipient": {...}, "messageText": "Your OTP is 482913", "referenceType": "Otp" } Response: Result<Guid>. Backend: CommunicationService.SendSmsAsync. Calls Meta API: No.

POST Send/Push

Purpose: queue a push notification. Permission: Communications.SendPush Request (SendPushRequest): { "recipient": {...}, "title": "Order Shipped", "body": "...", "eventKey": "OrderShipped" } Response: Result<Guid>. Backend: CommunicationService.SendPushAsync. Calls Meta API: No.

POST Send/Notification

Purpose: queue an in-app notification. Permission: Communications.Send Request (SendNotificationRequest): { "recipient": {...}, "eventKey": "PurchaseInvoicePosted", "data": {...} } Response: Result<Guid>. Backend: CommunicationService.SendNotificationAsync. Calls Meta API: No.


POST Send/Document

Purpose: channel-routing dispatcher for business documents — the caller picks a Channel and this endpoint routes to the correct underlying send. Permission: Communications.SendDocument · Request (SendDocumentRequest):

{ "channel": 2, "recipient": { "phone": "966501112222", "languageCode": "ar" },
"documentType": "Invoice", "documentId": "inv-...", "documentNumber": "INV-2026-00451",
"templateName": "send_document_invoice", "data": { "amount": "12500.00" } }

(channel: 2 = WhatsApp, per the CommunicationChannel enum used by this module — Email=1, WhatsApp=2, Sms=3, Push=4, InApp=5. Note this is a different, narrower enum than the Notification Framework's own NotificationChannelEmail=1, Sms=2, Push=3, InApp=4, SignalR=5, WhatsApp=6 — used by AppNotificationTemplate.Channel and documented in the Notification Framework's channel chapter. Do not confuse the two when integrating.) Response: Result<Guid>. Backend: CommunicationService.SendDocumentAsync, which internally calls the same channel-specific method as the dedicated Send/{Channel} endpoint. Calls Meta API: Yes, but only when Channel == WhatsApp.


POST Preview

Purpose: preview the resolved recipient/template/body a Send/Document call would produce, without actually sending. Permission: Communications.Preview · Request: same shape as Send/Document. Response (Result<CommunicationPreviewResult>):

{ "channel": 2, "subject": null, "body": "مرحباً أحمد، فاتورتك رقم INV-2026-00451 بمبلغ 12500.00 ر.س جاهزة.",
"recipientContact": "966501112222", "templateName": "send_document_invoice", "languageCode": "ar", "isValid": true }

Backend: CommunicationService.PreviewAsync. Calls Meta API: No. Angular/Flutter: a "Preview before sending" step in any document-send UI.


GET ValidateSettings/{channel}

Purpose: validate one channel's tenant configuration. Permission: Communications.ManageSettings Request: route channel:CommunicationChannel (e.g. 2 for WhatsApp). Response (Result<CommunicationValidationResult>): { "isValid": false, "errors": ["AccessToken is not configured"], "warnings": [] } Backend: CommunicationService.ValidateSettingsAsync. Calls Meta API: No.

GET ProviderInfo/Email · GET ProviderInfo/WhatsApp

Purpose: resolved provider info for a channel (which provider is active, whether configured/enabled). Permission: Communications.ManageSettings · Response data: { "source": 1, "providerName": "Meta WhatsApp Cloud API", "isConfigured": true, "isEnabled": true, "senderIdentity": "966501234567", "validationErrors": [], "validationWarnings": [] } Backend: CommunicationService.GetEmailProviderInfoAsync / GetWhatsAppProviderInfoAsync. Calls Meta API: No.


POST Test/Email

Purpose: test SMTP connectivity by sending a real test email. Permission: Communications.TestEmail Request (TestEmailRequest): { "toEmail": "admin@tenant.com", "subject": "Shumoul Test Email" } Response: Result<Guid>. Backend: CommunicationService.TestEmailAsync. Calls Meta API: No.

POST Test/WhatsApp

Purpose: test WhatsApp API connectivity via a business-account lookup (not a message send). Permission: Communications.TestWhatsApp · Request (TestWhatsAppRequest): { "toPhone": "966501112222", "templateName": "hello_world", "languageCode": "ar" } Response: Result<Guid>. Error cases: invalid/expired access token → failure message containing Meta's HTTP status + raw body. Backend: CommunicationService.TestWhatsAppAsyncITenantWhatsAppSender.TestConnectionAsync — a direct GET {BaseUrl}/{GraphApiVersion}/{BusinessAccountId}?fields=id,name call. Calls Meta API: Yes. Angular/Flutter: a "Test Connection" button on the tenant's WhatsApp settings screen.