← Blog
Developer playbook · 16 min read · Published April 2026 · Author Serhat Dogan

Hub di migrazione SMS-Activate 2026: lista di controllo per sviluppatori, mappatura API e confronto rimborsi

Hub di migrazione SMS-Activate 2026: lista di controllo per sviluppatori, mappatura API e confronto rimborsi

If you are still carrying handler_api.php calls in your repo pointed at sms-activate.org, this is the hub you open at 9pm on a Friday and close with a working integration before midnight. Real endpoint mapping, real code diffs, refund policy comparison, and the gotchas that will bite you between the line you change and the alert that wakes you up on Monday morning.

Perché esiste questo playbook

La maggior parte dei post "SMS-Activate è morto, ecco un elenco di alternative" tralascia la parte che in realtà consuma ore di lavoro degli sviluppatori: il codice. Iscriversi a un nuovo provider richiede cinque minuti. Riscrivere un'integrazione che è in produzione da anni, con casi limite non testati e un tracker dei costi allegato, richiede più tempo di quanto pensiate.

Dopo aver rilasciato il nostro livello di compatibilità a gennaio 2026, abbiamo iniziato a ricevere le stesse tre domande da ogni team che lo ha provato:

  1. Quali endpoint si mappano in modo pulito e quali richiedono modifiche manuali?
  2. Come posso mantenere funzionanti il mio tracciamento dei costi e il flusso di rimborso senza riscrivere tutto?
  3. Cosa si rompe silenziosamente e si presenta una settimana dopo come una sorpresa in fattura?

Questo playbook risponde a queste tre domande in ordine e fornisce codice copia-incolla che potete revisionare prima di eseguirlo.

Il riepilogo delle 48 ore: cosa è successo realmente

SMS-Activate è scomparso il 29 dicembre 2025. Non c'è stato alcun banner di manutenzione programmata, nessuno strumento di migrazione e nessun avviso pubblico. Gli utenti che tentavano di accedere si sono trovati di fronte a una singola pagina che diceva che il servizio aveva chiuso permanentemente. L'API restituiva reset di connessione su ogni endpoint nel giro di poche ore.

Sono successe tre cose velocemente:

Le conseguenze si stanno ancora svolgendo. Ad aprile 2026 ci sono casi attivi di piccole cause in Russia e almeno due cause legali comunitarie coordinate che cercano di recuperare i saldi bloccati. Niente di tutto ciò aiuta il vostro codice, motivo per cui ci concentreremo sulla parte che potete effettivamente risolvere.

Parte 1: Mappa di deprecazione API

SMS-Activate offriva un singolo endpoint pubblico all'indirizzo https://sms-activate.org/stubs/handler_api.php. Ogni azione era un parametro della query string su quell'URL. La tabella sottostante mappa ogni azione principale al suo equivalente VerifySMS. Il livello di compatibilità all'indirizzo https://api.verifysms.app/compat/handler_api.php accetta la stessa forma esatta di query string.

Azione SMS-ActivateScopoLivello di compatibilità VerifySMSAPI nativa VerifySMS
getBalanceRestituisce il saldo in USD come testoFunziona invariato. Restituisce ACCESS_BALANCE:X.YYGET /v1/balance restituisce JSON
getNumbersStatusDisponibilità per paeseFunziona. Restituisce il formato legacy della mappaGET /v1/countries/availability
getNumberNoleggia un numero per un servizioFunziona. Restituisce ACCESS_NUMBER:id:+telefonoPOST /v1/rentals
setStatusConferma o annulla un noleggioFunziona. I codici di stato 1/3/6/8 si comportano in modo identicoPOST /v1/rentals/{id}/status
getStatusInterroga per l'arrivo dell'SMSFunziona. Restituisce STATUS_WAIT_CODE, STATUS_OK:CODE, STATUS_WAIT_RETRYGET /v1/rentals/{id}
getPricesRecupera la tabella dei prezziFunziona. Restituisce i prezzi VerifySMS nel formato legacy JSONGET /v1/prices
getCountriesMappa dei codici paeseFunziona. Restituisce sia gli ID numerici legacy che i codici ISO-3166GET /v1/countries
getTopCountriesByServicePaesi principali per servizioRestituisce dati VerifySMS in tempo reale invece delle classifiche SMS-Activate memorizzate nella cacheGET /v1/services/{id}/top-countries

Una manciata di azioni SMS-Activate meno utilizzate non hanno una mappatura uno a uno. getRentServicesAndCountries e l'API di noleggio a lungo termine erano specifiche di SMS-Activate e non hanno un livello di compatibilità. Se la vostra integrazione utilizzava quelle, dovreste passare all'endpoint nativo VerifySMS per noleggi a lungo termine all'indirizzo POST /v1/rentals/long, che è documentato separatamente.

Parte 2: Guide alla migrazione del codice

Gli snippet seguenti sono esattamente nella forma in cui li ho testati sul nostro ambiente di staging a gennaio. Li ho mantenuti deliberatamente semplici in modo che possiate leggerli confrontandoli con il vostro codice senza cambiare contesto.

Python (requests)

L'unica modifica richiesta è l'URL di base. Se avete già incapsulato l'API in un piccolo modulo client, la differenza è una singola riga.

import os
import requests

# PRIMA
# BASE_URL = "https://sms-activate.org/stubs/handler_api.php"
# DOPO
BASE_URL = "https://api.verifysms.app/compat/handler_api.php"
API_KEY = os.environ["SMS_API_KEY"]

def get_number(service: str, country: int) -> tuple[str, str]:
    resp = requests.get(BASE_URL, params={
        "api_key": API_KEY,
        "action": "getNumber",
        "service": service,
        "country": country,
    }, timeout=30)
    resp.raise_for_status()
    # ACCESS_NUMBER:12345:+441234567890
    status, rental_id, phone = resp.text.split(":", 2)
    if status != "ACCESS_NUMBER":
        raise RuntimeError(f"risposta inattesa: {resp.text}")
    return rental_id, phone

def wait_for_code(rental_id: str, deadline_seconds: int = 180) -> str:
    import time
    start = time.monotonic()
    while time.monotonic() - start < deadline_seconds:
        resp = requests.get(BASE_URL, params={
            "api_key": API_KEY,
            "action": "getStatus",
            "id": rental_id,
        }, timeout=15).text
        if resp.startswith("STATUS_OK:"):
            return resp.split(":", 1)[1]
        time.sleep(4)
    # Segna come non utilizzato per ottenere il rimborso
    requests.get(BASE_URL, params={
        "api_key": API_KEY,
        "action": "setStatus",
        "status": 8,
        "id": rental_id,
    }, timeout=15)
    raise TimeoutError(f"nessun codice dopo {deadline_seconds}s")

Node.js (axios)

import axios from "axios";

// PRIMA
// const BASE_URL = "https://sms-activate.org/stubs/handler_api.php";
// DOPO
const BASE_URL = "https://api.verifysms.app/compat/handler_api.php";
const API_KEY = process.env.SMS_API_KEY;

export async function getNumber(service, country) {
  const { data } = await axios.get(BASE_URL, {
    params: { api_key: API_KEY, action: "getNumber", service, country },
    timeout: 30_000,
  });
  const [status, rentalId, phone] = data.split(":");
  if (status !== "ACCESS_NUMBER") {
    throw new Error(`risposta inattesa: ${data}`);
  }
  return { rentalId, phone };
}

export async function waitForCode(rentalId, deadlineMs = 180_000) {
  const start = Date.now();
  while (Date.now() - start < deadlineMs) {
    const { data } = await axios.get(BASE_URL, {
      params: { api_key: API_KEY, action: "getStatus", id: rentalId },
      timeout: 15_000,
    });
    if (data.startsWith("STATUS_OK:")) return data.split(":")[1];
    await new Promise((r) => setTimeout(r, 4000));
  }
  await axios.get(BASE_URL, {
    params: { api_key: API_KEY, action: "setStatus", status: 8, id: rentalId },
    timeout: 15_000,
  });
  throw new Error(`nessun codice dopo ${deadlineMs}ms`);
}

PHP (curl)

<?php
// PRIMA
// const BASE_URL = "https://sms-activate.org/stubs/handler_api.php";
// DOPO
const BASE_URL = "https://api.verifysms.app/compat/handler_api.php";

function sms_call(array $params): string {
    $params["api_key"] = getenv("SMS_API_KEY");
    $url = BASE_URL . "?" . http_build_query($params);
    $ch  = curl_init($url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_TIMEOUT, 30);
    $body = curl_exec($ch);
    curl_close($ch);
    return $body;
}

function get_number(string $service, int $country): array {
    $resp = sms_call(["action" => "getNumber", "service" => $service, "country" => $country]);
    [$status, $id, $phone] = explode(":", $resp, 3);
    if ($status !== "ACCESS_NUMBER") {
        throw new RuntimeException("inatteso: $resp");
    }
    return ["id" => $id, "phone" => $phone];
}

Go (net/http)

package sms

import (
    "errors"
    "fmt"
    "io"
    "net/http"
    "net/url"
    "os"
    "strings"
    "time"
)

// PRIMA
// const baseURL = "https://sms-activate.org/stubs/handler_api.php"
// DOPO
const baseURL = "https://api.verifysms.app/compat/handler_api.php"

func call(params url.Values) (string, error) {
    params.Set("api_key", os.Getenv("SMS_API_KEY"))
    req, _ := http.NewRequest("GET", baseURL+"?"+params.Encode(), nil)
    client := &http.Client{Timeout: 30 * time.Second}
    resp, err := client.Do(req)
    if err != nil {
        return "", err
    }
    defer resp.Body.Close()
    body, _ := io.ReadAll(resp.Body)
    return string(body), nil
}

func GetNumber(service string, country int) (id, phone string, err error) {
    body, err := call(url.Values{
        "action":  {"getNumber"},
        "service": {service},
        "country": {fmt.Sprint(country)},
    })
    if err != nil {
        return "", "", err
    }
    parts := strings.SplitN(body, ":", 3)
    if len(parts) != 3 || parts[0] != "ACCESS_NUMBER" {
        return "", "", errors.New("inatteso: " + body)
    }
    return parts[1], parts[2], nil
}

L'esempio Go è deliberatamente scritto senza client di terze parti in modo che possiate inserirlo in un servizio minimale senza aggiungere dipendenze. Lo stesso schema vale in ogni altra lingua: scambiate l'URL, mantenete il resto e lasciate che la vostra gestione degli errori esistente venga trasferita.

Parte 3: Insidie che vi fregheranno

Questi sono i punti in cui il livello di compatibilità è fedele alle stranezze di SMS-Activate, ma le stranezze stesse vi sorprenderanno se non toccate questo codice da un po'.

Gli ID paese non sono codici ISO

SMS-Activate numerava i paesi nel proprio ordine: Russia era 0, USA era 187, Indonesia era 6, e così via. Se la vostra integrazione ha questi numeri magici codificati, funzionano ancora sul livello di compatibilità. Se state scrivendo nuovo codice, preferite la forma alfanumerica ISO-3166 (RU, US, ID) che il livello di compatibilità accetta anche. Non mescolate entrambi gli stili nello stesso punto di chiamata, perché il debug futuro sarà doloroso.

Codice di stato 3 contro 6

Il codice di azione 3 di setStatus significava "richiedi un altro SMS" nel mondo SMS-Activate, e il codice 6 significava "accetta il codice come valido". Questi due codici sono facili da scambiare in fretta e hanno esiti di fatturazione opposti: 3 vi fa rimanere in fattura, 6 conferma la verifica riuscita. Il livello di compatibilità si comporta allo stesso modo. Cercate nel vostro codice setStatus e assicuratevi che il ramo che accetta il codice 6 venga eseguito solo dopo che siete certi che la verifica sia riuscita.

Timeout e circuit breaker

SMS-Activate sotto carico a volte restituiva un 200 con un corpo vuoto invece di un errore HTTP. I client difensivi incapsulano la chiamata in un timeout e trattano il corpo vuoto come un segnale di ritentativo. VerifySMS non restituisce mai un corpo vuoto sul livello di compatibilità. Se il vostro client tratta ancora il vuoto come un ritentativo, consumerà budget su una rete instabile perché il ritentativo colpirà un ID di noleggio diverso. Il modello più sicuro è controllare i prefissi di risposta noti (ACCESS_, STATUS_, BAD_) e trattare qualsiasi altra cosa come un errore grave, non transitorio.

I limiti di velocità passano da per chiave a per IP

I limiti di velocità di SMS-Activate erano legati al token API. I limiti di velocità di VerifySMS sono legati alla combinazione di token API e indirizzo IP sorgente, perché vediamo molti abusi da script di scraping che condividono una chiave su una botnet. Per il traffico di produzione normale da un singolo server o da un pool bilanciato, questo è invisibile. Se eseguite lavori CI distribuiti che condividono tutti una chiave di staging, potreste vedere un 429 la prima volta che l'intera flotta si riscalda insieme. La soluzione è lasciare che la canary venga eseguita da un nodo per un giorno prima di espandersi.

La tempistica dei rimborsi sembra istantanea perché è effettivamente istantanea

Questa non è una trappola tanto quanto una piacevole sorpresa. Mentre i rimborsi di SMS-Activate impiegavano alcune ore per apparire sul vostro saldo, i rimborsi di VerifySMS appaiono entro 60 secondi. Se il vostro tracker dei costi legge il saldo secondo una pianificazione, registrerà il rimborso come un credito che il vecchio sistema avrebbe perso. Le dashboard di riconciliazione a volte segnalano questo come un'anomalia il primo giorno.

Parte 4: Confronto prezzi realtà

Prima dello spegnimento, SMS-Activate era il fondo del mercato. I numeri russi costavano da 0,03 a 0,05 dollari per verifica, e gli acquirenti di grandi volumi pagavano ancora meno. Quel fondo è sparito. Ecco dove si posizionano i provider rimanenti nell'aprile 2026 per i servizi più comuni, estratti dalla pagina dei prezzi pubblici di ciascun provider in data :

Servizio5simTextVerifiedSMSPVASMS-MANVerifySMS
WhatsApp / Russia$0.014$0.05$0.035$0.10
WhatsApp / USA$0.27$0.25$0.28$0.22$0.18
Telegram / Russia$0.016$0.05$0.04$0.10
Telegram / USA$0.35$0.40$0.38$0.30$0.20
Google / Indonesia$0.07$0.08$0.06$0.10

Il modello è semplice: 5sim e SMS-MAN vincono sui prezzi russi al ribasso, TextVerified è il tier premium USA, e VerifySMS si posiziona nel mezzo con una base fissa di $0.10 per tutto tranne i numeri non VoIP USA più costosi. Se il vostro budget era impostato sui prezzi minimi di SMS-Activate, aspettatevi di pagare da due a cinque volte di più per verifica indipendentemente dal sostituto che scegliete.

Due note su questa tabella. Primo, ogni provider (incluso VerifySMS) alza e abbassa i prezzi dei singoli paesi in risposta ai costi degli operatori, quindi confermate il prezzo attuale nella vostra dashboard prima di impegnare un budget. Secondo, il prezzo *effettivo* per verifica riuscita dipende dal rapporto di rimborso. Un provider con un prezzo di copertina di $0.08 e un tasso di successo del 70% vi costa di più per successo di un provider da $0.10 con rimborsi automatici e un tasso di successo del 90%.

Parte 5: La checklist di migrazione in 10 passaggi

Questa è la sequenza effettiva che abbiamo seguito con i nostri utenti a gennaio. Presuppone un singolo sviluppatore con accesso al repository, un servizio di produzione e un ambiente di staging. Aumentate le percentuali della canary se state eseguendo più servizi o un monorepo.

  1. Inventaria ogni punto di chiamata. Esegui git grep -n 'sms-activate\.org\|handler_api\.php\|getNumber\|setStatus' e elenca ogni file che raggiunge la vecchia API. Se ne trovi più di una dozzina, scegli un modulo wrapper e centralizza prima le chiamate prima di migrare.
  2. Ottieni una chiave API VerifySMS. Iscriviti, aggiungi un piccolo importo di saldo e genera una chiave con ambito per lo staging. Tieni la chiave di produzione fuori dal repository.
  3. Cambia l'URL di base. Sostituisci l'host SMS-Activate con api.verifysms.app/compat/handler_api.php. Non cambiare la query string. Esegui il commit solo di questo, in modo che la differenza sia pulita.
  4. Esegui i tuoi test esistenti. Se i test raggiungono l'API reale, puntali allo staging e osserva eventuali discrepanze di formato. Se simulano l'API, eseguili anche sull'endpoint di staging live in modo da cogliere la deriva del contratto.
  5. Riconferma gli ID paese. Esamina il tuo codice alla ricerca di costanti paese. Se stai usando gli ID numerici legacy, funzionano ancora. Se hai la possibilità, sostituiscili con codici ISO-3166 perché il prossimo sviluppatore che toccherà questo file ti ringrazierà.
  6. Collega le richieste di rimborso. Conferma che il tuo percorso di timeout chiami setStatus con il codice di stato 8. Senza questo, riceverai comunque rimborsi (rimborsiamo automaticamente i noleggi scaduti) ma il tuo tracker dei costi sarà in ritardo rispetto alla realtà.
  7. Aggiorna il tuo tracker dei costi. Leggi il costo dall'header di risposta X-VerifySMS-Cost invece di analizzarlo dalla tabella dei prezzi. Questa singola modifica rende la tua dashboard finanziaria accurata al centesimo.
  8. Monitoraggio. Aggiungi alert sul tasso di successo, latenza p95 e rapporto di rimborso rispetto al tuo baseline esistente. Scegli soglie che puoi difendere, non quelle che pensi andranno "bene".
  9. Canary al 5% per 24 ore. Indirizza una piccola parte del traffico di produzione attraverso il nuovo endpoint. Osserva la dashboard, non solo gli alert.
  10. Passa il resto. Una volta che la finestra canary è pulita, sposta il restante 95% e lascia il vecchio codice client commentato (non eliminato) per un ciclo di rilascio, in modo da avere un rollback rapido.

Elimina il vecchio codice nel rilascio successivo. Non lasciare siti di chiamata morti in giro per più di una settimana perché la persona successiva che toccherà il modulo li incollerà accidentalmente in una nuova integrazione.

Domande frequenti

Il livello di compatibilità SMS-Activate è una vera API o solo uno stub?

È un endpoint reale all'indirizzo api.verifysms.app/compat/handler_api.php che accetta ogni azione principale dalla documentazione pubblica di SMS-Activate: getBalance, getNumber, getStatus, setStatus, getPrices e getCountries. Le richieste vengono inoltrate alla nostra API nativa sotto il cofano, quindi ottieni i prezzi, la copertura e il comportamento di rimborso di VerifySMS senza modifiche al codice da parte tua.

La mia vecchia chiave API funzionerà?

No. Le chiavi API di SMS-Activate hanno smesso di autenticare il giorno in cui il servizio è stato chiuso. Hai bisogno di una nuova chiave da VerifySMS. Iscriviti, aggiungi un piccolo importo di saldo e genera una chiave dalla dashboard. Il formato della chiave è identico in lunghezza, quindi puoi incollarla nella stessa variabile d'ambiente.

Come funzionano i rimborsi rispetto a SMS-Activate?

SMS-Activate richiedeva di chiamare setStatus con il codice di stato 8 entro 20 minuti per contrassegnare un numero come non utilizzato, e i rimborsi venivano elaborati manualmente entro poche ore. VerifySMS accetta la stessa chiamata setStatus e rimborsa l'intero importo sul tuo saldo entro 60 secondi. Se dimentichi di chiamare setStatus del tutto, il nostro sistema rimborsa comunque automaticamente qualsiasi numero che non ha mai ricevuto un SMS dopo la scadenza della finestra di noleggio.

Quali paesi sono supportati?

VerifySMS copre oltre 200 paesi. Ogni paese che SMS-Activate offriva è disponibile su VerifySMS, inclusi Russia, Indonesia, Vietnam, Nigeria e Stati Uniti. Puoi mantenere la tua mappatura ID paese esistente o migrare ai codici ISO-3166 alpha-2 quando vuoi.

Il prezzo è lo stesso?

No. I prezzi minimi di mercato di SMS-Activate da 0,03 a 0,05 dollari per verifica per i numeri russi sono scomparsi dal mercato aperto. I prezzi di mercato attuali vanno da 0,10 dollari per i servizi comuni fino a 0,25 dollari per i numeri non VoIP USA su piattaforme più restrittive. VerifySMS addebita 0,10 dollari come base e pubblica i prezzi per paese sulla dashboard.

Devo cambiare la mia logica di polling?

No. La chiamata getStatus restituisce STATUS_WAIT_CODE e STATUS_OK nello stesso formato utilizzato da SMS-Activate. Intervalli di polling di 3-5 secondi funzionano ancora. L'unica nuova funzionalità è che VerifySMS espone anche un URL webhook nella dashboard, quindi puoi interrompere completamente il polling se preferisci un flusso guidato da eventi.

Cosa succede se il livello di compatibilità viene mai deprecato?

Il livello di compatibilità è considerato un'interfaccia pubblica permanente. Se mai ne cambieremo il comportamento, pubblicheremo una finestra di deprecazione minima di sei mesi con una nota di migrazione completa. Anche l'API JSON nativa di VerifySMS è documentata, quindi puoi migrare dal livello di compatibilità al tuo ritmo, quando sarà opportuno.

Come posso testare senza spendere soldi?

La dashboard di VerifySMS espone una modalità sandbox che restituisce numeri di telefono simulati e codici SMS in scatola senza addebitare il tuo saldo. Attiva l'opzione sandbox nella dashboard o invia l'header X-Sandbox-Mode con qualsiasi richiesta per esercitare i tuoi percorsi di codice prima di andare in produzione.

Posso migrare anche da altri servizi?

Sì. Questo playbook è scritto attorno all'API SMS-Activate perché è lì che si trova la maggior parte del codice bloccato, ma la stessa checklist si applica alle migrazioni da 5sim, SMS-MAN o qualsiasi altro servizio compatibile con handler_api. Il livello di compatibilità riconosce i parametri di handler_api.php indipendentemente dal servizio che stavi chiamando in precedenza.

Quanto tempo richiede una migrazione reale?

Per un'integrazione di un singolo servizio con poche decine di punti di chiamata, prevedi da due a quattro ore di lavoro concentrato, più una finestra canary di 24 ore prima di passare al traffico completo. Migrazioni multi-servizio più grandi con gestione degli errori personalizzata, analisi e ritentativi possono richiedere più tempo, ma di solito finiscono comunque entro una singola giornata lavorativa.

Perdo i miei dati storici?

La cronologia delle verifiche di SMS-Activate è andata offline quando il servizio è stato chiuso e non è recuperabile. VerifySMS mantiene un registro di audit completo di ogni tentativo di verifica sul tuo account per 12 mesi, accessibile dalla dashboard e tramite l'estensione /compat/handler_api.php?action=getHistory.

Questo influisce sulla mia posizione GDPR o di conformità?

VerifySMS è registrata nel Regno Unito e segue il GDPR del Regno Unito. Pubblichiamo la nostra politica di conservazione dei dati, i sub-processori e il DPA sulla pagina della privacy. Se la tua precedente configurazione richiedeva un DPA con SMS-Activate, contattaci e controfirmeremo lo stesso accordo entro un giorno lavorativo.

Prossimi passi

Se hai letto fin qui, hai già i pezzi che ti servono. Inizia con il passaggio di inventario, fai rivedere lo scambio dell'URL di base a un collega e fai eseguire la canary durante la notte. Il playbook è volutamente piccolo; la parte difficile è la disciplina di fermarsi dopo la finestra canary invece di passare tutto in un unico commit.

Letture correlate sul resto del sito:

Pronto a completare la migrazione in una sola serata?

Crea una chiave API VerifySMS →

Modalità sandbox inclusa · Garanzia di rimborso automatico · 200+ paesi · Livello di compatibilità SMS-Activate su /compat/handler_api.php

Next steps

If you have read this far, you already have the pieces you need. Start with the inventory step, get the base URL swap in front of a teammate for review, and run the canary overnight. The playbook is small on purpose; the hard part is the discipline to stop after the canary window instead of cutting everything over in one commit.

Related reading on the rest of the site:

Ready to cut the migration to a single evening?

Create a VerifySMS API key →

Sandbox mode included · Auto-refund guarantee · 200+ countries · SMS-Activate compat layer on /compat/handler_api.php