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

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:

  1. Quais endpoints mapeiam limpa e quais precisam de alterações manuais?
  2. Como faço para manter meu rastreamento de custo e fluxo de reembolso funcionando sem reescrever?
  3. 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:

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-ActivatePropósitoCamada de compatibilidade do VerifySMSAPI nativa do VerifySMS
getBalanceRetornar saldo em USD como textoFunciona inalterado. Retorna ACCESS_BALANCE:X.YYGET /v1/balance retorna JSON
getNumbersStatusDisponibilidade por paísFunciona. Retorna o formato de mapa legadoGET /v1/countries/availability
getNumberAlugar um número para um serviçoFunciona. Retorna ACCESS_NUMBER:id:+phonePOST /v1/rentals
setStatusConfirmar ou cancelar um aluguelFunciona. Códigos de status 1/3/6/8 se comportam de forma idênticaPOST /v1/rentals/{id}/status
getStatusPoll para chegada de SMSFunciona. Retorna STATUS_WAIT_CODE, STATUS_OK:CODE, STATUS_WAIT_RETRYGET /v1/rentals/{id}
getPricesBuscar tabela de preçosFunciona. Retorna preços do VerifySMS no formato JSON legadoGET /v1/prices
getCountriesMapa de códigos de paísFunciona. Retorna IDs numéricos legados e códigos ISO-3166GET /v1/countries
getTopCountriesByServicePaíses principais por serviçoRetorna dados do VerifySMS em tempo real em vez de rankings armazenados em cache do SMS-ActivateGET /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ço5simTextVerifiedSMSPVASMS-MANVerifySMS
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.

  1. 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.
  2. 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.
  3. 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.
  4. 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.
  5. 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á.
  6. Conecte reivindicações de reembolso. Confirme que seu caminho de tempo limite chame setStatus com status=8. Sem isso, você ainda obterá reembolsos (nós reembolsamos automaticamente arrendamentos expirados), mas seu rastreador de custos ficará atrasado da realidade.
  7. Atualize seu rastreador de custos. Leia o custo do cabeçalho de resposta X-VerifySMS-Cost em vez de parseá-lo da tabela de preços. Essa única alteração torna seu painel de finanças preciso ao centavo.
  8. 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".
  9. 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.
  10. 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:

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:

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