> ## Documentation Index
> Fetch the complete documentation index at: https://docs.wsapi.chat/llms.txt
> Use this file to discover all available pages before exploring further.

# .NET SDK

> .NET SDK for integrating WSAPI into C# applications

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

<Tabs>
  <Tab title="NuGet CLI">
    ```bash theme={null}
    dotnet add package WSApi.Client
    ```
  </Tab>

  <Tab title="Package Manager Console">
    ```powershell theme={null}
    Install-Package WSApi.Client
    ```
  </Tab>
</Tabs>

## Requirements

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

## Quick start

```csharp theme={null}
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);
```

## Dependency injection (recommended)

Register the WSAPI client in your DI container for ASP.NET Core applications:

```csharp theme={null}
// Program.cs
builder.Services.AddWsApiClient("<your-api-key>", "<instance-id>");
```

Then inject `IWSApiClient` where needed:

```csharp theme={null}
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:

<Tabs>
  <Tab title="Exception-based">
    Standard methods throw exceptions when API calls fail and return the result directly on success:

    ```csharp theme={null}
    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}");
    }
    ```
  </Tab>

  <Tab title="Try-based (non-throwing)">
    Methods prefixed with `Try` never throw exceptions. They return an `ApiResponse<T>` object:

    ```csharp theme={null}
    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}");
    }
    ```

    The `ApiResponse<T>` object contains:

    * `Result` — response data (null if failed)
    * `Error` — error details as `ProblemDetails` (null if successful)
    * `IsSuccess` — boolean indicating success
  </Tab>
</Tabs>

## Receiving events via SSE

Create a `BackgroundService` to handle SSE events:

```csharp theme={null}
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`:

```csharp theme={null}
builder.Services.AddWsApiClient(apiKey, instanceId);
builder.Services.AddHostedService<SSEClientService>();
```

## Handling webhooks

<Steps>
  <Step title="Create an authorization attribute">
    ```csharp theme={null}
    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");
            }
        }
    }
    ```
  </Step>

  <Step title="Create the webhook controller">
    ```csharp theme={null}
    [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();
        }
    }
    ```
  </Step>

  <Step title="Configure appsettings.json">
    ```json theme={null}
    {
      "WSAPI": {
        "ApiKey": "sk_your_api_key_here",
        "InstanceId": "ins_your_instance_id_here",
        "WebhookHeader": "X-Auth-Secret",
        "WebhookSecret": "your_webhook_secret_here"
      }
    }
    ```
  </Step>
</Steps>

## GitHub

[github.com/wsapi-chat/wsapi-dotnet](https://github.com/wsapi-chat/wsapi-dotnet)
