FluentWhatsApp 2.0.0

dotnet add package FluentWhatsApp --version 2.0.0
                    
NuGet\Install-Package FluentWhatsApp -Version 2.0.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="FluentWhatsApp" Version="2.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="FluentWhatsApp" Version="2.0.0" />
                    
Directory.Packages.props
<PackageReference Include="FluentWhatsApp" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add FluentWhatsApp --version 2.0.0
                    
#r "nuget: FluentWhatsApp, 2.0.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package FluentWhatsApp@2.0.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=FluentWhatsApp&version=2.0.0
                    
Install as a Cake Addin
#tool nuget:?package=FluentWhatsApp&version=2.0.0
                    
Install as a Cake Tool

FluentWhatsApp

A modern, fluent dotnet SDK for sending WhatsApp messages through the WhatsApp Cloud API. Built as a lightweight class library using System.Text.Json for serialization β€” with no external JSON dependencies.

Installation

dotnet add package FluentWhatsApp

Sending messages

Every message is built using the fluent WhatsAppMessage API and sent via IWhatsAppClient.

// Build a request
var request = WhatsAppMessage.To("+1234567890").Text("Hello!").Build();

// Send it
SendMessageResponse response = await client.SendAsync(request);
Console.WriteLine(response.FirstMessageId); // wamid.xxx

Using the interface helpers

await client.SendToIndividualAsync("+1234567890", b =>
    b.Text("Hello!").Build());

await client.SendToGroupAsync("GROUP_ID", b =>
    b.Text("Hello group!").Build());

Setup

Register the client in your DI container with your phone number ID and access token:

builder.Services.AddWhatsAppClient(options =>
{
    options.PhoneNumberId = "YOUR_PHONE_NUMBER_ID";
    options.AccessToken   = "YOUR_ACCESS_TOKEN";
    // options.ApiVersion = "v22.0"; // default
});

Then inject IWhatsAppClient wherever you need it:

public class NotificationService(IWhatsAppClient whatsApp)
{
    public Task NotifyAsync(string phone) =>
        whatsApp.SendToIndividualAsync(phone, b => b.Text("Hello from FluentWhatsApp!").Build());
}

Resilience

The library registers a standard resilience pipeline (retry, circuit-breaker, timeouts) via Microsoft.Extensions.Http.Resilience. Customise it through the optional second parameter:

builder.Services.AddWhatsAppClient(
    options =>
    {
        options.PhoneNumberId = "...";
        options.AccessToken   = "...";
    },
    resilience =>
    {
        resilience.Retry.MaxRetryAttempts = 5;
    });

Custom client

Bring your own IWhatsAppClient implementation (e.g., for testing):

builder.Services.AddWhatsAppClient<MyCustomClient>();

Message types

Text

var request = WhatsAppMessage
    .To("+1234567890")
    .Text("Hello, World!")
    .Build();

With URL preview:

var request = WhatsAppMessage
    .To("+1234567890")
    .Text("Check this out: https://example.com", previewUrl: true)
    .Build();

Image

// By URL
var request = WhatsAppMessage
    .To("+1234567890")
    .Image(link: "https://example.com/image.jpg", caption: "Look at this!")
    .Build();

// By media ID (uploaded via Media API)
var request = WhatsAppMessage
    .To("+1234567890")
    .Image(mediaId: "MEDIA_ID")
    .Build();

Audio

var request = WhatsAppMessage
    .To("+1234567890")
    .Audio(link: "https://example.com/audio.mp3")
    .Build();

Video

var request = WhatsAppMessage
    .To("+1234567890")
    .Video(link: "https://example.com/video.mp4", caption: "Watch this")
    .Build();

Document

var request = WhatsAppMessage
    .To("+1234567890")
    .Document(link: "https://example.com/file.pdf", caption: "Your invoice")
    .WithFilename("invoice.pdf")
    .Build();

Sticker

var request = WhatsAppMessage
    .To("+1234567890")
    .Sticker(link: "https://example.com/sticker.webp")
    .Build();

Location

var request = WhatsAppMessage
    .To("+1234567890")
    .Location(37.7749, -122.4194)
    .WithName("San Francisco")
    .WithAddress("San Francisco, CA, USA")
    .Build();

Reaction

// Returns a MessageRequest directly β€” no .Build() needed
var request = WhatsAppMessage
    .To("+1234567890")
    .Reaction("wamid.MESSAGE_ID", "πŸ‘");

await client.SendAsync(request);

Contacts

var request = WhatsAppMessage
    .To("+1234567890")
    .Contacts()
    .Add(c => c
        .Name("John Doe", firstName: "John", lastName: "Doe")
        .Phone("+19998887777")
        .Email("john@example.com"))
    .Add(c => c
        .Name("Jane Doe", firstName: "Jane")
        .Phone("+19997776666", type: "WORK"))
    .Build();

Interactive β€” Reply buttons

Up to 3 buttons.

var request = WhatsAppMessage
    .To("+1234567890")
    .Interactive("Would you like to proceed?")
    .WithFooter("Tap a button to respond")
    .ReplyButtons()
    .Add("yes", "Yes, continue")
    .Add("no",  "No, cancel")
    .Build();

Interactive β€” List

var request = WhatsAppMessage
    .To("+1234567890")
    .Interactive("Choose a subscription plan")
    .WithHeader("Our Plans")
    .WithFooter("Prices are monthly")
    .List("View Plans")
    .Section("Monthly")
        .Row("m_basic", "Basic",   "$9/mo")
        .Row("m_pro",   "Pro",     "$19/mo")
        .Row("m_ultra", "Ultra",   "$49/mo")
    .Section("Annual")
        .Row("a_basic", "Basic Annual",  "$90/yr")
        .Row("a_pro",   "Pro Annual",    "$190/yr")
    .Build();

Interactive β€” CTA URL button

var request = WhatsAppMessage
    .To("+1234567890")
    .Interactive("Visit our website")
    .CtaUrl("Open site", "https://example.com");

Interactive β€” Flow

var request = WhatsAppMessage
    .To("+1234567890")
    .Interactive("Fill in your details")
    .Flow("FLOW_TOKEN", "FLOW_ID", "Start");

Interactive β€” Catalog

var request = WhatsAppMessage
    .To("+1234567890")
    .Interactive("Browse our catalog")
    .Catalog();

Template

var request = WhatsAppMessage
    .To("+1234567890")
    .Template("order_confirmation", "en_US")
    .AddBodyParameters(p => p
        .Text("John")
        .Text("Order #42")
        .Text("$59.99"))
    .AddButton(0, "url", p => p.Text("/orders/42"))
    .Build();

Typing indicator

Show a "typing…" indicator before sending a message:

var request = WhatsAppMessage
    .To("+1234567890")
    .TypingIndicator("wamid.INCOMING_MESSAGE_ID")
    .Build();

await client.SendAsync(request);

Reply context and callback data

Chain .ReplyTo() and/or .WithCallbackData() before the message type method to attach a reply context or a business opaque callback string:

var request = WhatsAppMessage
    .To("+1234567890")
    .ReplyTo("wamid.ORIGINAL_MESSAGE_ID")
    .WithCallbackData("order_ref_42")
    .Text("Got your message!")
    .Build();

Group messages

var request = WhatsAppMessage
    .ToGroup("GROUP_ID")
    .Text("Hello everyone!")
    .Build();

await client.SendAsync(request);

Or use the helper:

await client.SendToGroupAsync("GROUP_ID", b =>
    b.Text("Hello everyone!").Build());

Multi-tenant / factory usage

When you need to send from multiple phone numbers at runtime, inject IWhatsAppClientFactory:

public class MultiTenantSender(IWhatsAppClientFactory factory)
{
    public Task SendAsync(string phoneNumberId, string token, string to, string text)
    {
        var client = factory.Create(o =>
        {
            o.PhoneNumberId = phoneNumberId;
            o.AccessToken   = token;
        });

        return client.SendAsync(WhatsAppMessage.To(to).Text(text).Build());
    }
}

Register the factory-only overload (no static options required):

builder.Services.AddWhatsAppClient();

Error handling

Failed API calls throw WhatsAppApiException:

try
{
    await client.SendAsync(request);
}
catch (WhatsAppApiException ex)
{
    Console.WriteLine($"Code: {ex.ErrorCode}");
    Console.WriteLine($"Type: {ex.ErrorType}");
    Console.WriteLine($"Trace: {ex.FbTraceId}");
    Console.WriteLine($"Message: {ex.Message}");
}

Response

SendMessageResponse exposes the sent message ID and contact info returned by the API:

var response = await client.SendAsync(request);

if (response.IsSuccessful)
    Console.WriteLine($"Sent: {response.FirstMessageId}");

License

MIT

Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
2.0.0 96 5/18/2026
1.0.2 107 5/14/2026
1.0.1 86 5/14/2026
1.0.0 91 5/14/2026