SMS Provider Migration Checklist for Devs
Step-by-step checklist for migrating from one SMS or OTP provider to another. Covers API abstraction, testing, gradual rollout, monitoring, and rollback planning.
StartMessaging Team
Engineering
Switching SMS or OTP providers is something most development teams will face at least once. Maybe your current provider’s delivery rates have dropped. Maybe their pricing no longer makes sense at your current volume. Maybe you need better support, Indian-specific features, or simpler DLT compliance. Whatever the reason, migrating SMS providers requires careful planning to avoid disrupting your users.
This guide provides a complete, step-by-step checklist for migrating from one SMS or OTP provider to another. Follow it and you will get through the migration with zero downtime and minimal risk.
When to Migrate Providers
Migration carries risk and effort, so make sure the reasons justify it. Common valid reasons to switch providers include:
- Declining delivery rates: If your OTP delivery success rate drops below 95%, users are experiencing failed logins and abandoned transactions. This directly impacts revenue.
- Cost increases: Providers sometimes raise prices, especially after acquisitions or when your contract comes up for renewal. Compare your current effective rate against alternatives like StartMessaging at Rs 0.25 per OTP.
- Poor support responsiveness: When delivery issues arise and your provider takes days to respond, every hour of degraded service costs you users and money.
- DLT compliance burden: Managing your own DLT registration, template approvals, and compliance updates is time-consuming. Providers like StartMessaging handle this entirely.
- Currency and billing complexity: If your provider bills in USD and you operate in INR, exchange rate fluctuations make cost planning difficult.
- Missing features: You need idempotency keys, better status tracking, webhook notifications, or other features your current provider does not offer.
If you are experiencing two or more of these issues simultaneously, migration is likely overdue.
Pre-Migration Audit
Before writing any migration code, audit your current SMS usage. This step prevents surprises during the switch.
Checklist: Current Provider Inventory
- List all SMS use cases: OTP login, OTP for transactions, order notifications, appointment reminders, marketing campaigns. Each may have different requirements for the new provider.
- Document current API endpoints used: Which send, verify, status check, and webhook endpoints does your code call?
- Record current sender IDs: What sender ID (header) appears on messages? Will this change with the new provider?
- Measure current performance baselines: Average delivery time, delivery success rate, verification success rate, monthly volume by use case. You need these to compare against the new provider.
- Identify all integration points: Search your codebase for the current provider’s domain, SDK imports, and API key references. Every integration point must be updated.
- Check contractual obligations: Review your current contract for termination notice periods, minimum commitments, and any exit fees.
- Inventory DLT assets: If you manage your own DLT registration, document all registered templates, entity IDs, and sender IDs. These may need to be recreated or transferred.
Building the Abstraction Layer
If your current code calls the SMS provider’s API directly throughout the codebase, the first step is to refactor into an abstraction layer. This makes the actual migration trivial and protects you from future provider changes.
// sms-provider.interface.ts
interface SmsProvider {
sendOtp(phoneNumber: string, options?: SendOtpOptions): Promise<SendOtpResult>;
verifyOtp(requestId: string, code: string): Promise<VerifyResult>;
getDeliveryStatus(messageId: string): Promise<DeliveryStatus>;
}
interface SendOtpOptions {
idempotencyKey?: string;
expiryMinutes?: number;
}
interface SendOtpResult {
requestId: string;
expiresAt: string;
provider: string; // Track which provider handled it
}
interface VerifyResult {
verified: boolean;
attemptsRemaining?: number;
}
type DeliveryStatus = 'pending' | 'delivered' | 'failed' | 'expired';Implement this interface for your current provider first. Replace all direct API calls in your codebase with calls to this interface. Deploy and verify everything works exactly as before. Only then move to implementing the new provider.
// startmessaging-provider.ts
class StartMessagingProvider implements SmsProvider {
private baseUrl = 'https://api.startmessaging.com';
private apiKey: string;
constructor(apiKey: string) {
this.apiKey = apiKey;
}
async sendOtp(phoneNumber: string, options?: SendOtpOptions): Promise<SendOtpResult> {
const response = await fetch(`${this.baseUrl}/otp/send`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-API-Key': this.apiKey,
},
body: JSON.stringify({
phoneNumber,
idempotencyKey: options?.idempotencyKey,
}),
});
const { data } = await response.json();
return {
requestId: data.requestId,
expiresAt: data.expiresAt,
provider: 'startmessaging',
};
}
async verifyOtp(requestId: string, code: string): Promise<VerifyResult> {
const response = await fetch(`${this.baseUrl}/otp/verify`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-API-Key': this.apiKey,
},
body: JSON.stringify({ requestId, otpCode: code }),
});
const { data } = await response.json();
return { verified: data.verified };
}
async getDeliveryStatus(messageId: string): Promise<DeliveryStatus> {
// Query message status from StartMessaging
const response = await fetch(`${this.baseUrl}/messages/${messageId}`, {
headers: { 'X-API-Key': this.apiKey },
});
const { data } = await response.json();
return data.status;
}
}Setting Up the New Provider
With the abstraction layer in place, set up the new provider account and implementation:
- Create the account: Sign up at dashboard.startmessaging.com (or your chosen provider). Complete any verification steps.
- Generate API credentials: Create an API key for your production environment. Store it securely in your environment variables or secrets manager. Never commit it to source control.
- Add wallet credit: For prepaid providers like StartMessaging, add sufficient credit for testing and the initial rollout period. A starting balance of Rs 500 to Rs 1,000 is adequate for testing.
- Review the API documentation: Read the OTP API docs thoroughly. Note any differences in request format, response structure, error codes, or rate limits compared to your current provider.
- Implement the provider adapter: Write the implementation of your SmsProvider interface for the new provider. Map response formats to your standardized interface.
- Handle error mapping: Map the new provider’s error codes to your application’s error handling. Different providers use different HTTP status codes and error formats for the same conditions.
Testing Strategy
Never go directly from implementation to production. Follow this testing progression:
Unit Tests
Test the new provider adapter in isolation with mocked HTTP responses. Verify that request formatting, response parsing, and error handling all work correctly. Test edge cases: malformed phone numbers, expired OTPs, rate limiting responses, and network timeouts.
Integration Tests
Test against the actual new provider API in a staging environment. Send real OTPs to test phone numbers. Verify the complete send and verify cycle works end-to-end. Measure delivery latency.
Load Tests
If your production volume is significant (more than 10,000 OTPs per day), run a load test against the new provider. Send a burst of requests to verify rate limits, response times under load, and whether the provider throttles your account.
Canary Tests
Route a small percentage (1% to 5%) of production traffic to the new provider while the rest continues on the old provider. Monitor delivery rates and latency in real production conditions for at least 48 hours before expanding.
Gradual Rollout Plan
A gradual rollout minimizes risk by slowly shifting traffic to the new provider. Here is a proven rollout schedule:
| Phase | Traffic Split | Duration | Success Criteria |
|---|---|---|---|
| Canary | 5% new, 95% old | 2 days | Delivery rate within 1% of old provider |
| Early Rollout | 25% new, 75% old | 3 days | No increase in support tickets |
| Mid Rollout | 50% new, 50% old | 3 days | Latency within acceptable range |
| Late Rollout | 90% new, 10% old | 3 days | All metrics stable |
| Complete | 100% new | Ongoing | Old provider decommissioned |
Implement the traffic split using a feature flag or a simple configuration value. A random number check works for percentage-based routing:
// provider-router.ts
class ProviderRouter implements SmsProvider {
constructor(
private oldProvider: SmsProvider,
private newProvider: SmsProvider,
private newProviderPercentage: number, // 0 to 100
) {}
async sendOtp(phoneNumber: string, options?: SendOtpOptions) {
const useNew = Math.random() * 100 < this.newProviderPercentage;
const provider = useNew ? this.newProvider : this.oldProvider;
try {
return await provider.sendOtp(phoneNumber, options);
} catch (error) {
// Fallback to old provider if new one fails during rollout
if (useNew) {
console.warn('New provider failed, falling back to old provider');
return await this.oldProvider.sendOtp(phoneNumber, options);
}
throw error;
}
}
// Similar pattern for verifyOtp...
}The key detail: during the rollout phase, the new provider falls back to the old provider on failure. This means the worst case during migration is slightly slower delivery for some requests, never a complete failure.
Monitoring During Migration
Active monitoring during the migration is non-negotiable. Track these metrics continuously:
- Delivery success rate: The percentage of OTPs successfully delivered. Compare new vs. old provider in real-time. Any drop below 95% should trigger investigation.
- Average delivery latency: Time from API call to SMS delivery. Measure at the p50, p95, and p99 percentiles. Latency spikes at p99 can indicate provider-side queuing issues.
- Verification success rate: The percentage of sent OTPs that are successfully verified. A drop here could indicate delivery issues (users not receiving the SMS) or code generation problems.
- Error rates by type: Track 4xx and 5xx errors separately. 4xx errors usually indicate your integration issues. 5xx errors indicate provider-side problems.
- Fallback trigger rate: How often the new provider fails and falls back to the old provider. If this exceeds 5%, pause the rollout and investigate.
- Support ticket volume: Monitor for increases in user complaints about OTPs not being received or login issues.
Set up automated alerts for each metric crossing its threshold. Do not rely on manually checking dashboards during the migration period.
Rollback Plan
Every migration needs a tested rollback plan. Here is yours:
- Keep the old provider active: Do not cancel your old provider account or revoke API keys until at least two weeks after the migration is complete at 100%.
- One-line rollback: Your ProviderRouter should allow you to set
newProviderPercentageback to 0 instantly. This routes all traffic back to the old provider with no code deployment needed. Use a feature flag service or environment variable. - Verify rollback works: Before starting the migration, test the rollback by setting the percentage to 0 and confirming the old provider handles all traffic correctly.
- Handle in-flight OTPs: During rollback, OTPs sent via the new provider but not yet verified still need to verify against the new provider. Your verification logic should route to the correct provider based on which one issued the requestId.
- Communication plan: If a rollback is needed, notify your team. If users were affected, prepare a status page update.
Post-Migration Cleanup
After running at 100% on the new provider for at least two weeks with stable metrics, complete the cleanup:
- Remove the old provider implementation: Delete the old provider adapter code, SDK dependencies, and configuration values. Keep the abstraction interface for future flexibility.
- Remove the routing layer: Replace the ProviderRouter with a direct reference to the new provider. Simplify the code path now that migration is complete.
- Cancel the old provider account: After confirming there are no remaining dependencies, terminate the old provider contract and revoke API keys.
- Update documentation: Update internal documentation, runbooks, and environment variable templates to reflect the new provider.
- Archive migration metrics: Save the comparative delivery metrics from the migration period. This data is valuable for future provider evaluations.
- Conduct a retrospective: Document what went well and what could be improved. This saves time on any future provider migrations.
FAQ
Planning a migration to StartMessaging? Start by reviewing our OTP API documentation to understand the integration points, then check our pricing page to compare costs with your current provider. For a broader view of your options, see our guide to the best OTP APIs in India.
Related Articles
Compare the top OTP API providers for India in 2026: StartMessaging, Twilio, MSG91, Exotel, and Kaleyra. Pricing, DLT, delivery rates, and features.
Technical guide for SaaS founders on implementing OTP authentication. Covers architecture, UX design, cost projections, scaling, and integration with StartMessaging API.
Detailed 2026 pricing comparison of OTP APIs in India. Compare per-OTP costs, hidden fees, DLT charges, volume discounts, and billing models across top providers.
Ready to Send OTPs?
Integrate StartMessaging in 5 minutes. No DLT registration required.