← Blog
Developer playbook · 16 min de lectura · Published abril 2026 · Author Serhat Dogan

Centro de Migración de SMS-Activate 2026: Lista de Verificación para Desarrolladores, Mapeo de API y Comparación de Reembolsos

Centro de Migración de SMS-Activate 2026: Lista de Verificación para Desarrolladores, Mapeo de API y Comparación de Reembolsos

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.

Por qué existe este manual

La mayoría de las publicaciones de "SMS-Activate ha muerto, aquí hay una lista de alternativas" omiten la parte que realmente consume horas de desarrollo: el código. Registrarse en un nuevo proveedor lleva cinco minutos. Reescribir una integración que ha estado funcionando silenciosamente en producción durante años, con casos extremos no probados y un rastreador de costos adjunto, lleva más tiempo de lo que piensas.

Después de lanzar nuestra capa de compatibilidad en enero de 2026, comenzamos a recibir las mismas tres preguntas de cada equipo que la probó:

  1. ¿Qué puntos finales se mapean limpiamente y cuáles necesitan cambios manuales?
  2. ¿Cómo mantengo mi seguimiento de costos y mi flujo de reembolsos funcionando sin una reescritura?
  3. ¿Qué se rompe silenciosamente y aparece una semana después como una sorpresa en la facturación?

Este manual responde a esas tres preguntas en orden y te proporciona código para copiar y pegar que puedes auditar antes de ejecutarlo.

El resumen de 48 horas: lo que realmente sucedió

SMS-Activate se desconectó el 29 de diciembre de 2025. No hubo un banner de mantenimiento programado, ni una herramienta de migración, ni un aviso público. Los usuarios que intentaron iniciar sesión se encontraron con una sola página que decía que el servicio había cerrado permanentemente. La API devolvió reinicios de conexión en cada punto final en unas pocas horas.

Tres cosas sucedieron rápidamente:

Las consecuencias aún se están desarrollando. A partir de abril de 2026, hay casos activos de reclamaciones menores en Rusia y al menos dos demandas comunitarias coordinadas que intentan recuperar los saldos congelados. Nada de eso ayuda a tu código, por eso nos centraremos en la parte que realmente puedes arreglar.

Parte 1: Mapa de desuso de API

SMS-Activate proporcionó un único punto final público en https://sms-activate.org/stubs/handler_api.php. Cada acción era un parámetro de cadena de consulta en esa URL. La siguiente tabla mapea cada acción importante a su equivalente en VerifySMS. La capa de compatibilidad en https://api.verifysms.app/compat/handler_api.php acepta la misma forma exacta de cadena de consulta.

Acción de SMS-ActivatePropósitoCapa de compatibilidad de VerifySMSAPI nativa de VerifySMS
getBalanceDevuelve el saldo en USD como textoFunciona sin cambios. Devuelve ACCESS_BALANCE:X.YYGET /v1/balance devuelve JSON
getNumbersStatusDisponibilidad por paísFunciona. Devuelve el formato de mapa heredadoGET /v1/countries/availability
getNumberAlquilar un número para un servicioFunciona. Devuelve ACCESS_NUMBER:id:+phonePOST /v1/rentals
setStatusConfirmar o cancelar un alquilerFunciona. Los códigos de estado 1/3/6/8 se comportan de manera idénticaPOST /v1/rentals/{id}/status
getStatusConsultar la llegada de SMSFunciona. Devuelve STATUS_WAIT_CODE, STATUS_OK:CODE, STATUS_WAIT_RETRYGET /v1/rentals/{id}
getPricesObtener tabla de preciosFunciona. Devuelve los precios de VerifySMS en el formato JSON heredadoGET /v1/prices
getCountriesMapa de códigos de paísFunciona. Devuelve tanto los ID numéricos heredados como los códigos ISO-3166GET /v1/countries
getTopCountriesByServicePrincipales países por servicioDevuelve datos de VerifySMS en tiempo real en lugar de rangos cacheados de SMS-ActivateGET /v1/services/{id}/top-countries

Un puñado de acciones menos utilizadas de SMS-Activate no se mapean uno a uno. getRentServicesAndCountries y la API de alquileres de larga duración eran específicas de SMS-Activate y no tienen capa de compatibilidad. Si tu integración utilizaba esas, deberías migrar al punto final de alquileres de larga duración nativo de VerifySMS en POST /v1/rentals/long, que se documenta por separado.

Parte 2: Tutoriales de migración de código

Los siguientes fragmentos son la forma exacta que probé contra nuestro propio entorno de staging en enero. Los he mantenido deliberadamente sencillos para que puedas leerlos junto con tu propio código sin cambiar de contexto.

Python (requests)

El único cambio requerido es la URL base. Si ya has envuelto la API en un pequeño módulo cliente, la diferencia es una sola línea.

import os
import requests

# ANTES
# BASE_URL = "https://sms-activate.org/stubs/handler_api.php"
# DESPUÉ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"respuesta inesperada: {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)
    # Marcar como no utilizado para obtener el reembolso
    requests.get(BASE_URL, params={
        "api_key": API_KEY,
        "action": "setStatus",
        "status": 8,
        "id": rental_id,
    }, timeout=15)
    raise TimeoutError(f"no hay código después de {deadline_seconds}s")

Node.js (axios)

import axios from "axios";

// ANTES
// const BASE_URL = "https://sms-activate.org/stubs/handler_api.php";
// DESPUÉ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(`respuesta inesperada: ${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(`no hay código después de ${deadlineMs}ms`);
}

PHP (curl)

<?php
// ANTES
// const BASE_URL = "https://sms-activate.org/stubs/handler_api.php";
// DESPUÉ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("inesperado: $resp");
    }
    return ["id" => $id, "phone" => $phone];
}

Go (net/http)

package sms

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

// ANTES
// const baseURL = "https://sms-activate.org/stubs/handler_api.php"
// DESPUÉ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("inesperado: " + body)
    }
    return parts[1], parts[2], nil
}

El ejemplo de Go está escrito deliberadamente sin ningún cliente de terceros para que puedas integrarlo en un servicio mínimo sin añadir dependencias. El mismo patrón se mantiene en todos los demás lenguajes: cambia la URL, conserva el resto y deja que tu manejo de errores existente se traslade.

Parte 3: Trampas que te harán tropezar

Estos son los lugares donde la capa de compatibilidad es fiel a las peculiaridades de SMS-Activate, pero las peculiaridades en sí mismas te sorprenderán si no has tocado este código en mucho tiempo.

Los ID de país no son códigos ISO

SMS-Activate numeró los países en su propio orden: Rusia era 0, EE. UU. era 187, Indonesia era 6, y así sucesivamente. Si tu integración tiene estos números mágicos codificados, todavía funcionan en la capa de compatibilidad. Si estás escribiendo código nuevo, prefiere el formato alfa-2 ISO-3166 (RU, US, ID) que la capa de compatibilidad también acepta. No mezcles ambos estilos en el mismo sitio de llamada, porque la depuración futura será dolorosa.

Código de estado 3 frente a 6

El código de acción 3 de setStatus significaba "solicitar otro SMS" en el mundo de SMS-Activate, y el código 6 significaba "aceptar el código como válido". Estos dos códigos son fáciles de intercambiar con prisa y tienen resultados de facturación opuestos: el 3 te mantiene facturado, el 6 confirma la verificación exitosa. La capa de compatibilidad se comporta de la misma manera. Busca en tu código setStatus y asegúrate de que la rama que toma el código 6 solo se ejecute después de que estés seguro de que la verificación fue exitosa.

Tiempos de espera y disyuntores

SMS-Activate bajo carga a veces devolvía un 200 con un cuerpo vacío en lugar de un error HTTP. Los clientes defensivos envuelven la llamada en un tiempo de espera y tratan el cuerpo vacío como una señal de reintento. VerifySMS nunca devuelve un cuerpo vacío en la capa de compatibilidad. Si tu cliente todavía trata el cuerpo vacío como un reintento, quemará presupuesto en una red inestable porque el reintento alcanzará un ID de alquiler diferente. El patrón más seguro es verificar los prefijos de respuesta conocidos (ACCESS_, STATUS_, BAD_) y tratar cualquier otra cosa como un fallo duro, no como uno transitorio.

Los límites de tasa se mueven de por clave a por IP

Los límites de tasa de SMS-Activate estaban vinculados a la clave de API. Los límites de tasa de VerifySMS están vinculados a la combinación de la clave de API y la dirección IP de origen, porque vemos mucho abuso de scripts de raspado que comparten una clave en una botnet. Para el tráfico de producción normal desde un solo servidor o un grupo balanceado de carga, esto es invisible. Si ejecutas trabajos de CI distribuidos que comparten una clave de staging, es posible que veas un 429 la primera vez que toda la flota se caliente junta. La solución es dejar que el canario se ejecute desde un nodo durante un día antes de expandirse.

El momento de los reembolsos se siente instantáneo porque realmente lo es

Esto no es una trampa tanto como una sorpresa agradable. Mientras que los reembolsos de SMS-Activate tardaban unas horas en aparecer en tu saldo, los reembolsos de VerifySMS aparecen en 60 segundos. Si tu rastreador de costos lee el saldo en un horario, registrará el reembolso como un crédito que el sistema antiguo habría pasado por alto. Los paneles de reconciliación a veces marcan esto como una anomalía el primer día.

Parte 4: Realidad de la comparación de precios

Antes del cierre, SMS-Activate era el suelo del mercado. Los números rusos costaban entre $0.03 y $0.05 por verificación, y los compradores de gran volumen pagaban aún menos. Ese suelo ha desaparecido. Aquí es donde se encuentran los proveedores restantes en abril de 2026 para los servicios más comunes, extraído de la página de precios pública de cada proveedor en :

Servicio5simTextVerifiedSMSPVASMS-MANVerifySMS
WhatsApp / Rusia$0.014$0.05$0.035$0.10
WhatsApp / USA$0.27$0.25$0.28$0.22$0.18
Telegram / Rusia$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

El patrón es simple: 5sim y SMS-MAN ganan en precios rusos de precio de ganga, TextVerified es el nivel premium de EE. UU., y VerifySMS se sitúa en el medio con una base de $0.10 para todo excepto los números no VoIP más caros de EE. UU. Si tu presupuesto estaba ajustado a los precios de suelo de SMS-Activate, espera pagar de dos a cinco veces más por verificación, independientemente del reemplazo que elijas.

Dos notas sobre esta tabla. Primero, cada proveedor (incluido VerifySMS) aumenta y disminuye los precios individuales de los países en respuesta a los costos de los operadores, así que confirma el precio actual en tu propio panel antes de comprometer un presupuesto. Segundo, el precio efectivo por verificación exitosa depende de la proporción de reembolsos. Un proveedor con un precio de etiqueta de $0.08 y una tasa de éxito del 70% te cuesta más por éxito que un proveedor de $0.10 con reembolsos automáticos y una tasa de éxito del 90%.

Parte 5: La lista de verificación de migración de 10 pasos

Esta es la secuencia real que seguimos con nuestros propios usuarios en enero. Asume un solo desarrollador con acceso al repositorio, un servicio de producción y un entorno de staging. Escala los porcentajes del canario si estás ejecutando varios servicios o un monorepo.

  1. Inventaría cada sitio de llamada. Ejecuta git grep -n 'sms-activate\.org\|handler_api\.php\|getNumber\|setStatus' y lista cada archivo que accede a la antigua API. Si encuentras más de una docena, elige un módulo envolvente y centraliza las llamadas primero antes de migrar.
  2. Obtén una clave de API de VerifySMS. Regístrate, añade una pequeña cantidad de saldo y genera una clave con ámbito para staging. Mantén la clave de producción fuera del repositorio.
  3. Cambia la URL base. Reemplaza el host de SMS-Activate con api.verifysms.app/compat/handler_api.php. No cambies la cadena de consulta. Confirma esto solo para que la diferencia sea limpia.
  4. Ejecuta tus pruebas existentes. Si las pruebas acceden a la API real, apúntalas a staging y observa las discrepancias de formato. Si simulan la API, ejecútalas también contra el punto final de staging en vivo para detectar desviaciones de contrato.
  5. Reconfirma los ID de país. Revisa tu código en busca de constantes de país. Si estás usando los ID numéricos heredados, todavía funcionan. Si tienes la oportunidad, reemplázalos con códigos ISO-3166 porque el próximo desarrollador que toque este archivo te lo agradecerá.
  6. Conecta las reclamaciones de reembolso. Confirma que tu ruta de tiempo de espera llama a setStatus con status=8. Sin esto, todavía obtendrás reembolsos (reembolsamos automáticamente los alquileres caducados), pero tu rastreador de costos se retrasará respecto a la realidad.
  7. Actualiza tu rastreador de costos. Lee el costo del encabezado de respuesta X-VerifySMS-Cost en lugar de analizarlo de la tabla de precios. Este único cambio hace que tu panel de finanzas sea preciso hasta el céntimo.
  8. Monitoreo. Añade alertas de tasa de éxito, latencia p95 y ratio de reembolso contra tu línea de base existente. Elige umbrales que puedas defender, no los que creas que estarán "bien".
  9. Canary al 5 por ciento durante 24 horas. Dirige una pequeña parte del tráfico de producción a través del nuevo punto final. Observa el panel, no solo las alertas.
  10. Cambia el resto. Una vez que la ventana del canario esté limpia, mueve el 95 por ciento restante y deja el código del cliente antiguo comentado (no eliminado) durante un ciclo de lanzamiento para tener un rollback rápido.

Elimina el código antiguo en el siguiente lanzamiento después de ese. No dejes sitios de llamada muertos durante más de una semana porque la próxima persona que toque el módulo los pegará accidentalmente en una nueva integración.

Preguntas frecuentes

¿Es la capa de compatibilidad de SMS-Activate una API real o solo un stub?

Es un punto final real en api.verifysms.app/compat/handler_api.php que acepta cada acción importante de la documentación pública de SMS-Activate: getBalance, getNumber, getStatus, setStatus, getPrices y getCountries. Las solicitudes se reenvían a nuestra API nativa internamente, por lo que obtienes los precios, la cobertura y el comportamiento de reembolso de VerifySMS sin cambios en tu código.

¿Funcionará mi antigua clave de API?

No. Las claves de API de SMS-Activate dejaron de autenticarse el día en que el servicio se cerró. Necesitas una nueva clave de VerifySMS. Regístrate, añade una pequeña cantidad de saldo y genera una clave desde el panel. El formato de la clave es idéntico en longitud, por lo que puedes pegarla en la misma variable de entorno.

¿Cómo funcionan los reembolsos en comparación con SMS-Activate?

SMS-Activate requería que llamaras a setStatus con el código de estado 8 dentro de los 20 minutos para marcar un número como no utilizado, y los reembolsos se procesaban manualmente en unas pocas horas. VerifySMS acepta la misma llamada a setStatus y reembolsa el monto total a tu saldo en 60 segundos. Si olvidas llamar a setStatus por completo, nuestro sistema aún reembolsa automáticamente cualquier número que nunca recibió un SMS después de que expire la ventana de alquiler.

¿Qué países son compatibles?

VerifySMS cubre más de 200 países. Cada país que ofrecía SMS-Activate está disponible en VerifySMS, incluyendo Rusia, Indonesia, Vietnam, Nigeria y EE. UU. Puedes mantener tu mapeo de ID de país existente o migrar a códigos alfa-2 ISO-3166 cuando quieras.

¿Son los precios los mismos?

No. Los precios de SMS-Activate en la parte inferior del mercado de $0.03 a $0.05 por verificación para números rusos han desaparecido del mercado abierto. Los precios actuales del mercado oscilan entre $0.10 para servicios comunes hasta $0.25 para números no VoIP de EE. UU. en plataformas más estrictas. VerifySMS cobra $0.10 como base y publica precios por país en el panel.

¿Necesito cambiar mi lógica de sondeo?

No. La llamada a getStatus devuelve STATUS_WAIT_CODE y STATUS_OK en el mismo formato que utilizaba SMS-Activate. Los intervalos de sondeo de 3 a 5 segundos siguen funcionando. El único comportamiento nuevo es que VerifySMS también expone una URL de webhook en el panel, por lo que puedes dejar de sondear por completo si prefieres un flujo basado en eventos.

¿Qué sucede si la capa de compatibilidad se descontinúa alguna vez?

La capa de compatibilidad se considera una interfaz pública permanente. Si alguna vez cambiamos su comportamiento, publicaremos una ventana de desuso mínima de seis meses con una nota de migración completa. La API JSON nativa de VerifySMS también está documentada, por lo que puedes migrar de la capa de compatibilidad a tu propio ritmo cuando sea conveniente.

¿Cómo pruebo sin gastar dinero?

El panel de VerifySMS expone un modo sandbox que devuelve números de teléfono simulados y códigos SMS predefinidos sin deducir tu saldo. Activa el indicador sandbox en el panel o envía el encabezado X-Sandbox-Mode con cualquier solicitud para ejercitar tus rutas de código antes de salir en vivo.

¿Puedo migrar desde otros servicios también?

Sí. Este manual está escrito en torno a la API de SMS-Activate porque es donde reside la mayor parte del código varado, pero la misma lista de verificación se aplica a las migraciones desde 5sim, SMS-MAN o cualquier otro servicio compatible con handler_api.php. La capa de compatibilidad reconoce los parámetros de handler_api.php independientemente del servicio que estuvieras llamando anteriormente.

¿Cuánto tiempo lleva una migración real?

Para una integración de servicio único con unas pocas docenas de sitios de llamada, planifica de dos a cuatro horas de trabajo enfocado, más una ventana de canario de 24 horas antes de cortar el tráfico completo. Las migraciones multiserVICIO más grandes con manejo de errores personalizado, análisis y reintentos pueden llevar más tiempo, pero generalmente terminan dentro de un solo día hábil.

¿Pierdo mis datos históricos?

El historial de verificación de SMS-Activate se desconectó cuando el servicio se cerró y no es recuperable. VerifySMS mantiene un registro de auditoría completo de cada intento de verificación en tu cuenta durante 12 meses, accesible desde el panel y a través de la extensión /compat/handler_api.php?action=getHistory.

¿Afecta esto a mi postura de GDPR o cumplimiento?

VerifySMS está registrado en el Reino Unido y cumple con el RGPD del Reino Unido. Publicamos nuestra política de retención de datos, subprocesadores y DPA en la página de privacidad. Si tu configuración anterior requería un DPA con SMS-Activate, contáctanos y firmaremos el mismo acuerdo en un día hábil.

Próximos pasos

Si has leído hasta aquí, ya tienes las piezas que necesitas. Comienza con el paso de inventario, haz que un compañero revise el cambio de URL base y ejecuta el canario durante la noche. El manual es pequeño a propósito; la parte difícil es la disciplina de detenerse después de la ventana del canario en lugar de cortar todo en un solo commit.

Lectura relacionada en el resto del sitio:

¿Listo para realizar la migración en una sola tarde?

Crea una clave de API de VerifySMS →

Modo sandbox incluido · Garantía de reembolso automático · Más de 200 países · Capa de compatibilidad de SMS-Activate en /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