← Blog
Developer playbook · 16 min de lecture · Published avril 2026 · Author Serhat Dogan

Centre de migration SMS-Activate 2026 : Liste de contrôle pour les développeurs, mappage API et comparaison des remboursements

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.

Pourquoi ce playbook existe

La plupart des articles du type "SMS-Activate est mort, voici une liste d'alternatives" omettent la partie qui brûle réellement les heures de développement : le code. S'inscrire auprès d'un nouveau fournisseur prend cinq minutes. Réécrire une intégration qui a fonctionné silencieusement en production pendant des années, avec des cas de coin non testés et un suivi de coût attaché, prend plus de temps que vous ne le pensez.

Après avoir déployé notre couche de compatibilité en janvier 2026, nous avons commencé à recevoir les mêmes trois questions de chaque équipe qui l'a essayée :

  1. Quelles extrémités mappent proprement et lesquelles nécessitent des modifications manuelles ?
  2. Comment puis-je garder mon suivi de coût et mon flux de remboursement fonctionnels sans réécrire ?
  3. Qu'est-ce qui casse silencieusement et apparaît une semaine plus tard comme une surprise de facturation ?

Ce playbook répond à ces trois questions dans l'ordre et vous donne du code que vous pouvez copier-coller et auditer avant de l'exécuter.

Récapitulatif des 48 heures : ce qui s'est réellement passé

SMS-Activate a cessé de fonctionner le 29 décembre 2025. Il n'y avait pas de bandeau de maintenance planifiée, pas d'outil de migration et pas de notification publique. Les utilisateurs essayant de se connecter ont rencontré une page unique indiquant que le service avait fermé définitivement. L'API a renvoyé des réinitialisations de connexion sur chaque point de terminaison en quelques heures.

Trois choses se sont passées rapidement :

Les retombées sont encore en cours. En avril 2026, il y a des cas de petits litiges actifs en Russie et au moins deux poursuites communautaires coordonnées essayant de récupérer des soldes gelées. Aucun de cela n'aide votre code, c'est pourquoi nous allons nous concentrer sur la partie que vous pouvez réellement corriger.

Partie 1 : Carte de dépréciation de l'API

SMS-Activate a expédié un seul point de terminaison public à https://sms-activate.org/stubs/handler_api.php. Chaque action était un paramètre de chaîne de requête sur cette URL. Le tableau ci-dessous mappe chaque action majeure à son équivalent VerifySMS. La couche de compatibilité à https://api.verifysms.app/compat/handler_api.php accepte exactement la même forme de chaîne de requête.

Action SMS-ActivateObjetCouche de compatibilité VerifySMSAPI VerifySMS native
getBalanceRetourne le solde en USD sous forme de texteFonctionne inchangé. Renvoie ACCESS_BALANCE:X.YYGET /v1/balance renvoie JSON
getNumbersStatusDisponibilité par paysFonctionne. Renvoie le format de carte héritéGET /v1/countries/availability
getNumberLouer un numéro pour un serviceFonctionne. Renvoie ACCESS_NUMBER:id:+phonePOST /v1/rentals
setStatusConfirmer ou annuler une locationFonctionne. Les codes de statut 1/3/6/8 se comportent de manière identiquePOST /v1/rentals/{id}/status
getStatusSondage pour l'arrivée de SMSFonctionne. Renvoie STATUS_WAIT_CODE, STATUS_OK:CODE, STATUS_WAIT_RETRYGET /v1/rentals/{id}
getPricesRécupérer le tableau de prixFonctionne. Renvoie la tarification VerifySMS dans la forme JSON héritéeGET /v1/prices
getCountriesCarte des codes de paysFonctionne. Renvoie à la fois les ID numériques hérités et les codes ISO-3166GET /v1/countries
getTopCountriesByServiceMeilleurs pays par serviceRenvoie des données VerifySMS en temps réel au lieu de classements SMS-Activate mis en cacheGET /v1/services/{id}/top-countries

Une poignée d'actions SMS-Activate moins utilisées ne mappent pas de manière un à un. getRentServicesAndCountries et l'API de location longue durée étaient spécifiques à SMS-Activate et n'ont pas de couche de compatibilité. Si votre intégration les utilisait, vous devriez passer à l'extrémité de location longue durée native VerifySMS à POST /v1/rentals/long, qui est documentée séparément.

Partie 2 : Marche à suivre pour la migration du code

Les extraits suivants sont exactement la forme que j'ai testée contre notre propre environnement de préproduction en janvier. Je les ai délibérément gardés ennuyeux pour que vous puissiez les lire contre votre propre code sans changement de contexte.

Python (requests)

Le seul changement requis est l'URL de base. Si vous avez déjà enveloppé l'API dans un petit module client, la différence est une seule ligne.

import os
import requests

# AVANT
# BASE_URL = "https://sms-activate.org/stubs/handler_api.php"
# APRÈS
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"réponse inattendue: {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)
    # Marquer comme inutilisé pour obtenir le remboursement
    requests.get(BASE_URL, params={
        "api_key": API_KEY,
        "action": "setStatus",
        "status": 8,
        "id": rental_id,
    }, timeout=15)
    raise TimeoutError(f"pas de code après {deadline_seconds}s")

Node.js (axios)

import axios from "axios";

// AVANT
// const BASE_URL = "https://sms-activate.org/stubs/handler_api.php";
// APRÈS
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(`réponse inattendue: ${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(`pas de code après ${deadlineMs}ms`);
}

PHP (curl)

<?php
// AVANT
// const BASE_URL = "https://sms-activate.org/stubs/handler_api.php";
// APRÈS
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("inattendu: $resp");
    }
    return ["id" => $id, "phone" => $phone];
}

Go (net/http)

package sms

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

// AVANT
// const baseURL = "https://sms-activate.org/stubs/handler_api.php"
// APRÈS
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("inattendu: " + body)
    }
    return parts[1], parts[2], nil
}

L'exemple Go est délibérément écrit sans client tiers pour que vous puissiez le déposer dans un service minimal sans ajouter de dépendances. Le même modèle est valable dans chaque autre langage : échangez l'URL, gardez le reste et laissez votre gestion d'erreurs existante reprendre le relais.

Partie 3 : Pièges qui vous brûleront

Ce sont les endroits où la couche de compatibilité est fidèle aux bizarreries de SMS-Activate mais les bizarreries elles-mêmes vous surprendront si vous n'avez pas touché à ce code depuis un moment.

Les ID de pays ne sont pas des codes ISO

SMS-Activate a numéroté les pays dans leur propre ordre : la Russie était 0, les États-Unis étaient 187, l'Indonésie était 6, et ainsi de suite. Si votre intégration a ces nombres magiques codés en dur, ils fonctionnent toujours sur la couche de compatibilité. Si vous écrivez du nouveau code, préférez la forme alpha-2 ISO-3166 (RU, US, ID) que la couche de compatibilité accepte également. N'associez pas les deux styles dans le même site d'appel, car le débogage futur sera douloureux.

Code de statut 3 contre 6

Le code d'action setStatus 3 signifiait "demander un autre SMS" dans le monde SMS-Activate, et le code 6 signifiait "accepter le code comme valide". Ces deux codes sont faciles à échanger dans une précipitation et ils ont des résultats de facturation opposés : 3 vous maintient facturé, 6 confirme la vérification réussie. La couche de compatibilité se comporte de la même manière. Recherchez dans votre code setStatus et assurez-vous que la branche qui prend le code 6 ne fonctionne qu'après avoir été certain que la vérification a réussi.

Delais et disjoncteurs

SMS-Activate sous charge a parfois renvoyé un 200 avec un corps vide au lieu d'une erreur HTTP. Les clients défensifs enveloppent l'appel dans un délai et traitent le corps vide comme un signal de réessai. VerifySMS ne renvoie jamais un corps vide sur la couche de compatibilité. Si votre client traite toujours vide comme un réessai, il brûlera du budget sur un réseau flaky car le réessai heurtera un ID de location différent. Le modèle plus sûr consiste à vérifier les préfixes de réponse connus (ACCESS_, STATUS_, BAD_) et à traiter tout le reste comme une défaillance dure, et non transitoire.

Les limites de taux passent de par clé à par adresse IP

Les limites de taux SMS-Activate étaient indexées sur la clé API. Les limites de taux VerifySMS sont indexées sur la combinaison de la clé API et de l'adresse IP de la source, car nous voyons beaucoup d'abus de scripts de scrap qui partagent une clé entre un botnet. Pour le trafic de production normal provenant d'un seul serveur ou d'un pool équilibré, cela est invisible. Si vous exécutez des travaux de CI distribués qui partagent tous une clé de préproduction, vous pouvez voir un 429 la première fois que la flotte se réchauffe ensemble. La solution consiste à laisser le canari fonctionner à partir d'un nœud pendant une journée avant de s'étendre.

La synchronisation des remboursements semble instantanée parce qu'elle l'est

Ceci n'est pas un piège autant qu'une agréable surprise. Là où les remboursements SMS-Activate prenaient quelques heures pour apparaître dans votre solde, les remboursements VerifySMS apparaissent dans les 60 secondes. Si votre traqueur de coût lit la solde sur un calendrier, il enregistrera le remboursement comme un crédit que l'ancien système aurait manqué. Les tableaux de réconciliation signalent parfois cela comme une anomalie le premier jour.

Partie 4 : Vérification de la réalité de la comparaison des prix

Avant la fermeture, SMS-Activate était le plancher du marché. Les numéros russes coûtaient entre 0,03 $ et 0,05 $ par vérification, et les acheteurs à gros volume payaient encore moins. Ce plancher a disparu. Voici où se situent les fournisseurs restants en avril 2026 pour les services les plus courants, extraits de la page de tarification publique de chaque fournisseur le :

Service5simTextVerifiedSMSPVASMS-MANVerifySMS
WhatsApp / Russie0,014 $0,05 $0,035 $0,10 $
WhatsApp / États-Unis0,27 $0,25 $0,28 $0,22 $0,18 $
Telegram / Russie0,016 $0,05 $0,04 $0,10 $
Telegram / États-Unis0,35 $0,40 $0,38 $0,30 $0,20 $
Google / Indonésie0,07 $0,08 $0,06 $0,10 $

Le modèle est simple : 5sim et SMS-MAN gagnent sur les prix russes très bas, TextVerified est le niveau premium américain, et VerifySMS se situe au milieu avec un prix de base de 0,10 $ pour tout sauf les numéros américains non-VoIP les plus chers. Si votre budget était adapté aux prix de base de SMS-Activate, prévoyez de payer deux à cinq fois plus par vérification quelle que soit la solution de remplacement que vous choisissez.

Deux remarques sur ce tableau. Premièrement, chaque fournisseur (y compris VerifySMS) augmente et baisse les prix de pays individuels en réponse aux coûts des opérateurs, donc confirmez le prix actuel dans votre propre tableau de bord avant de vous engager sur un budget. Deuxièmement, le prix effectif par vérification réussie dépend du taux de remboursement. Un fournisseur avec un prix de 0,08 $ et un taux de réussite de 70 % vous coûte plus cher par succès qu'un fournisseur avec un prix de 0,10 $ et des remboursements automatiques et un taux de réussite de 90 %.

Partie 5 : La liste de vérification de migration en 10 étapes

C'est la séquence réelle que nous avons suivie pour nos propres utilisateurs en janvier. Elle suppose un seul développeur avec accès au dépôt, un service de production et un environnement de test. Augmentez les pourcentages de canari si vous exécutez plusieurs services ou un monodépôt.

  1. Inventairez tous les sites d'appel. Exécutez git grep -n 'sms-activate\.org\|handler_api\.php\|getNumber\|setStatus' et listez tous les fichiers qui frappent l'ancienne API. Si vous en trouvez plus d'une douzaine, choisissez un module de wrapper et centralisez les appels avant de migrer.
  2. Obtenez une clé API VerifySMS. Inscrivez-vous, ajoutez un petit montant de solde et générez une clé étendue pour le test. Gardez la clé de production hors du dépôt.
  3. Modifiez l'URL de base. Remplacez l'hôte SMS-Activate par api.verifysms.app/compat/handler_api.php. Ne modifiez pas la chaîne de requête. Commitez cela seul pour que la différence soit propre.
  4. Exécutez vos tests existants. Si les tests frappent l'API réelle, pointez-les vers le test et surveillez les incohérences de forme. Si ils se moquent de l'API, exécutez-les contre le point de terminaison de test en direct également pour attraper les dérives de contrat.
  5. Réconfirmez les IDs de pays. Parcourez votre code pour les constantes de pays. Si vous utilisez les IDs numériques hérités, ils fonctionnent toujours. Si vous avez la chance, remplacez-les par des codes ISO-3166 car le prochain développeur qui touchera ce fichier vous remerciera.
  6. Câblez les demandes de remboursement. Confirmez que votre chemin de délai appelle setStatus avec status=8. Sans cela, vous obtiendrez toujours des remboursements (nous remboursons automatiquement les baux expirés) mais votre suivi des coûts sera à la traîne de la réalité.
  7. Mettez à jour votre suivi des coûts. Lisez le coût à partir de l'en-tête de réponse X-VerifySMS-Cost au lieu de le parser à partir du tableau de tarification. Ce changement unique rend votre tableau de bord financier précis au centime près.
  8. Surveillance. Ajoutez des alertes de taux de réussite, de latence p95 et de ratio de remboursement contre votre ligne de base existante. Choisissez des seuils que vous pouvez défendre, pas ceux que vous pensez être "corrects".
  9. Canari 5 pour cent pendant 24 heures. Acheminez une petite tranche de trafic de production à travers le point de terminaison. Surveillez le tableau de bord, pas seulement les alertes.
  10. Coupez le reste. Une fois que la fenêtre de canari est propre, déplacez les 95 pour cent restants et laissez l'ancien code client commenté (pas supprimé) pendant un cycle de publication pour avoir une bascule rapide.

Supprimez l'ancien code dans la prochaine publication après cela. Ne laissez pas de sites d'appel morts pendant plus d'une semaine car la prochaine personne qui touche le module les recopiera par accident dans une nouvelle intégration.

Foire aux questions

La couche de compatibilité SMS-Activate est-elle une véritable API ou juste un stub ?

C'est un point de terminaison réel à api.verifysms.app/compat/handler_api.php qui accepte chaque action majeure de la documentation publique SMS-Activate : getBalance, getNumber, getStatus, setStatus, getPrices et getCountries. Les demandes sont proxénétisées vers notre API native sous le capot, vous obtenez donc les prix, la couverture et le comportement de remboursement de VerifySMS sans changement de code de votre côté.

Ma clé API ancienne fonctionnera-t-elle ?

Non. Les clés API SMS-Activate ont cessé de s'authentifier le jour où le service a fermé. Vous avez besoin d'une nouvelle clé de VerifySMS. Inscrivez-vous, ajoutez un petit montant de solde et générez une clé à partir du tableau de bord. Le format de clé est identique en longueur pour que vous puissiez la coller dans la même variable d'environnement.

Comment fonctionnent les remboursements par rapport à SMS-Activate ?

SMS-Activate vous obligeait à appeler setStatus avec le code de statut 8 dans les 20 minutes pour marquer un numéro comme inutilisé, et les remboursements étaient traités manuellement dans quelques heures. VerifySMS accepte le même appel setStatus et rembourse le montant total sur votre solde dans les 60 secondes. Si vous oubliez d'appeler setStatus entièrement, notre système rembourse automatiquement tout numéro qui n'a jamais reçu de SMS après l'expiration de la fenêtre de bail.

Quels pays sont pris en charge ?

VerifySMS couvre plus de 200 pays. Tous les pays que SMS-Activate offrait sont disponibles sur VerifySMS, y compris la Russie, l'Indonésie, le Vietnam, le Nigeria et les États-Unis. Vous pouvez conserver votre mappage d'ID de pays existant ou migrer vers des codes ISO-3166 alpha-2 quand vous le souhaitez.

Le prix est-il le même ?

Non. Les prix de base de SMS-Activate de 0,03 $ à 0,05 $ par vérification pour les numéros russes ont disparu du marché ouvert. La tarification actuelle du marché varie de 0,10 $ pour les services courants à 0,25 $ pour les numéros américains non-VoIP sur des plateformes plus strictes. VerifySMS facture 0,10 $ comme ligne de base et publie les prix par pays sur le tableau de bord.

Dois-je modifier ma logique de sondage ?

Non. L'appel getStatus retourne STATUS_WAIT_CODE et STATUS_OK dans le même format que SMS-Activate utilisé. Les intervalles de sondage de 3 à 5 secondes fonctionnent toujours. La seule nouvelle fonctionnalité est que VerifySMS expose également une URL de webhook dans le tableau de bord, vous pouvez donc arrêter le sondage entièrement si vous préférez un flux événementiel.

Que se passe-t-il si la couche de compatibilité est un jour dépréciée ?

La couche de compatibilité est considérée comme une interface publique permanente. Si nous changeons jamais son comportement, nous publierons une fenêtre de dépréciation minimale de six mois avec une note de migration complète. L'API JSON native VerifySMS est également documentée, vous pouvez donc migrer hors de la couche de compatibilité à votre propre rythme quand cela a du sens.

Comment puis-je tester sans dépenser d'argent ?

Le tableau de bord VerifySMS expose un mode sandbox qui retourne des numéros de téléphone simulés et des codes SMS préparés sans débiter votre solde. Retournez le drapeau sandbox dans le tableau de bord ou envoyez l'en-tête X-Sandbox-Mode avec n'importe quelle demande pour exercer vos chemins de code avant de devenir opérationnel.

Puis-je migrer depuis d'autres services également ?

Oui. Cette feuille de route est écrite autour de l'API SMS-Activate car c'est là que la plupart des codes errants vivent, mais la même liste de vérification s'applique aux migrations de 5sim, SMS-MAN ou tout autre service compatible handler_api. La couche de compatibilité reconnaît les paramètres handler_api.php quelle que soit la service que vous avez précédemment appelé.

Combien de temps prend une migration réelle ?

Pour une intégration de service unique avec quelques dizaines de sites d'appel, prévoyez deux à quatre heures de travail concentré, plus une fenêtre de canari de 24 heures avant de couper tout le trafic. Les migrations de services multiples plus importantes avec gestion d'erreurs personnalisée, analyse et réessais peuvent prendre plus de temps mais finissent généralement dans une journée ouvrable.

Perds-je mes données historiques ?

L'historique de vérification SMS-Activate est allé hors ligne lorsque le service a fermé et n'est pas récupérable. VerifySMS maintient un journal d'audit complet de chaque tentative de vérification sur votre compte pendant 12 mois, accessible depuis le tableau de bord et via l'extension /compat/handler_api.php?action=getHistory.

Cela affecte-t-il ma posture GDPR ou de conformité ?

VerifySMS est enregistré au Royaume-Uni et suit le RGPD britannique. Nous publions notre politique de rétention des données, nos sous-traitants et notre DPA sur la page de confidentialité. Si votre configuration précédente nécessitait un DPA avec SMS-Activate, contactez-nous et nous contre-signerons le même accord dans un jour ouvrable.

Étapes suivantes

Si vous avez lu jusque-là, vous avez déjà les pièces nécessaires. Commencez par l'étape d'inventaire, obtenez le swap d'URL de base devant un collègue pour examen et exécutez le canari pendant la nuit. La feuille de route est petite exprès ; la partie difficile est la discipline d'arrêter après la fenêtre de canari au lieu de tout couper en un seul commit.

Lectures connexes sur le reste du site :

Prêt à réduire la migration à une seule soirée ?

Créez une clé API VerifySMS →

Mode sandbox inclus · Garantie de remboursement automatique · 200+ pays · Couche de compatibilité SMS-Activate sur /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