Skip to main content
The WSAPI .NET SDK provides a strongly-typed C# client for sending WhatsApp messages, managing groups and chats, and receiving real-time events via webhooks or Server-Sent Events (SSE).

Installation

dotnet add package WSApi.Client

Requirements

  • .NET 7.0 or later
  • Valid WSAPI API key and instance ID

Quick start

using WSApi.Client.ApiClient;
using WSApi.Client.Models.Requests.Messages;

var httpClient = new HttpClient
{
    BaseAddress = new Uri("https://api.wsapi.chat")
};
httpClient.DefaultRequestHeaders.Add("X-Api-Key", "<your-api-key>");
httpClient.DefaultRequestHeaders.Add("X-Instance-Id", "<instance-id>");

var messagesClient = new MessagesClient(httpClient);
var request = new MessageSendTextRequest
{
    To = "1234567890@s.whatsapp.net",
    Text = "Hello from .NET SDK!"
};
await messagesClient.SendTextAsync(request);
Register the WSAPI client in your DI container for ASP.NET Core applications:
// Program.cs
builder.Services.AddWsApiClient("<your-api-key>", "<instance-id>");
Then inject IWSApiClient where needed:
public class MyService
{
    private readonly IWSApiClient _wsApiClient;

    public MyService(IWSApiClient wsApiClient)
    {
        _wsApiClient = wsApiClient;
    }

    public async Task SendMessage()
    {
        var request = new MessageSendTextRequest
        {
            To = "1234567890@s.whatsapp.net",
            Text = "Hello from .NET SDK!"
        };
        await _wsApiClient.Messages.SendTextAsync(request);
    }
}
All API endpoints are available via the corresponding client classes in WSApi.Client.ApiClient (e.g., GroupsClient, ChatsClient, ContactsClient) or through the unified IWSApiClient interface.

Error handling

The SDK provides two method variants for every operation:
Standard methods throw exceptions when API calls fail and return the result directly on success:
try
{
    var result = await messagesClient.SendTextAsync(request);
    Console.WriteLine($"Message sent with ID: {result.MessageId}");
}
catch (ApiException ex)
{
    Console.WriteLine($"Failed to send message: {ex.Message}");
}

Receiving events via SSE

Create a BackgroundService to handle SSE events:
using WSApi.Client;
using WSApi.Client.Models.Constants;
using WSApi.Client.Models.Events.Messages;
using WSApi.Client.SSE;

public class SSEClientService : BackgroundService
{
    private readonly IServiceScopeFactory _scopeFactory;
    private readonly ILogger<SSEClientService> _logger;
    private readonly ISSEClient _sseClient;

    public SSEClientService(
        IServiceScopeFactory scopeFactory,
        ILogger<SSEClientService> logger,
        ISSEClient sseClient)
    {
        _scopeFactory = scopeFactory;
        _logger = logger;
        _sseClient = sseClient;
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        _sseClient.RawEventReceived += OnRawEventReceived;
        _sseClient.ConnectionStateChanged += OnConnectionStateChanged;

        _logger.LogInformation("Starting SSE client...");
        await _sseClient.StartAsync(stoppingToken);
    }

    private void OnRawEventReceived(object? sender, RawEventReceivedEventArgs args)
    {
        var evt = EventFactory.ParseEvent(args.RawJson);

        switch (evt.EventType)
        {
            case EventTypes.Message:
                var messageEvent = (MessageEvent)evt;
                _logger.LogInformation(
                    "Message received: {Text} From: {From}",
                    messageEvent.Text, messageEvent.SenderName);
                break;
        }
    }

    private void OnConnectionStateChanged(
        object? sender, SSEConnectionStateChangedEventArgs args)
    {
        _logger.LogInformation("SSE state changed to: {State}", args.State);
    }
}
Register the service in Program.cs:
builder.Services.AddWsApiClient(apiKey, instanceId);
builder.Services.AddHostedService<SSEClientService>();

Handling webhooks

1

Create an authorization attribute

public class WebhookAuthorizationAttribute : Attribute, IAuthorizationFilter
{
    public void OnAuthorization(AuthorizationFilterContext context)
    {
        var config = context.HttpContext.RequestServices
            .GetRequiredService<IConfiguration>();
        var header = config["WSAPI:WebhookHeader"];
        var secret = config["WSAPI:WebhookSecret"];

        if (string.IsNullOrEmpty(header) || string.IsNullOrEmpty(secret))
            return;

        if (!context.HttpContext.Request.Headers
                .TryGetValue(header, out var value) || value != secret)
        {
            context.Result = new UnauthorizedObjectResult(
                "Invalid or missing webhook secret");
        }
    }
}
2

Create the webhook controller

[ApiController]
[Route("wsapi")]
public class WebhookController : ControllerBase
{
    private readonly ILogger<WebhookController> _logger;

    public WebhookController(ILogger<WebhookController> logger)
    {
        _logger = logger;
    }

    [WebhookAuthorization]
    [HttpPost("webhook")]
    public async Task<IActionResult> Webhook(CancellationToken ct)
    {
        var json = await new StreamReader(
            HttpContext.Request.Body).ReadToEndAsync(ct);
        var evt = EventFactory.ParseEvent(json);

        switch (evt.EventType)
        {
            case EventTypes.Message:
                var msg = (MessageEvent)evt;
                _logger.LogInformation(
                    "Message: {Text} From: {From}",
                    msg.Text, msg.Sender.User);
                break;
        }

        return Ok();
    }
}
3

Configure appsettings.json

{
  "WSAPI": {
    "ApiKey": "sk_your_api_key_here",
    "InstanceId": "ins_your_instance_id_here",
    "WebhookHeader": "X-Auth-Secret",
    "WebhookSecret": "your_webhook_secret_here"
  }
}

GitHub

github.com/wsapi-chat/wsapi-dotnet