ROI Calculator
Sliders in, a payback chart out, for proposals and sales pages.
Objectives, key results and confidence, rolled up to a company score.
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.
/v1/pagesCreate the “okr-system” container page under the page you chose
/v1/databasesCreate the “Objectives” database with 6 base properties
/v1/databases/{objectives_database_id}Read back Objectives to get its default data source id
/v1/data_sources/{objectives_data_source_id}Add 7 deferred properties to Objectives: relations (with resolved data_source_ids), then the rollups and formulas that read them
/v1/databasesCreate the “Key Results” database with 9 base properties
/v1/databases/{keyResults_database_id}Read back Key Results to get its default data source id
/v1/data_sources/{keyResults_data_source_id}Add 6 deferred properties to Key Results: relations (with resolved data_source_ids), then the rollups and formulas that read them
/v1/databasesCreate the “Initiatives” database with 5 base properties
/v1/databases/{initiatives_database_id}Read back Initiatives to get its default data source id
/v1/data_sources/{initiatives_data_source_id}Add 1 deferred properties to Initiatives: relations (with resolved data_source_ids), then the rollups and formulas that read them
/v1/viewsCreate the “This quarter” board view on objectives
/v1/viewsCreate the “Scores by team” chart view on objectives
/v1/viewsCreate the “Needs an update” table view on keyResults
/v1/viewsCreate the “All key results” list view on keyResults
/v1/viewsCreate the “Initiative board” board view on initiatives
/v1/pagesSeed 2 rows into Objectives so the views are not empty on first open (one request per row; Notion has no bulk insert)
/v1/pagesSeed 3 rows into Key Results so the views are not empty on first open (one request per row; Notion has no bulk insert)
/v1/pagesSeed 2 rows into Initiatives so the views are not empty on first open (one request per row; Notion has no bulk insert)
/v1/pagesCreate the “Weekly OKR check-in” page
/v1/blocks/{weekly_okr_check_in_page_id}/childrenAppend 9 blocks of page body
2 steps cannot be scripted: Automation: flag confidence below 5; Recurring template: weekly check-in page.
curl -X POST https://notionarena.vercel.app/api/install \
-H 'content-type: application/json' \
-d '{
"component": "okr-system",
"mode": "plan"
}'
# add "token" and "parentPageId" and switch to "mode": "api" to install for realThe 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.
ref: objectivesn/a2026 Q3 · 2026 Q4 · 2027 Q1 · 2027 Q2Company · Product · Engineering · Revenuen/aDraft → Committed → Tracking → Achieved +1n/a→ keyResults (two-way)count_values(Key results.Name)average(Key results.Progress)average(Key results.Confidence)if(prop("KR count") == 0, 0, round(prop("Average progress") * 100))ifs(prop("Score") >= 70, "🟢 On track", prop("Score") >= 40, "🟡 At risk", prop("Score") > 0, "🔴 Off track", true, "⚪ Not started")dateBetween(dateAdd(now(), 90, "days"), now(), "days")ref: keyResultsn/a→ objectivesn/aCount · Percentage · Revenue · Time +1numbernumbernumbern/anumbern/a→ initiatives (two-way)if(prop("Target value") == prop("Start value"), 0, min(1, max(0, (prop("Current value") - prop("Start value")) / (prop("Target value") - prop("Start value")))))format(round(prop("Progress") * 100)) + "%"if(empty(prop("Last updated")), true, dateBetween(now(), prop("Last updated"), "days") > 10)ifs(prop("Confidence") >= 8, "🟢 " + format(prop("Confidence")), prop("Confidence") >= 5, "🟡 " + format(prop("Confidence")), true, "🔴 " + format(prop("Confidence")))ref: initiativesn/adefault Not started / In progress / Donen/an/a→ keyResultsn/aCreated through POST /v1/views, which shipped in March 2026 and is the reason provisioning a workspace from code finally works end to end.
on objectives
filter: {"property":"Quarter","select":{"equals":"2026 Q4"}}…
on objectives
on keyResults
filter: {"property":"Stale","checkbox":{"equals":true}}…
on keyResults
on initiatives
Appended with real block types (headings, toggles, callouts, to-dos, column lists) in chunks of 100, the Append block children limit.
For each key result: what is the current value, and what moved it this week?
Confidence is a judgement, not a computation. If it dropped by three or more points, that key result is the agenda.
Every check-in ends with exactly one decision: keep, add an initiative, or abandon. Not three.
A formula can only see properties on the same row. Confidence is a forecast about the future, which no property can express. Notion formulas cannot trigger side effects either, so a low confidence cannot itself alert anyone. That is what the automation below is for.
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.
Database automations have no public API surface. They are configured per-database in the Notion app under ••• → Automations.
Recurring database templates (daily/weekly/monthly) are configured in the app on the template's ••• menu; the API can create pages from a template but cannot schedule recurrence.
Objectives hold a quarter, an owner and a confidence level. Key results hold a start, a target and a current value, with a formula that computes progress as a percentage. A rollup on the Objective averages its key results, so the company score is never stale.
Sliders in, a payback chart out, for proposals and sales pages.
Compare monthly income against four editable expense buckets.
Adjust a small item list with plus and minus stock controls.