SMSwitch 10.2.1

dotnet add package SMSwitch --version 10.2.1
                    
NuGet\Install-Package SMSwitch -Version 10.2.1
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="SMSwitch" Version="10.2.1" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="SMSwitch" Version="10.2.1" />
                    
Directory.Packages.props
<PackageReference Include="SMSwitch" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add SMSwitch --version 10.2.1
                    
#r "nuget: SMSwitch, 10.2.1"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package SMSwitch@10.2.1
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=SMSwitch&version=10.2.1
                    
Install as a Cake Addin
#tool nuget:?package=SMSwitch&version=10.2.1
                    
Install as a Cake Tool

SMSwitch

NuGet NuGet Downloads License: GPL v3

SMSwitch is an open-source C# class library that acts as a switchboard in front of multiple SMS providers. It sends one-time passwords (OTPs) and plain SMS messages through Twilio or Plivo, choosing the provider per destination country and automatically failing over to the next provider when one fails. All sessions and attempts are stored in your own MongoDB instance for auditing.

Features

  • Multi-provider with failover — configure a provider priority per country phone code plus a global fallback; failed sends automatically retry with the next provider in the queue.
  • OTP send & verify — delegates to the providers' hosted verification products (Twilio Verify, Plivo Verify), including localized OTP message templates.
  • Plain SMS — with delivery-status confirmation and resend-cooldown deduplication.
  • DevConsole provider for local testing — prints the OTP to the console instead of sending a real SMS (see below).
  • Audit trail in your own MongoDB — every session, attempt, and delivery notification is stored in your database.
  • Android SMS Retriever support — pass your app hash so OTP messages can be auto-read on Android.

How it works

For each phone number, SMSwitch builds a queue of providers from your configured priorities (PriorityBasedOnCountryPhoneCode, falling back to FallBackPriority), repeated MaxRoundRobinAttempts times. Each send works through the queue until a provider succeeds; verification is routed to the provider that sent the OTP. A verification session expires after SessionTimeoutInSeconds or MaximumFailedAttemptsToVerify failed attempts. Repeated sends inside the resend cooldown return the previous result instead of sending again.

Getting started

1. Install

dotnet add package SMSwitch

2. Prerequisites

SMSwitch builds on two companion packages that are installed automatically but need configuration:

  • MongoDbService — provides the MongoDB connection. Requires a MongoDbSettings section (connection string + database name).
  • uSignIn.CommonSettings — provides your application's public base URL, which SMSwitch uses to build the Plivo delivery-notification callback URL. Requires a Settings section with a BaseUrl.

3. Configure

Add the following to your appsettings.json and adjust the values (keep real credentials in user secrets or environment variables):

{
  "Settings": {
    "BaseUrl": "https://your-public-hostname/"
  },
  "MongoDbSettings": {
    "ConnectionString": "MovedToSecret",
    "DatabaseName": "MyDatabase"
  },
  "SMSwitchSettings": {
    "SupportedCountriesIsoCodes": [ "IN", "FI", "DK" ],
    "Controls": {
      "MaximumFailedAttemptsToVerify": 4,
      "SessionTimeoutInSeconds": 240,
      "MaxRoundRobinAttempts": 2,
      "PriorityBasedOnCountryPhoneCode": {
        "44": [ "Twilio", "Plivo" ],
        "45": [ "Twilio", "Plivo" ],
        "91": [ "Plivo", "Twilio" ]
      },
      "FallBackPriority": [ "Twilio", "Plivo" ]
    },
    "AndroidAppHash": "MovedToSecret",
    "OtpLength": 6,
    "Twilio": {
      "AccountSid": "MovedToSecret",
      "AuthToken": "MovedToSecret",
      "ServiceSid": "MovedToSecret",
      "RegisteredSenderPhoneNumber": "MovedToSecret"
    },
    "Plivo": {
      "AuthId": "MovedToSecret",
      "AuthToken": "MovedToSecret",
      "AppUuid": "MovedToSecret",
      "SourceNumber": "MovedToSecret",
      "WebhookSecret": "MovedToSecret"
    }
  }
}
Setting Meaning
SupportedCountriesIsoCodes Countries marked as supported in the country database. Empty list means all countries are supported.
Controls:MaximumFailedAttemptsToVerify Failed verification attempts before a session expires (default 3).
Controls:SessionTimeoutInSeconds Lifetime of an OTP session (default 240).
Controls:MaxRoundRobinAttempts How many times the provider priority list is repeated in the retry queue (default 1).
Controls:PriorityBasedOnCountryPhoneCode Provider order per country phone code.
Controls:FallBackPriority Provider order for phone codes not listed above. Required.
AndroidAppHash Your Android app hash for SMS Retriever auto-read.
OtpLength OTP digit count. Applied to Twilio; Plivo is fixed at 6 (a warning is logged if they differ).
Plivo:SourceNumber Sender number for plain SMS via Plivo (not needed for OTPs).
Plivo:WebhookSecret Optional but recommended. Appended to the delivery-notification callback URL registered with Plivo; webhook calls without the matching secret are rejected with 401 Unauthorized.

4. Register the services

using MongoDbService;
using SMSwitch;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddMongoDbServices();
builder.Services.AddSMSwitchServices();

var app = builder.Build();

// Maps the Plivo delivery-notification webhook at /smswitch/plivonotification.
// Required if you use Plivo; harmless otherwise.
app.AddSMSwitchApiEndpoints();

app.Run();

5. Use it

Dependency-inject SMSwitchService wherever you need it:

using HumanLanguages;
using SMSwitch;
using SMSwitch.Common.DTOs;

public sealed class SignInFlow
{
	private readonly SMSwitchService _smSwitch;

	public SignInFlow(SMSwitchService smSwitch) => _smSwitch = smSwitch;

	public async Task<bool> Demo()
	{
		var mobileNumber = new MobileNumber
		{
			CountryIsoCodeString = "DK",
			CountryPhoneCode = "45",
			PhoneNumber = "12345678"
		};
		var preferredLanguages = new HashSet<LanguageIsoCode> { HumanHelper.CreateLanguageIsoCode("en") };

		// Send a one-time password (provider is picked from your configured priorities)
		var sendResponse = await _smSwitch.SendOTP(mobileNumber, preferredLanguages, UserAgent.WebBrowser);
		// sendResponse.IsSent, sendResponse.OtpLength

		// Later, verify the OTP the user typed in
		var verifyResponse = await _smSwitch.VerifyOTP(mobileNumber, "123456");
		// verifyResponse.Verified, verifyResponse.Expired

		// Or send a plain SMS
		var smsSent = await _smSwitch.SendSMS(mobileNumber, "Hello from SMSwitch!");

		return verifyResponse.Verified;
	}
}

Local testing without real SMS

For local development you can route messages to the DevConsole provider instead of Twilio or Plivo, so no credits are spent and no credentials are needed. The OTP (or SMS text) is printed to the console via the logger, and OTPs are generated and verified through MongoDbTokenManager in your own MongoDB instance — the full SendOTPVerifyOTP flow works end to end.

Put this in your appsettings.Development.json:

{
  "SMSwitchSettings": {
    "Controls": {
      "PriorityBasedOnCountryPhoneCode": {
        "45": [ "DevConsole" ]
      },
      "FallBackPriority": [ "DevConsole" ]
    }
  }
}

As a safety measure the DevConsole provider refuses to operate when the app runs in the Production environment: it logs a critical error and reports the send as failed, so the provider queue falls through to a real provider if one is configured.

Contributing

We welcome contributions! If you find a bug or have an idea for an improvement, please submit an issue or a pull request on GitHub. The repository includes a TestAPIs project — a minimal ASP.NET Core app with Swagger and ready-made .http requests for exercising the library locally.

License

This project is licensed under the GNU General Public License v3.0.

Happy coding! 🚀🌐📚

Product 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (1)

Showing the top 1 NuGet packages that depend on SMSwitch:

Package Downloads
EmailSwitch

Package Description

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
10.2.1 44 7/16/2026
10.2.0 44 7/16/2026
10.1.0 284 11/25/2025
10.0.0 299 6/28/2025
9.2.0 323 4/16/2025
9.1.0 290 4/15/2025
9.0.0 285 4/15/2025
8.3.1 284 4/13/2025
8.3.0 294 4/2/2025
8.2.0 258 4/2/2025
8.1.0 432 1/8/2025
8.0.0 183 1/8/2025
7.0.0 288 8/11/2024
6.0.6 207 8/2/2024
6.0.5 184 8/2/2024
6.0.4 268 7/30/2024
6.0.3 221 7/30/2024
6.0.2 204 7/29/2024
6.0.1 421 7/21/2024
6.0.0 223 7/21/2024
Loading failed