DevFlowMessaging.Sdk
1.0.0-preview.2
dotnet add package DevFlowMessaging.Sdk --version 1.0.0-preview.2
NuGet\Install-Package DevFlowMessaging.Sdk -Version 1.0.0-preview.2
<PackageReference Include="DevFlowMessaging.Sdk" Version="1.0.0-preview.2" />
<PackageVersion Include="DevFlowMessaging.Sdk" Version="1.0.0-preview.2" />
<PackageReference Include="DevFlowMessaging.Sdk" />
paket add DevFlowMessaging.Sdk --version 1.0.0-preview.2
#r "nuget: DevFlowMessaging.Sdk, 1.0.0-preview.2"
#:package DevFlowMessaging.Sdk@1.0.0-preview.2
#addin nuget:?package=DevFlowMessaging.Sdk&version=1.0.0-preview.2&prerelease
#tool nuget:?package=DevFlowMessaging.Sdk&version=1.0.0-preview.2&prerelease
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 | Versions 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. |
-
net8.0
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.2)
- Microsoft.Extensions.Http (>= 10.0.2)
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.