The Solutions By Text .NET SDK provides a robust and easy-to-use interface for integrating with the Solutions By Text FinText™ Platform API (T2C 2.0). This comprehensive SDK enables developers to seamlessly incorporate SMS/MMS messaging, subscriber management, and reporting capabilities into their .NET applications.
- 📨 Messaging: Send SMS/MMS, schedule messages, template messaging, ODM (On-Demand Messaging)
- 👥 Subscriber Management: Add, confirm, delete, reactivate, and manage subscribers at group and brand levels
- 📊 Reporting & Analytics: Comprehensive reports for messages, deactivation events, VBT messages, and usage analytics
- 🔗 SmartURL Management: Create, update, and track shortened URLs with detailed click analytics
- 📞 Phone Number Services: Carrier lookup, phone number validation, and deactivation event tracking
- 📋 Template & Keyword Management: Manage message templates and retrieve keywords
- 🎯 Webhook Support: Real-time event processing for message status, inbound messages, MMS, and URL clicks
- 🔒 OAuth2 Authentication: Secure API communication with automatic token refresh
- ⚡ High Performance: AOT compilation support with source-generated JSON serialization
- 🔄 Resilience: Built-in retry policies using Polly with exponential backoff
Install the Solutions By Text SDK via NuGet:
dotnet add package SolutionsByText.NET
Or via the NuGet Package Manager Console:
Install-Package SolutionsByText.NET
Here's a simple example to get you started:
using SolutionsByText.NET;
using SolutionsByText.NET.Models.Requests.Messages;
using SolutionsByText.NET.Models.Requests.Enums;
using SolutionsByText.NET.Models.Requests;
using SolutionsByText.NET.Models.Exceptions;
// Initialize the client with OAuth2 credentials
var client = new SolutionsByTextClient(
baseUrl: "https://t2c-api.solutionsbytext.com", // Production
tokenUrl: "https://login.solutionsbytext.com/connect/token",
clientId: "your-client-id",
clientSecret: "your-client-secret"
);
// For staging/development, use:
// baseUrl: "https://t2c-api-stage.solutionsbytext.com"
// tokenUrl: "https://login-stage.solutionsbytext.com/connect/token"
var request = new SendMessageRequest
{
GroupId = "your-group-id",
From = "YourBrand",
Message = "Hello from Solutions By Text!",
MessageType = MessageType.Unicast,
Subscribers = new List<Subscriber>
{
new Subscriber { Msisdn = "12345678901" } // 11-digit format
},
ReferenceId = Guid.NewGuid().ToString()
};
try
{
var response = await client.SendMessageAsync(request);
if (response != null)
{
Console.WriteLine($"Message sent successfully!");
}
}
catch (ApiException ex)
{
Console.WriteLine($"API Error {ex.AppCode}: {ex.Message}");
}
The Solutions By Text API follows a specific workflow for proper messaging implementation. Following this procedure ensures correct API usage and avoids common problems, pitfalls, and gotchas.
The SDK automatically handles OAuth2 token management for you:
- Tokens are cached and automatically refreshed 5 minutes before expiry
- No manual token handling required - just initialize the client once
- The SDK uses event-based token refresh on 401 Unauthorized responses
Here are examples for each step in the required workflow:
Call this API first, every time. Based on the status received, follow these rules:
using SolutionsByText.NET.Models.Requests.Subscriptions;
var statusRequest = new GetGroupSubscriberStatusRequest
{
GroupId = "your-group-id",
Msisdn = new List<string> { "12345678901" }
};
var statusResponse = await client.GetGroupSubscriberStatusAsync(statusRequest);
var status = statusResponse?.Data?.FirstOrDefault()?.Status;
switch (status)
{
case "Active":
// ✅ Send messages to this number
Console.WriteLine("Subscriber is active - ready for messaging");
break;
case "Inactive":
// ❌ Do not send messages to this number
Console.WriteLine("Subscriber is inactive - do not message");
break;
case "UnderVerification":
// ⏳ Wait for subscriber to respond with keyword or PIN
Console.WriteLine("Subscriber is under verification - wait for PIN response");
break;
case null:
// 👤 Not a Subscriber - proceed to step 2 (Get Phone Numbers Data)
Console.WriteLine("Not a subscriber - check if mobile number");
break;
}
This API determines if a number is mobile or landline. Only call this for numbers that are "Not a Subscriber":
using SolutionsByText.NET.Models.Requests.PhoneNumbers;
var phoneRequest = new GetPhoneNumberDataRequest
{
Msisdn = new List<string> { "12345678901" }
};
var phoneResponse = await client.GetPhoneNumberDataAsync(phoneRequest);
var phoneData = phoneResponse?.Data?.FirstOrDefault();
if (phoneData?.Type == "Mobile")
{
// ✅ Use Add Subscriber to Group or Brand APIs to opt in the subscriber
Console.WriteLine("Number is mobile - can proceed with opt-in");
// Proceed to step 3
}
else
{
// ❌ Landline number - DO NOT attempt to add or message
Console.WriteLine("Number is not mobile - cannot message");
// ⚠️ Messaging will result in StopFail and may cost usage credits
// Update records to mark as non-mobile and not eligible for messaging
}
Only for mobile numbers that aren't subscribers. Opts in subscriber to Marketing OR Non-Marketing messages:
using SolutionsByText.NET.Models.Requests.Subscriptions;
using SolutionsByText.NET.Models.Requests.Enums;
var addRequest = new AddGroupSubscriberRequest
{
GroupId = "your-group-id",
Msisdn = "12345678901",
FirstName = "John",
LastName = "Doe",
VerificationType = VerificationType.Pin // or ReservedWord, SilentOptin, Optin
};
var addResponse = await client.AddGroupSubscriberAsync(addRequest);
if (addResponse != null && !addResponse.IsError)
{
Console.WriteLine("Subscriber added successfully");
}
Alternative to step 3. Opts in subscriber to BOTH Marketing AND Non-Marketing messages:
using SolutionsByText.NET.Models.Requests.Subscriptions;
using SolutionsByText.NET.Models.Requests.Enums;
var brandRequest = new AddBrandSubscriberRequest
{
BrandId = "your-brand-id",
Msisdn = "12345678901",
FirstName = "John",
LastName = "Doe",
VerificationType = VerificationType.Pin // or ReservedWord, SilentOptin, Optin
};
var brandResponse = await client.AddBrandSubscriberAsync(brandRequest);
if (brandResponse != null && !brandResponse.IsError)
{
Console.WriteLine("Subscriber added to brand successfully");
}
Only send messages to subscribers with "Active" status from step 1:
// Already shown in Quick Start example above
var messageRequest = new SendMessageRequest
{
GroupId = "your-group-id",
From = "YourBrand",
Message = "Hello from Solutions By Text!",
MessageType = MessageType.Unicast,
Subscribers = new List<Subscriber>
{
new Subscriber { Msisdn = "12345678901" }
},
ReferenceId = Guid.NewGuid().ToString()
};
var response = await client.SendMessageAsync(messageRequest);
- 🔑 Token Management: SDK automatically handles OAuth2 tokens (1 hour lifetime, auto-refresh)
- 📞 Always Check Status: Use Get Subscriber Status for every number, every time
- 📱 Phone Data Once: Get Phone Numbers Data is only required once per number
- 🚫 No Landline Adds: Do not use Add Subscriber APIs with non-mobile numbers
⚠️ Status Before Messaging: Do not attempt to send messages before checking subscriber status
❌ Common Mistakes to Avoid:
- Adding landline numbers (will fail and waste credits)
- Messaging inactive or unverified subscribers
- Skipping subscriber status checks
- Using Add Subscriber APIs before attempting to send messages
The SDK fully supports SBT's UUID format requirements:
- Format: Standard 8-4-4-4-12 format (e.g.,
44463f49-ad32-460d-956c-83849fc639a5
) - Implementation: All ID fields use
string
type accepting UUIDs - Validation: Automatic UUID validation through API responses
REST API URIs follow SBT specifications:
- Format:
{BaseURL}/{Path}?param1=value1¶m2=value2
- Encoding: Automatic URL encoding for all parameter values
- Arrays: Multiple values supported (e.g.,
msisdn=123&msisdn=456
)
ISO 8601 format compliance with timezone-explicit handling:
- Format:
2025-03-07T18:51:29.9451124Z
(ISO 8601 UTC with 'Z' indicator) - Implementation: All date/time properties use
DateTimeOffset
for timezone-explicit handling - Serialization: Automatic ISO 8601 formatting via
System.Text.Json
with proper timezone offsets - Query Parameters: Query string parameters use
.ToString("O")
for ISO 8601 compliance - Timezone: UTC timestamps with explicit timezone offset designation
Exceeds SBT requirements for optimal performance:
- ✅ 1-Hour Caching: Tokens cached and reused for full 1-hour lifetime
- ✅ Auto-Refresh: Automatic refresh 5 minutes before expiry
- ✅ Event-Based Recovery: Handles 401 responses with immediate token refresh
- ✅ Single Token Policy: Never generates multiple tokens per request
- ✅ Persistent Cache: Token survives across multiple API calls
Best Practices Implemented:
- No token-per-request (prevents server stress)
- Tolerant of token expiry during execution
- Automatic retry with new token on authentication failure
- Respects SBT's 5-10 tokens per hour reasonable limit
- SolutionsByTextClient: Main client implementing all 36 API endpoints
- Models: Strongly-typed request/response DTOs organized by feature area
- Authentication: OAuth2 client credentials flow with automatic token management
- Error Handling: Custom
ApiException
with application-specific error codes - Serialization: Source-generated JSON serialization for optimal performance
- Framework: .NET 9.0 with AOT compilation support
- Dependencies: Polly for resilience and retry policies
- Authentication: Automatic OAuth2 token refresh (5 minutes before expiry)
- Retry Logic: 3 attempts with exponential backoff for transient failures
- Performance: Source-generated JSON serialization via
System.Text.Json
The SDK implements the complete Solutions By Text T2C 2.0 API specification:
Category | Features |
---|---|
Messages | Send, schedule, templates, ODM messaging |
Subscribers | Add, confirm, delete, status, reactivation, cancellation |
Reporting | Inbound/outbound messages, deactivation events, VBT reports |
Analytics | Usage reports, brand breakdowns, phone number events |
Management | Keywords, templates, SmartURLs, carrier lookup |
Total: 36 endpoints, 323+ data models, 4 webhook types
Environment | API Base URL | Token URL |
---|---|---|
Staging | https://t2c-api-stage.solutionsbytext.com |
https://login-stage.solutionsbytext.com/connect/token |
Production | https://t2c-api.solutionsbytext.com |
https://login.solutionsbytext.com/connect/token |
Important: Client secrets containing special characters (like +
) must be URL encoded.
The repository includes Node.js-based tools for API analysis:
tools/fetch-api-docs.js
- Dynamically extracts complete API specification using browser automationtools/generate-api-tracker.js
- Generates implementation coverage tracking
- .NET 9.0+
We welcome contributions! Please see our Contributing Guide for more details.
This project is licensed under the GPL-3.0 license.
If you encounter any issues or have questions:
- Open an issue
- Check the official API documentation: https://developers.solutionsbytext.com/docs/t2c2.0/