Skip to content
Notion Arena
💼
💼 Business & CRMProNative recipePopular

CRM Pipeline

Companies, people and deals: related databases with a board and a pipeline chart.

Version
v2.1.0
Updated
2026-10-07
Plan
Plus

The install plan

Exactly what Notion Arena sends to Notion, in order. Notion's data-source model forces two passes: relations, rollups and the formulas that read them need data_source_ids that only exist once the databases do.

26
requests
13
manual steps
1POST
/v1/pages

Create the “crm-pipeline” container page under the page you chose

2POST
/v1/databases

Create the “Companies” database with 10 base properties

3GET
/v1/databases/{companies_database_id}

Read back Companies to get its default data source id

4PATCH
/v1/data_sources/{companies_data_source_id}

Add 6 deferred properties to Companies: relations (with resolved data_source_ids), then the rollups and formulas that read them

5POST
/v1/databases

Create the “People” database with 9 base properties

6GET
/v1/databases/{people_database_id}

Read back People to get its default data source id

7PATCH
/v1/data_sources/{people_data_source_id}

Add 3 deferred properties to People: relations (with resolved data_source_ids), then the rollups and formulas that read them

8POST
/v1/databases

Create the “Deals” database with 13 base properties

9GET
/v1/databases/{deals_database_id}

Read back Deals to get its default data source id

10PATCH
/v1/data_sources/{deals_data_source_id}

Add 6 deferred properties to Deals: relations (with resolved data_source_ids), then the rollups and formulas that read them

11POST
/v1/views

Create the “Pipeline board” board view on deals

12POST
/v1/views

Create the “Weighted pipeline” chart view on deals

13POST
/v1/views

Create the “Closing this month” list view on deals

14POST
/v1/views

Create the “Slipped” table view on deals

15POST
/v1/views

Create the “Accounts gallery” gallery view on companies

16POST
/v1/views

Create the “Needs a touch” table view on people

17POST
/v1/pages

Seed 3 rows into Companies so the views are not empty on first open (one request per row; Notion has no bulk insert)

×3
18POST
/v1/pages

Seed 2 rows into People so the views are not empty on first open (one request per row; Notion has no bulk insert)

×2
19POST
/v1/pages

Seed 3 rows into Deals so the views are not empty on first open (one request per row; Notion has no bulk insert)

×3
20POST
/v1/pages

Create the “CRM: how this system works” page

21PATCH
/v1/blocks/{crm_how_this_system_works_page_id}/children

Append 13 blocks of page body

3 steps cannot be scripted: Button: “Log a call” on every Deal; Automation: stamp “Last stage change” when Stage moves; Automation: nudge the owner when a deal slips.

Run it yourselfNotion-Version 2026-03-11
curl -X POST https://notionarena.vercel.app/api/install \
  -H 'content-type: application/json' \
  -d '{
    "component": "crm-pipeline",
    "mode": "plan"
  }'

# add "token" and "parentPageId" and switch to "mode": "api" to install for real

What gets created

The real property schemas, not a description of them. Every formula below is a Notion Formula 2.0 expression you can paste into a property by hand if you would rather not use the API at all.

🏢

Companies

ref: companies
1× title1× url3× select1× number1× people1× date1× rich_text2× relation2× rollup2× formula1× created_time
Namen/a
Websiten/a
IndustrySoftware · Services · Retail · Finance +2
SegmentSMB · Mid-market · Enterprise
Employee countnumber
Account ownern/a
HealthHealthy · At risk · Critical
Next touchn/a
Notesn/a
People→ people (two-way)
Deals→ deals (two-way)
Open pipelinesum(Deals.Value)
Closed wonsum(Won deals.Value)
Lifetime valueprop("Closed won")
Days since touchif(empty(prop("Next touch")), 999, dateBetween(now(), prop("Next touch"), "days"))
Createdn/a
👤

People

ref: people
1× title1× rich_text1× email1× phone_number2× checkbox1× relation1× date1× multi_select1× created_by2× formula
Namen/a
Job titlen/a
Emailn/a
Phonen/a
Decision makern/a
Championn/a
Company→ companies
Last contactn/a
ChannelsEmail · Call · LinkedIn · Event
Added byn/a
Days quietif(empty(prop("Last contact")), 0, dateBetween(now(), prop("Last contact"), "days"))
Follow upifs(prop("Days quiet") > 30, "🔴 Overdue", prop("Days quiet") > 14, "🟡 Soon", true, "🟢 Fresh")
💰

Deals

ref: deals
1× title1× unique_id1× status2× number2× select1× date1× people2× relation1× checkbox1× rich_text4× formula1× created_time1× files
Namen/a
Deal IDprefix DL
StageLead → Qualified → Demo given → Proposal out +3
Valuedollar
CurrencyUSD · EUR · GBP · PKR
Probabilitypercent
Expected closen/a
Ownern/a
Company→ companies
Primary contact→ people
SourceInbound · Outbound · Referral · Event +1
Blockedn/a
Next stepn/a
Weighted valueprop("Value") * prop("Probability")
Days in stagedateBetween(now(), date(prop("Last stage change") ?? prop("Created")), "days")
Staleif(prop("Days in stage") > 21, "⚠️ Stale", "")
Overdueif(and(prop("Expected close") < now(), not(or(prop("Stage") == "Won", prop("Stage") == "Lost"))), "🔴 Slipped", "")
Createdn/a
Attachmentsn/a

Views

Created through POST /v1/views, which shipped in March 2026 and is the reason provisioning a workspace from code finally works end to end.

Pipeline boardboard

on deals

Weighted pipelinechart

on deals

Closing this monthlist

on deals

filter: {"and":[{"property":"Expected close","on_or_before":{"value":"en…

Slippedtable

on deals

filter: {"property":"Overdue","string":{"equals":"🔴 Slipped"}}…

Accounts gallerygallery

on companies

Needs a touchtable

on people

filter: {"property":"Follow up","string":{"equals":"🔴 Overdue"}}…

Documentation pages

Appended with real block types (headings, toggles, callouts, to-dos, column lists) in chunks of 100, the Append block children limit.

🧭CRM: how this system works13 blocks
🧭Three data sources, one pipeline. Deals hold the money, Companies hold the relationship, People hold the conversations. Every deal links to one company and one primary contact, and the rollups on Companies mean lifetime value is never stale.
The stage ladder

Stage is a Status property, not a Select. That matters: Status options belong to groups (To-do / In progress / Complete), so Notion's board view can group by group, and the group_does_not_equal filter operator can exclude everything closed in one condition.

StageGroupExit criterion
LeadTo-doA real person has replied
QualifiedTo-doBudget, authority and timeline confirmed
Demo givenIn progressTechnical evaluation started
Proposal outIn progressPricing sent in writing
NegotiationIn progressRedlines or procurement in play
Won / LostCompleteContract signed, or a written no
Formulas you will actually use
Weighted value
prop("Value") * prop("Probability")

Feed this into the chart view's Y axis with a sum aggregator and you get a forecast that respects probability, not just a count of deals.

Days in stage → Stale
dateBetween(now(), prop("Last stage change"), "days") > 21

Deals do not die loudly, they go quiet. This surfaces anything that has not moved in three weeks. It needs a date property that changes when the stage changes; set that with an automation (see the manual steps).


Adding a deal
Create the Company first if it does not exist. Never a deal without one
Set Value, Probability and Expected close on the same day you create it
Link a Primary contact; an unlinked deal has nobody to follow up with
Write the Next step in one sentence, as a verb

The parts the API cannot do

Every recipe ships with its manual steps written out, because pretending the API covers everything is how people end up with a half-built workspace. These are real Notion limitations, quoted from the API reference.

Button: “Log a call” on every Deal

Button properties are response-only in the Notion API: the schema is returned on read, but the API ignores button settings on write and cannot create a button or configure its actions.

  1. 1Open the Deals database → ••• → Property → Button.
  2. 2Name it “Log a call”.
  3. 3Action 1: Add page to → People. Pre-fill Company with the deal's Company, and Last contact with Today.
  4. 4Action 2: Edit pages in → Deals (this page). Set Last touch to Today.
  5. 5Place the button in the Deals page layout so it sits above the notes.

Automation: stamp “Last stage change” when Stage moves

Database automations have no public API surface. They are configured per-database in the Notion app under ••• → Automations.

  1. 1Deals → ••• → Automations → New automation.
  2. 2Trigger: Stage changes. Leave “from” as Any.
  3. 3Action: Edit page → set Last stage change to Today.
  4. 4Optional second action: add a Slack message to #sales when Stage becomes Won.
  5. 5This is what makes the Days in stage formula meaningful.

Automation: nudge the owner when a deal slips

Database automations have no public API surface. They are configured per-database in the Notion app under ••• → Automations.

  1. 1Trigger: Expected close is before Today AND Stage is not in the Complete group.
  2. 2Action: Add a comment @mentioning the Owner with “This deal has slipped: update the close date or move the stage.”
  3. 3Action: set Blocked to true, so the Slipped view stays honest.

About this component

Three related databases with the property schemas, status groups, rollups and formulas a working CRM needs, plus a board view grouped by deal stage, a chart view of weighted pipeline value, and a dashboard view that assembles both.

What it does

  • Status property with Notion's native stage groups (To begin / In progress / Done / Blocked)
  • Rollups from Deals → Companies for lifetime value and open pipeline
  • Formula-driven 'Days in stage' that flags stale deals in red
  • Dashboard view combining a number widget, a board and a chart

Where people put it

↳Solo founders tracking inbound
↳Agencies managing 10-100 client relationships
↳Recruiters running a candidate pipeline

Pairs well with

All in Business & CRM
🧮

ROI Calculator

Sliders in, a payback chart out, for proposals and sales pages.

BusinessFreeWidgetv1.0.1
💵
New

Monthly Budget Planner

Compare monthly income against four editable expense buckets.

BusinessFreeWidgetv1.0.0
📦
New

Inventory Counter

Adjust a small item list with plus and minus stock controls.

BusinessFreeWidgetv1.0.0