Ein n8n-Flow, der Account-seitige Intent-Spikes aus Common Room, 6sense (via Salesforce-CRM-Sync) und Bombora (via Salesforce-CRM-Sync) erfasst, innerhalb eines tagesweisen Zeitfensters dedupliziert, jeden Spike dem bestehenden Salesforce-Account-Owner oder einem territorialen SDR-Pool zuweist, Claude beauftragt, eine Erstkontakt-Nachricht zu entwerfen — verankert in den spezifischen Themen, die der Account gerade recherchiert — und den vollständigen Kontext inklusive Entwurf als Slack-Benachrichtigung und als Salesforce-Task ausliefert. Das Bundle unter apps/web/public/artifacts/intent-spike-handler-n8n/ enthält den vollständigen n8n-Export sowie eine _README.md mit Import-Anleitung, Umgebungsvariablen, Credential-Setup, Salesforce-Custom-Fields und Branch-Verifikation.
Wann man diesen Flow verwendet
Verwenden Sie ihn, wenn Ihre Intent-Daten bereits in Salesforce fließen (via Managed Packages von 6sense oder Bombora) oder Common Room, das Follow-up der Reps bei Spikes aber inkonsistent ist — manche Accounts werden innerhalb einer Stunde bearbeitet, andere bleiben tagelang unberührt, weil das Signal in einer CRM-View einging, die niemand prüft. Das Symptom ist, dass das Reporting Ihrer Intent-Plattform Accounts mit hohem Spike zeigt, die in derselben Woche nie einen Erstkontakt erhalten haben.
Der Flow ist außerdem das richtige Muster, wenn mehr als ein SDR ein Territorium betreut und Spikes automatisch zum richtigen Rep geroutet werden sollen, anstatt in einem gemeinsamen Posteingang zu landen, in dem die Zuständigkeit unklar ist. Die Zuteilungslogik prüft zunächst den bestehenden Salesforce-Account-Owner; existiert kein Account, routet sie je nach Rechnungsland des Accounts in den SDR-Pool AMER, EMEA oder ROW. Diese Regel steckt in einem Code-Node, nicht in einer Konfigurationsdatei — das Ops-Team kann sie also prüfen und ändern, ohne ein Ticket zu öffnen.
Das Design „Entwurf statt Versand” ist bewusst gewählt. Intent-Daten zeigen, dass ein Account ein Thema recherchiert — nicht, dass eine bestimmte Person kaufbereit ist. Der Claude-Entwurf ist ein Ausgangspunkt, den der SDR vor dem Versand bearbeitet. Er referenziert die spezifischen Recherche-Themen des Accounts und reduziert die Recherchezeit des SDR von 10–15 Minuten auf unter 2 Minuten, aber das Urteil des Reps über Timing und Ton bleibt im Prozess.
Wann man den Flow NICHT verwendet
Überspringen Sie ihn, wenn Ihre Intent-Plattformen keine Daten nach Salesforce synchronisieren. Der Polling-Pfad hängt von Salesforce-Account-Feldern ab, die von den Managed Packages von 6sense oder Bombora geschrieben werden. Ohne diese Felder liefert der Polling-Pfad null Zeilen. Der Echtzeit-Pfad (Common-Room-Outgoing-Webhooks) funktioniert unabhängig davon, aber wenn Sie keine dieser Integrationen betreiben, gibt es nichts zu verarbeiten.
Überspringen Sie ihn auch, wenn Ihr SDR-Team weniger als 3 Reps hat und Intent-Signale täglich in der Plattform-UI prüft. In dieser Größe und mit dieser Disziplin erzeugt die Benachrichtigungsschicht Infrastrukturkosten, ohne die Reaktionszeit wesentlich zu verändern.
Verwenden Sie diesen Flow nicht als einzigen Priorisierungsmechanismus für wichtige Accounts. Der Flow übernimmt die Benachrichtigung und Task-Erstellung; er ersetzt nicht das wöchentliche Account-Review, bei dem AE und SDR entscheiden, welche Spikes priorisiert werden. Eine hochgradig-dringlich-Slack-Benachrichtigung bedeutet nicht, dass der Account kaufbereit ist — sie bedeutet, dass jemand in diesem Unternehmen relevante Themen recherchiert. Der Rep entscheidet, was damit zu tun ist.
Beachten Sie schließlich, dass dieser Flow nicht behandelt, ob dieselbe Person bereits kontaktiert wurde. Er sucht den Salesforce-Account, prüft aber nicht, ob ein Kontakt dieses Accounts bereits in einer aktiven Sequenz ist. Bevor der SDR den Claude-Entwurf versendet, sollte er in seinem Sequenzierungstool prüfen, dass der Kontakt nicht bereits eingeschrieben ist.
Setup
Bundle importieren. Laden Sie apps/web/public/artifacts/intent-spike-handler-n8n/intent-spike-handler-n8n.json in n8n via Workflows → Import from File. Zwei Einstiegspunkte: ein Webhook für den Echtzeit-Pfad von Common Room und ein Schedule-Trigger, der Salesforce alle 4 Stunden für den 6sense/Bombora-CRM-Sync-Pfad abfragt.
Umgebungsvariablen setzen. Der Flow verwendet 10 Umgebungsvariablen (Instanz-URLs, SDR-Pool-E-Mails und Slack-Handles). Setzen Sie diese in n8n Cloud unter Settings → Environment Variables oder in Ihrer selbst-gehosteten .env-Datei. Die vollständige Liste mit Fundort jedes Werts steht in der _README.md.
Credentials verknüpfen. Vier Credentials sind erforderlich:
PLACEHOLDER_ANTHROPIC_CRED_ID — HTTP Header Auth mit x-api-key auf Ihren Anthropic-Schlüssel gesetzt
PLACEHOLDER_SLACK_CRED_ID — HTTP Header Auth mit Authorization: Bearer xoxb-…
PLACEHOLDER_SALESFORCE_CRED_ID — HTTP Header Auth mit Authorization: Bearer <sfdc_token>
Keine direkte 6sense- oder Bombora-Credential ist in n8n erforderlich — Daten kommen über Salesforce-Account-Felder, die von den Vendor-Packages geschrieben werden
Salesforce-Custom-Fields anlegen. Drei Felder im Task-Objekt: Intent_Spike_Source__c (Text 50), Intent_Score__c (Number 18,0), Intent_Buying_Stage__c (Text 50). Die Account-Felder von 6sense und Bombora werden von den jeweiligen Vendor-Packages installiert — prüfen Sie, ob die API-Namen mit denen in Ihrer Org übereinstimmen.
Common Room verknüpfen (Echtzeit-Pfad). In Common Room einen Outgoing-Webhook anlegen, der auf https://<ihr-n8n-host>/webhook/intent-spike-handler zeigt, mit Payload-Typ Organization. Einen Workflow-Trigger auf das Signal konfigurieren, das für Ihr Team einen Spike definiert.
Jeden Pfad verifizieren. Die fünf Verifikationsschritte in der _README.md abarbeiten, bevor der Workflow aktiviert wird.
Was der Flow macht
Webhook — Intent Spike Ingest akzeptiert POST-Requests und gibt sofort 202 an den Aufrufer zurück. Normalize Intent Payload ist ein Code-Node, der drei Payload-Formen verarbeitet: das Common-Room-Organisation-Webhook-Format (erkannt an type: "organization"), eine 6sense-CRM-Sync-Form, die vom Polling-Cron weitergeleitet wird (erkannt an _source: "6sense"), und eine Bombora-CRM-Sync-Form (erkannt an _source: "bombora"). Der Normalisierungsschritt mappt jede Form auf einen einheitlichen internen Datensatz mit konsistenten Feldern: domain, accountName, intentScore, buyingStage, topTopics, spikeSeverity. Die Spike-Schwere (niedrig/mittel/hoch) wird zuerst aus dem Buying Stage abgeleitet (Decision und Purchase → hoch; Consideration → mittel; Awareness und Target → niedrig) und als Fallback aus dem numerischen Intent-Score (≥70 = hoch, 40–69 = mittel, <40 = niedrig).
Dedup Gate (Static Data) ist ein einzelner Code-Node, der die gesamte Deduplizierung an einer Stelle über die statischen Workflow-Daten von n8n abwickelt — $getWorkflowStaticData('global'). Dieses Objekt ist der einzig korrekte Weg, um Zustand über Ausführungen hinweg aus einem Code-Node zu persistieren: Die öffentliche REST-API von n8n hat keine static-data-Ressource, ein früherer HTTP-basierter Entwurf hätte daher bei jedem Aufruf 404 zurückgegeben und das Gate hätte nie ausgelöst — und genau die wiederholten Benachrichtigungen erzeugt, die es verhindern soll. Der Node liest/schreibt einen Schlüssel pro Account und Tag (dedup_acme.com_2026-05-23). Existiert der Schlüssel bereits, hat der Flow diesen Account heute schon verarbeitet, und der Node gibt ein leeres Array zurück und stoppt die Ausführung lautlos. Andernfalls stempelt er den Schlüssel vor jedem externen Aufruf — was eine Race-Condition verhindert, bei der zwei gleichzeitige Spikes derselben Domain beide passieren — und entfernt Schlüssel früherer Tage, damit der Speicher klein bleibt. Das tagesweise Fenster ist der richtige Dedup-Horizont, weil Intent-Plattformen Accounts häufig alle paar Stunden neu bewerten; ohne Fenster würde derselbe Spike 4–6 Benachrichtigungen pro Tag und Account erzeugen. Ein Hinweis: n8n persistiert statische Daten nur bei Produktionsausführungen (Webhook oder Schedule Trigger), nicht bei manuellen Testläufen — die Deduplizierung wird daher durch zweimaliges Aufrufen des Live-Webhooks verifiziert, nicht über den Execute-Workflow-Button.
Salesforce — Account Lookup fragt Salesforce nach einem Account ab, bei dem das Website-Feld die Domain des Spikes enthält. Assignment Logic nutzt das Ergebnis: Wurde ein Account gefunden, erhält der bestehende Owner den Spike, und der Node erfasst die Salesforce-User-Id des Owners (OwnerId, eine 15/18-stellige Id, die mit 005 beginnt) zur Verwendung als Task-Owner. Wurde kein Account gefunden, wählt der Node anhand des Rechnungslandes einen Pool (AMER, EMEA, ROW). Pool-E-Mails und Slack-Handles kommen aus Umgebungsvariablen.
Claude — Draft First Touch sendet eine Anfrage an die Anthropic-API mit claude-haiku-4-5, einem Timeout von 8 Sekunden und neverError: true. Der System-Prompt verbietet explizit Füllphrasen und weist Claude an, die spezifischen Recherche-Themen zu referenzieren — nicht generischen Branchen-Pain. Parse Draft (with fallback) behandelt Claude-Timeouts oder fehlerhaftes JSON, indem er einen template-basierten Entwurf mit dem Tag draftSource: template-fallback erzeugt.
Slack — Notify Assignee postet in #intent-spikes mit einer strukturierten Block-Kit-Nachricht: eine Kopfzeile mit Schwere-Indikator und @-Erwähnung des Slack-Handles des Zugewiesenen, ein Firmografik-Block und der Claude-Entwurf mit explizitem Hinweis „vor dem Versand bearbeiten”. Salesforce — Create Task erstellt einen Task am Account (via WhatId) mit vollem Kontext im Beschreibungsfeld. Wurde der Account-Owner aufgelöst, wird die OwnerId des Tasks auf dessen Salesforce-User-Id gesetzt — nie auf eine E-Mail, die Salesforce mit MALFORMED_ID ablehnt. Wurde der Spike an einen SDR-Pool geroutet (kein Account), wird die OwnerId weggelassen, sodass der Task standardmäßig dem Integrationsbenutzer gehört; ebenso wird die WhatId weggelassen statt leer gesendet, und der vorgesehene Rep wird in der Beschreibung festgehalten und in Slack @-erwähnt.
Der zweite Einstiegspunkt — Polling Cron — Every 4h — fragt Salesforce alle 4 Stunden nach Accounts ab, die in den letzten 4 Stunden geändert wurden und deren 6sense-Buying-Stage Decision oder Purchase ist oder deren Bombora-Surge-Level hoch ist. Build Forward Payloads konvertiert jeden Account-Datensatz in die passende Payload-Form, und Forward to Ingest Webhook sendet jeden an den Haupt-Webhook mit batchSize: 3 und batchInterval: 3000ms.
Kosten in der Praxis
Pro Spike empfängt claude-haiku-4-5 etwa 700 Input-Tokens und erzeugt rund 150 Output-Tokens für den dreiteiligen Entwurf. Zu Haiku 4.5-Preisen (~$0,80/M Input, ~$4/M Output) sind das rund $0,0009 pro Spike — unter $0,001. Für ein Team, das 500 Intent-Spikes pro Monat verarbeitet, liegen die Claude-Kosten unter $0,50/Monat. Das Dedup-Fenster sorgt dafür, dass Accounts mit hohem Volumen, die mehrfach täglich spiken, nur einmal pro Tag und Account abgerechnet werden.
Die Salesforce-API-Calls (eine Abfrage + eine Task-Erstellung pro Spike) verbrauchen das tägliche API-Call-Limit Ihrer Org. Salesforce Enterprise erlaubt standardmäßig 150.000 API-Calls pro 24 Stunden; mit 500 Spikes/Monat (~17/Tag) verwendet dieser Flow rund 34 Calls/Tag. Der Polling-Pfad fügt alle 4 Stunden eine Batch-Abfrage hinzu (6 Abfragen/Tag), unabhängig vom Spike-Volumen.
Fehlermodi
Feldnamen von 6sense / Bombora stimmen nicht überein. Die SOQL-Abfrage in Salesforce — Poll Intent Fields verwendet spezifische API-Namen. Wenn Ihr Vendor das Managed Package mit anderen Feldnamen installiert hat, gibt die Abfrage lautlos null Zeilen zurück. Guard: Führen Sie nach dem Import Salesforce — Poll Intent Fields manuell aus und prüfen Sie die Rohausgabe. Kommen Datensätze zurück, aber die Intent-Felder sind null, vergleichen Sie die API-Namen im SOQL mit denen in Ihrem Account-Objekt unter Salesforce Setup → Object Manager.
Statische Dedup-Daten persistieren nur bei Produktionsausführungen. Der Node Dedup Gate (Static Data) liest und schreibt $getWorkflowStaticData('global'), das n8n nur dann in seiner Datenbank speichert, wenn die Ausführung in Produktion ausgelöst wird (ein echter Webhook-POST oder der Schedule Trigger) — nie bei einer manuellen Execute-Workflow-Ausführung. Wenn Sie die Deduplizierung testen, indem Sie zweimal auf Execute Workflow klicken, sieht der zweite Lauf den Schlüssel des ersten nicht, und das Gate scheint defekt, obwohl es wie vorgesehen funktioniert. Guard: Aktivieren Sie den Workflow und senden Sie zweimal einen POST an die Live-Webhook-URL, um den Block zu verifizieren (die Verifikation in der _README.md weist darauf hin). Der Node entfernt bei jedem Lauf Schlüssel früherer Tage, sodass der Speicher sich selbst bereinigt und nicht unbegrenzt wächst; ein separater Wartungs-Cron ist nicht nötig.
Rotation des Salesforce-Bearer-Tokens bricht den Polling-Pfad. Das rohe Bearer-Token in SFDC_ACCESS_TOKEN rotiert standardmäßig alle 2 Stunden. Wenn es abläuft, geben die Salesforce-Nodes lautlos 401-Fehler zurück (wegen neverError: true). Guard: Beobachten Sie ein Muster, bei dem Salesforce-Nodes leere Ergebnisse zurückgeben, obwohl Sie wissen, dass Intent-Spikes auftreten. Ersetzen Sie für die Produktion den rohen Bearer-Token-Ansatz durch eine Salesforce-Connected-App mit OAuth-2.0-Client-Credentials-Flow.
Claude-Entwurf referenziert veraltete Themen. Das topTopics-Feld von Common Room oder Bombora ist ein semikolon-delimitierter String aus dem letzten Synchronisierungsfenster der Plattform. Wenn die Plattform seit mehr als 12 Stunden nicht synchronisiert hat, können die Themen Recherchen von vor zwei Tagen widerspiegeln. Guard: Die Slack-Benachrichtigung enthält den receivedAt-Zeitstempel und die Intent-Quelle, damit der SDR das Signalalter prüfen kann, bevor er auf der Grundlage des Entwurfs handelt.
vs Alternativen
vs native 6sense Workflows (Orchestrations). Die Orchestrations von 6sense können Aktionen auslösen, wie das Einschreiben von Kontakten in Outreach- oder Salesloft-Sequenzen direkt aus Intent-Signalen. Das ist das richtige Tool, wenn Ihre Aktion die Einschreibung in eine bestehende Sequenz ist. Es ist nicht das richtige Tool, wenn Sie Folgendes wollen: (a) einen Nachrichtenentwurf, der auf die spezifischen Recherchethemen zugeschnitten ist, (b) einen Salesforce-Task als Erstkontakt-Datensatz, oder (c) Multi-Source-Normalisierung zwischen 6sense und Bombora im selben Routing-Pfad. Der n8n-Flow lässt sich mit Orchestrations kombinieren — nutzen Sie Orchestrations für die Sequenzeinschreibung und diesen Flow für die Benachrichtigungs- und Task-Erstellungsschicht.
vs manuelle SDR-Triage. Der Status quo für die meisten Teams ist ein gemeinsamer Slack-Kanal oder eine CRM-View, in der Intent-Signal-Zusammenfassungen ankommen. SDRs prüfen, wenn sie Zeit haben. Der Hauptkostenfaktor ist die Reaktionslatenz — die mediane Zeit vom Spike bis zum Erstkontakt wird in Tagen gemessen, nicht in Stunden. Dieser Flow garantiert keine schnellere Reaktion; er garantiert, dass der richtige Rep den Spike sofort mit dem nötigen Kontext sieht.
vs eine Clay-Tabelle, die Intent-Signale scrapet. Clay kann Bombora- oder 6sense-Daten in eine Tabelle ziehen, anreichern und angereicherte Zeilen an Salesforce oder ein Sequenzierungstool senden. Das ist ein guter Fit für Batch-Outbound-Prospecting-Durchläufe (wöchentlich, nicht echtzeit). Clay-Tabellen sind nicht event-driven — verwenden Sie Clay für die Prospecting-Schicht und diesen Flow für die Echtzeit-Spike-Response-Schicht.
# Intent spike handler — n8n flow
This bundle contains a complete n8n workflow that catches account-level intent spikes from Common Room, 6sense (via Salesforce CRM sync), and Bombora (via Salesforce CRM sync), deduplicates within a day-level window, looks up the Salesforce account owner, assigns the spike to the right rep or SDR pool by territory, drafts a first-touch message with Claude, posts a Slack notification to the assignee, and creates a Salesforce Task with full context.
Two entry points:
- **Real-time path** — `Webhook — Intent Spike Ingest` accepts `POST /webhook/intent-spike-handler` from Common Room outgoing webhooks (or any system that can POST a structured payload).
- **Polling path** — `Polling Cron — Every 4h` queries Salesforce every 4 hours for Accounts modified with Decision/Purchase buying stage (6sense) or high Bombora surge, then forwards each as a self-POST to the ingest webhook.
## What this flow does
The webhook normalizes multi-source intent payloads (Common Room organization shape, 6sense CRM-sync shape, Bombora CRM-sync shape) into a single internal record. A day-level dedup check prevents the same account from firing multiple times in a day — a direct response to the reality that intent platforms re-evaluate scores on short windows and will otherwise flood reps with repeat notifications for the same signal. The dedup window is set at day-level (not hour-level) because the relevant question is not "did the score tick up again?" but "has this rep been notified today?"
Dedup runs entirely inside one Code node (`Dedup Gate (Static Data)`) using n8n's workflow static data — `$getWorkflowStaticData('global')`. That is the only correct way to persist cross-execution state from a Code node: n8n's public REST API has **no** static-data resource, so an HTTP-based approach would 404 and the gate would never fire. The node reads/writes a `dedup_<domain>_<date>` key, prunes keys from previous days on every run (so the store stays small), and stamps the key before any external call so two concurrent spikes for the same domain can't both pass. Important: workflow static data only persists for **production** executions (webhook / Schedule Trigger) — not manual test runs — so dedup is verified live (see step 2 below), not via the manual Execute Workflow button.
Assignment logic prioritizes the existing Salesforce Account owner. If no Account exists, the spike routes to a territory-based SDR pool (AMER, EMEA, ROW) configured via environment variables. Claude generates a three-part draft: a subject line, a short outreach body anchored to the specific topics the account is researching, and a talking point for the SDR's call prep. The draft is explicitly labeled a starting point in the Slack message — it ships as prose the rep edits, not as a send-ready email.
## Import
1. In n8n, open **Workflows → Import from File** and select `intent-spike-handler-n8n.json`.
2. Open the workflow's **Settings** and confirm `Execution Order` is `v1` and `Timezone` is set to match your business hours (defaults to `America/New_York`). The cron interprets its schedule in this zone. The dedup window rolls over at UTC midnight (the key uses the UTC date); if you need it aligned to a local business day, change the date derivation in `Dedup Gate (Static Data)` to use the workflow timezone.
3. Set the environment variables listed in the **Environment variables** section below.
4. Wire all four credentials listed in the **Credentials** section.
5. Create the three Salesforce custom fields listed in the **Salesforce custom fields** section.
6. Activate the workflow only after the first-run verification below passes.
## Environment variables
Set these in your n8n instance's environment (n8n Cloud: **Settings → Environment Variables**; self-hosted: your `.env` file or container environment):
| Variable | Where to find it | Example |
|---|---|---|
| `N8N_SELF_URL_HOST` | Your n8n instance's public hostname, no trailing slash. Used by the polling path to self-POST forwarded spikes to the ingest webhook. | `n8n.example.com` |
| `SFDC_INSTANCE_URL` | Salesforce Setup → Company Information → Salesforce.com Base URL | `https://yourorg.my.salesforce.com` |
| `SFDC_ACCESS_TOKEN` | From your Salesforce connected app OAuth flow | `00D…` |
| `SDR_POOL_AMER_EMAIL` | SDR pool lead email for AMER territory | `sdr-amer@yourcompany.com` |
| `SDR_POOL_AMER_SLACK` | Slack handle (no @) for AMER SDR pool | `sdr-amer` |
| `SDR_POOL_EMEA_EMAIL` | SDR pool lead email for EMEA territory | `sdr-emea@yourcompany.com` |
| `SDR_POOL_EMEA_SLACK` | Slack handle (no @) for EMEA SDR pool | `sdr-emea` |
| `SDR_POOL_ROW_EMAIL` | SDR pool lead email for ROW territory | `sdr-row@yourcompany.com` |
| `SDR_POOL_ROW_SLACK` | Slack handle (no @) for ROW SDR pool | `sdr-row` |
The `SFDC_ACCESS_TOKEN` rotates. For production, use a Connected App with OAuth 2.0 client credentials flow and a short-lived token refresh node, or use the Salesforce OAuth2 credential in n8n instead of the raw Bearer token approach.
## Credentials
### `PLACEHOLDER_ANTHROPIC_CRED_ID` — Anthropic
Used by `Claude — Draft First Touch`. Generate an API key at `https://console.anthropic.com`. In n8n, add an **HTTP Header Auth** credential with header name `x-api-key` and value set to the key. The node uses `claude-haiku-4-5` to keep the latency under 2 seconds on a typical account payload. Swap to `claude-sonnet-4-6` only if draft quality is consistently off for complex industry segments — the cost difference is roughly 10×.
### `PLACEHOLDER_SLACK_CRED_ID` — Slack bot token
Used by `Slack — Notify Assignee`. Create a Slack app at `https://api.slack.com/apps`, add the `chat:write` bot scope, install it to your workspace, and invite the bot user to `#intent-spikes`. In n8n, add an **HTTP Header Auth** credential with header name `Authorization` and value `Bearer xoxb-…`. Create `#intent-spikes` as the landing channel before activating; you can split high-severity spikes to a separate `#intent-spikes-hot` channel by modifying the channel field in `Slack — Notify Assignee`.
### `PLACEHOLDER_SALESFORCE_CRED_ID` — Salesforce Bearer token
Used by `Salesforce — Account Lookup`, `Salesforce — Create Task`, and `Salesforce — Poll Intent Fields`. In n8n, add an **HTTP Header Auth** credential with header name `Authorization` and value `Bearer <your_token>`. For a stable long-running credential, create a Salesforce Connected App with OAuth 2.0 and configure a token refresh; the raw Bearer approach works for initial setup but rotates every 2 hours by default. The credential requires `api`, `read`, `write`, and `chatter_api` OAuth scopes at minimum.
**Task ownership.** When the account lookup finds an existing Account, `Salesforce — Create Task` sets the Task's `OwnerId` to that Account owner's Salesforce **User Id** (a 15/18-char Id starting with `005`), which the lookup returns. Salesforce `OwnerId` does not accept an email address — passing one fails with `MALFORMED_ID`. When no Account is found (the spike routes to a territory SDR pool), `OwnerId` is omitted entirely, so the Task defaults to the user behind this credential (the integration/running user); the intended SDR pool is recorded in the Task Description and the rep is @-mentioned in the Slack notification. To hand these pool Tasks off to a real Salesforce queue or user, add a step that resolves a User/Queue Id (prefix `005`/`00G`) and set `OwnerId` to it.
### `PLACEHOLDER_6SENSE_CRED_ID` / Common Room (for real-time path)
The real-time webhook path accepts payloads from **Common Room outgoing webhooks**. In Common Room, go to **Settings → Webhooks → Add webhook**, set the Payload URL to `https://<your-n8n-host>/webhook/intent-spike-handler`, choose **Organization** as the payload type, and configure a workflow trigger on "contacts meeting criteria" or "new activity" filtered to high-intent signals. No n8n credential is required for this — the webhook is public; optionally verify the `x-commonroom-webhook-secret` header in the `Normalize Intent Payload` node if you add a shared secret.
The polling path uses 6sense and Bombora data **already synced into Salesforce** via those platforms' native managed packages. No direct 6sense or Bombora API credentials are needed in n8n — the Salesforce credential covers the poll.
## Salesforce custom fields
Create these three custom fields on the **Task** object in Salesforce Setup → Object Manager → Task → Fields & Relationships:
| API Name | Field Type | Notes |
|---|---|---|
| `Intent_Spike_Source__c` | Text (50) | Stores `common-room`, `6sense`, `bombora`, or `generic` |
| `Intent_Score__c` | Number (18, 0) | Stores the raw intent score (0–100) |
| `Intent_Buying_Stage__c` | Text (50) | Stores the buying stage string from the source |
The 6sense and Bombora **Account** fields queried by `Salesforce — Poll Intent Fields` are installed by each vendor's managed package. Verify the following API names exist on your Account object before activating the polling path:
- **6sense:** `sixsense_Intent_Score__c`, `sixsense_Buying_Stage__c`, `sixsense_Top_Topics__c`
- **Bombora:** `Bombora_Composite_Score__c`, `Bombora_Surge_Level__c`, `Bombora_Top_Topics__c`
If your managed package uses different API names, update the SOQL query in `Salesforce — Poll Intent Fields` to match.
## First-run verification
Run each path before enabling the cron or wiring Common Room:
**Note on testing dedup:** workflow static data only persists across **production** executions (a real `POST` to the webhook URL, or a Schedule Trigger run), not manual **Execute Workflow** runs. Activate the workflow and `curl` the webhook for steps 1–2 so the dedup key actually persists between the two requests.
1. **High-severity spike (Common Room shape).** `POST` to `https://<your-n8n-host>/webhook/intent-spike-handler` (workflow active) with:
```json
{
"body": {
"type": "organization",
"version": "1",
"name": "Acme Corp",
"domain": "acme-test-spike.com",
"industry": "Software",
"employeeCount": 500,
"location": { "country": "US" },
"technologies": ["Salesforce", "Slack"],
"customFields": {
"sixsense_buying_stage": "Decision",
"sixsense_intent_score": 78,
"sixsense_top_topics": "CRM automation,pipeline management"
}
}
}
```
Expected: dedup passes (no prior key), Slack message lands in `#intent-spikes` with red circle, Salesforce Task created with `Priority: High`, Claude draft present.
2. **Dedup block — same domain same day.** `POST` the identical payload from step 1 a second time (workflow still active). Expected: `Dedup Gate (Static Data)` finds the existing `dedup_acme-test-spike.com_<today>` key and returns an empty array — no Slack message, no Salesforce Task.
3. **Mid-severity spike (Bombora CRM-sync shape).** Send:
```json
{
"_source": "bombora",
"domain": "midco-test-spike.com",
"company_name": "MidCo",
"country": "DE",
"composite_score": 55,
"surge_level": "medium",
"topics": [{ "topic": "data integration" }, { "topic": "ETL tools" }]
}
```
Expected: spike severity maps to `medium`, EMEA SDR pool assigned, yellow circle in Slack.
4. **Claude failure fallback.** Temporarily revoke the Anthropic credential and send any payload. Expected: `Parse Draft (with fallback)` outputs a template-based draft tagged `draftSource: template-fallback`; Slack message and Salesforce Task still fire with the fallback draft.
5. **Polling path.** In Salesforce, set one test Account's `sixsense_Buying_Stage__c` to `Decision` and bump `SystemModstamp` (edit any field and save). Trigger `Polling Cron — Every 4h` manually. Expected: the Account appears in the SOQL results, `Build Forward Payloads` fans it out, `Forward to Ingest Webhook` POSTs it to the main webhook, and the full real-time path runs (dedup key will differ since domain is different from steps 1-4).
Only after all five pass should you enable the workflow and wire Common Room.