メインコンテンツにスキップ

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分


前提条件

  1. n8nのインスタンス(Dockerでのセルフホスト、またはn8n Cloud)
  2. Surmado APIキー(sur_live_...)。app.surmado.com → Settings → API Keys で作成します
  3. 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ノードから、この認証情報を参照します。


連携の基本パターン

  1. Webhookトリガーノード。n8nが https://n8n.yourdomain.com/webhook/abc123 のようなURLを発行します。
  2. Surmadoの設定:レポートを作成するときに webhook_url を指定して、完了通知をそのURLにPOSTするようにします。
  3. IFノードで、event と report.product を絞り込みます。
  4. (任意)HTTP Requestノードで GET /v1/reports/{{ $json.report.id }} を呼び出し、さらに詳しいデータを取得します。
  5. 送信先ノード: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にはサマリーが含まれません。流れは次のとおりです。

  1. 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連携