Webhook通知
PDF生成完了時に自動的にWebhook通知を受け取ることができます。これにより、ポーリング不要でリアルタイムに完了を検知し、メール送信などのワークフローを自動化できます。
概要
Webhook通知は、以下のすべてのPDF生成エンドポイントで自動的に送信されます:
POST /file/sync/single- 同期単一ファイル生成POST /file/sync/multiple- 同期複数ファイル生成POST /file/async/single- 非同期単一ファイル生成POST /file/async/multiple- 非同期複数ファイル生成
Webhook URLの設定
Webhook URLを設定するには、ReportFlowのワークスペース設定画面から行います:
- ワークスペース設定を開く
- 「開発者」タブに移動
- 「Webhook URL」フィールドに、通知を受け取るHTTPS URLを入力
- 「更新」をクリック
Webhook通知ペイロード
PDF生成が完了すると、設定されたWebhook URLに以下のペイロードがPOSTされます。
ペイロード形式
{
"event": "file.completed",
"timestamp": "2026-02-15T10:30:45.123Z",
"workspaceId": "ws_abc123",
"requestId": "550e8400-e29b-41d4-a716-446655440000",
"designId": "design_123",
"version": 5,
"files": [
{
"fileId": "7f3d1a2b-4c5e-6f7a-8b9c-0d1e2f3a4b5c",
"fileName": "請求書.pdf",
"passthrough": { "pageId": "abc123" },
"share": {
"shareType": "workspace",
"url": "https://app.re-port-flow.com/file/{requestId}/{fileId}",
"passcodeEnabled": false
}
}
]
}
フィールド説明
| フィールド | 型 | 説明 |
|---|---|---|
event | string | 固定値: "file.completed" |
timestamp | string | イベント発生時刻 (ISO 8601形式) |
workspaceId | string | ワークスペースID(参照用) |
requestId | string | リクエストID(ダウンロードエンドポイントで使用) |
designId | string | デザインID |
version | number | バージョン番号 |
files | array | 生成ファイル情報の配列 |
files[].fileId | string | ファイルID(個別ダウンロードエンドポイントで使用) |
files[].fileName | string | ファイル名(拡張子付き) |
files[].passthrough | object | リクエスト時に指定した passthrough の値(指定時のみ) |
files[].share.shareType | string | 共有タイプ(workspace / invited / public) |
files[].share.url | string | ファイル表示URL |
files[].share.passcodeEnabled | boolean | パスコード有効フラグ |
files[].share.passcode | string | サーバー生成パスコード(passcodeEnabled=true かつ生成直後のみ) |
PDFのダウンロード
Webhook通知のペイロードから、以下の情報を使ってPDFをダウンロードできます:
requestId: ペイロードのrequestId(ZIP一括ダウンロード用)fileId: ペイロードのfiles[].fileId(個別ダウンロード用)
# ZIP一括ダウンロード
GET /v1/file/download/{requestId}
# 個別ファイルダウンロード
GET /v1/file/download/{requestId}/{fileId}
詳細はファイルダウンロードを参照してください。
実装例
Node.js (Express)
import express from 'express';
import axios from 'axios';
const app = express();
app.use(express.json());
app.post('/webhooks/pdf-completed', async (req, res) => {
const payload = req.body;
// イベント検証
if (payload.event !== 'file.completed') {
return res.status(400).json({ error: 'Unknown event' });
}
console.log(`PDF生成完了: ${payload.files.length}件`);
// 各ファイルをダウンロード
for (const file of payload.files) {
const downloadUrl = `https://api.re-port-flow.com/v1/file/download/${payload.requestId}/${file.fileId}`;
try {
// PDFダウンロード
const pdfResponse = await axios.get(downloadUrl, {
headers: {
'appkey': process.env.APP_KEY
},
responseType: 'arraybuffer'
});
const pdfBuffer = Buffer.from(pdfResponse.data);
// メール送信など
await sendEmailWithAttachment({
to: extractEmailFromParams(file.params),
subject: `PDFファイル: ${file.fileName}`,
attachments: [{
filename: file.fileName,
content: pdfBuffer
}]
});
console.log(`メール送信完了: ${file.fileName}`);
} catch (error) {
console.error(`ファイルダウンロードエラー: ${file.fileName}`, error.message);
}
}
// 200 OKを返す
res.status(200).json({ received: true });
});
app.listen(3000, () => {
console.log('Webhook server listening on port 3000');
});
Python (Flask)
from flask import Flask, request, jsonify
import requests
import os
app = Flask(__name__)
@app.route('/webhooks/pdf-completed', methods=['POST'])
def webhook_handler():
payload = request.json
# イベント検証
if payload.get('event') != 'file.completed':
return jsonify({'error': 'Unknown event'}), 400
print(f"PDF生成完了: {len(payload['files'])}件")
# 各ファイルをダウンロード
request_id = payload['requestId']
for file_info in payload['files']:
download_url = f"https://api.re-port-flow.com/v1/file/download/{request_id}/{file_info['fileId']}"
try:
# PDFダウンロード
pdf_response = requests.get(
download_url,
headers={
'appkey': os.getenv('APP_KEY')
}
)
pdf_response.raise_for_status()
# ファイルに保存
with open(file_info['fileName'], 'wb') as f:
f.write(pdf_response.content)
print(f"ダウンロード完了: {file_info['fileName']}")
except Exception as e:
print(f"エラー: {file_info['fileName']}, {str(e)}")
# 200 OKを返す
return jsonify({'received': True}), 200
if __name__ == '__main__':
app.run(port=3000)
セキュリティベストプラクティス
1. HTTPS URLを使用
Webhook URLは必ずHTTPSを使用してください。HTTP URLは拒否されます。
2. 署名検証の実装
現在、Webhook通知にはペイロード署名がありません。なりすましを防ぐため、以下の方法で受信元を検証す ることを推奨します:
- IPホワイトリスト
- API Keyやシークレットトークンによる認証
- 独自の署名スキーム
3. タイムアウト設定
Webhookエンドポイントは5秒以内に応答することを推奨します。重い処理(メール送信、データベース書き込みなど)は非同期ジョブキューで実行してください。
4. URLに認証情報を含めない
Webhook URLのクエリパラメータに認証トークンやシークレットを含めないでください。認証が必要な場合は、Headerで送信するか、別途管理してください。
リトライ動作
Webhookエンドポイントが以下のステータスコードを返した場合、ReportFlowは自動的にリトライします:
- 200-299: 成功(リトライしない)
- 400-499: クライアントエラー(リトライしない)
- 500-599: サーバーエラー(リトライする)
リトライは最大3回まで行われます。すべてのリトライが失敗しても、PDF生成処理自体は成功扱いとなります。
トラブルシューティング
通知が届かない
以下を確認してください:
-
Webhook URLが設定されているか
- ワークスペース設定 > 開発者タブで確認
-
HTTPSを使用しているか
- HTTP URLは拒否されます
-
公開URLを使用しているか
localhostやプライベートIPアドレスは拒否されます- テスト環境ではwebhook.siteなどのサービスを利用してください
-
エンドポイントが200を返すか
- エラーステータスコード(4xx/5xx)を返している場合、リトライされます
- エンドポイントのログを確認してください
通知が届かない場合は、サポートにお問い合わせください。