CastBricks Docs

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.SDK

Add 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

StatusMeaningAction
401Invalid API keyCheck CastBrick:ApiKey in config
402Insufficient SMS balanceTop up packs on the dashboard
422Validation errorCheck phone format (+244...) and content length

Next steps