Skip to content
Notion Arena
🚪
📚 Docs & SystemsProNative recipe

Client Portal

A published page with intake form, status board and a synced header.

Version
v1.2.0
Updated
2026-09-26
Plan
Business

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.

21
requests
11
manual steps
1POST
/v1/pages

Create the “client-portal” container page under the page you chose

2POST
/v1/databases

Create the “Clients” database with 8 base properties

3GET
/v1/databases/{clients_database_id}

Read back Clients to get its default data source id

4PATCH
/v1/data_sources/{clients_data_source_id}

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

5POST
/v1/databases

Create the “Deliverables” database with 7 base properties

6GET
/v1/databases/{deliverables_database_id}

Read back Deliverables to get its default data source id

7PATCH
/v1/data_sources/{deliverables_data_source_id}

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

8POST
/v1/databases

Create the “Intake Requests” database with 8 base properties

9GET
/v1/databases/{intake_database_id}

Read back Intake Requests to get its default data source id

10PATCH
/v1/data_sources/{intake_data_source_id}

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

11POST
/v1/views

Create the “Client intake form” form view on intake

12POST
/v1/views

Create the “Portal board” board view on deliverables

13POST
/v1/views

Create the “Delivery timeline” timeline view on deliverables

14POST
/v1/views

Create the “Delivered gallery” gallery view on deliverables

15POST
/v1/views

Create the “All clients” table view on clients

16POST
/v1/views

Create the “Requests queue” table view on intake

17POST
/v1/pages

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

18POST
/v1/pages

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

×2
19POST
/v1/pages

Create the “Client portal page” page

20PATCH
/v1/blocks/{client_portal_page_page_id}/children

Append 13 blocks of page body

3 steps cannot be scripted: Automation: notify on new intake; Automation: tell the client when a deliverable lands; Publish the portal.

Run it yourselfNotion-Version 2026-03-11
curl -X POST https://notionarena.vercel.app/api/install \
  -H 'content-type: application/json' \
  -d '{
    "component": "client-portal",
    "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.

🤝

Clients

ref: clients
1× title1× status1× people1× email1× url2× date1× number2× relation1× rollup1× formula
Namen/a
StatusOnboarding → Active → Paused → Offboarded
Primary contactn/a
Emailn/a
Portal URLn/a
Kickoff daten/a
Next milestonen/a
Retainerdollar
Deliverables→ deliverables (two-way)
Requests→ intake (two-way)
Open itemscount(Deliverables.Status)
Days to milestoneif(empty(prop("Next milestone")), 0, dateBetween(prop("Next milestone"), now(), "days"))
📦

Deliverables

ref: deliverables
1× title1× status1× relation1× people1× date1× checkbox1× url1× rich_text1× formula
Namen/a
StatusQueued → In progress → In client review → Changes requested +1
Client→ clients
Ownern/a
Duen/a
Client visiblen/a
Linkn/a
Notesn/a
Timelineifs(prop("Status") == "Delivered", "✅ Delivered", empty(prop("Due")), "⚪ No date", prop("Due") < now(), "🔴 Late", true, "🟢 Due " + formatDate(prop("Due"), "MMM D"))
📥

Intake Requests

ref: intake
1× title1× relation2× select2× rich_text1× created_time1× status1× files
Namen/a
Client→ clients
TypeNew request · Change request · Question · Bug
PriorityLow · Normal · Urgent
Detailn/a
Submittedn/a
Statusdefault Not started / In progress / Done
Attachmentn/a
Answern/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.

Client intake formform

on intake

Portal boardboard

on deliverables

filter: {"and":[{"property":"Client visible","checkbox":{"equals":true}}…

Delivery timelinetimeline

on deliverables

filter: {"property":"Client visible","checkbox":{"equals":true}}…

Delivered gallerygallery

on deliverables

All clientstable

on clients

Requests queuetable

on intake

Documentation pages

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

🚪Client portal page13 blocks
🔁 synced block
👋 Welcome

Everything about our work together, in one place. Updated as it happens. No weekly status email.

Your contact

@you

Next milestone

· linked Days to milestone


Where things stand

Linked view: Deliverables → Portal board, filtered to this client and Client visible = checked.

⏳Embed the Countdown widget here, pointed at the Next milestone date. It is the one thing clients actually look at.
📺 https://example.com/widgets/countdown.html?label=Next%20milestone&to=2026-12-01

Request something

Publish the Client intake form view and embed it here. Submitters need no Notion account.

What we have delivered

Linked view: Deliverables → Delivered gallery.


🔒Before you publish: audit every linked view on this page. Anything not filtered to this client and not marked Client visible will leak. Publishing exposes the page body, not the properties of the rows, but a linked view shows whatever its filter allows.

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.

Automation: notify on new intake

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

  1. 1Intake Requests → Automations → New automation.
  2. 2Trigger: Page created.
  3. 3Action: Send a Slack message to #client-requests with the Name, Client and Priority.
  4. 4Action: set Status to In progress and Owner to the account lead.

Automation: tell the client when a deliverable lands

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

  1. 1Deliverables → Automations → New automation.
  2. 2Trigger: Status changes to “In client review”.
  3. 3Action: add a comment @mentioning the client's contact; if they are a guest on the page, they are notified by email.

Publish the portal

Share settings and public publishing are workspace-level and not exposed on the pages API.

  1. 1Share → Publish, and enable “Allow duplicate as template” only if you want clients to copy the structure.
  2. 2Invite the client as a Guest on the portal page rather than on the whole workspace.
  3. 3Turn off comments if you do not want client comments landing in your notification feed.
  4. 4Put the Countdown widget embed in the page before publishing, so the milestone date is visible immediately.

About this component

Everything a client needs on one publishable page: a form view they can submit without a Notion account, a filtered board showing only their work, a synced header block with contact details, and an embedded countdown to the next milestone.

What it does

  • Form view configuration created through the Views API
  • Linked database views scoped with a client filter
  • Pairs with the Countdown widget for milestone dates
  • Publish-ready: no private properties leak into the page body

Where people put it

↳Agencies giving each client a live status page
↳Freelancers replacing a weekly status email
↳Consultants running a self-serve intake

Pairs well with

All in Docs & Systems
📖
New

Reading Progress Tracker

Track pages read in one book, with progress saved on this device.

DocsFreeWidgetv1.0.0
🧠
New

Spaced Repetition Deck

A due-card queue with simple local review intervals.

DocsFreeWidgetv1.0.0
🧠
New

Flashcards

A focused question-and-answer deck with active-recall progress.

DocsFreeWidgetv1.0.0