Guida all'integrazione con n8n
Risposta rapida: usa il nodo trigger Webhook di n8n per ricevere gli eventi report.completed di Surmado. Punta un webhook_url di Surmado all’URL del webhook di n8n, filtra su event e report.product e passa il payload a Google Sheets, Slack, Postgres o a qualsiasi altra integrazione. n8n self-hosted è gratuito; n8n Cloud costa $20/mese.
Tempo di lettura: 16 minuti
Prerequisiti
- Un’istanza n8n (self-hosted con Docker, oppure n8n Cloud)
- Chiave API Surmado (
sur_live_...): creala su app.surmado.com → Settings → API Keys - Un URL pubblico per il tuo webhook n8n (n8n Cloud se ne occupa da solo; il self-hosted richiede un dominio o un tunnel)
Perché n8n
- Self-hostable: il workflow gira sulla tua infrastruttura (Docker, Kubernetes, bare metal)
- Open source: puoi ispezionare ogni nodo ed estenderlo con codice personalizzato
- Nessuna fatturazione per task: esecuzioni illimitate in self-hosted (paghi solo il server)
- Oltre 400 nodi integrati: Notion, Google Sheets, Slack, Airtable, PostgreSQL, HTTP Request, Code e altri
- Credentials vault: conservi la chiave API Surmado una sola volta e la richiami in tutti i workflow
Avvio rapido: self-hosted con 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
Poi imposta un reverse proxy da n8n.yourdomain.com a http://localhost:5678 con Caddy / Nginx / Traefik, così Surmado può raggiungere il tuo endpoint webhook in HTTPS.
Conserva la tua chiave API Surmado
In n8n vai su Credentials → New → Header Auth (oppure usa la credenziale integrata del nodo generico HTTP Request):
- Name:
Surmado API - Header name:
Authorization - Header value:
Bearer sur_live_YOUR_API_KEY
Usa questa credenziale in ogni nodo HTTP Request che chiama api.surmado.com.
Lo schema di integrazione
- Nodo trigger Webhook. n8n ti dà un URL come
https://n8n.yourdomain.com/webhook/abc123. - Configura Surmado perché invii con POST i completamenti dei report a quell’URL tramite
webhook_urlquando crei un report. - Nodo IF per filtrare su
eventereport.product. - (Facoltativo) HTTP Request: nodo per chiamare
GET /v1/reports/{{ $json.report.id }}e ottenere dati più approfonditi. - Nodi di destinazione: Google Sheets, Slack, Notion, Postgres e così via.
Payload di esempio dal nodo 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"
}
}
}
I report di Strategy (
"product": "solutions") arrivano senza un oggettosummary, solo conreport.tokenereport.pdf_url.
Workflow 1: da AI Visibility a Google Sheets
Nodo 1: trigger Webhook
- HTTP method: POST
- Path:
surmado-signal(n8n genereràhttps://n8n.yourdomain.com/webhook/surmado-signal) - Response mode: Immediately (restituisce 200 OK non appena n8n riceve la richiesta)
Passa quell’URL a 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"
}'
Clicca Listen for test event nel nodo Webhook, poi avvia un report così n8n rileva la struttura del payload.
Nodo 2: IF
Condizione 1: {{ $json.event }} equals report.completed
Condizione 2: {{ $json.report.product }} equals signal
Combinazione: AND
Nodo 3: Google Sheets: Append row
Operation: Append Spreadsheet / Sheet: il tuo foglio di monitoraggio
Associazione delle colonne:
- 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 }}
Attiva il workflow. Ogni report AI Visibility completato viene ora tracciato.
Workflow 2: Site Audit con alert Slack condizionale
Webhook → IF (report.product = scan) → Google Sheets (sempre) → IF (report.summary.performance_score < 70) → Slack.
Messaggio 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 }}
Workflow 3: digest PDF di Strategy
Strategy non include una sintesi. Schema:
- Webhook → IF (
report.product = solutions) → Send Email (Gmail, SMTP, SendGrid).
Corpo dell’email:
<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>
Recuperare dati più approfonditi tramite REST API
La sintesi del webhook copre la maggior parte delle esigenze. Per la variazione tra piattaforme, i problemi pagina per pagina o i dettagli sulle lacune di contenuto, aggiungi un nodo HTTP Request dopo il filtro:
Nodo: HTTP Request
- Method: GET
- URL:
https://api.surmado.com/v1/reports/{{ $json.report.id }} - Authentication: predefined credential → Surmado API (l’Header Auth che hai creato sopra)
- Response format: JSON
I nodi successivi possono poi usare {{ $json.public_intelligence.data.platform_variance.chatgpt.presence_score }}, {{ $json.public_intelligence.data.audit_data.enrichment.content_gaps.executive_summary }} e così via.
Verifica della firma del webhook
In produzione, verifica l’header X-Surmado-Signature prima di fidarti del payload. Surmado firma i webhook con HMAC-SHA256 su una rappresentazione JSON canonicalizzata.
Nodo Function: verifica della firma
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 }];
Catena: Webhook → Function (verifica) → IF (filtro) → nodi di destinazione.
Formati dei token
- AI Visibility:
SIG-YYYY-MM-XXXXX(regex:SIG-\d{4}-\d{2}-[A-Z0-9]{5}) - Site Audit:
SCN-YYYY-MM-XXXXX(regex:SCN-\d{4}-\d{2}-[A-Z0-9]{5}) - Strategy:
SOL-YYYY-MM-XXXXX(regex:SOL-\d{4}-\d{2}-[A-Z0-9]{5})
I token non scadono. Gli URL di download firmati della REST API sono validi per circa 15 minuti; i magic link pdf_url nei webhook sono validi per circa 30 giorni.
Schemi avanzati
Instradare per prodotto con Switch
Usa un nodo Switch su $json.report.product con i casi signal, scan, solutions. Ogni caso porta a un workflow specifico per prodotto. Un solo URL webhook gestisce ogni tipo di report.
Salvare in Postgres per analisi di serie storiche
Aggiungi un nodo Postgres dopo il filtro IF che esegue un INSERT di (timestamp, token, report_id, product, business_name, presence_score, authority_score, ...) in una tabella dei report. Poi interroga i dati con Grafana o Metabase per costruire grafici di andamento.
Instradamento multi-cliente per agenzie
Usa un Data store (o un database esterno) che associa business_name / brand_slug alla configurazione del cliente (quale canale Slack, quale scheda del foglio e così via). Fai la ricerca a ogni report e instrada in modo dinamico.
Risoluzione dei problemi
Il webhook non parte: attiva il workflow (n8n elabora i webhook solo quando è attivo, non durante i test). Controlla che webhook_url sia stato impostato quando hai creato il report. Usa webhook.site come URL di prova per verificare che Surmado invii il payload previsto.
Il nodo HTTP Request restituisce 401: la credenziale non è collegata, oppure alla chiave manca il prefisso Bearer . Il valore completo dell’header deve essere Bearer sur_live_....
I campi sono vuoti nei nodi successivi: controlla il tipo di prodotto. I webhook di Strategy non includono report.summary; sono valorizzati solo report.token e report.pdf_url.
Il webhook self-hosted non è raggiungibile: Surmado richiede HTTPS. Se esegui n8n su localhost, usa un tunnel (ngrok, Cloudflare Tunnel) oppure distribuiscilo dietro un reverse proxy con un certificato TLS valido.
La verifica della firma fallisce con caratteri non ASCII: la funzione canonicalize qui sopra li gestisce; se ne hai scritta una tua, assicurati di fare l’escape ASCII dei caratteri non ASCII, in modo da ottenere lo stesso output di json.dumps(..., ensure_ascii=True) di Python usato da Surmado.
Correlati: Guida all’integrazione API | Dati strutturati e Intelligence Token | Integrazione con Zapier | Integrazione con Make | Integrazione con Notion