DevFlowMessaging.Sdk 1.0.0-preview.2

This is a prerelease version of DevFlowMessaging.Sdk.
dotnet add package DevFlowMessaging.Sdk --version 1.0.0-preview.2
                    
NuGet\Install-Package DevFlowMessaging.Sdk -Version 1.0.0-preview.2
                    
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="DevFlowMessaging.Sdk" Version="1.0.0-preview.2" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="DevFlowMessaging.Sdk" Version="1.0.0-preview.2" />
                    
Directory.Packages.props
<PackageReference Include="DevFlowMessaging.Sdk" />
                    
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 DevFlowMessaging.Sdk --version 1.0.0-preview.2
                    
#r "nuget: DevFlowMessaging.Sdk, 1.0.0-preview.2"
                    
#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 DevFlowMessaging.Sdk@1.0.0-preview.2
                    
#: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=DevFlowMessaging.Sdk&version=1.0.0-preview.2&prerelease
                    
Install as a Cake Addin
#tool nuget:?package=DevFlowMessaging.Sdk&version=1.0.0-preview.2&prerelease
                    
Install as a Cake Tool

DevFlow Messaging SDK for .NET

The official .NET SDK for sending messages through DevFlow Messaging. Build plain-text and rich messages with a channel-neutral API, send approved WhatsApp templates and published WhatsApp Flows, set typing indicators, and read message history.

The package targets .NET 8. Channel availability depends on the messaging providers enabled for your DevFlow account; the examples below use WhatsApp.

Install

dotnet add package DevFlowMessaging.Sdk --version 1.0.0-preview.1

You need:

  • A DevFlow Messaging account with an API key.
  • A connected messaging channel.
  • For WhatsApp, the phone-number ID used as the message sender.
  • Customer phone numbers in complete international format, such as +27821234567.

Keep the API key in your application's secret store or environment configuration. Do not commit it to source control.

Register the SDK

Add these namespaces where needed:

using DevFlowMessaging;
using DevFlowMessaging.BusinessMessaging;
using DevFlowMessaging.BusinessMessaging.Model;
using DevFlowMessaging.BusinessMessaging.Model.MultiChannel;
using DevFlowMessaging.Extensions;
using DevFlowMessaging.Interfaces;
using DevFlowMessaging.Models;

In an ASP.NET Core or worker application, register the client once during startup:

var apiKey = builder.Configuration["DevFlowMessaging:ApiKey"]
    ?? throw new InvalidOperationException("DevFlow Messaging API key is missing.");

builder.Services
    .AddDevFlowMessaging()
    .WithApiKey(apiKey);

For local development, set the key with .NET user secrets:

dotnet user-secrets set "DevFlowMessaging:ApiKey" "YOUR_API_KEY"

In a deployed environment, the equivalent environment-variable name is DevFlowMessaging__ApiKey.

Inject IDevFlowMessagingClient into the service that sends messages:

public sealed class OrderNotifier(IDevFlowMessagingClient messaging)
{
    public async Task NotifyShippedAsync(
        string phoneNumberId,
        string customerNumber,
        string orderNumber,
        CancellationToken cancellationToken = default)
    {
        var message = new MessageBuilder(
                $"Your order {orderNumber} has shipped.",
                from: phoneNumberId,
                to: customerNumber)
            .WithAllowedChannels(Channel.WhatsApp)
            .WithReference($"order-{orderNumber}")
            .Build();

        await messaging.SendMessageAsync(message, cancellationToken);
    }
}

Use the SDK without dependency injection

For a console application or a small integration, construct the client directly:

var apiKey = Environment.GetEnvironmentVariable("DEVFLOW_MESSAGING_API_KEY")
    ?? throw new InvalidOperationException("DevFlow Messaging API key is missing.");

var messaging = new DevFlowMessagingClient(apiKey);

Send a text message

from is the channel-specific sender. For WhatsApp, use the connected phone-number ID. One message can contain one or more recipients.

var message = new MessageBuilder(
        "Your order is ready for collection.",
        from: phoneNumberId,
        to: customerNumber)
    .WithAllowedChannels(Channel.WhatsApp)
    .WithReference("order-123")
    .WithMetadata("customerId", "customer-456")
    .Build();

var result = await messaging.SendMessageAsync(message, cancellationToken);

foreach (var detail in result.Details)
{
    Console.WriteLine($"{detail.To}: {detail.Status} ({detail.MessageId})");
}

The reference is your application-defined correlation value and is returned with message results and events.

To send the same message to multiple recipients, pass additional numbers to the constructor:

var message = new MessageBuilder(
        "The store will close at 17:00 today.",
        from: phoneNumberId,
        customerNumber1,
        customerNumber2)
    .WithAllowedChannels(Channel.WhatsApp)
    .Build();

Send media

Media can be supplied with a publicly accessible HTTPS URL. The exact media types and size limits depend on the selected channel.

var document = new MediaMessage(
    MediaType.Document,
    mediaUri: "https://cdn.example.com/invoices/invoice-123.pdf",
    mimeType: "application/pdf",
    mediaName: "invoice-123.pdf")
{
    Caption = "Invoice 123"
};

var message = new MessageBuilder("Your invoice", phoneNumberId, customerNumber)
    .WithAllowedChannels(Channel.WhatsApp)
    .WithRichMessage(document)
    .WithReference("invoice-123")
    .Build();

await messaging.SendMessageAsync(message, cancellationToken);

MediaType supports Image, Video, Audio, Document, and Sticker.

Send a location

var location = new LocationMessage(
    latitude: -26.2041,
    longitude: 28.0473,
    name: "Collection point",
    address: "Johannesburg, South Africa");

var message = new MessageBuilder("Find us here", phoneNumberId, customerNumber)
    .WithAllowedChannels(Channel.WhatsApp)
    .WithRichMessage(location)
    .Build();

await messaging.SendMessageAsync(message, cancellationToken);

Send a menu or reply list

Channels can render a menu as reply buttons or as a selectable list.

var menu = new MenuMessage
{
    Text = "Choose an order",
    Style = MenuStyle.List,
    ButtonLabel = "View orders",
    Footer = "Select one option",
    Sections =
    [
        new MenuSection
        {
            Title = "Open orders",
            Items =
            [
                new MenuItem
                {
                    Id = "order-123",
                    Title = "Order #123",
                    Description = "Ready for collection"
                }
            ]
        }
    ]
};

var message = new MessageBuilder("Choose an order", phoneNumberId, customerNumber)
    .WithAllowedChannels(Channel.WhatsApp)
    .WithRichMessage(menu)
    .Build();

await messaging.SendMessageAsync(message, cancellationToken);

For channels that support suggestions, attach reply, URL, or dial actions:

var message = new MessageBuilder("Would you like help?", phoneNumberId, customerNumber)
    .WithAllowedChannels(Channel.WhatsApp)
    .WithSuggestions(
        new ReplySuggestion("Yes", "support-yes"),
        new ReplySuggestion("No", "support-no"))
    .Build();

Send an approved WhatsApp template

Templates must already exist and be approved for the connected WhatsApp Business account. The template name, language, component order, and parameter types must match the approved template.

var template = new TemplateMessage
{
    Content = new TemplateMessageContent
    {
        WhatsApp = new WhatsAppTemplate
        {
            Name = "order_update",
            Language = new TemplateLanguage("en_US"),
            Components =
            [
                new TemplateComponent
                {
                    Type = "body",
                    Parameters =
                    [
                        TemplateParameter.FromText("Jonathan"),
                        TemplateParameter.FromText("#123")
                    ]
                }
            ]
        }
    }
};

var message = new MessageBuilder(string.Empty, phoneNumberId, customerNumber)
    .WithAllowedChannels(Channel.WhatsApp)
    .WithTemplate(template)
    .WithReference("order-123")
    .Build();

await messaging.SendMessageAsync(message, cancellationToken);

The SDK sends approved templates; it does not create, edit, or submit templates for approval.

Send a published WhatsApp Flow

Create, validate, and publish the Flow in the DevFlow portal first. Its Developer tab shows the Meta Flow ID, initial screen, valid prefill keys, and response properties. The SDK sends the published Flow; it does not create or update Flow definitions.

var flow = new FlowMessage(
        flowId: "YOUR_META_FLOW_ID",
        text: "Please confirm your details.",
        callToAction: "Open Flow",
        screenId: "DETAILS")
    .WithFlowToken("customer-123")
    .WithPrefill("full_name", "Ava Customer")
    .WithPrefill("interests", new[] { "support", "sales" });

var message = new MessageBuilder(string.Empty, phoneNumberId, customerNumber)
    .WithAllowedChannels(Channel.WhatsApp)
    .WithFlow(flow)
    .WithReference("customer-123-flow")
    .Build();

await messaging.SendMessageAsync(message, cancellationToken);

screenId is required when prefill data is supplied. DevFlow checks that the Flow is published for the sender's WhatsApp Business Account and that every prefill key was configured from the selected screen onward.

A direct Flow message is a non-template WhatsApp message, so the customer must have an active customer-service conversation window. Use an approved template with a Flow button when initiating a conversation outside that window.

When the customer submits the Flow, a subscribed messages webhook receives normalized Flow content:

{
  "event": "messages",
  "type": "interactive",
  "content": {
    "kind": "flow",
    "flow": {
      "name": "flow",
      "body": "Sent",
      "flowToken": "customer-123",
      "replyToMessageId": "wamid.sent-flow...",
      "data": {
        "full_name": "Ava Customer",
        "interests": ["support", "sales"]
      }
    }
  },
  "providerPayload": {}
}

Use flowToken to correlate the submission with your record. replyToMessageId identifies the outbound Flow message, and data contains the response property names shown in the published Flow's Developer tab. The original Meta webhook remains in providerPayload.

Reply to a message

Add a rich message before setting its reply context. Use the channel-provider message ID of the message being answered.

var reply = new MessageBuilder("Thanks, we received your message.", phoneNumberId, customerNumber)
    .WithAllowedChannels(Channel.WhatsApp)
    .WithRichMessage(new TextMessage("Thanks, we received your message."))
    .ReplyTo(inboundMessageId)
    .Build();

await messaging.SendMessageAsync(reply, cancellationToken);

Set a typing indicator

Use the inbound provider message ID and the sender that will respond:

var indicator = new MessageIndicatorBuilder(
        inboundMessageId,
        from: phoneNumberId,
        channel: Channel.WhatsApp)
    .WithIndicator(MessageIndicatorType.Typing)
    .Build();

var result = await messaging.SetMessageIndicatorAsync(indicator, cancellationToken);

Read message history

Return all inbound and outbound messages available to the API key:

var history = await messaging.GetMessageHistoryAsync(
    cancellationToken: cancellationToken);

foreach (var item in history.Messages)
{
    Console.WriteLine($"{item.CreatedAt:u} {item.Direction} {item.Channel} {item.Status}");
}

Or combine optional customer, inclusive date-range, and channel filters:

var history = await messaging.GetMessageHistoryAsync(
    new MessageHistoryQuery
    {
        PhoneNumber = "+27821234567",
        StartDate = new DateTimeOffset(2026, 7, 1, 0, 0, 0, TimeSpan.Zero),
        EndDate = new DateTimeOffset(2026, 7, 31, 23, 59, 59, TimeSpan.Zero),
        Channel = Channel.WhatsApp
    },
    cancellationToken);

Results are newest first and include direction, channel, customer identifiers, status timestamps, provider message IDs, and error details when available.

Configure the timeout

Use the options overload when the application needs a timeout other than the 30-second default:

builder.Services.AddDevFlowMessaging(options =>
{
    options.ApiKey = builder.Configuration["DevFlowMessaging:ApiKey"]
        ?? throw new InvalidOperationException("DevFlow Messaging API key is missing.");
    options.Timeout = TimeSpan.FromSeconds(60);
});

Handle SDK errors

Invalid message construction throws InvalidOperationException before a request is sent. Unsuccessful responses throw DevFlowMessagingApiException, which includes the status code and response details.

try
{
    await messaging.SendMessageAsync(message, cancellationToken);
}
catch (DevFlowMessagingApiException exception)
{
    logger.LogError(
        exception,
        "DevFlow Messaging rejected the message with status {StatusCode}: {ResponseBody}",
        exception.StatusCode,
        exception.ResponseBody);
}
catch (OperationCanceledException) when (cancellationToken.IsCancellationRequested)
{
    // The caller cancelled the operation.
}

Pass a CancellationToken to all SDK operations in web requests, background services, and shutdown-sensitive workflows.

Support

API keys, connected senders, and account configuration are managed in the DevFlow developer portal.

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  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
1.0.0-preview.2 82 8/12/2026

Initial public preview of the DevFlow Messaging .NET SDK.