Skip to content

LearnTutorials

Automate Notion from your terminal with the Notion CLI

Use the Notion CLI to query databases, write pages from Markdown and deploy Workers that sync data into Notion, all from your terminal in under 35 minutes.

By Recaply EditorsIntermediate33 min6 stepsUpdated

A small keyboard with a cable running from it into a neat stack of paper cards

What you need

The Notion CLI is in beta. It runs in a desktop terminal and doesn't work on mobile.

  1. Step 1: Install the Notion CLI

    3 min

    The CLI is called ntn, and one install gives you API calls, page edits and Workers.

    1. On macOS or Linux, open a terminal and run the install script below.
    2. On Windows x64, run winget install Notion.ntn instead. With Node.js 22 or later, npm install --global ntn works on any system.
    3. Restart your terminal so it can find ntn, then check the version.
    Run this
    curl -fsSL https://ntn.dev | bash
    ntn --version

    You should see a version number printed under the command.

    The installer can't write to /usr/local/bin?

    Run it again with a folder you own: curl -fsSL https://ntn.dev | NTN_INSTALL_DIR="$HOME/.local/bin" bash. If that folder isn't on your PATH, the installer prints the line to add.

    To read the script before you run it, open ntn.dev/install.sh.

  2. Step 2: Log in to your workspace

    3 min

    Logging in links the CLI to one workspace and keeps your token in the system keychain.

    1. Run ntn login. A browser window opens.
    2. Check that the code in the browser matches the code in your terminal, then approve.
    3. Run ntn doctor to check your login, keychain, network and config.
    4. Run ntn api v1/users/me to make your first API call.
    Run this
    ntn login
    ntn doctor
    ntn api v1/users/me

    You should see a JSON reply with your Notion user name and ID.

    Login fails with a keychain error?

    This happens in containers, CI runners and SSH sessions. Run NOTION_KEYRING=0 ntn login to keep the token in a file instead, and guard that file like a password.

    For scripts and CI, create a personal access token in the Developer portal and export it as NOTION_API_TOKEN. Keep it out of code and shared files.

  3. Step 3: Query a database

    5 min

    A Notion database holds one or more data sources, and you query the data source, not the database.

    1. In Notion, open the database's settings menu and choose Manage data sources.
    2. Click the data source's ••• menu, then Copy data source ID.
    3. Run the query below with your ID. Change Status and Open to a property and option from your own database.
    4. Add --json to the command when a script or jq needs to read the output.
    Run this
    ntn datasources query [DATA SOURCE ID] --limit 50 --filter '{"property":"Status","select":{"equals":"Open"}}'

    You should see up to 50 rows from your database where Status is Open.

    The query fails on a property name?

    Names must match the database exactly, capitals included. Run ntn api v1/data_sources/[DATA SOURCE ID] to print the schema and copy the names from it.

    Only have a database ID? Run ntn datasources resolve [DATABASE ID] to list its data source IDs.

  4. Step 4: Write pages from Markdown

    4 min

    Writing pages as Markdown lets a script post notes, logs or reports into Notion without building API JSON.

    1. Find the page to write under: ntn api v1/search query="[PAGE TITLE]", and copy its id.
    2. Save your notes in a file called notes.md.
    3. Create a child page from the file with ntn pages create.
    4. Read any page back as Markdown with ntn pages get.
    Run this
    ntn api v1/search query="[PAGE TITLE]"
    ntn pages create --parent page:[PAGE ID] < notes.md
    ntn pages get [NEW PAGE ID]

    You should see a new page under your parent page, with the headings and lists from notes.md.

    An edit won't remove a child page?

    ntn pages edit protects child pages and databases by default. Add --allow-deleting-content only when you really mean to delete them.

    The CLI can only read and change pages your Notion account can open.

  5. Step 5: Deploy your first Worker

    10 min

    A Worker is a small TypeScript program that Notion hosts and runs, so nothing has to stay running on your laptop.

    1. Run ntn workers new my-worker, then cd my-worker.
    2. Open src/index.ts. It holds a sample tool called sayHello.
    3. Run ntn workers deploy and follow the prompts.
    4. Run the sample tool from the same folder to test it.
    Run this
    ntn workers new my-worker
    cd my-worker
    ntn workers deploy
    ntn workers exec sayHello -d '{"name": "World"}'

    You should see the reply Hello, World! in your terminal.

    Workers commands fail with a plan or access error?

    Workers need a Business or Enterprise plan. They're on for owners by default, and admins choose who else can use them, so ask an admin to add you.

    Workers are free to try during the beta. Notion says they will later use Notion credits, at about $0.0023 a run.

  6. Step 6: Add a scheduled sync or a webhook

    8 min

    A sync pulls outside data into a Notion database on a schedule, and a webhook runs your code when another service sends an event.

    1. Store the outside service's API key as a Worker secret with ntn workers env set.
    2. Add a sync to src/index.ts with a schedule such as "1h". The template ships with a /sync skill your coding agent can use.
    3. Redeploy, then test with --preview, which runs the sync without writing to Notion.
    4. For a webhook, run ntn workers webhooks list and paste the URL into the other service.
    Run this
    ntn workers env set GITHUB_TOKEN=[YOUR TOKEN]
    ntn workers deploy
    ntn workers sync trigger [SYNC KEY] --preview
    ntn workers sync status

    You should see a live status view for your sync, updated every 2 seconds.

    Runs fail with a rate limit error?

    Each workspace gets 600 sync runs an hour across all Workers. Use a longer schedule, such as "1h" or "1d", for data that changes slowly.

    Treat secrets and webhook URLs like passwords. Anyone with a webhook's full URL can send it events, so keep both out of code and shared files.

You get

A terminal setup that reads and writes Notion, plus a Worker that keeps a database in sync on its own

Did this guide work for you?

Sources