Skip to main content

Notion Integration Guide

Paste this into Claude Code, Copilot, Cursor, or any AI coding agent to apply changes in your repo.

Quick answer: There is no direct Surmado → Notion integration. Connect the two with Zapier, Make, n8n, or a small custom script. Catch the Surmado report.completed webhook, then call Notion’s “Create database item” action with the fields from report.summary.

Reading time: 10 minutes


Pattern

  1. Trigger: Surmado posts a report.completed payload to a webhook endpoint (Zapier Catch Hook, Make Custom Webhook, n8n Webhook, or your own server).
  2. Read report.summary for curated metrics. For AI Visibility, that’s presence_score, authority_score, competitive_rank, etc. For Site Audit, it’s seo_score, performance_score, accessibility_score, critical_issues_count, and the quick_wins object. Strategy reports don’t include a summary — use report.pdf_url and report.token only.
  3. Create a Notion database item with the property values mapped from the payload.
  4. (Optional) Enrich with a REST API call to GET /v1/reports/{report_id} if you need deeper data like public_intelligence.data.platform_variance or public_intelligence.data.audit_data.enrichment.

Set up the webhook path by passing webhook_url when you create a Surmado report:

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://your-webhook-endpoint.example.com/surmado"
  }'

AI Visibility Reports

PropertyTypePayload field
TitleTitlereport.summary.business_name
TokenTextreport.token
Report IDTextreport.id
Presence ScoreNumberreport.summary.presence_score
Authority ScoreNumberreport.summary.authority_score
Competitive RankNumberreport.summary.competitive_rank
Top CompetitorTextreport.summary.top_competitor
Report DateDatetimestamp
PDFURLreport.pdf_url
StatusSelectderived from presence_score below

A Status select can be computed with a lookup table:

  • presence_score < 30 → At Risk
  • 30 <= presence_score < 60 → Needs Work
  • presence_score >= 60 → Leading

Site Audit Reports

PropertyTypePayload field
TitleTitlereport.summary.business_name or URL
TokenTextreport.token
Report IDTextreport.id
SEO ScoreNumberreport.summary.seo_score
Performance ScoreNumberreport.summary.performance_score
Accessibility ScoreNumberreport.summary.accessibility_score
Total PagesNumberreport.summary.total_pages
Critical IssuesNumberreport.summary.critical_issues_count
Report DateDatetimestamp
PDFURLreport.pdf_url

Strategy Reports

Strategy reports only surface the token and the PDF URL over the webhook. A lean schema:

PropertyTypePayload field
TitleTitlederived (brand + date)
TokenTextreport.token
Report IDTextreport.id
Report DateDatetimestamp
PDFURLreport.pdf_url

Zapier’s Notion integration has a “Create Database Item” action that maps cleanly to the webhook payload.

  1. Create a Zap: Webhooks by Zapier → Catch Hook (copy the URL it gives you).
  2. Configure a Surmado report with webhook_url set to that URL.
  3. Filter: event = report.completed AND report__product = signal (or scan).
  4. Action: Notion → Create Database Item. Map the fields using the webhook output (Zapier flattens nested keys with double underscore — report__summary__presence_score).

Full walkthrough with sample Zaps: Zapier Integration Guide.


Custom Script (No Zapier)

If you prefer code, run a tiny server that accepts the Surmado webhook and calls Notion’s API directly.

Node.js example

const express = require('express');
const { Client } = require('@notionhq/client');

const notion = new Client({ auth: process.env.NOTION_API_KEY });
const DATABASE_ID = process.env.NOTION_DATABASE_ID;

const app = express();
app.use(express.json());

app.post('/surmado-webhook', async (req, res) => {
  const { event, report, timestamp } = req.body;
  if (event !== 'report.completed' || report.product !== 'signal') {
    return res.status(200).end();
  }

  await notion.pages.create({
    parent: { database_id: DATABASE_ID },
    properties: {
      'Name': { title: [{ text: { content: report.summary.business_name || report.token } }] },
      'Token': { rich_text: [{ text: { content: report.token } }] },
      'Report ID': { rich_text: [{ text: { content: report.id } }] },
      'Presence Score': { number: report.summary.presence_score ?? null },
      'Authority Score': { number: report.summary.authority_score ?? null },
      'Competitive Rank': { number: report.summary.competitive_rank ?? null },
      'Top Competitor': { rich_text: [{ text: { content: report.summary.top_competitor || '' } }] },
      'Report Date': { date: { start: timestamp } },
      'PDF': { url: report.pdf_url || null }
    }
  });

  res.status(200).end();
});

app.listen(process.env.PORT || 3000);

Verify the webhook signature before trusting the payload — see the API Integration Guide for the HMAC-SHA256 algorithm.


Enriching Notion Pages with Deeper Data

The webhook summary covers most needs. If you want platform-specific breakdowns (e.g. ChatGPT vs Claude), call the REST API after Notion page creation:

curl -s https://api.surmado.com/v1/reports/{report_id} \
  -H "Authorization: Bearer sur_live_YOUR_API_KEY" \
  | jq '.public_intelligence.data.platform_variance'

Then update the Notion page with a rich text block containing the platform-specific scores.


Troubleshooting

Notion creates the page but properties are empty — the field type in Notion must match the payload. Numbers like presence_score need a Number property, not Rich Text. Verify each property’s type matches the table above.

The webhook fires but Notion call fails — Surmado retries 3x on 5xx responses, then gives up. Check your server logs, fix the bug, then manually re-fetch the report via REST API for the reports that were dropped.

Strategy reports show no scores — expected. Strategy doesn’t expose public_intelligence; only report.token and report.pdf_url are available.


Related: API Integration Guide | Structured Data & Intelligence Tokens | Zapier Integration | Make Integration | n8n Integration