n8n連携ガイド
結論:n8n(エヌエイトエヌ)のWebhookトリガーノードで、Surmado(スルマド)の report.completed イベントを受け取ります。Surmadoの webhook_url をn8nのwebhook URLに向け、event と report.product で絞り込み、ペイロードをGoogle Sheets、Slack、Postgres、そのほかの連携先へ流します。セルフホスト版のn8nは無料です。n8n Cloudは$20/monthです。
読了時間:16分
前提条件
- n8nのインスタンス(Dockerでのセルフホスト、またはn8n Cloud)
- Surmado APIキー(
sur_live_...)。app.surmado.com → Settings → API Keys で作成します - n8nのwebhook用の公開URL(n8n Cloudなら用意されています。セルフホストの場合は、ドメインまたはトンネルが必要です)
n8nを選ぶ理由
- セルフホストできます:ワークフローを自社のインフラ(Docker、Kubernetes、ベアメタル)で動かせます
- オープンソースです:すべてのノードの中身を確認でき、独自のコードで拡張できます
- タスクごとの課金がありません:セルフホストなら実行回数は無制限です(かかるのはサーバー費用だけです)
- 400以上の組み込みノード:Notion、Google Sheets、Slack、Airtable、PostgreSQL、HTTP Request、Codeなど
- 認証情報の保管庫があります:Surmado APIキーを1回保存すれば、すべてのワークフローから参照できます
クイックスタート:Dockerでセルフホストする
docker volume create n8n_data
docker run -d --name n8n \
-p 5678:5678 \
-v n8n_data:/home/node/.n8n \
-e N8N_HOST="n8n.yourdomain.com" \
-e WEBHOOK_URL="https://n8n.yourdomain.com/" \
n8nio/n8n
そのうえで、Surmadoがwebhookのエンドポイントにhttps経由で届くように、Caddy / Nginx / Traefikで n8n.yourdomain.com を http://localhost:5678 へリバースプロキシします。
Surmado APIキーを保存する
n8nで Credentials → New → Header Auth を開きます(または、汎用の HTTP Request ノードに組み込まれた認証情報を使います)。
- Name:
Surmado API - Header name:
Authorization - Header value:
Bearer sur_live_YOUR_API_KEY
api.surmado.com を呼び出すHTTP Requestノードから、この認証情報を参照します。
連携の基本パターン
- Webhookトリガーノード。n8nが
https://n8n.yourdomain.com/webhook/abc123のようなURLを発行します。 - Surmadoの設定:レポートを作成するときに
webhook_urlを指定して、完了通知をそのURLにPOSTするようにします。 - IFノードで、
eventとreport.productを絞り込みます。 - (任意)HTTP Requestノードで
GET /v1/reports/{{ $json.report.id }}を呼び出し、さらに詳しいデータを取得します。 - 送信先ノード:Google Sheets、Slack、Notion、Postgresなど。
Webhookノードに届くペイロードの例
{
"event": "report.completed",
"timestamp": "2026-04-15T12:00:00+00:00",
"report": {
"id": "rpt_abc123xyz",
"token": "SIG-2026-04-A1B2C",
"product": "signal",
"status": "completed",
"tier": "basic",
"data_url": "https://api.surmado.com/v1/reports/rpt_abc123xyz",
"pdf_url": "https://api.surmado.com/v1/reports/view/VIEW_TOKEN",
"summary": {
"business_name": "Acme Coffee Roasters",
"presence_score": 34.2,
"authority_score": 42.7,
"competitive_rank": 4,
"top_competitor": "Blue Bottle"
}
}
}
Strategyレポート(
"product": "solutions")にはsummaryオブジェクトが含まれません。届くのはreport.tokenとreport.pdf_urlだけです。
ワークフロー1:AI VisibilityをGoogle Sheetsへ
ノード1:Webhookトリガー
- HTTP method: POST
- Path:
surmado-signal(n8nがhttps://n8n.yourdomain.com/webhook/surmado-signalを生成します) - Response mode: Immediately(n8nが受信したらすぐに200 OKを返します)
そのURLをSurmadoに渡します。
curl -X POST https://api.surmado.com/v1/reports/signal \
-H "Authorization: Bearer sur_live_YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"brand_slug": "acme_corp",
"url": "https://acme.com",
"email": "founder@acme.com",
"industry": "B2B SaaS",
"location": "United States",
"persona": "Small business owners",
"pain_points": "Losing track of customer conversations",
"brand_details": "Simple CRM with email integration",
"direct_competitors": "HubSpot, Pipedrive",
"webhook_url": "https://n8n.yourdomain.com/webhook/surmado-signal"
}'
Webhookノードで Listen for test event をクリックし、そのあとレポートを実行して、n8nにペイロードの形を取得させます。
ノード2:IF
条件1:{{ $json.event }} が report.completed と等しい
条件2:{{ $json.report.product }} が signal と等しい
組み合わせ:AND
ノード3:Google Sheets: Append row
Operation: Append Spreadsheet / Sheet: 追跡用のシート
列のマッピング:
- Date:
{{ $json.timestamp }} - Token:
{{ $json.report.token }} - Business:
{{ $json.report.summary.business_name }} - Presence Score:
{{ $json.report.summary.presence_score }} - Authority Score:
{{ $json.report.summary.authority_score }} - Competitive Rank:
{{ $json.report.summary.competitive_rank }} - Top Competitor:
{{ $json.report.summary.top_competitor }}
ワークフローを有効にします。これで、完了したAI Visibilityのレポートがすべて追跡されます。
ワークフロー2:Site Auditと条件付きSlackアラート
Webhook → IF(report.product = scan)→ Google Sheets(常に実行)→ IF(report.summary.performance_score < 70)→ Slack。
Slackのメッセージ:
:warning: Performance regression on {{ $json.report.summary.business_name }}
Performance: {{ $json.report.summary.performance_score }} (below 70 threshold)
SEO: {{ $json.report.summary.seo_score }}
Accessibility: {{ $json.report.summary.accessibility_score }}
Critical issues: {{ $json.report.summary.critical_issues_count }}
View report: {{ $json.report.pdf_url }}
ワークフロー3:StrategyのPDF要約配信
Strategyにはサマリーが含まれません。流れは次のとおりです。
- Webhook → IF(
report.product = solutions)→ Send Email(Gmail、SMTP、SendGrid)。
メールの本文:
<p>Strategy report <code>{{ $json.report.token }}</code> is ready.</p>
<p><a href="{{ $json.report.pdf_url }}">View the full report (PDF)</a></p>
REST APIでさらに詳しいデータを取得する
webhookのサマリーでほとんどの用途はまかなえます。プラットフォーム別の差、ページごとの問題、コンテンツギャップの詳細が必要な場合は、フィルターのあとにHTTP Requestノードを追加します。
ノード:HTTP Request
- Method: GET
- URL:
https://api.surmado.com/v1/reports/{{ $json.report.id }} - Authentication: predefined credential → Surmado API(先ほど作成したHeader Auth)
- Response format: JSON
これで、下流のノードから {{ $json.public_intelligence.data.platform_variance.chatgpt.presence_score }} や {{ $json.public_intelligence.data.audit_data.enrichment.content_gaps.executive_summary }} などを参照できます。
Webhook署名の検証
本番環境では、ペイロードを信頼する前に X-Surmado-Signature ヘッダーを検証してください。Surmadoは、正規化したJSON表現に対するHMAC-SHA256でwebhookに署名しています。
Functionノード:署名を検証する
const crypto = require('crypto');
const secret = $env.SURMADO_WEBHOOK_SECRET;
const signature = $('Webhook').first().json.headers['x-surmado-signature'];
const body = $('Webhook').first().json.body;
function canonicalize(value) {
if (value === null || typeof value !== 'object') return JSON.stringify(value);
if (Array.isArray(value)) return '[' + value.map(canonicalize).join(',') + ']';
const keys = Object.keys(value).sort();
return '{' + keys.map(k => JSON.stringify(k) + ':' + canonicalize(value[k])).join(',') + '}';
}
function asciiEscape(str) {
return str.replace(/[\u0080-\uffff]/g, c =>
'\\u' + ('0000' + c.charCodeAt(0).toString(16)).slice(-4)
);
}
const canonical = asciiEscape(canonicalize(body));
const expected = crypto.createHmac('sha256', secret).update(canonical).digest('hex');
if (!crypto.timingSafeEqual(Buffer.from(expected, 'hex'), Buffer.from(signature, 'hex'))) {
throw new Error('Invalid webhook signature');
}
return [{ json: body }];
つなぎ方:Webhook → Function(検証)→ IF(絞り込み)→ 送信先ノード。
トークンの形式
- AI Visibility:
SIG-YYYY-MM-XXXXX(正規表現:SIG-\d{4}-\d{2}-[A-Z0-9]{5}) - Site Audit:
SCN-YYYY-MM-XXXXX(正規表現:SCN-\d{4}-\d{2}-[A-Z0-9]{5}) - Strategy:
SOL-YYYY-MM-XXXXX(正規表現:SOL-\d{4}-\d{2}-[A-Z0-9]{5})
トークンに有効期限はありません。REST APIの署名付きダウンロードURLは約15分間有効です。webhookに入っている pdf_url のマジックリンクは、約30日間有効です。
応用パターン
Switchでプロダクトごとに振り分ける
$json.report.product に対してSwitchノードを使い、signal、scan、solutions の各ケースを用意します。それぞれのケースを、プロダクト専用のワークフローに分岐させます。1つのwebhook URLで、すべての種類のレポートを処理できます。
時系列分析のためにPostgresへ保存する
IFフィルターのあとにPostgresノードを追加し、(timestamp, token, report_id, product, business_name, presence_score, authority_score, ...) をレポート用のテーブルにINSERTします。あとから、GrafanaやMetabaseで推移の集計を確認できます。
複数クライアント向けのエージェンシーの振り分け
business_name や brand_slug を、クライアントごとの設定(どのSlackチャンネルか、シートのどのタブかなど)に対応づけるData store(または外部のデータベース)を使います。レポートごとにそれを参照して、動的に振り分けます。
トラブルシューティング
webhookが動作しない:ワークフローを有効にしてください(n8nは、テスト中ではなく有効な状態のときだけwebhookを処理します)。レポートの作成時に webhook_url を設定したか確認してください。webhook.site をテスト用のURLに使うと、Surmadoが期待どおりのペイロードを送っているか確認できます。
HTTP Requestノードが401を返す:認証情報が紐づいていないか、キーに Bearer の接頭辞がありません。ヘッダーの値全体が Bearer sur_live_... になっている必要があります。
下流でフィールドが空になる:プロダクトの種類を確認してください。Strategyのwebhookには report.summary が含まれず、report.token と report.pdf_url だけが入ります。
セルフホストのwebhookに届かない:SurmadoはHTTPSを必須としています。n8nを localhost で動かしている場合は、トンネル(ngrok、Cloudflare Tunnel)を使うか、有効なTLS証明書を備えたリバースプロキシの内側にデプロイしてください。
非ASCII文字で署名の検証に失敗する:上記のcanonicalizeヘルパーはこれに対応しています。独自に書く場合は、Surmadoが使っているPythonの json.dumps(..., ensure_ascii=True) の出力と一致するように、非ASCII文字をASCIIエスケープしてください。
関連:API連携ガイド | 構造化データとIntelligence Token | Zapier連携 | Make連携 | Notion連携