受信サンプル
Custom: Node.js (Express)
Bearer 認証付きの最小サンプル。エラー判定は errors 配列の有無で行います。
// Node.js (Express) + Bearer 認証
import express from 'express';
const app = express();
app.use(express.json());
app.post('/webhook', (req, res) => {
// 1. Bearer トークン検証
const auth = req.headers.authorization ?? '';
if (auth !== `Bearer ${process.env.RECHO_WEBHOOK_TOKEN}`) {
return res.status(401).send('unauthorized');
}
const { eventType, body } = req.body;
// 2. エラー判定は body.errors の有無で
const hasErrors = Array.isArray(body.errors) && body.errors.length > 0;
if (hasErrors) {
console.error(`[${eventType}] callId=${body.data.callId} has ${body.errors.length} error(s)`);
for (const err of body.errors) {
console.error(` - [${err.code}] ${err.message} (phase: ${err.phase})`);
}
} else {
console.log(`[${eventType}] callId=${body.data.callId} status=${body.data.callStatus}`);
}
res.status(200).send('ok');
});
app.listen(3000);
Custom: Python (FastAPI)
RSA 署名検証付きの最小サンプル。リプレイ攻撃対策のタイムスタンプ検証も含まれます。
# Python (FastAPI) + RSA 署名検証
import base64
import time
from fastapi import FastAPI, HTTPException, Request
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import padding
app = FastAPI()
with open("recho_public_key.pem", "rb") as f:
public_key = serialization.load_pem_public_key(f.read())
@app.post("/webhook")
async def receive(request: Request):
raw_body = await request.body()
signature_b64 = request.headers.get("x-recho-signature", "")
timestamp = request.headers.get("x-recho-timestamp", "")
# 1. タイムスタンプ検証(5分以内)
if not timestamp or abs(time.time() - int(timestamp)) > 300:
raise HTTPException(401, "stale timestamp")
# 2. 署名検証
signed_payload = f"{timestamp}.{raw_body.decode()}".encode()
try:
public_key.verify(
base64.b64decode(signature_b64),
signed_payload,
padding.PKCS1v15(),
hashes.SHA256(),
)
except Exception:
raise HTTPException(401, "invalid signature")
payload = await request.json()
body = payload["body"]
# 3. エラー判定
if body.get("errors"):
for err in body["errors"]:
print(f"[{err['code']}] {err['message']}")
return {"ok": True}
Slack
Slack の Incoming Webhook URL を登録すると、整形済みの text 内容が自動でチャンネルに投稿されます。受信側の実装は不要です。
例えば「発信通話エラー」のときは以下のような内容が投稿されます:
[Recho] 発信通話エラー
━━━━━━━━━━━━━━
callId: abc-123
callStatus: CALLING
callSid: CA94b51...
clientId: client-1
━━━━━━━━━━━━━━
エラー一覧:
- [NETWORK_ERROR] Connection timed out (phase: CONNECTING)
━━━━━━━━━━━━━━
時刻: 2026-05-12 10:24:00
Microsoft Teams
Microsoft Teams も Slack 同様、Workflows / Incoming Webhook URL を登録するだけで、整形済みメッセージが自動投稿されます。受信側の実装は不要です。
Teams 向けには内部でアダプティブカード形式に変換されて送信されます。
Email
Email エンドポイントを登録すると、件名(subject)と本文(text)がそのまま指定アドレスへ送信されます。
通知先メールアドレスは設定時に指定。配信は内部のメール送信基盤経由で行われます。