A complete technical migration guide. The actual code diff is 12 lines. The validation process takes 24-48 hours. The full migration — parallel-send validation, webhook updates, phone-number porting decisions, final cutover — fits in 4-8 hours of engineering time for a standard Twilio SDK integration. This guide walks the 9 concrete steps, maps every Twilio API field to its smsroute equivalent, and shows the real code diffs you'll commit.

The 9-step migration checklist

  1. Create an smsroute accountSign up at smsroute.cc with email only. 30 seconds, no KYC. Top up $5 USDT TRC-20 for testing. Generate two API keys in /dashboard/api-keys: one sandbox (sk_test_*) and one production (sk_live_*).
  2. Install the smsroute clientPython: pip install smsroute. Node.js: npm install smsroute. Go: go get github.com/smsroute/smsroute-go. PHP: composer require smsroute/smsroute. All official clients are MIT-licensed and mirror the smsroute REST API surface.
  3. Replace the Twilio send callSwap the client instantiation and update the messages.create() arguments. Field shape is close — see the code diff below. Reserve a feature flag so you can switch between Twilio and smsroute with a config change, not a redeploy.
  4. Update your webhook handlerOption A: update the handler to accept smsroute's payload shape (see field mapping table below). Option B: install github.com/smsroute/twilio-compat in front of your handler — it translates smsroute webhooks into Twilio shape with <5ms latency and zero handler changes.
  5. Validate in sandboxSend to these magic test numbers: +15005550001 (returns accepted → delivered), +15005550002 (returns accepted → failed), +15005550003 (returns accepted → undelivered), +15005550004 (HTTP 429 rate_limited), +15005550005 (HTTP 500 internal_error). Verify your app handles every status and error path. Sandbox sends are free.
  6. Parallel-send validationTurn on shadow-traffic mode: for 24-48 hours, duplicate 10% of outbound SMS to smsroute while the other 100% goes through Twilio. Compare delivery receipts. Any edge cases (weird sender IDs, UCS-2 characters, specific destination carriers) surface during this window. Cost of the 10% shadow traffic at 50k total volume: ~$1.50.
  7. Flip the flagRoute 100% of outbound traffic to smsroute. Keep Twilio credentials in place and the Twilio account funded for 7 days as emergency rollback. Monitor Grafana / Datadog / your equivalent for delivery-rate regressions vs the Twilio baseline.
  8. Migrate phone numbers (if needed)Alphanumeric sender IDs: no action, they work day one on smsroute. Long codes: submit RespOrg transfer via smsroute support, 7-10 business days. US A2P 10DLC campaigns: re-register campaign under smsroute's TCR relationship, 2-5 days + small TCR fees. Shortcodes: plan a 6-12 week port or keep on Twilio during migration.
  9. Cancel TwilioAfter 7 days of clean smsroute operation in production, cancel your Twilio subscription. Keep the Twilio account open with $0 balance for 30 days in case of a surprise regression in a low-volume destination country. Export Messaging Logs from Twilio first if you need the historical data for compliance.

API endpoint mapping — every Twilio endpoint to its smsroute equivalent

Twilio endpointsmsroute equivalentNotes
POST /Accounts/{SID}/Messages.jsonPOST /v1/messagesJSON body instead of form-encoded. Fields To/From/Bodyto/from/body (lowercase).
GET /Accounts/{SID}/Messages/{MessageSid}GET /v1/messages/{id}Message ID format differs: Twilio SMxxxxxxx...; smsroute msg_01HZX... (ULID).
(no bulk endpoint — loop Messages.json)POST /v1/messages/bulksmsroute supports up to 1,000 messages in one call. Single auth + TLS handshake for the batch.
GET /Accounts/{SID}/Balance.jsonGET /v1/balanceBoth return USD balance as decimal string.
GET /Pricing/v2/Messaging/Countries/{IsoCode}GET /v1/pricing?country={iso2}smsroute returns single flat rate per country; Twilio returns per-carrier breakdown. Use GET /v1/pricing/lookup?to=+NUMBER for exact per-number quote.
GET /Accounts/{SID}/IncomingPhoneNumbers.jsonGET /v1/phone-numbersInventory of rented long codes for two-way SMS.
Webhook: form-encoded POST to StatusCallbackWebhook: JSON POST to status_callbackHMAC-SHA256 signature on both, different header names.

The 12-line code diff — Twilio Python SDK to smsroute

Using httpx directly (minimum-dependency migration)

- from twilio.rest import Client
- client = Client(account_sid=os.environ["TWILIO_SID"],
-                 auth_token=os.environ["TWILIO_AUTH"])
- message = client.messages.create(
-     to="+5491123456789",
-     from_="smsroute",
-     body="Your verification code is 384921",
-     status_callback="https://api.example.com/webhooks/status"
- )
- print(message.sid, message.status)
+ import httpx, os
+ r = httpx.post(
+     "https://api.smsroute.cc/v1/messages",
+     headers={"Authorization": f"Bearer {os.environ['SMSROUTE_API_KEY']}"},
+     json={
+         "to": "+5491123456789",
+         "from": "smsroute",
+         "body": "Your verification code is 384921",
+         "status_callback": "https://api.example.com/webhooks/status"
+     },
+ )
+ data = r.json()
+ print(data["id"], data["status"])

Using the official smsroute-python client (idiomatic migration)

- from twilio.rest import Client
- client = Client(os.environ["TWILIO_SID"], os.environ["TWILIO_AUTH"])
+ from smsroute import Client
+ client = Client(api_key=os.environ["SMSROUTE_API_KEY"])

message = client.messages.create(
    to="+5491123456789",
-   from_="smsroute",
+   from_="smsroute",   # unchanged
    body="Your verification code is 384921",
    status_callback="https://api.example.com/webhooks/status"
)
- print(message.sid, message.status)
+ print(message.id, message.status)   # .sid → .id

That's the whole thing for the send path. The surface is deliberately kept close to Twilio's so teams familiar with the Twilio SDK don't have to re-learn a new idiom.

Webhook payload translation

Delivery receipts are where Twilio and smsroute differ most. The functional content is identical — message ID, status, destination, timestamp, carrier — but field names and serialization format differ:

Twilio field (form-encoded)smsroute field (JSON)Notes
MessageSidmessage_idTwilio: SMxxx...; smsroute: msg_01HZX... (ULID)
MessageStatusstatusValues: Twilio queued/sending/sent/delivered/undelivered/failed; smsroute accepted/sent/delivered/undelivered/failed
TotoBoth E.164 format
FromfromAlphanumeric sender ID or E.164 long code
BodybodyNot included in smsroute status callbacks by default — use include_body=true on send if you need it back on the webhook
NumSegmentssegmentsInteger count of SMS segments
Priceprice_usdString decimal; smsroute always USD
ErrorCodeerror_codeTwilio numeric (30003, 30005); smsroute string (invalid_destination, carrier_unreachable)
ErrorMessageerror_messageHuman-readable explanation
X-Twilio-SignatureX-SmsRoute-SignatureBoth HMAC-SHA256; different header name. smsroute includes a timestamp: t=1713724912,v1=abc123...
Content-Type: form-urlencodedContent-Type: application/jsonThe biggest functional difference — parsing changes

Webhook handler — before

@app.post("/webhooks/twilio-status")
async def handle_status(request: Request):
    form = await request.form()
    msg_sid = form["MessageSid"]
    status = form["MessageStatus"]
    if status == "delivered":
        mark_delivered(msg_sid)
    elif status in ("failed", "undelivered"):
        mark_failed(msg_sid, form.get("ErrorCode"))

Webhook handler — after (native smsroute)

@app.post("/webhooks/smsroute-status")
async def handle_status(request: Request):
    payload = await request.json()
    msg_id = payload["message_id"]
    status = payload["status"]
    if status == "delivered":
        mark_delivered(msg_id)
    elif status in ("failed", "undelivered"):
        mark_failed(msg_id, payload.get("error_code"))

Webhook handler — after (using twilio-compat shim)

# No handler changes. Install the middleware in your request chain:
from twilio_compat import translate_smsroute_to_twilio

app.add_middleware(translate_smsroute_to_twilio)
# Your existing /webhooks/twilio-status handler keeps working unchanged.

Error code mapping

Twilio uses numeric error codes in the 30000-range for SMS errors; smsroute uses descriptive strings. The semantic mapping is direct:

Twilio codesmsroute codeHTTPMeaning
30003invalid_destination400Destination phone number is invalid or unreachable
30004forbidden_destination403Destination country is not supported or currently suspended
30005invalid_sender_id400Sender ID violates destination country's rules
30006carrier_unreachable503Carrier is temporarily not accepting traffic
30007body_too_long400Body exceeds segmentation limits
30008spam_filteredCarrier flagged as spam (webhook error_code only)
30010rate_limited429Exceeded per-key throughput; respect Retry-After
20003unauthorized401Missing or invalid API key
20403insufficient_balance402Account balance below destination's price; top up
20500internal_error500Our problem; safe to retry with idempotency key

Full mapping table at github.com/smsroute/twilio-compat/blob/main/error_codes.md, kept in sync with Twilio's published error-code registry.

Idempotency handling — a feature Twilio doesn't have

One place where smsroute actually has a feature Twilio lacks: idempotency keys on POST /v1/messages. Pass an Idempotency-Key header (any unique string, typically UUIDv4) and smsroute dedups retries within 24 hours:

r = httpx.post(
    "https://api.smsroute.cc/v1/messages",
    headers={
        "Authorization": f"Bearer {KEY}",
        "Idempotency-Key": "8f1e0b82-7c59-4a8c-b5e9-2c4f3d9a1e2f",
    },
    json={"to": "+5491123456789", "from": "smsroute", "body": "..."},
)

Safely retry on transient network failures without risk of duplicate sends. Twilio has no equivalent — migration users frequently add idempotency to their retry logic during the switch. It's strictly additive: your pre-migration Twilio code doesn't break without it, it just can't take advantage of it.

Cost comparison at realistic volume

The concrete ROI. A SaaS sending 50,000 OTP SMS/month split across 10 international countries (excluding US) — a typical transactional workload for a consumer fintech, exchange, or notification service:

MetricTwiliosmsrouteDelta
Blended per-SMS rate~$0.0476~$0.013671% lower
Monthly SMS cost (50k msgs)$2,380$680-$1,700/mo
Annual SMS cost$28,560$8,160-$20,400/yr
Migration engineering time4-8 hours
Break-even (hours of saved cost to recover migration time)~13 hrsBreak-even week 1
3-year cumulative savings$85,680 spent$24,480 spent$61,200 saved
The cost story compounds. Beyond per-SMS savings, crypto billing eliminates card-processor fees (~3% on Twilio invoices paid by credit card) and the 2-4 hours/month of finance-team overhead that invoicing + chargeback-reserve-tracking add. For a bootstrapped or indie-scale team, that's a week of engineering-time every year recovered from operations.

Parallel-send validation pattern — the shadow-traffic approach

The standard way to de-risk the migration is dual-write for 24-48 hours. A simple middleware pattern:

import random, os, httpx
from twilio.rest import Client as TwilioClient

twilio = TwilioClient(os.environ["TWILIO_SID"], os.environ["TWILIO_AUTH"])
SHADOW_PCT = float(os.environ.get("SMSROUTE_SHADOW_PCT", "0.10"))  # 10% shadow

def send_sms(to: str, body: str, **kwargs) -> dict:
    # Primary: Twilio (users get the Twilio response)
    msg = twilio.messages.create(to=to, from_="smsroute", body=body, **kwargs)
    result = {"id": msg.sid, "status": msg.status, "provider": "twilio"}

    # Shadow: smsroute (discarded, logged for comparison)
    if random.random() < SHADOW_PCT:
        try:
            r = httpx.post(
                "https://api.smsroute.cc/v1/messages",
                headers={"Authorization": f"Bearer {os.environ['SMSROUTE_API_KEY']}"},
                json={"to": to, "from": "smsroute", "body": body, **kwargs},
                timeout=10,
            )
            log.info("shadow_sms", twilio_id=msg.sid, smsroute=r.json())
        except Exception as e:
            log.warning("shadow_sms_failed", error=str(e))

    return result

After 24-48 hours of shadow logs, query for:

Once the comparison is clean, flip SHADOW_PCT to 1.0 and reverse primary/shadow roles — smsroute becomes primary, Twilio becomes shadow (or drops out entirely).

Frequently asked questions

How long does a typical Twilio to smsroute migration take?

4-8 hours of engineering work for a standard codebase using the Twilio Python or Node.js SDK. The actual code diff is 12-30 lines. Most of the time is spent on webhook URL updates, validating the first 100-1000 test sends, and updating CI/staging secrets. Teams running Twilio-specific products (Flex, Studio, Verify) will need more work — those aren't 1:1 replaceable.

Can I run Twilio and smsroute in parallel during migration?

Yes — this is the recommended validation pattern. Route 10% of outbound SMS through smsroute for 24-48 hours while 90% continues on Twilio. Compare delivery receipts to catch any edge cases specific to your destination countries.

What is the twilio-compat middleware?

A 30-line open-source middleware at github.com/smsroute/twilio-compat that translates smsroute's delivery-receipt webhook payload into Twilio's webhook shape. Install it in front of your existing handler and smsroute webhooks arrive with Twilio's field names — no handler changes needed. Adds <5ms latency.

Do I need to port my Twilio phone numbers?

Depends on which numbers. Alphanumeric sender IDs are free and work day one. Long codes are portable via RespOrg transfer (7-10 business days). Shortcodes require 6-12 weeks and CTIA re-approval — most teams keep shortcodes on Twilio during migration. US A2P 10DLC campaigns must be re-registered.

Can I keep my Twilio error-handling logic?

Mostly yes. Twilio uses numeric error codes; smsroute uses descriptive strings. Semantic mapping is clean and documented in the table above and at github.com/smsroute/twilio-compat.

What happens to my existing Twilio usage data?

It stays on Twilio. smsroute does not import historical message logs. Export from Twilio's Messaging Logs before cancellation if you need the historical data for compliance. Going forward, smsroute's /v1/messages/{id} endpoint and webhook delivery receipts feed your own logging infrastructure.

Is there a cost during migration?

Minimal. During parallel-send validation you pay both providers for the 10% overlap — ~$3-8 total on 50k/month volume. No migration fees from either provider. smsroute's sandbox is free.

Does smsroute support all the same destination countries as Twilio?

smsroute covers 149 countries — effectively the same international coverage as Twilio. For the top 50 destinations that account for 95%+ of most teams' SMS traffic, smsroute and Twilio route to the same tier-1 carriers.

Related pages

How long does a typical Twilio to smsroute migration take?

4-8 hours of engineering work for a standard codebase using the Twilio Python or Node.js SDK. The actual code diff is 12-30 lines. Most of the time is spent on webhook URL updates in your provider panel, validating the first 100-1000 test sends, and updating CI/staging secrets. Teams running Twilio-specific products (Flex, Studio, Verify) will need more work — those are not 1:1 replaceable and may stay on Twilio while SMS moves to smsroute.

Can I run Twilio and smsroute in parallel during migration?

Yes — this is the recommended validation pattern. Route 10% of outbound SMS through smsroute for 24-48 hours while 90% continues on Twilio. Compare delivery receipts between the two providers to catch any edge cases specific to your destination countries. Once parallel-send passes cleanly, flip to 100% smsroute and keep Twilio credentials in place for a week as emergency rollback.

What is the twilio-compat middleware?

twilio-compat is a 30-line open-source middleware at github.com/smsroute/twilio-compat that translates smsroute's delivery-receipt webhook payload into Twilio's webhook shape. If you don't want to modify your existing Twilio webhook handler during the migration, install twilio-compat in front of your handler and smsroute webhooks will arrive with Twilio's field names (MessageSid, MessageStatus, To, From, etc.). Adds <5ms latency.

Do I need to port my Twilio phone numbers?

It depends on which numbers. Alphanumeric sender IDs are portable for free — they are per-send configuration, not account-bound. Long codes (regular phone numbers) can be ported via RespOrg transfer, typically 7-10 business days and some carrier fees. Shortcodes are technically portable but require 6-12 weeks and CTIA re-approval — most teams keep shortcodes on Twilio during migration. US A2P 10DLC campaigns must be re-registered under smsroute's TCR relationship.

Can I keep my Twilio error-handling logic?

Mostly yes. Twilio uses numeric error codes (30003, 30005, 30007, etc.) documented in their error-code table. smsroute uses descriptive string codes (invalid_destination, insufficient_balance, rate_limited). The semantic mapping is clean: most Twilio numeric codes have a direct smsroute string equivalent. We maintain a mapping table at github.com/smsroute/twilio-compat/blob/main/error_codes.md so you can translate existing error-handling conditionals. For retry logic, both providers return the same HTTP status class for the same failure categories (400 for permanent, 429 for rate limit, 500/503 for transient).

What happens to my existing Twilio usage data?

It stays on Twilio. smsroute does not import historical message logs or billing data from Twilio. If you need to retain message logs for compliance or analytics, export from Twilio's Messaging Logs before cancellation (retention varies by Twilio plan, typically 30 days for standard accounts). Going forward, smsroute provides /v1/messages/{id} endpoint for retrieval of individual messages and webhook delivery receipts that your own logging infrastructure can persist.

Is there a cost during migration?

Minimal. During parallel-send validation you pay both providers for the overlap — typically 24-48 hours of ~10% double-sending. On 50k messages/month volume, that overlap costs ~$3-8 total. There is no migration fee from either provider. smsroute's sandbox API is free (no balance consumed) so all pre-production testing costs zero.

Does smsroute support all the same destination countries as Twilio?

smsroute covers 149 countries — effectively the same international coverage as Twilio for SMS. There are a handful of small Pacific and African markets where Twilio has direct connections smsroute routes through aggregator partners, which shows up as slightly longer latency (~300-600ms vs ~150-300ms). For the top 50 destination countries that account for 95%+ of most teams' SMS traffic, smsroute and Twilio route to the same tier-1 carriers. See our full country list at /send-sms-to.

How long does a typical Twilio to smsroute migration take?

4-8 hours of engineering work for a standard codebase using the Twilio Python or Node.js SDK. The actual code diff is 12-30 lines. Most of the time is spent on webhook URL updates in your provider panel, validating the first 100-1000 test sends, and updating CI/staging secrets. Teams running Twilio-specific products (Flex, Studio, Verify) will need more work — those are not 1:1 replaceable and may stay on Twilio while SMS moves to smsroute.

Can I run Twilio and smsroute in parallel during migration?

Yes — this is the recommended validation pattern. Route 10% of outbound SMS through smsroute for 24-48 hours while 90% continues on Twilio. Compare delivery receipts between the two providers to catch any edge cases specific to your destination countries. Once parallel-send passes cleanly, flip to 100% smsroute and keep Twilio credentials in place for a week as emergency rollback.

What is the twilio-compat middleware?

twilio-compat is a 30-line open-source middleware at github.com/smsroute/twilio-compat that translates smsroute's delivery-receipt webhook payload into Twilio's webhook shape. If you don't want to modify your existing Twilio webhook handler during the migration, install twilio-compat in front of your handler and smsroute webhooks will arrive with Twilio's field names (MessageSid, MessageStatus, To, From, etc.). Adds <5ms latency.

Do I need to port my Twilio phone numbers?

It depends on which numbers. Alphanumeric sender IDs are portable for free — they are per-send configuration, not account-bound. Long codes (regular phone numbers) can be ported via RespOrg transfer, typically 7-10 business days and some carrier fees. Shortcodes are technically portable but require 6-12 weeks and CTIA re-approval — most teams keep shortcodes on Twilio during migration. US A2P 10DLC campaigns must be re-registered under smsroute's TCR relationship.

Can I keep my Twilio error-handling logic?

Mostly yes. Twilio uses numeric error codes (30003, 30005, 30007, etc.) documented in their error-code table. smsroute uses descriptive string codes (invalid_destination, insufficient_balance, rate_limited). The semantic mapping is clean: most Twilio numeric codes have a direct smsroute string equivalent. We maintain a mapping table at github.com/smsroute/twilio-compat/blob/main/error_codes.md so you can translate existing error-handling conditionals. For retry logic, both providers return the same HTTP status class for the same failure categories (400 for permanent, 429 for rate limit, 500/503 for transient).

What happens to my existing Twilio usage data?

It stays on Twilio. smsroute does not import historical message logs or billing data from Twilio. If you need to retain message logs for compliance or analytics, export from Twilio's Messaging Logs before cancellation (retention varies by Twilio plan, typically 30 days for standard accounts). Going forward, smsroute provides /v1/messages/{id} endpoint for retrieval of individual messages and webhook delivery receipts that your own logging infrastructure can persist.

Is there a cost during migration?

Minimal. During parallel-send validation you pay both providers for the overlap — typically 24-48 hours of ~10% double-sending. On 50k messages/month volume, that overlap costs ~$3-8 total. There is no migration fee from either provider. smsroute's sandbox API is free (no balance consumed) so all pre-production testing costs zero.

Does smsroute support all the same destination countries as Twilio?

smsroute covers 149 countries — effectively the same international coverage as Twilio for SMS. There are a handful of small Pacific and African markets where Twilio has direct connections smsroute routes through aggregator partners, which shows up as slightly longer latency (~300-600ms vs ~150-300ms). For the top 50 destination countries that account for 95%+ of most teams' SMS traffic, smsroute and Twilio route to the same tier-1 carriers. See our full country list at /send-sms-to.

How long does a typical Twilio to smsroute migration take?

4-8 hours of engineering work for a standard codebase using the Twilio Python or Node.js SDK. The actual code diff is 12-30 lines. Most of the time is spent on webhook URL updates in your provider panel, validating the first 100-1000 test sends, and updating CI/staging secrets. Teams running Twilio-specific products (Flex, Studio, Verify) will need more work — those are not 1:1 replaceable and may stay on Twilio while SMS moves to smsroute.

Can I run Twilio and smsroute in parallel during migration?

Yes — this is the recommended validation pattern. Route 10% of outbound SMS through smsroute for 24-48 hours while 90% continues on Twilio. Compare delivery receipts between the two providers to catch any edge cases specific to your destination countries. Once parallel-send passes cleanly, flip to 100% smsroute and keep Twilio credentials in place for a week as emergency rollback.

What is the twilio-compat middleware?

twilio-compat is a 30-line open-source middleware at github.com/smsroute/twilio-compat that translates smsroute's delivery-receipt webhook payload into Twilio's webhook shape. If you don't want to modify your existing Twilio webhook handler during the migration, install twilio-compat in front of your handler and smsroute webhooks will arrive with Twilio's field names (MessageSid, MessageStatus, To, From, etc.). Adds <5ms latency.

Do I need to port my Twilio phone numbers?

It depends on which numbers. Alphanumeric sender IDs are portable for free — they are per-send configuration, not account-bound. Long codes (regular phone numbers) can be ported via RespOrg transfer, typically 7-10 business days and some carrier fees. Shortcodes are technically portable but require 6-12 weeks and CTIA re-approval — most teams keep shortcodes on Twilio during migration. US A2P 10DLC campaigns must be re-registered under smsroute's TCR relationship.

Can I keep my Twilio error-handling logic?

Mostly yes. Twilio uses numeric error codes (30003, 30005, 30007, etc.) documented in their error-code table. smsroute uses descriptive string codes (invalid_destination, insufficient_balance, rate_limited). The semantic mapping is clean: most Twilio numeric codes have a direct smsroute string equivalent. We maintain a mapping table at github.com/smsroute/twilio-compat/blob/main/error_codes.md so you can translate existing error-handling conditionals. For retry logic, both providers return the same HTTP status class for the same failure categories (400 for permanent, 429 for rate limit, 500/503 for transient).

What happens to my existing Twilio usage data?

It stays on Twilio. smsroute does not import historical message logs or billing data from Twilio. If you need to retain message logs for compliance or analytics, export from Twilio's Messaging Logs before cancellation (retention varies by Twilio plan, typically 30 days for standard accounts). Going forward, smsroute provides /v1/messages/{id} endpoint for retrieval of individual messages and webhook delivery receipts that your own logging infrastructure can persist.

Is there a cost during migration?

Minimal. During parallel-send validation you pay both providers for the overlap — typically 24-48 hours of ~10% double-sending. On 50k messages/month volume, that overlap costs ~$3-8 total. There is no migration fee from either provider. smsroute's sandbox API is free (no balance consumed) so all pre-production testing costs zero.

Does smsroute support all the same destination countries as Twilio?

smsroute covers 149 countries — effectively the same international coverage as Twilio for SMS. There are a handful of small Pacific and African markets where Twilio has direct connections smsroute routes through aggregator partners, which shows up as slightly longer latency (~300-600ms vs ~150-300ms). For the top 50 destination countries that account for 95%+ of most teams' SMS traffic, smsroute and Twilio route to the same tier-1 carriers. See our full country list at /send-sms-to.

How long does a typical Twilio to smsroute migration take?

4-8 hours of engineering work for a standard codebase using the Twilio Python or Node.js SDK. The actual code diff is 12-30 lines. Most of the time is spent on webhook URL updates in your provider panel, validating the first 100-1000 test sends, and updating CI/staging secrets. Teams running Twilio-specific products (Flex, Studio, Verify) will need more work — those are not 1:1 replaceable and may stay on Twilio while SMS moves to smsroute.

Can I run Twilio and smsroute in parallel during migration?

Yes — this is the recommended validation pattern. Route 10% of outbound SMS through smsroute for 24-48 hours while 90% continues on Twilio. Compare delivery receipts between the two providers to catch any edge cases specific to your destination countries. Once parallel-send passes cleanly, flip to 100% smsroute and keep Twilio credentials in place for a week as emergency rollback.

What is the twilio-compat middleware?

twilio-compat is a 30-line open-source middleware at github.com/smsroute/twilio-compat that translates smsroute's delivery-receipt webhook payload into Twilio's webhook shape. If you don't want to modify your existing Twilio webhook handler during the migration, install twilio-compat in front of your handler and smsroute webhooks will arrive with Twilio's field names (MessageSid, MessageStatus, To, From, etc.). Adds <5ms latency.

Do I need to port my Twilio phone numbers?

It depends on which numbers. Alphanumeric sender IDs are portable for free — they are per-send configuration, not account-bound. Long codes (regular phone numbers) can be ported via RespOrg transfer, typically 7-10 business days and some carrier fees. Shortcodes are technically portable but require 6-12 weeks and CTIA re-approval — most teams keep shortcodes on Twilio during migration. US A2P 10DLC campaigns must be re-registered under smsroute's TCR relationship.

Can I keep my Twilio error-handling logic?

Mostly yes. Twilio uses numeric error codes (30003, 30005, 30007, etc.) documented in their error-code table. smsroute uses descriptive string codes (invalid_destination, insufficient_balance, rate_limited). The semantic mapping is clean: most Twilio numeric codes have a direct smsroute string equivalent. We maintain a mapping table at github.com/smsroute/twilio-compat/blob/main/error_codes.md so you can translate existing error-handling conditionals. For retry logic, both providers return the same HTTP status class for the same failure categories (400 for permanent, 429 for rate limit, 500/503 for transient).

What happens to my existing Twilio usage data?

It stays on Twilio. smsroute does not import historical message logs or billing data from Twilio. If you need to retain message logs for compliance or analytics, export from Twilio's Messaging Logs before cancellation (retention varies by Twilio plan, typically 30 days for standard accounts). Going forward, smsroute provides /v1/messages/{id} endpoint for retrieval of individual messages and webhook delivery receipts that your own logging infrastructure can persist.

Is there a cost during migration?

Minimal. During parallel-send validation you pay both providers for the overlap — typically 24-48 hours of ~10% double-sending. On 50k messages/month volume, that overlap costs ~$3-8 total. There is no migration fee from either provider. smsroute's sandbox API is free (no balance consumed) so all pre-production testing costs zero.

Does smsroute support all the same destination countries as Twilio?

smsroute covers 149 countries — effectively the same international coverage as Twilio for SMS. There are a handful of small Pacific and African markets where Twilio has direct connections smsroute routes through aggregator partners, which shows up as slightly longer latency (~300-600ms vs ~150-300ms). For the top 50 destination countries that account for 95%+ of most teams' SMS traffic, smsroute and Twilio route to the same tier-1 carriers. See our full country list at /send-sms-to.