OneSend2U.Sdk
2.0.0
dotnet add package OneSend2U.Sdk --version 2.0.0
NuGet\Install-Package OneSend2U.Sdk -Version 2.0.0
<PackageReference Include="OneSend2U.Sdk" Version="2.0.0" />
<PackageVersion Include="OneSend2U.Sdk" Version="2.0.0" />
<PackageReference Include="OneSend2U.Sdk" />
paket add OneSend2U.Sdk --version 2.0.0
#r "nuget: OneSend2U.Sdk, 2.0.0"
#:package OneSend2U.Sdk@2.0.0
#addin nuget:?package=OneSend2U.Sdk&version=2.0.0
#tool nuget:?package=OneSend2U.Sdk&version=2.0.0
OneSend2U.Sdk
Lightweight .NET SDK for the OneSend2U CPaaS platform. Send notifications (SMS, Email, WhatsApp), query template configurations, track messages, manage webhooks, query API logs, manage contacts and contacts groups, and manage consents — all with API Key authentication, zero ABP dependencies.
Installation
dotnet add package OneSend2U.Sdk
Quick Start
DI Registration (Recommended)
Includes resilience policies (retry + circuit breaker) via Microsoft.Extensions.Http.Resilience.
services.AddOneSend2U(options =>
{
options.BaseUrl = "https://api.onesend2u.com";
options.ApiKey = "sk_prefix.your-api-key";
options.TenantId = "your-tenant-id";
});
Then inject OneSend2UClient:
public class MyService(OneSend2UClient client)
{
public async Task SendInvoiceAsync()
{
var result = await client.Notifications.SendAsync(new SendNotificationRequest
{
TransactionId = Guid.NewGuid().ToString(),
Application = "myapp",
Region = "es",
Language = "es-ES",
NotificationType = "ORD",
NotificationSubtype = "CNF",
Recipients = [new NotificationRecipient { Channel = "sms", Recipient = "+34699999999" }],
TemplateVariables = [new Dictionary<string, string>
{
{ "customer_name", "John Doe" },
{ "invoice_number", "INV-001" }
}]
});
Console.WriteLine($"Status: {result.Status}");
}
}
Non-DI Usage
Does not include resilience policies.
using var client = new OneSend2UClient(new OneSend2UClientOptions
{
BaseUrl = "https://api.onesend2u.com",
ApiKey = "sk_prefix.your-api-key",
TenantId = "your-tenant-id"
});
var result = await client.Notifications.SendAsync(request);
Template Discovery Workflow
Find template configurations for your app/region/environment:
var configs = await client.Templates.GetListAsync(new GetTemplateConfigurationsRequest { IsActive = true, ApplicationId = myAppId });Get full details including the linked template:
var details = await client.Templates.GetWithDetailsAsync(configId); var templateId = details.TemplateConfiguration!.TemplateId!.Value;Discover required variables:
var variables = await client.Templates.GetTemplateVariableDefinitionsAsync(templateId); // Returns: [{ Name: "customer_name", SampleValue: "John" }, ...]Send using discovered variable names:
await client.Notifications.SendAsync(new SendNotificationRequest { // ... codes from the template configuration ... TemplateVariables = [variables.ToDictionary(v => v.Name!, v => "actual value")] });
Validate Before Sending
Check if templates exist for a combination (uses codes, not IDs):
var validation = await client.Templates.ValidateAsync(new TemplateConfigurationValidationRequest
{
ApplicationCode = "myapp",
RegionCode = "br",
Language = "pt-BR",
NotificationTypeCode = "trans",
NotificationSubtypeCode = "invoice",
DeploymentEnvironmentId = envId,
TargetChannels = [new TargetChannel { Channel = "sms" }]
});
if (validation.Status == TemplateConfigurationValidationStatus.All)
Console.WriteLine("All channels configured!");
Webhooks
// Create
var webhook = await client.Webhooks.CreateAsync(new CreateWebhookRequest
{
Name = "Status Updates",
TargetEndPoint = "https://my-api.com/webhook",
EventTypes = [EventType.Status],
Statuses = [MessageProcessState.Success, MessageProcessState.Error]
});
// Update (requires ConcurrencyStamp from last read)
var current = await client.Webhooks.GetAsync(webhook.Id);
await client.Webhooks.UpdateAsync(webhook.Id, new UpdateWebhookRequest
{
Name = "Updated Name",
TargetEndPoint = current.TargetEndPoint!,
ConcurrencyStamp = current.ConcurrencyStamp!,
// ... other fields ...
});
// Test
var testResult = await client.Webhooks.TestAsync(current);
Console.WriteLine($"Test status: {testResult.StatusCode}");
Notifications (Read)
// List notifications with filters
var notifications = await client.Notifications.GetListAsync(new GetNotificationsRequest
{
Status = NotificationStatus.Success,
MaxResultCount = 50
});
// Get notification with navigation properties
var details = await client.Notifications.GetWithDetailsAsync(notificationId);
Console.WriteLine($"App: {details.Application?.Label}");
Messages
// List messages with filters
var messages = await client.Messages.GetListAsync(new GetMessagesRequest
{
MessageProcessState = MessageProcessState.Error,
CreationTimeMin = DateTime.UtcNow.AddDays(-7),
MaxResultCount = 50
});
// Get message with full navigation properties
var details = await client.Messages.GetWithDetailsAsync(messageId);
Console.WriteLine($"Channel: {details.ChannelType?.Label}");
API Logs
// List API logs
var logs = await client.ApiLogs.GetListAsync(new GetApiLogsRequest
{
Status = NotificationApiLogStatus.Error,
MaxResultCount = 25
});
// Get single log with status history
var log = await client.ApiLogs.GetAsync(logId);
Console.WriteLine($"Duration: {log.DurationMs}ms, Statuses: {log.StatusHistory.Count}");
Contacts
// Create a contact
var contact = await client.Contacts.CreateAsync(new CreateContactRequest
{
Name = "John",
Email = "john@example.com",
Phone = "+34699999999"
});
// Update (requires ConcurrencyStamp)
var current = await client.Contacts.GetAsync(contact.Id);
await client.Contacts.UpdateAsync(contact.Id, new UpdateContactRequest
{
Name = "John Updated",
Email = current.Email!,
ConcurrencyStamp = current.ConcurrencyStamp!
});
Contacts Groups
// Create a group with contacts
var group = await client.ContactsGroups.CreateAsync(new CreateContactsGroupRequest
{
Name = "VIP Customers",
ContactIds = [contactId1, contactId2]
});
// Get group with contact details
var details = await client.ContactsGroups.GetWithDetailsAsync(group.Id);
Console.WriteLine($"Contacts: {details.Contacts.Count}");
Consents
// Create a consent
var consent = await client.Consents.CreateAsync(new CreateConsentRequest
{
Recipient = "+34699999999",
IsConsented = true,
ApplicationId = appId,
ChannelTypeId = smsChannelId
});
// Revoke consent
var current = await client.Consents.GetAsync(consent.Id);
await client.Consents.UpdateAsync(consent.Id, new UpdateConsentRequest
{
Recipient = current.Recipient!,
IsConsented = false,
ConcurrencyStamp = current.ConcurrencyStamp!
});
Error Handling
The SDK throws typed exceptions:
try
{
await client.Notifications.SendAsync(request);
}
catch (OneSend2UValidationException ex)
{
// Client-side validation (before HTTP call)
Console.WriteLine($"Field: {ex.FieldName}, Error: {ex.Message}");
}
catch (OneSend2URateLimitException ex)
{
// HTTP 429 - retry after delay
Console.WriteLine($"Retry after {ex.RetryAfterSeconds}s");
}
catch (OneSend2UApiException ex)
{
// HTTP error from API
Console.WriteLine($"Status: {ex.StatusCode}, Message: {ex.Message}");
if (ex.ValidationErrors is not null)
{
foreach (var error in ex.ValidationErrors)
Console.WriteLine($" - {error.Message} ({string.Join(", ", error.Members ?? [])})");
}
}
Configuration Options
| Property | Default | Description |
|---|---|---|
BaseUrl |
(required) | API base URL |
ApiKey |
(required) | API key for X-API-Key header |
TenantId |
(required) | Tenant ID for X-Tenant-Id header |
Timeout |
30s | HTTP request timeout |
MaxRetries |
3 | Max retries (DI mode only) |
Requirements
- .NET 10.0+
- No ABP framework dependencies
License
MIT
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. 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. |
-
net10.0
- Microsoft.Extensions.Http (>= 10.0.0)
- Microsoft.Extensions.Http.Resilience (>= 10.0.0)
- Microsoft.Extensions.Options (>= 10.0.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.