C# / .NET SDK

C# / .NET SDK

The official .NET SDK for Sent LogoSent provides first-class C# support with native async/await, dependency injection integration, and full compatibility with .NET Standard 2.0+.

Requirements

This library requires .NET Standard 2.0 or later.

Installation

dotnet add package Sentdm
Install-Package Sentdm
<PackageReference Include="Sentdm" Version="0.7.0" />

Quick Start

Initialize the client

using Sentdm;

// Configured using the SENT_DM_API_KEY environment variable
SentDmClient client = new();

Send your first message

using Sentdm;
using Sentdm.Models.Messages;
using System.Collections.Generic;

SentDmClient client = new();

MessageSendParams parameters = new()
{
    To = new List<string> { "+1234567890" },
    Channels = new List<string> { "sms", "whatsapp" },
    Template = new MessageSendParamsTemplate
    {
        Id = "7ba7b820-9dad-11d1-80b4-00c04fd430c8",
        Name = "welcome",
        Parameters = new Dictionary<string, string>()
        {
            { "name", "John Doe" },
            { "order_id", "12345" }
        }
    }
};

var response = await client.Messages.SendAsync(parameters);
Console.WriteLine($"Sent: {response.Data.Messages[0].Id}");
Console.WriteLine($"Status: {response.Data.Messages[0].Status}");

Client configuration

Configure the client using environment variables or explicitly:

PropertyEnvironment variableRequiredDefault value
ApiKeySENT_DM_API_KEYtrue-
BaseUrlSENT_DM_BASE_URLtrue"https://api.sent.dm"
using Sentdm;

// Using environment variables
SentDmClient client = new();

// Or explicit configuration
SentDmClient client = new()
{
    ApiKey = "your_api_key",
};

// Or a combination
SentDmClient client = new()
{
    ApiKey = "your_api_key",  // Explicit
    // Other settings from environment
};

Modifying configuration

To temporarily use a modified client configuration, while reusing the same connection and thread pools, call WithOptions:

var clientWithOptions = client.WithOptions(options =>
    options with
    {
        BaseUrl = "https://example.com",
        MaxRetries = 5,
    }
);

Using a with expression makes it easy to construct the modified options.

Send Messages

Send a message

using Sentdm.Models.Messages;

MessageSendParams parameters = new()
{
    To = new List<string> { "+1234567890" },
    Channels = new List<string> { "sms", "whatsapp" },
    Template = new MessageSendParamsTemplate
    {
        Id = "7ba7b820-9dad-11d1-80b4-00c04fd430c8",
        Name = "welcome",
        Parameters = new Dictionary<string, string>()
        {
            { "name", "John Doe" },
            { "order_id", "12345" }
        }
    }
};

var response = await client.Messages.SendAsync(parameters);
Console.WriteLine($"Message ID: {response.Data.Messages[0].Id}");
Console.WriteLine($"Status: {response.Data.Messages[0].Status}");

Test mode

Use TestMode = true to validate requests without sending real messages:

MessageSendParams parameters = new()
{
    To = new List<string> { "+1234567890" },
    Template = new MessageSendParamsTemplate
    {
        Id = "7ba7b820-9dad-11d1-80b4-00c04fd430c8",
        Name = "welcome"
    },
    TestMode = true // Validates but doesn't send
};

var response = await client.Messages.SendAsync(parameters);

// Response will have test data
Console.WriteLine($"Validation passed: {response.Data.Messages[0].Id}");

Error handling

The SDK throws custom unchecked exception types:

StatusException
400SentDmBadRequestException
401SentDmUnauthorizedException
403SentDmForbiddenException
404SentDmNotFoundException
422SentDmUnprocessableEntityException
429SentDmRateLimitException
5xxSentDm5xxException
try
{
    var response = await client.Messages.SendAsync(parameters);
    Console.WriteLine($"Sent: {response.Data.Messages[0].Id}");
}
catch (SentDmNotFoundException e)
{
    Console.WriteLine($"Not found: {e.Message}");
}
catch (SentDmRateLimitException e)
{
    Console.WriteLine($"Rate limited. Retry after delay");
}
catch (SentDmApiException e)
{
    Console.WriteLine($"API Error: {e.Message}");
}

Raw responses

To access response headers, status code, or raw body, prefix any HTTP method call with WithRawResponse:

var response = await client.WithRawResponse.Messages.SendAsync(parameters);
var statusCode = response.StatusCode;
var headers = response.Headers;

// Deserialize if needed
var deserialized = await response.Deserialize();

Retries

The SDK automatically retries 2 times by default, with a short exponential backoff between requests.

Only the following error types are retried:

  • Connection errors
  • 408 Request Timeout
  • 409 Conflict
  • 429 Rate Limit
  • 5xx Internal
using Sentdm;

// Configure for all requests
SentDmClient client = new() { MaxRetries = 3 };

// Or per-request
await client
    .WithOptions(options => options with { MaxRetries = 3 })
    .Messages.SendAsync(parameters);

Timeouts

Requests time out after 1 minute by default.

using System;
using Sentdm;

// Configure for all requests
SentDmClient client = new() { Timeout = TimeSpan.FromSeconds(30) };

// Or per-request
await client
    .WithOptions(options => options with { Timeout = TimeSpan.FromSeconds(30) })
    .Messages.SendAsync(parameters);

Contacts

Create and manage contacts:

using Sentdm.Models.Contacts;

// Create a contact
ContactCreateParams createParams = new()
{
    PhoneNumber = "+1234567890"
};

var contact = await client.Contacts.CreateAsync(createParams);
Console.WriteLine($"Contact ID: {contact.Data.Id}");

// List contacts
ContactListParams listParams = new()
{
    Limit = 100
};

var contacts = await client.Contacts.ListAsync(listParams);
foreach (var c in contacts.Data.Data)
{
    Console.WriteLine($"{c.PhoneNumber} - {c.AvailableChannels}");
}

// Get a contact
var contact = await client.Contacts.GetAsync("contact-uuid");

// Update a contact
ContactUpdateParams updateParams = new()
{
    PhoneNumber = "+1987654321"
};

var updated = await client.Contacts.UpdateAsync("contact-uuid", updateParams);

// Delete a contact
await client.Contacts.DeleteAsync("contact-uuid");

Templates

List and retrieve templates:

using Sentdm.Models.Templates;

// List templates
var templates = await client.Templates.ListAsync();
foreach (var template in templates.Data.Data)
{
    Console.WriteLine($"{template.Name} ({template.Status}): {template.Id}");
}

// Get a specific template
var template = await client.Templates.GetAsync("template-uuid");
Console.WriteLine($"Name: {template.Data.Name}");
Console.WriteLine($"Status: {template.Data.Status}");

ASP.NET Core Integration

Dependency Injection Setup

// Program.cs
using Sentdm;

var builder = WebApplication.CreateBuilder(args);

// Add Sent client
builder.Services.AddSentDm(options =>
{
    options.ApiKey = builder.Configuration["Sent:ApiKey"]!;
});

var app = builder.Build();

Minimal API Example

// Program.cs
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddSentDm(options =>
{
    options.ApiKey = builder.Configuration["Sent:ApiKey"]!;
});

var app = builder.Build();

// Send message endpoint
app.MapPost("/api/send-message", async (
    MessageSendParams req,
    SentDmClient client,
    CancellationToken ct) =>
{
    try
    {
        var result = await client.Messages.SendAsync(req, ct);
        return Results.Ok(new
        {
            MessageId = result.Data.Messages[0].Id,
            Status = result.Data.Messages[0].Status,
        });
    }
    catch (SentDmApiException ex)
    {
        return Results.BadRequest(new { Error = ex.Message });
    }
});

app.Run();

MVC Controller

// Controllers/MessagesController.cs
using Microsoft.AspNetCore.Mvc;
using Sentdm;
using Sentdm.Models.Messages;

namespace MyApp.Controllers;

[ApiController]
[Route("api/[controller]")]
public class MessagesController : ControllerBase
{
    private readonly SentDmClient _client;
    private readonly ILogger<MessagesController> _logger;

    public MessagesController(SentDmClient client, ILogger<MessagesController> logger)
    {
        _client = client;
        _logger = logger;
    }

    [HttpPost("send")]
    public async Task<IActionResult> SendMessage([FromBody] MessageSendParams request)
    {
        try
        {
            var result = await _client.Messages.SendAsync(request);
            return Ok(new
            {
                MessageId = result.Data.Messages[0].Id,
                Status = result.Data.Messages[0].Status
            });
        }
        catch (SentDmApiException ex)
        {
            _logger.LogError(ex, "Failed to send message");
            return BadRequest(new { Error = ex.Message });
        }
    }
}

Client configuration from appsettings.json

{
  "Sent": {
    "ApiKey": "your_api_key_here",
    "BaseUrl": "https://api.sent.dm",
    "Timeout": 30,
    "MaxRetries": 3
  }
}
// Program.cs
builder.Services.AddSentDm(options =>
{
    var config = builder.Configuration.GetSection("Sent");
    options.ApiKey = config["ApiKey"]!;
    options.BaseUrl = config["BaseUrl"];
    options.Timeout = TimeSpan.FromSeconds(config.GetValue<int>("Timeout"));
    options.MaxRetries = config.GetValue<int>("MaxRetries");
});

Source & Issues

Getting Help

On this page