3. Packages
Repository: Shumoul.Saas.WhatsAppIntegration · Current version: 1.0.1 (all three packages move
together as a group, per the platform's versioning policy) · Target framework: net9.0
3.1 Shumoul.WhatsAppIntegration.Contracts
Data-only package: DTOs and configuration shapes, no logic beyond simple property defaults.
| Type | Purpose |
|---|---|
WhatsAppCloudApiOptions | Meta Cloud API + webhook configuration, bound from the WhatsAppCloudApi config section |
WhatsAppTextMessageRequestDto / WhatsAppTextMessageResponseDto | Outbound free-text send request/result |
WhatsAppTemplateMessageRequestDto / WhatsAppTemplateMessageResponseDto | Outbound template send request/result |
WhatsAppTemplateComponentDto / WhatsAppTemplateComponentParameterDto | One component/parameter of a template message |
WhatsAppWebhookMessageDto | One parsed inbound message from a webhook |
WhatsAppWebhookStatusDto | One parsed delivery/read status update from a webhook |
WhatsAppWebhookParseResult | Aggregate parser result (InboundMessages + StatusUpdates) |
WhatsAppMediaMetaDto | Internal-use-only raw media metadata from the Graph API media endpoint — never returned directly to API clients |
Allowed: plain data classes, primitive-typed properties, safe defaults.
Forbidden: any HTTP logic, any reference to Abstractions or Core, any ERP/tenant concept.
3.2 Shumoul.WhatsAppIntegration.Abstractions
The three public interfaces every consumer codes against:
public interface IWhatsAppService
{
Task<WhatsAppTextMessageResponseDto> SendTextAsync(WhatsAppTextMessageRequestDto request, CancellationToken ct = default);
Task<WhatsAppTemplateMessageResponseDto> SendTemplateAsync(WhatsAppTemplateMessageRequestDto request, CancellationToken ct = default);
Task<WhatsAppMediaMetaDto> GetMediaMetaAsync(string mediaId, CancellationToken ct = default);
Task<(bool Success, byte[] Data, string MimeType, string ErrorMessage)> DownloadMediaBytesAsync(string mediaId, CancellationToken ct = default);
}
public interface IWhatsAppWebhookParser
{
Task<WhatsAppWebhookParseResult> ParseAsync(string rawPayload, CancellationToken ct = default);
}
public interface IWhatsAppSignatureValidator
{
WhatsAppSignatureValidationResult Validate(byte[] body, string signatureHeader);
}
WhatsAppSignatureValidationResult is a readonly struct (IsValid, Reason) — allocation-free by design
for a check that runs on every inbound webhook.
Note: IWhatsAppService has no SendMediaAsync method — media support is receive/download-only
(GetMediaMetaAsync, DownloadMediaBytesAsync). Outbound media is sent as a URL reference inside a template
component (ImageUrl/DocumentUrl/VideoUrl on WhatsAppTemplateComponentParameterDto), not as an
uploaded binary — see §9 Templates.
Allowed: interface definitions, the one readonly struct result type.
Forbidden: any implementation logic — that belongs exclusively in Core.
3.3 Shumoul.WhatsAppIntegration.Core
The only package with implementation logic and the only package that talks to the network.
| Type | Purpose |
|---|---|
WhatsAppCloudApiClient | IWhatsAppService implementation — all outbound Meta Graph API HTTP calls |
WhatsAppSignatureValidator | IWhatsAppSignatureValidator implementation — HMAC-SHA256 constant-time compare via CryptographicOperations.FixedTimeEquals |
WhatsAppWebhookParser | IWhatsAppWebhookParser implementation — parses Meta's entry[].changes[] webhook shape |
WhatsAppIntegrationServiceCollectionExtensions | AddWhatsAppIntegration(IServiceCollection, IConfiguration) — registers all three services + a named HttpClient("WhatsAppCloudApi") |
Allowed: HTTP client logic, JSON parsing, cryptographic signature checks, IHttpClientFactory usage.
Forbidden: any persistence, any tenant-awareness, any dependency on the ERP's assemblies (enforced simply
by this being a separate repository with its own solution — there is no ERP project reference to violate).
3.4 Tests
Tests/ — xUnit, 29 test cases across 4 files:
| File | Cases | Covers |
|---|---|---|
WhatsAppWebhookParserTests.cs | 9 | Text/media/status message parsing, ProfileName regression coverage |
WhatsAppSignatureValidatorTests.cs | 7 | Valid/invalid/missing/malformed signature headers |
WhatsAppCloudApiClientRequestConstructionTests.cs | 8 | Text/template send HTTP request shape |
WhatsAppCloudApiClientMediaTests.cs | 5 | Media metadata lookup and binary download |
See §12 Testing for full coverage detail.
3.5 Allowed and Forbidden Responsibilities — Summary
| Allowed | Forbidden | |
|---|---|---|
| Any package in this repo | Meta Cloud API concepts, DTOs, HTTP, cryptography | Tenant IDs, database access, ERP business rules, phone-number business logic |
| This repo as a whole | Growing new Meta-specific capabilities (e.g. new message types Meta adds) | Growing an Adapters or Persistence package, becoming a MessagingFramework, absorbing Inbox/Conversation/Communication code from the ERP |
