Guia de Migração do SMS-Activate 2026: Checklist de Desenvolvedor, Mapeamento de API e Comparação de Reembolso
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 que este playbook existe
A maioria dos posts "SMS-Activate morreu, aqui está uma lista de alternativas" deixa de lado a parte que realmente consome horas de desenvolvedor: o código. Se inscrever em um novo provedor leva cinco minutos. Reescrever uma integração que tem funcionado silenciosamente em produção por anos, com casos de canto não testados e um rastreador de custo anexado, leva mais tempo do que você pensa.
Depois de enviarmos nossa camada de compatibilidade em janeiro de 2026, começamos a receber as mesmas três perguntas de todas as equipes que tentaram:
- Quais endpoints mapeiam limpa e quais precisam de alterações manuais?
- Como faço para manter meu rastreamento de custo e fluxo de reembolso funcionando sem reescrever?
- O que quebra silenciosamente e aparece uma semana depois como uma surpresa de cobrança?
Este playbook responde a essas três perguntas em ordem e fornece código de copiar e colar que você pode auditar antes de executar.
O resumo de 48 horas: o que realmente aconteceu
SMS-Activate ficou escuro em 29 de dezembro de 2025. Não havia banner de manutenção programada, nenhuma ferramenta de migração e nenhum aviso público. Usuários tentando entrar encontraram uma página única dizendo que o serviço havia fechado permanentemente. A API retornou resets de conexão em todos os endpoints em poucas horas.
Três coisas aconteceram rapidamente:
- Os saldos do painel se tornaram inacessíveis. Relatórios no subreddit
r/smse nos canais oficiais do Telegram descreveram saldos de $20 a vários milhares de dólares congelados sem caminho de recuperação. - As integrações em execução quebraram. Qualquer serviço que polasse
handler_api.phpcomeçou a receber erros de conexão HTTP, o que na maioria dos rastreadores de bugs significa "disjuntor disparado, alertar a equipe". - A janela de migração fechou em dias, não semanas. Em 72 horas, todos os provedores restantes tinham uma fila. 5sim, SMSPVA e SMS-MAN reconheceram a tensão de capacidade. O VerifySMS se manteve porque éramos o menor do grupo e tínhamos espaço de cabeça sobressalente, mas estava genuinamente perto.
As consequências ainda estão acontecendo. Em abril de 2026, há casos ativos de pequenas causas na Rússia e pelo menos duas ações judiciais coordenadas pela comunidade tentando recuperar saldos congelados. Nada disso ajuda com o seu código, que é por isso que vamos nos concentrar na parte que você pode realmente consertar.
Parte 1: Mapa de descontinuação de API
SMS-Activate enviou um único endpoint público em https://sms-activate.org/stubs/handler_api.php. Cada ação era um parâmetro de string de consulta nesse URL. A tabela abaixo mapeia cada ação importante para o equivalente do VerifySMS. A camada de compatibilidade em https://api.verifysms.app/compat/handler_api.php aceita exatamente a mesma forma de string de consulta.
| Ação do SMS-Activate | Propósito | Camada de compatibilidade do VerifySMS | API nativa do VerifySMS |
|---|---|---|---|
getBalance | Retornar saldo em USD como texto | Funciona inalterado. Retorna ACCESS_BALANCE:X.YY | GET /v1/balance retorna JSON |
getNumbersStatus | Disponibilidade por país | Funciona. Retorna o formato de mapa legado | GET /v1/countries/availability |
getNumber | Alugar um número para um serviço | Funciona. Retorna ACCESS_NUMBER:id:+phone | POST /v1/rentals |
setStatus | Confirmar ou cancelar um aluguel | Funciona. Códigos de status 1/3/6/8 se comportam de forma idêntica | POST /v1/rentals/{id}/status |
getStatus | Poll para chegada de SMS | Funciona. Retorna STATUS_WAIT_CODE, STATUS_OK:CODE, STATUS_WAIT_RETRY | GET /v1/rentals/{id} |
getPrices | Buscar tabela de preços | Funciona. Retorna preços do VerifySMS no formato JSON legado | GET /v1/prices |
getCountries | Mapa de códigos de país | Funciona. Retorna IDs numéricos legados e códigos ISO-3166 | GET /v1/countries |
getTopCountriesByService | Países principais por serviço | Retorna dados do VerifySMS em tempo real em vez de rankings armazenados em cache do SMS-Activate | GET /v1/services/{id}/top-countries |
Uma mão-cheia de ações menos usadas do SMS-Activate não mapeiam um para um. getRentServicesAndCountries e a API de aluguel de longo prazo eram específicas do SMS-Activate e não têm camada de compatibilidade. Se sua integração usou essas, você deve mudar para o endpoint de aluguel de longo prazo nativo do VerifySMS em POST /v1/rentals/long, que é documentado separadamente.
Parte 2: Migração de código passo a passo
Os trechos a seguir são exatamente o formato que testei contra nosso próprio ambiente de teste em janeiro. Eu os mantive deliberadamente simples para que você possa lê-los contra seu próprio código sem mudar de contexto.
Python (requests)
A única alteração necessária é a URL base. Se você já envolveu a API em um pequeno módulo de cliente, a diferença é uma linha única.
import os
import requests
# ANTES
# BASE_URL = "https://sms-activate.org/stubs/handler_api.php"
# DEPOIS
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"resposta 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 não usado para obter o reembolso
requests.get(BASE_URL, params={
"api_key": API_KEY,
"action": "setStatus",
"status": 8,
"id": rental_id,
}, timeout=15)
raise TimeoutError(f"sem código após {deadline_seconds}s")
Node.js (axios)
import axios from "axios";
// ANTES
// const BASE_URL = "https://sms-activate.org/stubs/handler_api.php";
// DEPOIS
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(`resposta 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(`sem código após ${deadlineMs}ms`);
}
PHP (curl)
<?php
// ANTES
// const BASE_URL = "https://sms-activate.org/stubs/handler_api.php";
// DEPOIS
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"
// DEPOIS
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
}
O exemplo em Go foi deliberadamente escrito sem nenhum cliente de terceiros para que você possa inseri-lo em um serviço mínimo sem adicionar dependências. O mesmo padrão se aplica em todas as outras linguagens: troque a URL, mantenha o resto e deixe o tratamento de erros existente funcionar.
Parte 3: Armadilhas que vão queimar você
Essas são as coisas em que a camada de compatibilidade é fiel às peculiaridades do SMS-Activate, mas as peculiaridades em si vão surpreender você se você não tiver tocado esse código há um tempo.
IDs de país não são códigos ISO
O SMS-Activate numerou os países em sua própria ordem: a Rússia era 0, os EUA eram 187, a Indonésia era 6, e assim por diante. Se sua integração tiver esses números mágicos codificados, eles ainda funcionam na camada de compatibilidade. Se você estiver escrevendo código novo, prefira a forma alfa-2 ISO-3166 (RU, US, ID) que a camada de compatibilidade também aceita. Não misture ambos os estilos no mesmo local de chamada, porque a depuração futura será dolorosa.
Código de status 3 versus 6
A ação setStatus código 3 significava "pequisar outro SMS" no mundo do SMS-Activate, e o código 6 significava "aceitar o código como válido". Esses dois códigos são fáceis de trocar em um momento de pressa e têm resultados de cobrança opostos: 3 mantém você cobrado, 6 confirma a verificação bem-sucedida. A camada de compatibilidade se comporta da mesma forma. Faça uma busca em seu código por setStatus e certifique-se de que o ramo que leva o código 6 só seja executado depois de ter certeza de que a verificação foi bem-sucedida.
Tempo limite e disjuntores
O SMS-Activate sob carga às vezes retornava um 200 com um corpo vazio em vez de um erro HTTP. Clientes defensivos envolvem a chamada em um tempo limite e tratam o corpo vazio como um sinal de repetição. O VerifySMS nunca retorna um corpo vazio na camada de compatibilidade. Se o seu cliente ainda tratar o vazio como uma repetição, isso queimará o orçamento em uma rede instável porque a repetição atingirá um ID de aluguel diferente. O padrão mais seguro é verificar os prefixos de resposta conhecidos (ACCESS_, STATUS_, BAD_) e tratar qualquer outra coisa como uma falha dura, não uma falha transitória.
Limites de taxa mudam de por-chave para por-IP
Os limites de taxa do SMS-Activate eram vinculados à chave de API. Os limites de taxa do VerifySMS são vinculados à combinação da chave de API e do endereço IP de origem, porque vemos muito abuso de scripts de raspagem compartilhando uma chave entre uma botnet. Para tráfego de produção normal de um único servidor ou um pool equilibrado, isso é invisível. Se você executar trabalhos de CI distribuídos que compartilham uma chave de teste, você pode ver um 429 na primeira vez que a frota aquecer juntos. A solução é deixar o canário funcionar de um nó por um dia antes de expandir.
O tempo de reembolso parece instantâneo porque é instantâneo
Este não é uma armadilha, mas sim uma surpresa agradável. Onde os reembolsos do SMS-Activate levavam algumas horas para aparecer no seu saldo, os reembolsos do VerifySMS aparecem em 60 segundos. Se o seu rastreador de custo ler o saldo em uma programação, ele registrará o reembolso como um crédito que o sistema antigo teria perdido. Os painéis de reconciliação às vezes sinalizam isso como uma anomalia no primeiro dia.
Parte 4: Verificação de realidade de comparação de preços
Antes do desligamento, o SMS-Activate era o piso do mercado. Números russos custavam entre $0,03 e $0,05 por verificação, e compradores de grande volume pagavam ainda menos. Esse piso desapareceu. Aqui está onde os provedores restantes se encontram em abril de 2026 para os serviços mais comuns, retirados da página de preços pública de cada provedor em :
| Serviço | 5sim | TextVerified | SMSPVA | SMS-MAN | VerifySMS |
|---|---|---|---|---|---|
| WhatsApp / Rússia | $0,014 | — | $0,05 | $0,035 | $0,10 |
| WhatsApp / EUA | $0,27 | $0,25 | $0,28 | $0,22 | $0,18 |
| Telegram / Rússia | $0,016 | — | $0,05 | $0,04 | $0,10 |
| Telegram / EUA | $0,35 | $0,40 | $0,38 | $0,30 | $0,20 |
| Google / Indonésia | $0,07 | — | $0,08 | $0,06 | $0,10 |
O padrão é simples: 5sim e SMS-MAN ganham em preços baixos para Rússia, TextVerified é a camada premium dos EUA, e VerifySMS fica no meio com uma linha de base de $0,10 para tudo, exceto os números não-VoIP mais caros dos EUA. Se o seu orçamento foi ajustado para os preços mínimos do SMS-Activate, espere pagar duas a cinco vezes mais por verificação, independentemente de qual substituto você escolher.
Duas notas sobre esta tabela. Primeiro, cada provedor (incluindo VerifySMS) aumenta e diminui os preços de países individuais em resposta aos custos de operadora, então confirme o preço atual em seu próprio painel antes de comprometer um orçamento. Segundo, o preço efetivo por verificação bem-sucedida depende da taxa de reembolso. Um provedor com um preço de etiqueta de $0,08 e uma taxa de sucesso de 70% custa mais por sucesso do que um provedor com um preço de $0,10 e reembolsos automáticos e uma taxa de sucesso de 90%.
Parte 5: Lista de verificação de migração em 10 etapas
Esta é a sequência real que percorremos com nossos próprios usuários em janeiro. Assume um desenvolvedor único com acesso ao repositório, um serviço de produção e um ambiente de teste. Aumente as porcentagens do canário se você estiver executando vários serviços ou um monorepo.
- Inventarie todos os locais de chamada. Execute
git grep -n 'sms-activate\.org\|handler_api\.php\|getNumber\|setStatus'e liste todos os arquivos que atingem a API antiga. Se você encontrar mais de uma dúzia, escolha um módulo wrapper e centralize as chamadas primeiro antes de migrar. - Obtenha uma chave de API VerifySMS. Cadastre-se, adicione uma pequena quantidade de saldo e gere uma chave com escopo para teste. Mantenha a chave de produção fora do repositório.
- Altere o URL base. Substitua o host do SMS-Activate por
api.verifysms.app/compat/handler_api.php. Não altere a string de consulta. Confirme isso sozinho para que o diff seja limpo. - Execute seus testes existentes. Se os testes atingirem a API real, aponte-os para o estágio e observe discrepâncias de formato. Se eles mockarem a API, execute-os contra o endpoint de estágio ao vivo também para capturar desvios de contrato.
- Reconirme IDs de país. Percorra seu código em busca de constantes de país. Se você estiver usando os IDs numéricos legados, eles ainda funcionam. Se você tiver a chance, substitua-os por códigos ISO-3166 porque o próximo desenvolvedor a tocar este arquivo agradecerá.
- Conecte reivindicações de reembolso. Confirme que seu caminho de tempo limite chame
setStatuscomstatus=8. Sem isso, você ainda obterá reembolsos (nós reembolsamos automaticamente arrendamentos expirados), mas seu rastreador de custos ficará atrasado da realidade. - Atualize seu rastreador de custos. Leia o custo do cabeçalho de resposta
X-VerifySMS-Costem vez de parseá-lo da tabela de preços. Essa única alteração torna seu painel de finanças preciso ao centavo. - Monitoramento. Adicione taxa de sucesso, latência p95 e alertas de taxa de reembolso contra sua linha de base existente. Escolha limites que você possa defender, não aqueles que você acha que serão "finos".
- Canário 5 por cento por 24 horas. Direcione uma pequena fatia do tráfego de produção através do endpoint novo. Observe o painel, não apenas os alertas.
- Corte o restante. Uma vez que a janela do canário esteja limpa, mova os 95 por cento restantes e deixe o código do cliente antigo comentado (não excluído) por um ciclo de lançamento para que você tenha um retorno rápido.
Exclua o código antigo no próximo lançamento após isso. Não deixe locais de chamada mortos por mais de uma semana porque a próxima pessoa a tocar o módulo os colará de volta em uma nova integração por acidente.
Perguntas frequentes
A camada de compatibilidade do SMS-Activate é uma API real ou apenas um stub?
É um endpoint real em api.verifysms.app/compat/handler_api.php que aceita todas as principais ações da documentação pública do SMS-Activate: getBalance, getNumber, getStatus, setStatus, getPrices e getCountries. As solicitações são encaminhadas para nossa API nativa por baixo, então você obtém preços, cobertura e comportamento de reembolso do VerifySMS sem alterações de código do seu lado.
Minha chave de API antiga funcionará?
Não. As chaves de API do SMS-Activate pararam de autenticar no dia em que o serviço foi desligado. Você precisa de uma nova chave do VerifySMS. Cadastre-se, adicione uma pequena quantidade de saldo e gere uma chave do painel. O formato da chave é idêntico em comprimento para que você possa colá-la na mesma variável de ambiente.
Como os reembolsos funcionam em comparação com o SMS-Activate?
O SMS-Activate exigia que você chamasse setStatus com o código de status 8 dentro de 20 minutos para marcar um número como não usado, e os reembolsos eram processados manualmente dentro de algumas horas. O VerifySMS aceita a mesma chamada setStatus e reembolsa o valor total para o seu saldo em até 60 segundos. Se você esquecer de chamar setStatus completamente, nosso sistema ainda reembolsa automaticamente qualquer número que nunca recebeu um SMS após a janela de arrendamento expirar.
Quais países são suportados?
O VerifySMS cobre mais de 200 países. Todos os países que o SMS-Activate ofereceu estão disponíveis no VerifySMS, incluindo Rússia, Indonésia, Vietnã, Nigéria e EUA. Você pode manter seu mapeamento de ID de país existente ou migrar para códigos alfa-2 ISO-3166 quando quiser.
O preço é o mesmo?
Não. Os preços mínimos do SMS-Activate de $0,03 a $0,05 por verificação para números russos desapareceram do mercado aberto. Os preços atuais do mercado variam de $0,10 para serviços comuns até $0,25 para números não-VoIP dos EUA em plataformas mais rigorosas. O VerifySMS cobra $0,10 como linha de base e publica preços por país no painel.
Preciso alterar minha lógica de polling?
Não. A chamada getStatus retorna STATUS_WAIT_CODE e STATUS_OK no mesmo formato que o SMS-Activate usou. Intervalos de polling de 3 a 5 segundos ainda funcionam. O único novo comportamento é que o VerifySMS também expõe uma URL de webhook no painel, para que você possa parar de fazer polling completamente se preferir um fluxo orientado por eventos.
O que acontece se a camada de compatibilidade for algum dia descontinuada?
A camada de compatibilidade é considerada uma interface pública permanente. Se mudarmos seu comportamento, publicaremos uma janela de descontinuação mínima de seis meses com uma nota de migração completa. A API JSON nativa do VerifySMS também é documentada, para que você possa migrar da camada de compatibilidade no seu próprio ritmo quando fizer sentido.
Como testo sem gastar dinheiro?
O painel do VerifySMS expõe um modo de sandbox que retorna números de telefone simulados e códigos SMS enlatados sem debitar seu saldo. Alterne a bandeira de sandbox no painel ou envie o cabeçalho X-Sandbox-Mode com qualquer solicitação para exercitar seus caminhos de código antes de ir ao vivo.
Posso migrar de outros serviços também?
Sim. Este playbook é escrito em torno da API do SMS-Activate porque é onde a maioria do código abandonado vive, mas a mesma lista de verificação se aplica a migrações de 5sim, SMS-MAN ou qualquer outro serviço compatível com handler_api. A camada de compatibilidade reconhece parâmetros handler_api.php independentemente de qual serviço você estava chamando anteriormente.
Quanto tempo leva uma migração real?
Para uma integração de serviço único com algumas dezenas de locais de chamada, planeje duas a quatro horas de trabalho focado, mais uma janela de canário de 24 horas antes de cortar o tráfego completo. Migrações maiores de vários serviços com tratamento de erro personalizado, análise e repetição podem levar mais tempo, mas geralmente terminam dentro de um único dia útil.
Perco meus dados históricos?
O histórico de verificação do SMS-Activate foi desligado quando o serviço foi desligado e não é recuperável. O VerifySMS mantém um registro de auditoria completo de cada tentativa de verificação em sua conta por 12 meses, acessível pelo painel e pela extensão /compat/handler_api.php?action=getHistory.
Isso afeta minha postura de GDPR ou conformidade?
O VerifySMS está registrado no Reino Unido e segue o UK GDPR. Publicamos nossa política de retenção de dados, subprocessadores e DPA na página de privacidade. Se sua configuração anterior exigia um DPA com o SMS-Activate, entre em contato conosco e assinaremos o mesmo acordo em um dia útil.
Próximos passos
Se você leu até aqui, já tem as peças necessárias. Comece com a etapa de inventário, obtenha a troca de URL base na frente de um colega para revisão e execute o canário durante a noite. O playbook é pequeno de propósito; a parte difícil é a disciplina de parar após a janela do canário em vez de cortar tudo em um único commit.
Leitura relacionada no resto do site:
- Estado da Verificação de SMS 2026 — benchmark independente completo de 8 serviços com dados de preços, tráfego e política de reembolso.
- Melhores alternativas ao SMS-Activate em 2026 — Guia completo — guia para não desenvolvedores para as opções de substituição.
- VerifySMS vs SMS-Activate — Comparação completa — comparação lado a lado para equipes ainda avaliando.
- Guia de Integração de API de Verificação de SMS — walkthrough da API nativa do VerifySMS para quando você estiver pronto para sair da camada de compatibilidade.
Pronto para cortar a migração em uma única noite?
Crie uma chave de API VerifySMS →Modo de sandbox incluído · Garantia de reembolso automático · 200+ países · Camada de compatibilidade SMS-Activate em /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:
- State of SMS Verification 2026 — full independent benchmark of 8 services with pricing, traffic, and refund policy data.
- Melhores alternativas ao SMS-Activate em 2026 — Guia completo — non-developer guide to the replacement options.
- VerifySMS vs SMS-Activate — Comparação completa — side-by-side comparison for teams still evaluating.
- SMS Verification API Integration Guide — native VerifySMS API walkthrough for when you are ready to move off the compat layer.
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