メインコンテンツへスキップ
Beta — この機能は現在ベータ版です。APIは変更される場合があります。
本ドキュメントでは、ChainStream Webhookの動作原理、設定方法、ベストプラクティスを紹介し、リアルタイムのオンチェーンイベント配信の実装を支援します。
Webhook機能はすべてのユーザーが利用可能です。

動作原理

データフロー

コア機能

機能説明
リアルタイム配信イベント発生後ミリ秒単位で配信
信頼性の高い配信失敗時に自動リトライ
署名検証HMAC署名による偽造防止
フィルタールールイベントタイプフィルタリングをサポート

対応イベントタイプ

Webhookは現在、以下のイベントタイプ(チャネル)をサポートしています:
チャネル説明一般的な用途
sol.token.createdSolana新規トークン作成新規トークン発見、初期の機会
sol.token.migratedSolanaトークン卒業/マイグレーションPump.funなどのプラットフォームからの卒業トークンの追跡
追加のイベントタイプは開発中です。お楽しみに!

Webhookエンドポイントの作成

APIエンドポイント

POST /v1/webhook/endpoint
Content-Type: application/json
Authorization: Bearer YOUR_ACCESS_TOKEN

リクエストパラメータ

パラメータ必須説明
urlstringはいWebhookコールバック URL(HTTPSが必須)
channelsarrayはい購読するイベントタイプのリスト
descriptionstringいいえエンドポイントの説明
disabledbooleanいいえ無効かどうか、デフォルトはfalse
filterTypesarrayいいえフィルタータイプ
metadataobjectいいえカスタムメタデータ
rateLimitintegerいいえレート制限

リクエスト例

{
  "url": "https://your-server.com/webhook",
  "channels": ["sol.token.created", "sol.token.migrated"],
  "description": "Monitor new tokens and graduated tokens"
}

レスポンス例

{
  "id": "ep_abc123",
  "url": "https://your-server.com/webhook",
  "channels": ["sol.token.created", "sol.token.migrated"],
  "description": "Monitor new tokens and graduated tokens",
  "disabled": false
}

Webhook通知フォーマット

Webhook通知のデータ構造はWebSocketプッシュと一貫しています。

新規トークン作成(sol.token.created)

{
  "channel": "sol.token.created",
  "timestamp": 1706947200000,
  "data": {
    "a": "6p6xgHyF7AeE6TZkSmFsko444wqoP15icUSqi2jfGiPN",
    "n": "Example Token",
    "s": "EXT",
    "dec": 9,
    "cts": 1706947200000,
    "lf": {
      "pa": "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P",
      "pf": "pump_fun",
      "pn": "Pump.fun"
    }
  }
}
フィールド説明
フィールド説明
aトークンアドレス
nトークン名
sトークンシンボル
dec小数点桁数
cts作成タイムスタンプ(ミリ秒)
lf.paローンチプラットフォームプログラムアドレス
lf.pfプロトコルファミリー
lf.pnプロトコル名

トークン卒業(sol.token.migrated)

{
  "channel": "sol.token.migrated",
  "timestamp": 1706947200000,
  "data": {
    "a": "6p6xgHyF7AeE6TZkSmFsko444wqoP15icUSqi2jfGiPN",
    "n": "Example Token",
    "s": "EXT",
    "cts": 1706947200000,
    "lf": {
      "pa": "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P",
      "pf": "pump_fun",
      "pn": "Pump.fun"
    },
    "mt": {
      "pa": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8",
      "pf": "raydium",
      "pn": "Raydium"
    }
  }
}
追加フィールド
フィールド説明
mt.paマイグレーション先プラットフォームプログラムアドレス
mt.pfマイグレーション先プロトコルファミリー
mt.pnマイグレーション先プロトコル名

Webhook URLの要件

要件説明
✅ HTTPSHTTPSプロトコルの使用が必須
✅ 公開アクセス可能URLはパブリックインターネットからアクセス可能であること
✅ 2xxレスポンス成功時に2xxステータスコードを返すこと
✅ レスポンス時間5秒以内にレスポンスすること
✅ 冪等処理重複リクエストを処理できること

セキュリティ検証

Webhookシークレットの取得

エンドポイント作成後、このAPIでシークレットを取得:
GET /v1/webhook/endpoint/{id}/secret
レスポンス
{
  "secret": "whsec_abcdXXX"
}

署名検証

各Webhookリクエストには、リクエスト元を検証するための署名ヘッダーが含まれています:
X-Webhook-Signature: <signature>
X-Webhook-Timestamp: <timestamp>

検証フロー

コード例

const crypto = require('crypto');

function verifyWebhook(req, secret) {
  const signature = req.headers['x-webhook-signature'];
  const timestamp = req.headers['x-webhook-timestamp'];
  const body = JSON.stringify(req.body);
  
  // タイムスタンプの確認(5分間のウィンドウ)
  const now = Date.now();
  if (Math.abs(now - parseInt(timestamp)) > 300000) {
    return false;
  }
  
  // 署名の計算
  const message = `${timestamp}.${body}`;
  const expectedSignature = crypto
    .createHmac('sha256', secret)
    .update(message)
    .digest('hex');
  
  // 安全な比較
  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expectedSignature)
  );
}

Webhookエンドポイントの管理

エンドポイント一覧

GET /v1/webhook/endpoint
クエリパラメータ
パラメータ説明
limitinteger1ページあたりの件数(1-100、デフォルト100)
iteratorstringページネーションイテレータ
orderstringソート順(昇順/降順)

エンドポイント詳細取得

GET /v1/webhook/endpoint/{id}

エンドポイント更新

PATCH /v1/webhook/endpoint
{
  "endpointId": "ep_abc123",
  "channels": ["sol.token.created"],
  "description": "Monitor new tokens only"
}

エンドポイント削除

DELETE /v1/webhook/endpoint/{id}

シークレットのローテーション

POST /v1/webhook/endpoint/{id}/secret/rotate

ベストプラクティス

✅ 高速レスポンス

# 推奨:先にレスポンスを返し、後で処理
@app.route('/webhook', methods=['POST'])
def webhook():
    # 署名の検証
    if not verify_webhook(request, SECRET):
        return "Invalid signature", 401
    
    # キューに入れて非同期処理
    queue.put(request.json)
    
    # すぐに200を返す
    return "OK", 200

✅ 冪等性の処理

各イベントにはユニークな識別子が含まれています。サーバー側で処理済みイベントを記録してください:
# Redisを使用して処理済みイベントを記録
def process_webhook(event):
    event_id = f"{event['channel']}:{event['data']['a']}:{event['timestamp']}"
    
    # 処理済みか確認
    if redis.exists(f"processed:{event_id}"):
        return {"status": "already_processed"}
    
    # イベントを処理
    handle_event(event)
    
    # 処理済みとしてマーク(TTL 24時間)
    redis.setex(f"processed:{event_id}", 86400, "1")
    
    return {"status": "ok"}

✅ セキュリティ

常に署名を検証

すべてのリクエストで署名を検証

HTTPSを使用

通信のセキュリティを確保

シークレットを定期的にローテーション

90日ごとを推奨

機密データを保護

機密データをログに記録しない

✅ 信頼性

冪等性を実装

重複リクエストを処理

メッセージキューバッファ

キューを使用した非同期処理

適切なタイムアウト

長時間のブロッキングを避ける

包括的なログ

トラブルシューティングのために重要な情報を記録

FAQ

トラブルシューティング手順
  1. URLがアクセス可能か確認 — URLがパブリックインターネットから到達可能かテスト
  2. HTTPSを確認 — 有効なSSL証明書を使用していること
  3. エンドポイントステータスを確認disabledtrueでないことを確認
  4. チャネルを確認 — 正しいイベントタイプを購読しているか確認
これはリトライメカニズムによる可能性があります。冪等性の処理を実装してください:
  1. ユニークなイベント識別子を使用(チャネル + トークンアドレス + タイムスタンプ)
  2. リクエスト受信時に処理済みか確認
  3. TTL付きキャッシュ(Redisなど)を使用して保存
  1. ngrokを使用してローカルサービスを公開
  2. ngrok URLを指すWebhookエンドポイントを作成
  3. 実際のイベントのトリガーを待つか、テスト環境を使用
  4. ローカルサービスのログを確認

APIエンドポイント一覧

機能エンドポイント
エンドポイント一覧GET /v1/webhook/endpoint
エンドポイント作成POST /v1/webhook/endpoint
エンドポイント更新PATCH /v1/webhook/endpoint
エンドポイント詳細取得GET /v1/webhook/endpoint/{id}
エンドポイント削除DELETE /v1/webhook/endpoint/{id}
シークレット取得GET /v1/webhook/endpoint/{id}/secret
シークレットローテーションPOST /v1/webhook/endpoint/{id}/secret/rotate

関連ドキュメント

WebSocket API

リアルタイムデータ購読

エンドポイントAPIリファレンス

完全なAPIドキュメント