SMS-Activate 移行ハブ 2026: 開発者チェックリスト、API マッピング & 返金比較
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.
このプレイブックが存在する理由
ほとんどの「SMS-Activate は死んだ、代替リストはこちら」といった投稿は、実際に開発者の時間を浪費するコード部分を見逃している。新しいプロバイダーにサインアップするのは 5 分で済むが、長年生産環境で静かに動作し、テストされていないコーナーケースやコストトラッカーが付随する統合を書き直すには、思いのほか時間がかかる。
私たちが 2026 年 1 月に互換性レイヤーを出荷した後、試したすべてのチームから同じ 3 つの質問が寄せられた。
- どのエンドポイントがきれいにマッピングされ、どれが手動変更を必要とするか?
- コストトラッキングと返金フローを書き直すことなく動作させるにはどうすればよいか?
- 何が黙って壊れ、後日請求サプライズとして現れるか?
このプレイブックは、これら 3 つの質問に順番に答え、実行前に監査できるコピーアンドペーストコードを提供する。
48時間のまとめ:実際に何が起こったのか
SMS-Activate は 2025 年 12 月 29 日 に消えた。予定されたメンテナンスバナーはなく、移行ツールも公開通知もなかった。ログインしようとしたユーザーは、サービスが永久に閉鎖されたという単一のページに遭遇した。API は数時間以内にすべてのエンドポイントで接続リセットを返した。
3 つの事態が急速に発生した。
- ダッシュボードの残高は到達不能になった。
r/smsサブレディットと公式の Telegram チャンネルのレポートでは、20 ドルから数千ドルまでの残高が回復パスなしで凍結されたと説明されている。 - 実行中の統合が激しく壊れた。
handler_api.phpをポーリングしているサービスは、HTTP 接続エラーを受け取り始めた。これは、ほとんどのバグトラッカーでは「サーキットブレーカーがトリップした、チームに警告する」という意味である。 - 移行ウィンドウは数日で閉じた。 72 時間以内に、残りのすべてのプロバイダーにはキューができた。5sim、SMSPVA、SMS-MAN はすべて、容量ひっ迫を認めた。VerifySMS は、グループ内で最小であり、余裕があったため持ちこたえたが、実際に近かった。
余波はまだ続いている。2026 年 4 月現在、ロシアでは少額訴訟事件が活発化しており、少なくとも 2 つの調整されたコミュニティ訴訟が、凍結された残高を回収しようとしている。これらはコードとは関係がないため、実際に修正できる部分に焦点を当てる。
パート1:API廃止マップ
SMS-Activate は、https://sms-activate.org/stubs/handler_api.php で単一の公開エンドポイントを出荷した。すべてのアクションは、その URL のクエリ文字列パラメータであった。下の表は、すべての主要アクションをその VerifySMS 等価にマッピングする。https://api.verifysms.app/compat/handler_api.php でのコンパットレイヤーは、まったく同じクエリ文字列形状を受け入れる。
| SMS-Activate アクション | 目的 | VerifySMS コンパットレイヤー | ネイティブ VerifySMS API |
|---|---|---|---|
getBalance | USD 残高をテキストとして返す | 動作は変わらない。ACCESS_BALANCE:X.YY を返す | GET /v1/balance は JSON を返す |
getNumbersStatus | 国別可用性 | 動作する。レガシー マップ形式を返す | GET /v1/countries/availability |
getNumber | サービス用の番号をリースする | 動作する。ACCESS_NUMBER:id:+phone を返す | POST /v1/rentals |
setStatus | リースを確認またはキャンセルする | 動作する。ステータス コード 1/3/6/8 は同じように動作する | POST /v1/rentals/{id}/status |
getStatus | SMS 到着をポーリングする | 動作する。STATUS_WAIT_CODE、STATUS_OK:CODE、STATUS_WAIT_RETRY を返す | GET /v1/rentals/{id} |
getPrices | 価格表をフェッチする | 動作する。レガシー JSON 形状の VerifySMS 価格を返す | GET /v1/prices |
getCountries | 国コード マップ | 動作する。レガシー数値 ID と ISO-3166 コードの両方を返す | GET /v1/countries |
getTopCountriesByService | サービス別の上位国 | リアルタイムの VerifySMS データをキャッシュされた SMS-Activate ランキングの代わりに返す | GET /v1/services/{id}/top-countries |
使用頻度の低い SMS-Activate アクションのいくつかは、1 対 1 でマッピングされない。getRentServicesAndCountries と長期リース API は SMS-Activate 特有のものであり、コンパットレイヤーはない。統合でこれらを使用した場合、ネイティブの VerifySMS 長期リースエンドポイントに移行すべきである。POST /v1/rentals/long は別途文書化されている。
パート2:コード移行ウォークスルー
以下のスニペットは、1 月に当社のステージング環境に対してテストした正確な形状である。コンテキストスイッチングを避けるために、意図的に退屈なものにしている。
Python (requests)
必要な変更は、ベース URL のみである。すでに API を小さなクライアント モジュールでラッピングしている場合、差分は 1 行である。
import os
import requests
# BEFORE
# BASE_URL = "https://sms-activate.org/stubs/handler_api.php"
# AFTER
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"予期しない応答: {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)
# 未使用としてマークして返金を受ける
requests.get(BASE_URL, params={
"api_key": API_KEY,
"action": "setStatus",
"status": 8,
"id": rental_id,
}, timeout=15)
raise TimeoutError(f"{deadline_seconds} 秒後にコードなし")
Node.js (axios)
import axios from "axios";
// BEFORE
// const BASE_URL = "https://sms-activate.org/stubs/handler_api.php";
// AFTER
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(`予期しない応答: ${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(`${deadlineMs}ms 後コードなし`);
}
PHP (curl)
<?php
// BEFORE
// const BASE_URL = "https://sms-activate.org/stubs/handler_api.php";
// AFTER
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("予期しない: $resp");
}
return ["id" => $id, "phone" => $phone];
}
Go (net/http)
package sms
import (
"errors"
"fmt"
"io"
"net/http"
"net/url"
"os"
"strings"
"time"
)
// BEFORE
// const baseURL = "https://sms-activate.org/stubs/handler_api.php"
// AFTER
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("予期しない: " + body)
}
return parts[1], parts[2], nil
}
Go の例は、依存関係を追加せずに最小のサービスにドロップできるように、意図的にサードパーティクライアントなしで記述されている。他の言語でも同じパターンが当てはまる。URL を交換し、残りはそのままにして、既存のエラー処理をそのまま使用する。
パート3:あなたを焼く落とし穴
これらは、SMS-Activate の癖性に忠実であるが、実際に触れていないと驚かされる部分である。
国 ID は ISO コードではない
SMS-Activate は国を独自の順序で番号付けした。ロシアは 0、米国は 187、インドネシアは 6 などである。統合にこれらのマジックナンバーがハードコードされている場合、コンパットレイヤーではまだ動作するが、新しいコードを書く場合は、ISO-3166 alpha-2 形式 (RU、US、ID) を使用する方がよい。コンパットレイヤーもこれを受け入れる。同じ呼び出しサイトで両方のスタイルを混在させないでください。将来のデバッグは苦痛になる。
ステータスコード 3 と 6
setStatus アクションコード 3 は、SMS-Activate の世界では「別の SMS を要求する」を意味し、コード 6 は「コードを有効として受け入れる」を意味した。これら 2 つのコードは簡単に交換でき、反対の請求結果になる。3 は課金され続け、6 は検証の成功を確認する。コンパットレイヤーは同じように動作する。コードを grep して setStatus を探し、コード 6 のみが実行されるブランチは、検証が成功したことを確認してから実行されるようにする。
タイムアウトとサーキットブレーカー
SMS-Activate は、負荷時に空の本文で 200 を返すことがあった。防御的なクライアントは、呼び出しをタイムアウトでラッピングし、空の本文を再試行シグナルとして扱う。VerifySMS はコンパットレイヤーで空の本文を返すことはない。クライアントがまだ空を再試行として扱う場合、フレーキーネットワークで予算を浪費することになるため、再試行は異なるレンタル ID にヒットする。より安全なパターンは、既知の応答プレフィックス (ACCESS_、STATUS_、BAD_) をチェックし、ハード障害として未知のものを扱う。
レート制限はキー単位から IP 単位に移動
SMS-Activate のレート制限は API トークンに基づいてキーが付けられていた。VerifySMS のレート制限は、API トークンとソース IP アドレスの組み合わせに基づいてキーが付けられている。スクレイパースクリプトがボットネット全体で 1 つのキーを共有している場合、通常の生産トラフィックではこれは見えない。複数の CI ジョブがすべて 1 つのステージングキーを共有している場合、ファンアウト前にキャナリが 1 日間実行されるまで待つという修正で、429 が最初に表示されることがある。
返金タイミングは瞬時であるため実際には瞬時である
これは罠というよりは、嬉しい驚きである。SMS-Activate では返金が数時間かかったが、VerifySMS では 60 秒以内に返金が表示される。コストトラッカーがスケジュールで残高を読む場合、古いシステムでは見逃されていたであろうクレジットとして返金を登録する。リコンサレーションダッシュボードは、初日に異常としてフラグする場合がある。
パート4:価格比較の現実チェック
サービス終了前、SMS-Activateは市場で最低価格帯でした。ロシアの番号は1件あたり$0.03~$0.05で、大量購入者はさらに安くなりました。しかし、その最低価格帯は消えました。2026年4月7日現在の主要プロバイダーの公開価格ページから、最も一般的なサービスについて以下に示します。
| サービス | 5sim | TextVerified | SMSPVA | SMS-MAN | VerifySMS |
|---|---|---|---|---|---|
| WhatsApp / ロシア | $0.014 | ー | $0.05 | $0.035 | $0.10 |
| WhatsApp / アメリカ | $0.27 | $0.25 | $0.28 | $0.22 | $0.18 |
| Telegram / ロシア | $0.016 | ー | $0.05 | $0.04 | $0.10 |
| Telegram / アメリカ | $0.35 | $0.40 | $0.38 | $0.30 | $0.20 |
| Google / インドネシア | $0.07 | ー | $0.08 | $0.06 | $0.10 |
パターンは単純です。5simとSMS-MANはロシアの最低価格で勝利し、TextVerifiedはアメリカのプレミアムティア、VerifySMSはすべてのものに対して$0.10のフラットレートの中間に座っています。 SMS-Activateの最低価格に合わせて予算を設定していた場合、どの代替プロバイダーを選択しても、検証ごとに2〜5倍のコストがかかることが予想されます。
この表に関する2つの注意点。 まず、すべてのプロバイダー(VerifySMSを含む)は、キャリアコストに応じて個々の国価格を上げ下げするため、予算を確定する前に独自のダッシュボードで現在の価格を確認してください。 第二に、実効 価格は、返金率によって成功した検証ごとに異なります。 $ 0.08のラベル価格と70%の成功率のプロバイダーは、$ 0.10のプロバイダーよりも成功ごとにコストがかかる可能性があります。自動返金と90%の成功率。
パート5:10ステップの移行チェックリスト
これは、1月の当社ユーザーに実際に提供した手順です。 単一の開発者、リポジトリへのアクセス、1つの本番サービス、およびステージング環境を前提としています。 複数のサービスまたはモノレポジトリを実行している場合は、カナリアの割合をスケールアップしてください。
- すべての呼び出しサイトをインベントリします。
git grep -n 'sms-activate\.org\|handler_api\.php\|getNumber\|setStatus'を実行し、古いAPIにヒットするすべてのファイルをリストします。 12以上見つかった場合は、移行する前にラッパーモジュールをピックし、呼び出しを一元化します。 - VerifySMS APIキーを取得します。 サインアップし、少額の残高を追加して、ステージング用のスコープ付きキー生成します。 本番キーをリポジトリの外部に保管します。
- 基本URLを変更します。 SMS-Activateホストを
api.verifysms.app/compat/handler_api.phpに置き換えます。 クエリ文字列を変更しないでください。 これをコミットして、diffをクリーンにします。 - 既存のテストを実行します。 テストが実際のAPIにヒットした場合、ステージングを対象とし、形状の不一致を監視します。 APIをモックする場合は、ライブステージングエンドポイントに対しても実行して、コントラクトのドリフトをキャッチします。
- 国IDを確認します。 コード内の国定数をスキムします。 従来の数値IDを使用している場合、まだ機能します。 機会があれば、ISO-3166コードに置き換えてください。
- 返金請求を配線します。 タイムアウトパスが
setStatusをstatus=8で呼び出すことを確認します。 これがないと、(期限切れのリースを自動返金しますが)コストトラッカーは現実に遅れます。 - コストトラッカーを更新します。
X-VerifySMS-Costレスポンスヘッダーからコストを読み取ります。 この単一の変更により、ファイナンスダッシュボードは正確になります。 - 監視。 成功率、p95レイテンシ、および返金率のアラートを既存のベースラインに対して追加します。 議論できるしきい値を選択します。
- 5%を24時間カナリアに。 生産トラフィックのごく一部を新しいエンドポイントにルーティングします。 ダッシュボードを見て、アラートだけではありません。
- 残りをカットオーバーします。 カナリアウィンドウがクリーンになったら、残りの95%を移動し、古いクライアントコードをコメントアウト(削除しない)して、1つのリリースサイクルのためにロールバックできるようにします。
次のリリース後に古いコードを削除してください。 1週間以上経過した場合は、呼び出しサイトを死んだままにしないでください。
よくある質問
SMS-Activate互換性レイヤーは実際のAPIですか?
api.verifysms.app/compat/handler_api.phpの実際のエンドポイントで、SMS-Activateパブリックドキュメントからのすべての主要アクションを受け入れます:getBalance、getNumber、getStatus、setStatus、getPrices、およびgetCountries。 リクエストはネイティブAPIにプロキシされるため、コード変更なしでVerifySMSの価格、サービス、カバレッジ、および返金動作が得られます。
古いAPIキーは使えますか?
いいえ。 SMS-Activate APIキーはサービス終了日に認証を停止しました。 VerifySMSから新しいキーが必要です。 サインアップし、少額の残高を追加して、ダッシュボードからキーを生成します。 キーのフォーマットは同じ長さなので、同じ環境変数に貼り付けることができます。
SMS-Activateと比較して返金はどうですか?
SMS-Activateでは、20分以内にステータスコード8でsetStatusを呼び出して未使用として番号をマークする必要があり、返金は手動で数時間以内に処理されました。 VerifySMSは、同じsetStatus呼び出しを受け入れ、60秒以内に全額をあなたの残高に返金します。 また、setStatusを呼び忘れた場合、システムはリースウィンドウが期限切れになった後にSMSを受信しなかった番号を自動的に返金します。
どの国がサポートされていますか?
VerifySMSは200以上の国をカバーしています。 SMS-Activateが提供していたすべての国がVerifySMSで利用可能であり、ロシア、インドネシア、ベトナム、ナイジェリア、アメリカを含みます。 既存の国IDマッピングを維持するか、ISO-3166アルファ2コードに移行することができます。
価格は同じですか?
いいえ。 SMS-Activateのロシアの番号の検証あたり$0.03〜$0.05の最安値は、オープンマーケットから消えています。 現在の市場価格は、一般的なサービスに対して$0.10から、厳格なプラットフォームでのアメリカの非VoIP番号に対して$0.25までです。 VerifySMSは、基本として$0.10を請求し、ダッシュボードに国別の価格を公開しています。
ポーリングロジックを変更する必要がありますか?
いいえ。 getStatus呼び出しは、SMS-Activateが使用していたのと同じ形式でSTATUS_WAIT_CODEおよびSTATUS_OKを返します。 3〜5秒のポーリング間隔は引き続き機能します。 唯一の新しい動作は、VerifySMSがダッシュボードにWebhook URLも公開しているため、イベント駆動型のフローが必要な場合はポーリングを停止できることです。
互換性レイヤーが廃止された場合はどうなりますか?
互換性レイヤーは、パブリックインターフェースと見なされます。 将来的に動作を変更する場合は、完全な移行ノート付きの6か月以上の廃止期間を公開します。 ネイティブのVerifySMS JSON APIも文書化されているため、互換性レイヤーから独自のペースで移行できます。
お金を使わずにテストするにはどうすればよいですか?
VerifySMSダッシュボードには、電話番号をシミュレートし、SMSコードを缶詰に返金せずに返すサンドボックスモードがあります。 ダッシュボードでサンドボックスフラグを切り替えるか、ライブ前にコードパスをテストするためにX-Sandbox-Modeヘッダーをリクエストに送信します。
他のサービスからも移行できますか?
はい。 このプレイブックはSMS-Activate APIを中心に書かれていますが、ほとんどの行き詰まったコードが存在するため、同じチェックリストが5sim、SMS-MAN、またはその他のhandler_apiと互換性のあるサービスからの移行に適用されます。 互換性レイヤーは、以前に呼び出していたサービスに関係なく、handler_api.phpパラメータを認識します。
実際の移行にはどれくらいの時間がかかりますか?
いくつかの呼び出しサイトを持つ単一のサービス統合の場合、2〜4時間の集中作業に加えて、24時間のカナリアウィンドウを計画します。 カスタムエラー処理、分析、および再試行を備えた大規模なマルチサービス移行は、より長く実行される可能性がありますが、通常は1日以内に終了します。
履歴データは失われますか?
SMS-Activate検証履歴はサービス終了とともにオフラインになり、回復できません。 VerifySMSは、12か月間のすべての検証試行の監査ログをアカウントで維持し、ダッシュボードからおよび/compat/handler_api.php?action=getHistory拡張機能を介してアクセスできます。
GDPRまたはコンプライアンスの姿勢に影響しますか?
VerifySMSは英国に登録されており、英国のGDPRに従っています。 当社のデータ保持ポリシー、サブプロセッサー、およびDPAは、プライバシーページに公開されています。 以前の設定でDPAがSMS-Activateに必要だった場合、当社に連絡して、同じ契約に1営業日以内に署名します。
次のステップ
ここまで読んだ場合は、必要なピースがすでに揃っています。 在庫ステップから始めて、基本URLの交換を同僚にレビューしてもらい、夜間にカナリアを実行してください。 プレイブックは小さいですが、難しい部分は、カナリアウィンドウの後に停止する代わりに、すべてを1つのコミットでカットオーバーしないという規律です。
サイトの他の関連記事:
- SMS Verification 2026の状態 — 8つのサービスと価格、トラフィック、返金ポリシーのデータの完全な独立したベンチマーク。
- 2026年 SMS-Activateの代替サービス ベスト7 — 完全ガイド — 開発者以外のガイド。
- VerifySMS vs SMS-Activate — 完全比較 — チームがまだ評価している場合の並行比較。
- SMS Verification API統合ガイド — ネイティブVerifySMS APIのウォークスルー。
1回の移行を1晩で終了する準備はできましたか?
VerifySMS APIキーを作成する→サンドボックスモード付き・自動返金保証・200カ国以上・SMS-Activateコンパチ層 /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.
- 2026年 SMS-Activateの代替サービス ベスト7 — 完全ガイド — non-developer guide to the replacement options.
- VerifySMS vs SMS-Activate — 完全比較 — 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