メインコンテンツまでスキップ

受信サンプル

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)がそのまま指定アドレスへ送信されます。

通知先メールアドレスは設定時に指定。配信は内部のメール送信基盤経由で行われます。