← 全記事
更新履歴

UnifyPort v1 API が本番運用可能に:最初の安定版に含まれるすべて — UnifyPort

UnifyPort v1 API が本番運用可能になりました。これが最初の安定版です。1 つの送信エンドポイント、正規化された Webhook イベント層、そして全 6 チャネル——WhatsApp、Telegram、LINE、TikTok、Zalo、X——のアカウント接続フローを、すべて 1 つの API の下に集約しています。

この記事は、そのリリースのチェンジログです。下層が突然破壊的に変わる心配をせずに構築できるバージョンを待っていたなら、それがこれです。以下、エンドポイントごとに、実際のイベント名・認証フロー・信頼性の挙動とともに、何がリリースされたかを説明します。

6 チャネルを貫く 1 つの送信 API

v1 の中核は 1 つのエンドポイントです。POST /v1/messages は、選択した provider アカウントを通じて正規化されたテキストメッセージを送信します。6 つの SDK や 6 種類のペイロード形式を覚える必要はありません。覚えるのは 1 つだけです。

プラットフォーム固有の挙動が消えたわけではなく、構造化された provider_data フィールドに移動しました。特定のメッセージへの返信や Telegram の parse mode の設定は、トップレベルのリクエスト構造を変えずに provider_data(例:reply_toparse_mode)に収まります。一般的なケースはシンプルなまま、プラットフォーム固有のケースも引き続き可能です。

6 つのチャネルは WhatsApp、Telegram、LINE、TikTok、Zalo、X です。API では、provider アカウントは telegramwhatsapptwitterlinezalo といった名前で作成します。

日本ではとりわけ LINE が中心的なチャネルです。v1 は LINE の QR ログイン(URL と PIN)を他のチャネルとまったく同じ標準イベント層に統合しているため、LINE を起点にしても、その後の処理コードは他チャネルと共通になります。

11 個の標準 Webhook イベント

v1 のもう半分は標準イベント層です。provider からのすべてのメッセージ、配信ステータスの更新、アカウントのライフサイクルイベントは、1 つの安定した JSON 形状に変換されます。本リリースには 11 個の標準イベントがあり、バックエンドはそれらすべてを同じハンドラで処理します。

最もよく使う 2 つ:

  • message.received —— 接続済みアカウントに受信メッセージが到着
  • message.status.updated —— 送信したメッセージの配信ステータスが変化

アカウントのライフサイクルイベントは、接続状態を不透明ではなく観測可能にします:

  • account.auth.required —— アカウントにログイン操作(QR スキャンまたは認証コード)が必要
  • account.auth.succeeded —— ログイン完了。provider_account_ref が設定され、イベントは標準プロフィールフィールド(display_namepicture_urlregionstatus_message)を伴う
  • account.started —— アカウントのランタイムがオンライン
  • account.status.updated —— アカウントのステータスが変化

message.received イベントは、6 チャネルのどれから来ても同じ形をしています:

{
  "event": "message.received",
  "account_id": "acct_8Q2vK",
  "provider": "line",
  "from": "U4af4980629...",
  "text": "注文状況を確認したいです",
  "timestamp": 1749254400,
  "message_id": "line_msg_8f3a2c"
}

linewhatsappzalo に変えても、ルーティングロジックは 1 行も変わりません。それこそが標準層の存在意義です。

アカウント接続:QR とコードの 2 つのフロー

v1 ではアカウント接続が独立したフローになっており、その設計思想は「認証状態は監視し続けるものではなく、Webhook が観測できるもの」です。

アカウントエンドポイントに POST してアカウントを作成し、接続方式に合った auth_mode を選びます:

{
  "provider": "whatsapp",
  "auth_mode": "code",
  "provider_data": { "phone": "+819012345678" }
}

コードベースのフローでは、E.164 形式の電話番号を provider_data.phone で渡します。これはアカウントに永続化され、以降の認証アクションで自動的に再利用されるため、毎回送り直す必要はありません。重複する provider 識別子の作成は、静かに 2 つ目のアカウントを作るのではなく、明確に 409 duplicate_provider_account を返します。

QR ベースのフローでは、認証情報が Webhook 経由で非同期に届きます:

  • WhatsApp —— /auth/qr/start を呼んでデバイスセッションを開始します。QR トークンは account.auth.required イベントとして Webhook に届き(auth_payload.qr_code が UI で QR 画像にレンダリングする生のトークン)、/auth/qr/check でのポーリングでも同期的に取得できます。スキャン後、account.auth.succeededprovider_account_ref を伴って到着し、続いて account.started が届きます。
  • LINE —— QR の URL と PIN が非同期に届きます。account.auth.required をリッスンするか、/auth/session をポーリングして auth_payload.url(QR 画像)と auth_payload.pin を読み取ります。

アカウント設定時に Webhook URL は自動注入されます。認証状態の遷移とログインイベントは、受信メッセージと同じエンドポイントに届きます。1 つの Webhook で、すべてのイベントを。

account.auth.succeeded が届いたら、POST /v1/accounts/{account_id}/runtime/start でアカウントをオンラインにします(ランタイムが既に起動済みなら no-op)。

Webhook コントロールプレーン

v1 の Webhook エンドポイントは、設定の奥に埋もれた単一の URL フィールドではなく、第一級の設定可能なオブジェクトです。

Webhook レシーバーを作成するとき、どのイベントを受け取るかを正確に選びます。subscribed_events は標準イベント名(message.receivedaccount.status.updated など)を受け付け、["*"] ですべてを購読できます。未知のイベント名は、後で静かに失敗するのではなく、書き込み時に拒否されます。

署名は組み込みです。signing_secret を指定すると、すべての配信が HMAC-SHA256 で署名され、エンドポイントは真正性を検証できます。空にすると署名は明示的に無効化されます——これは事故ではなく意図的な選択です。

リトライ挙動は自分で設定します。retry_policy.max_attempts は非負整数で、0 はリトライを完全に無効化し、非整数値は拒否されます。再配信はプラットフォームが担い、エンドポイントは応答するだけで構いません。

変動をプラットフォーム層に閉じ込める信頼性

本番リリースには本番のデフォルトが必要であり、v1 はそれを備えています。受信配信はレート制限・リトライ・冪等性・障害分離を備えたキューを通るため、provider 側の変動はアプリケーションに連鎖せず、プラットフォーム層の内側に留まります。

アカウントのランタイム状態も正規化されています。runtime_status は各 provider 独自の語彙ではなく、8 つのプラットフォーム標準値——unknownstartingrunningstoppingstoppedreconnectingdisconnectederror——のいずれかを取り、provider 固有のラベルは目に触れる前にこのセットへマッピングされます。状態機械は 6 個ではなく 1 個で済みます。

地理的ルーティングが必要なアカウントには、任意の proxy_config オブジェクトがアカウントとともに永続化され、自動的に適用されます。

このリリースの意味

v1 が本番運用可能になったことは、単なるバージョン番号ではなく約束です。送信エンドポイント、11 個の標準イベント、認証フロー、Webhook コントロールプレーンが、その上に製品を構築できる安定面です。UnifyPort の目的は一貫して、チームが同じ統合を 6 回作り直さずに済むようにすることでした。v1 は、その面が動かなくなるバージョンです。

公式 API の摩擦なしにメッセージを受信する方法についての他の記事——公式 API なしで WhatsApp の受信を扱う公式アカウントなしで LINE メッセージを受信する、または WhatsApp と Telegram のコスト比較——を読んだなら、それらの経路が動いているのがこの API です。

始め方:API キーを作成し、チャネルに合った auth_mode で最初のアカウントを接続し、signing_secret 付きの Webhook エンドポイントを登録し、message.received を購読します。同じ作業時間内に、正規化された受信イベントがバックエンドに届くはずです。そこから先、チャネルを 1 つ増やすたびに同じフローであり、新たな統合プロジェクトではありません。