CRM — Resolve Context
Sub-workflow: from a seller mailbox and a customer e-mail, returns the Membership, the person and the open Deal in the CRM.
- Platform
- n8n · Open in n8n
- Status
- Inactive
- Workflow ID
WkbRsPadLZfEgxTu- Nodes
- 11
- n8n version
044a2d8c-ed1f-463f-9eae-3a8498928609- Last saved in n8n
- 2026-11-06T21:25:38.009Z
- Systems
- CRMTooling and Access
- Called by
- Email Capture
CRM — Resolve Context answers one question for other workflows: given a seller’s mailbox and a customer’s e-mail address, who are they in the CRM? It returns the seller’s Membership and company, the customer as a CRM person with their company, and the customer’s open Deal, preferring the one owned by that seller. It only reads. It never creates a person or a Deal.
It is a sub-workflow: it has no trigger of its own and runs when another workflow calls it. Email Capture calls it once per e-mail. Cal.com Booking Intake still does the same lookups inline; moving it to this sub-workflow is a pending work item.
The CRM maintainer owns the Membership, People and Deal records it reads; the Tooling and Access maintainer owns the Tool Account and its Identity Binding.
Flow
Generated from the n8n version in the box above: every box is a node and every arrow is a connection in n8n. Pink pills are triggers, yellow hexagons are If and Switch nodes with their outputs on the arrows, blue cylinders read (Airtable, Data Table, HTTP GET), green cylinders write, purple boxes call another workflow, and dashed arrows are error outputs.
Mermaid source
flowchart TD
subgraph g0["Request"]
n1(["Context Request"]):::trigger
n0["Build Lookups"]:::logic
end
subgraph g1["Seller"]
n6[("Find Tool Account<br/><small>GET Tooling Tool Account</small>")]:::read
n9["Resolve Seller"]:::logic
n3[("Find Membership (CRM)<br/><small>GET CRM Membership</small>")]:::read
n4[("Find Membership by Email<br/><small>GET CRM Membership</small>")]:::read
end
subgraph g2["Counterparty and open Deal"]
n5[("Find Person (CRM)<br/><small>GET CRM People</small>")]:::read
n8["Resolve Person"]:::logic
n2[("Find Deals<br/><small>GET CRM Deal</small>")]:::read
n7["Resolve Context"]:::logic
end
n1 --> n0
n0 --> n6
n6 --> n9
n9 --> n3
n3 --> n4
n4 --> n5
n5 --> n8
n8 --> n2
n2 --> n7
classDef trigger fill:#fde7f3,stroke:#d6409f,color:#111
classDef decision fill:#fff7e0,stroke:#c99a00,color:#111
classDef read fill:#e8f1ff,stroke:#3b82f6,color:#111
classDef write fill:#e7f8ee,stroke:#16a34a,color:#111
classDef subflow fill:#f3e8ff,stroke:#9333ea,color:#111
classDef wait fill:#f1f1f1,stroke:#888,color:#111
classDef logic fill:#ffffff,stroke:#999,color:#111Systems it touches
| System | Table | Reads | Writes |
|---|---|---|---|
| Tooling and Access | Tool Account | Find Tool Account | Nothing |
| CRM | Membership (mirror) | Find Membership (CRM), Find Membership by Email | Nothing |
| CRM | People (mirror) | Find Person (CRM) | Nothing |
| CRM | Deal | Find Deals | Nothing |
Every Airtable call is an HTTP Request node with an Airtable token credential. The reads filter by field name: {Login Alias} and {Tool} on Tool Account, {Membership #} and {Company Email} on the Membership mirror, {Email} on the People mirror, and record ids on Deal. Renaming one of those fields breaks the lookup without an error: the node returns no record and the flow continues as if nothing was found.
Input and output
Context Request receives three values from the caller:
| Input | Meaning |
|---|---|
sellerEmail |
The internal mailbox that sent or received the e-mail |
counterpartyEmail |
The external person’s address |
counterpartyName |
The display name from the e-mail, used only in notes |
Resolve Context returns one item:
| Output | Value |
|---|---|
toolAccountId |
The Tooling Tool Account of the seller, when found |
membershipId, membershipNumber |
The CRM Membership mirror record of the seller |
accountableCompanyId |
The Business Unit of that Membership |
personId, personName, personCompanyId |
The CRM People mirror record of the counterparty and the first company of their memberships |
dealId, dealStage |
The open Deal picked, when any |
openDealCount |
How many open Deals the person has |
notes |
Warnings and notes, one line each, for the caller to store |
Seller
Build Lookups lowercases both addresses and builds the formulas. Find Tool Account looks for the Tooling Tool Account whose Login Alias is the seller’s address and whose Tool contains Google Workspace. Resolve Seller reads its Bound Membership ID. Find Membership (CRM) looks for the Membership mirror record whose Membership # starts with that number followed by “ - “. Find Membership by Email looks for the Membership mirror record whose Company Email is the seller’s address.
Resolve Context takes the Membership found by number, then the one found by e-mail. Its Business Unit becomes the accountable company. The notes say which path was used and what is missing: no Tool Account and no Company Email; found by e-mail only (add an Identity Binding); Tool Account without a binding.
Counterparty and open Deal
Find Person (CRM) looks for the counterparty’s e-mail in the CRM People mirror. Resolve Person reads the person’s companies and the ids in Deals (Counterparty), and builds the Deal lookup. Find Deals reads those Deals.
Resolve Context keeps the Deals whose Deal Status is Open. When the seller is known as a CRM Person (the Member of the Membership found), it picks the first open Deal whose Accountable (Person)* contains them, and none otherwise. When the seller is unknown, it picks the first open Deal. The notes record a person not in the mirror, or a person without an open Deal.
Nodes
The workflow has 11 nodes: 10 that run and one sticky note.
| Node | Type | What it does |
|---|---|---|
| Context Request | executeWorkflowTrigger | Receives sellerEmail, counterpartyEmail and counterpartyName from the caller |
| Build Lookups | code | Lowercases the addresses and builds the three formulas |
| Find Tool Account | httpRequest | Tooling Tool Account by Login Alias and Tool |
| Resolve Seller | code | Reads Bound Membership ID and builds the Membership lookup by number |
| Find Membership (CRM) | httpRequest | CRM Membership mirror by membership number |
| Find Membership by Email | httpRequest | CRM Membership mirror by Company Email |
| Find Person (CRM) | httpRequest | CRM People mirror by counterparty e-mail |
| Resolve Person | code | Reads the person’s companies and builds the Deal lookup |
| Find Deals | httpRequest | The person’s Deals |
| Resolve Context | code | Picks the Membership and the open Deal; returns the context and the notes |
| Sticky Note | stickyNote | Setup note on the canvas; does not run |
Connections
| From | Output | To |
|---|---|---|
| Context Request | 0 | Build Lookups |
| Build Lookups | 0 | Find Tool Account |
| Find Tool Account | 0 | Resolve Seller |
| Resolve Seller | 0 | Find Membership (CRM) |
| Find Membership (CRM) | 0 | Find Membership by Email |
| Find Membership by Email | 0 | Find Person (CRM) |
| Find Person (CRM) | 0 | Resolve Person |
| Resolve Person | 0 | Find Deals |
| Find Deals | 0 | Resolve Context |
Settings and error handling
| Setting | Value |
|---|---|
| Status | Inactive; a sub-workflow runs when called even while inactive |
| Execution order | v1 |
| Error workflow | None |
| Retry on fail | On every HTTP Request node, 3 tries |
| On error | Stop the workflow (default) on every node; the caller receives the error |
| Caller policy | Workflows from the same owner |
| Execution data retention | Instance default; this workflow sets none |
Before activating
| Step | Where | State at the last review |
|---|---|---|
| Every seller mailbox has a Tool Account (Google Workspace, Login Alias = e-mail) with a valid Identity Binding | Tooling and Access | Pending; without it the seller resolves by Company Email only, or not at all |
| The Membership mirror in the CRM carries Company Email | CRM | Present |
Known gaps
| Gap | Effect |
|---|---|
| Find nodes read one page (up to 100 records) | A person with more than 100 Deals may get the wrong one |
| The first company of the person’s memberships is taken | A person with memberships in several companies gets the first one as personCompanyId |
| Without a seller Membership, the first open Deal is taken | The thread can land on another seller’s Deal |
| The Deal match ignores the stage | A Deal at a late stage is still the open one |
Keep this page in sync
The box at the top shows the n8n version this page describes. Open the workflow in n8n: when its last save is newer than the date in the box, this page is out of date until the next review. Every node and every connection of that version is in Nodes and Connections.