WSApi.Client
1.0.5
dotnet add package WSApi.Client --version 1.0.5
NuGet\Install-Package WSApi.Client -Version 1.0.5
<PackageReference Include="WSApi.Client" Version="1.0.5" />
<PackageVersion Include="WSApi.Client" Version="1.0.5" />
<PackageReference Include="WSApi.Client" />
paket add WSApi.Client --version 1.0.5
#r "nuget: WSApi.Client, 1.0.5"
#:package WSApi.Client@1.0.5
#addin nuget:?package=WSApi.Client&version=1.0.5
#tool nuget:?package=WSApi.Client&version=1.0.5
WSApi.Client (.NET SDK)
A .NET SDK for integrating with the WSApi API, enabling developers to send WhatsApp messages, manage groups and chats, and receive real-time events via Webhooks or Server-Sent Events (SSE).
Features
- HTTP Client: Simple, strongly-typed client for all API commands (messages, groups, chats, contacts, etc).
- Events: Receive real-time events from the API via:
- Webhooks: Configure your endpoint to receive HTTP POST events.
- SSE: Use the built-in SSE client to receive events over a persistent connection.
- Example Projects:
- Console Example: Demonstrates SSE event handling.
- Web Example: Demonstrates webhook event handling.
Getting Started
Prerequisites
- .NET 6.0 or later (change .csproj
TargetFramework
tag if necessary) - Access to the WSApi API (Valid instance with ID and API key)
Installation
From NuGet (Recommended)
dotnet add package WSApi.Client
Or using Package Manager Console in Visual Studio:
Install-Package WSApi.Client
From Source
Clone the repository and add a reference to WSApi.Client
in your project:
dotnet add package WSApi.Client --source ./WSApi.Client
Or add the project reference directly in your .csproj
:
<ProjectReference Include="../WSApi.Client/WSApi.Client.csproj" />
Usage
1. Sending Messages & Using the API
// Method 1: Direct instantiation
using System.Net.Http;
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", // Phone number in WhatsApp format
Text = "Hello from .NET SDK!"
};
await messagesClient.SendTextAsync(request);
// Method 2: Using dependency injection (recommended)
// In Program.cs or Startup.cs:
builder.Services.AddWsApiClient("<your-api-key>", "<instance-id>");
// Then inject IWSApiClient in your services:
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", // Phone number in WhatsApp format
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
, etc) or through the unified IWSApiClient
interface.
Exception Handling: Two Method Versions
For each API method available in the SDK, there are two versions to handle different error scenarios:
Standard Methods (e.g.,
SendTextAsync()
,SendImageAsync()
, etc.)- Throws exceptions when API calls fail
- Returns the result directly on success
- Use when you want exceptions to bubble up for centralized error handling
Try Methods (e.g.,
TrySendTextAsync()
,TrySendImageAsync()
, etc.)- Never throws exceptions
- Returns an
ApiResponse<T>
object that contains either the result or error details - Use when you want to handle errors inline without exception handling
ApiResponse<T> Object Structure:
Result
: Contains the successful response data (null if failed)Error
: Contains error details asProblemDetails
(null if successful)IsSuccess
: Boolean indicating if the operation was successful
Example:
// Method 1: Exception-based (throws on error)
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}");
}
// Method 2: ApiResponse-based (no exceptions)
var response = await messagesClient.TrySendTextAsync(request);
if (response.IsSuccess)
{
Console.WriteLine($"Message sent with ID: {response.Result.MessageId}");
}
else
{
Console.WriteLine($"Failed to send message: {response.Error.Detail}");
}
2. Receiving Events
a) Webhooks
Configure your webhook URL in the WSApi dashboard.
Set up authentication using the
WebhookAuthorizationAttribute
:
// Authorization/WebhookAuthorizationAttribute.cs
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
public class WebhookAuthorizationAttribute : Attribute, IAuthorizationFilter
{
public void OnAuthorization(AuthorizationFilterContext context)
{
var configuration = context.HttpContext.RequestServices.GetRequiredService<IConfiguration>();
var webhookHeader = configuration["WSAPI:WebhookHeader"];
var webhookSecret = configuration["WSAPI:WebhookSecret"];
if (string.IsNullOrEmpty(webhookHeader) || string.IsNullOrEmpty(webhookSecret))
return; // Skip validation if not configured
if (!context.HttpContext.Request.Headers.TryGetValue(webhookHeader, out var headerValue) || headerValue != webhookSecret)
{
context.Result = new UnauthorizedObjectResult("Invalid or missing webhook secret");
}
}
}
- Configure your application in
Program.cs
:
using WSApi.Client;
var builder = WebApplication.CreateBuilder(args);
// Configure WSAPI Client
var apiKey = builder.Configuration["WSAPI:ApiKey"] ?? throw new InvalidOperationException("WSAPI:ApiKey is not set in configuration");
var instanceId = builder.Configuration["WSAPI:InstanceId"] ?? throw new InvalidOperationException("WSAPI:InstanceId is not set in configuration");
builder.Services.AddWsApiClient(apiKey, instanceId);
builder.Services.AddControllers();
var app = builder.Build();
app.UseRouting();
app.MapControllers();
app.Run();
- Create your webhook controller:
using Microsoft.AspNetCore.Mvc;
using WSApi.Client;
using WSApi.Client.Models.Constants;
using WSApi.Client.Models.Events.Messages;
[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 cancellationToken)
{
var json = await new StreamReader(HttpContext.Request.Body).ReadToEndAsync(cancellationToken);
var evt = EventFactory.ParseEvent(json);
switch (evt.EventType)
{
case EventTypes.Message:
var messageEvent = (MessageEvent)evt;
_logger.LogInformation("Message received: {Text} From: {From} at {ReceivedAt}",
messageEvent.Text, messageEvent.Sender.User, messageEvent.ReceivedAt);
break;
// Handle other event types as needed
}
return Ok();
}
}
- Configure authentication in
appsettings.json
:
{
"WSAPI": {
"ApiKey": "sk_your_api_key_here",
"InstanceId": "ins_your_instance_id_here",
"WebhookHeader": "X-Auth-Secret",
"WebhookSecret": "your_webhook_secret_here"
}
}
The webhook authorization is not required, but strongly recommended. The WebhookAuthorizationAttribute
validates incoming webhook requests by checking for a specific header (configured as WebhookHeader
) containing a secret value (configured as WebhookSecret
). This ensures that only authorized requests from WSApi reach your webhook endpoint. If the header is missing or contains an incorrect value, the request is rejected with a 401 Unauthorized response.
b) SSE (Server-Sent Events)
- Configure your application in
Program.cs
:
using WSApi.Client;
var builder = WebApplication.CreateBuilder(args);
builder.Logging.AddSimpleConsole(o =>
{
o.TimestampFormat = "[HH:mm:ss.fff] ";
o.SingleLine = true;
});
//Configure WSAPI Client
var apiKey = builder.Configuration["WSAPI:ApiKey"] ?? throw new InvalidOperationException("WSApi:ApiKey is not set in configuration");
var instanceId = builder.Configuration["WSAPI:InstanceId"] ?? throw new InvalidOperationException("WSApi:InstanceId is not set in configuration");
builder.Services.AddWsApiClient(apiKey, instanceId);
//End WSAPI Config
//Add SSE Client Service
builder.Services.AddHostedService<SSEClientService>();
var app = builder.Build();
app.Run();
- Create an SSE service to handle 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)
{
// Subscribe to SSE events
_sseClient.RawEventReceived += OnRawEventReceived;
_sseClient.ConnectionStateChanged += OnConnectionStateChanged;
_logger.LogInformation("Starting SSE client...");
// Start the SSE client
await _sseClient.StartAsync(stoppingToken);
}
private void OnRawEventReceived(object? sender, RawEventReceivedEventArgs args)
{
_logger.LogDebug("Raw event received: {Json}", args.RawJson);
try
{
// Parse the event using EventFactory
var evt = EventFactory.ParseEvent(args.RawJson);
// Create a scope for dependency injection (if needed)
using var scope = _scopeFactory.CreateScope();
// Handle specific event types
switch (evt.EventType)
{
case EventTypes.Message:
var messageEvent = (MessageEvent)evt;
_logger.LogInformation("Message received: {Text} From: {From} at {ReceivedAt}",
messageEvent.Text, messageEvent.SenderName, messageEvent.ReceivedAt);
break;
// Add more event type handlers as needed
}
}
catch (Exception ex)
{
_logger.LogError(ex, "Error handling event: {ExMessage} - Json: {Json}", ex.Message, args.RawJson);
}
}
private void OnConnectionStateChanged(object? sender, SSEConnectionStateChangedEventArgs args)
{
_logger.LogInformation("SSE Connection state changed to: {State}", args.State);
if (args.Exception != null)
{
_logger.LogError(args.Exception, "Connection error occurred");
}
}
public override async Task StopAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("Stopping SSE client...");
await _sseClient.StopAsync(cancellationToken);
await base.StopAsync(cancellationToken);
}
}
- Configure your
appsettings.json
:
{
"Logging": {
"LogLevel": {
"Default": "Debug",
"System": "Information",
"Microsoft": "Information"
}
},
"WSAPI": {
"ApiKey": "sk_your_api_key_here",
"InstanceId": "ins_your_instance_id_here"
}
}
Available Event Types
The SDK supports the following event types that you can handle in your application:
Session Events:
SessionLoggedInEvent
- When the WhatsApp session is establishedSessionLoggedOutEvent
- When the session is terminatedSessionLoggedErrorEvent
- When there's an authentication error
Message Events:
MessageEvent
- New incoming/outgoing messagesMessageDeleteEvent
- When messages are deletedMessageReadEvent
- When messages are readMessageStarEvent
- When messages are starredMessageHistorySyncEvent
- Message history synchronization
Chat Events:
ChatPresenceEvent
- User typing indicators, online statusChatSettingEvent
- Chat settings changes
Contact Events:
ContactEvent
- Contact information updates
User Events:
UserPushNameEvent
- User display name changesUserPictureEvent
- Profile picture updatesUserPresenceEvent
- Online/offline status changesUserStatusEvent
- Status message updates
Call Events:
CallOfferEvent
- Incoming call offersCallAcceptEvent
- Call acceptanceCallTerminateEvent
- Call termination
You only need to implement handlers for the events relevant to your application. The EventFactory.ParseEvent()
method automatically deserializes the JSON into the appropriate strongly-typed event object.
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net7.0 is compatible. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. 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 is compatible. 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. |
-
net7.0
- Microsoft.Extensions.Http (>= 7.0.0)
-
net8.0
- Microsoft.Extensions.Http (>= 8.0.1)
-
net9.0
- Microsoft.Extensions.Http (>= 9.0.8)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.