Best Practices

Guidelines for building reliable, secure, and compliant messaging applications with the Approved Contact Texting API. Following these practices will help ensure high delivery rates, maintain compliance, and provide excellent user experiences.

Security

Protect your API credentials and ensure all communications are secure. Security breaches can lead to unauthorized usage, data leaks, and compliance violations.

Credential Management

Example: Secure Configuration (C#)

// appsettings.json - DO NOT store credentials here in production
{
  "ApprovedContact": {
    "ApiBaseUrl": "https://api.approvedcontact.com"
  }
}

// Use User Secrets for development
// dotnet user-secrets set "ApprovedContact:Username" "your-email@example.com"
// dotnet user-secrets set "ApprovedContact:Password" "your-password"

// Use Azure Key Vault for production
public class ApprovedContactClient
{
    private readonly IConfiguration _configuration;
    
    public ApprovedContactClient(IConfiguration configuration)
    {
        _configuration = configuration;
    }
    
    private string GetUsername() => 
        _configuration["ApprovedContact:Username"] ?? 
        throw new InvalidOperationException("API username not configured");
    
    private string GetPassword() => 
        _configuration["ApprovedContact:Password"] ?? 
        throw new InvalidOperationException("API password not configured");
}

Transport Security

Webhook Security

public bool ValidateWebhookSignature(string payload, string signature, string secret)
{
    using var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(secret));
    var hash = hmac.ComputeHash(Encoding.UTF8.GetBytes(payload));
    var expectedSignature = Convert.ToBase64String(hash);
    
    // Use timing-safe comparison to prevent timing attacks
    return CryptographicOperations.FixedTimeEquals(
        Encoding.UTF8.GetBytes(signature),
        Encoding.UTF8.GetBytes(expectedSignature)
    );
}

Reliability

Build resilient applications that handle failures gracefully and ensure message delivery even when services are temporarily unavailable.

Retry Logic

Example: Polly Retry Policy (C#)

using Polly;
using Polly.Extensions.Http;

public static IAsyncPolicy GetRetryPolicy()
{
    return HttpPolicyExtensions
        .HandleTransientHttpError() // 5xx and 408
        .Or()
        .WaitAndRetryAsync(
            retryCount: 3,
            sleepDurationProvider: retryAttempt => 
                TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)),
            onRetry: (outcome, timespan, retryCount, context) =>
            {
                Console.WriteLine($"Retry {retryCount} after {timespan.TotalSeconds}s");
            }
        );
}

// Configure HttpClient with retry policy
services.AddHttpClient("ApprovedContactAPI")
    .AddPolicyHandler(GetRetryPolicy())
    .SetHandlerLifetime(TimeSpan.FromMinutes(5));

Rate Limiting

Example: Rate Limiting (C#)

using System.Threading.RateLimiting;

public class MessageService
{
    private readonly RateLimiter _rateLimiter;
    
    public MessageService()
    {
        // Limit to 10 requests per second
        _rateLimiter = new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions
        {
            TokenLimit = 10,
            ReplenishmentPeriod = TimeSpan.FromSeconds(1),
            TokensPerPeriod = 10,
            AutoReplenishment = true
        });
    }
    
    public async Task SendMessageAsync(MessageRequest message)
    {
        using var lease = await _rateLimiter.AcquireAsync();
        
        if (!lease.IsAcquired)
        {
            throw new InvalidOperationException("Rate limit exceeded");
        }
        
        return await _httpClient.PostAsJsonAsync("/api/v1/messages", message);
    }
}

Connection Management

Compliance

Follow legal requirements and industry standards to avoid penalties, maintain trust, and ensure your messaging program's longevity.

TCPA Compliance

Legal Requirement: The Telephone Consumer Protection Act (TCPA) requires explicit written consent before sending marketing messages. Violations can result in fines up to $1,500 per message.

Opt-Out Management

Example: Opt-Out Handler

public async Task HandleOptOutAsync(IncomingMessage message)
{
    var optOutKeywords = new[] { "STOP", "UNSUBSCRIBE", "CANCEL", "END", "QUIT" };
    
    if (optOutKeywords.Contains(message.Message.ToUpperInvariant()))
    {
        // Add to opt-out list
        await _optOutService.AddAsync(new OptOut
        {
            PhoneNumber = message.From,
            Timestamp = DateTime.UtcNow,
            Source = "SMS_KEYWORD"
        });
        
        // Send confirmation
        await _messageService.SendAsync(new MessageRequest
        {
            From = message.TargetNumber,
            To = new[] { message.From },
            Body = "You have been unsubscribed. Reply START to resubscribe."
        });
        
        return true;
    }
    
    return false;
}

Message Content Requirements

Example: Compliant Marketing Message

Hi Sarah! It's Acme Store. ?? 20% off this weekend only! 
Show this text in-store or use code SMS20 online.

Shop now: acme.co/sale

Msg frequency varies. Reply HELP for help, STOP to unsubscribe.
Msg&data rates may apply. Terms: acme.co/terms

Performance

Optimize your integration for speed, efficiency, and scalability.

Caching Strategies

Example: Response Caching

public class CachedApprovedContactClient
{
    private readonly IMemoryCache _cache;
    private readonly HttpClient _httpClient;
    
    public async Task GetPhoneNumberAsync(Guid phoneNumberId)
    {
        var cacheKey = $"phonenumber:{phoneNumberId}";
        
        if (_cache.TryGetValue(cacheKey, out PhoneNumber cached))
        {
            return cached;
        }
        
        var response = await _httpClient.GetAsync($"/api/v1/phonenumbers/{phoneNumberId}");
        var phoneNumber = await response.Content.ReadFromJsonAsync();
        
        _cache.Set(cacheKey, phoneNumber, TimeSpan.FromMinutes(10));
        
        return phoneNumber;
    }
}

Batch Operations

Database Optimization

Messaging Guidelines

Message Timing

Content Best Practices

Deliverability Tips

Monitoring & Observability

Key Metrics to Track

Metric Target Action If Below Target
Delivery Rate >95% Check phone numbers, content, timing
API Success Rate >99% Review error logs, implement retries
Webhook Success Rate >98% Check endpoint health, increase timeout
Opt-Out Rate <3% Review content, reduce frequency
Response Latency (p95) <500ms Optimize queries, add caching

Logging

Example: Structured Logging

public class MessageService
{
    private readonly ILogger _logger;
    
    public async Task SendAsync(MessageRequest request)
    {
        using var scope = _logger.BeginScope(new Dictionary
        {
            ["MessageId"] = Guid.NewGuid(),
            ["From"] = MaskPhoneNumber(request.From),
            ["RecipientCount"] = request.To.Length
        });
        
        try
        {
            _logger.LogInformation("Sending message to {RecipientCount} recipients", 
                request.To.Length);
            
            var response = await _httpClient.PostAsJsonAsync("/api/v1/messages", request);
            
            _logger.LogInformation("Message sent successfully. Status: {StatusCode}", 
                response.StatusCode);
            
            return await response.Content.ReadFromJsonAsync();
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Failed to send message");
            throw;
        }
    }
    
    private string MaskPhoneNumber(string phoneNumber) =>
        phoneNumber.Length > 4 
            ? $"+1****{phoneNumber.Substring(phoneNumber.Length - 4)}" 
            : "****";
}

Alerting

Pro Tip: Set up a dashboard with real-time metrics for delivery rates, error rates, and webhook health. Use tools like Grafana, Datadog, or Application Insights to visualize trends and identify issues quickly.

Additional Resources

Need Help? Contact our support team at support@approvedcontact.com for guidance on implementing these best practices or for architecture review.