SMS Notifications in ASP.NET Core
Send order confirmations and appointment reminders from an ASP.NET Core API using CastBrick
SMS Notifications in ASP.NET Core
This tutorial integrates CastBrick into an ASP.NET Core Web API to send two common notification types: order confirmations triggered by an API call, and scheduled appointment reminders sent by a background service.
Prerequisites
- .NET 8+
- A CastBrick API key from the dashboard
Setup
dotnet new webapi -n SmsNotifications --use-minimal-apis
cd SmsNotifications
dotnet add package CastBrick.SDKAdd your API key to appsettings.json:
{
"CastBrick": {
"ApiKey": "your_api_key_here"
}
}In production, use environment variables or a secrets manager — never commit API keys to source control.
Register the SDK
In Program.cs:
using CastBrick.SDK;
var builder = WebApplication.CreateBuilder(args);
// Register CastBrick
builder.Services.AddSingleton(new CastBrickOptions
{
ApiKey = builder.Configuration["CastBrick:ApiKey"]!,
});
builder.Services.AddHttpClient<CastBrickClient>();Part 1: Order confirmation endpoint
Add an order model and endpoint:
// Models/Order.cs
public record Order(string Id, string CustomerPhone, string CustomerName, decimal Total);// In Program.cs — after builder.Build()
var app = builder.Build();
app.MapPost("/orders", async (Order order, CastBrickClient cb) =>
{
// Your order processing logic here...
try
{
await cb.Sms.SendAsync(new SendSmsRequest
{
Recipients = [order.CustomerPhone],
Content = $"Hi {order.CustomerName}! Your order #{order.Id} has been confirmed. " +
$"Total: {order.Total:C}. Thank you for shopping with us!",
SenderId = "MyShop",
});
}
catch (CastBrickApiException ex)
{
// Log but don't fail the order — SMS is best-effort
app.Logger.LogWarning("SMS failed for order {OrderId}: {Status} {Body}",
order.Id, ex.StatusCode, ex.ResponseBody);
}
return Results.Created($"/orders/{order.Id}", order);
});Test it:
curl -X POST http://localhost:5000/orders \
-H "Content-Type: application/json" \
-d '{
"id": "ORD-001",
"customerPhone": "+244923000000",
"customerName": "Ana",
"total": 4500.00
}'Part 2: Appointment reminder background service
This service runs on startup and sends SMS reminders for appointments scheduled in the next 24 hours.
// Services/AppointmentReminderService.cs
using CastBrick.SDK;
using CastBrick.SDK.Models.Sms;
public class AppointmentReminderService : BackgroundService
{
private readonly CastBrickClient _cb;
private readonly ILogger<AppointmentReminderService> _logger;
public AppointmentReminderService(CastBrickClient cb, ILogger<AppointmentReminderService> logger)
{
_cb = cb;
_logger = logger;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
await SendRemindersAsync(stoppingToken);
// Check every hour
await Task.Delay(TimeSpan.FromHours(1), stoppingToken);
}
}
private async Task SendRemindersAsync(CancellationToken ct)
{
var upcoming = await GetAppointmentsInNext24HoursAsync(ct);
foreach (var appt in upcoming)
{
try
{
await _cb.Sms.SendAsync(new SendSmsRequest
{
Recipients = [appt.PatientPhone],
Content = $"Reminder: You have an appointment tomorrow at {appt.Time:HH:mm}. " +
"Reply CONFIRM to confirm or CANCEL to cancel.",
SenderId = "Clinic",
});
_logger.LogInformation("Reminder sent to {Phone} for appointment {Id}",
appt.PatientPhone, appt.Id);
}
catch (CastBrickApiException ex)
{
_logger.LogError("Failed to send reminder for {Id}: {Status}",
appt.Id, ex.StatusCode);
}
}
}
// Replace with your real data source
private Task<List<Appointment>> GetAppointmentsInNext24HoursAsync(CancellationToken ct)
{
var tomorrow = DateTime.UtcNow.AddHours(24);
var fakeData = new List<Appointment>
{
new("APT-001", "+244923000000", tomorrow),
};
return Task.FromResult(fakeData);
}
private record Appointment(string Id, string PatientPhone, DateTime Time);
}Register the background service in Program.cs:
builder.Services.AddHostedService<AppointmentReminderService>();Part 3: Sending to a contact list
For marketing campaigns or bulk notifications, use broadcasts instead of individual sends:
app.MapPost("/campaigns/promo", async (CastBrickClient cb) =>
{
var listId = await cb.Contacts.CreateListAsync("Promo June");
await cb.Contacts.CreateAsync(new CreateContactRequest
{
PhoneNumbers = "+244923000000,+244912000001,+244933000002",
});
var broadcastId = await cb.Broadcasts.CreateAsync(new CreateBroadcastRequest
{
Name = "June Promo",
Message = "Special offer this week — 20% off all products! Shop now at myshop.co.ao",
ContactListId = listId,
SenderId = "MyShop",
});
await cb.Broadcasts.SendAsync(broadcastId);
return Results.Ok(new { broadcastId });
});Error handling reference
| Status | Meaning | Action |
|---|---|---|
401 | Invalid API key | Check CastBrick:ApiKey in config |
402 | Insufficient SMS balance | Top up packs on the dashboard |
422 | Validation error | Check phone format (+244...) and content length |
Next steps
- C# SDK reference — all methods and models
- Broadcasts API — bulk campaigns
- Webhooks — track delivery status callbacks