For AI agents and tools: the complete index of this documentation is at /llms.txt; every page is also available as Markdown by adding .md to its address.

⚑

API quickstart

Updated Oct 26, 2026

This page takes you from nothing to a page created by a script. It uses the workspace address and a token, so you need an account and a workspace first.

1. Get your address and a token

  1. Open Settings β†’ MCP & API in your workspace.

  2. Copy the MCP server address. It ends with your workspace's name, for example https://app.thenotemaker.com/api/mcp/your-workspace.

  3. Under API tokens for this workspace, type a name and click Create token. Copy the token now: it starts with nm_ and is shown only once.

Put both in environment variables so the examples below work as they are:

export NOTEMAKER_URL="https://app.thenotemaker.com/api/mcp/your-workspace"
export NOTEMAKER_TOKEN="nm_YOUR_TOKEN"
⚠️

Treat a token like a password. Never put a real one in a page, a script you share, or a public repository.

2. Check that it works

A call is a POST of one JSON-RPC message. The Accept header must list both types shown.

curl -s -X POST "$NOTEMAKER_URL" \
  -H "Authorization: Bearer $NOTEMAKER_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'

The answer names the fourteen tools:

{"result":{"tools":[{"name":"workspace", "...": "..."}, {"name":"pages", "...": "..."}, "..."]},"jsonrpc":"2.0","id":1}

Every call is self-contained: there is no session to open and nothing to close.

3. Read your workspace

curl -s -X POST "$NOTEMAKER_URL" \
  -H "Authorization: Bearer $NOTEMAKER_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"workspace","arguments":{"action":"get"}}}'

The text in result.content[0].text reads like this (shortened):

My workspace
- slug: your-workspace
- your role: OWNER
- pages: 5

## Collections (1)
- Handbook  (id: cmvk…, private, 2 pages)

## Forms (1)
- Contact us (id: cmvk…, 0 responses, https://app.thenotemaker.com/f/contact-us-t4948j4u)

4. Create a page

Pass the tool's name and its arguments. content_markdown is ordinary Markdown. The Idempotency-Key header makes the call safe to repeat: send the same key again after a timeout and you get the first answer back instead of a second page.

curl -s -X POST "$NOTEMAKER_URL" \
  -H "Authorization: Bearer $NOTEMAKER_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"pages_write","arguments":{"action":"create","title":"Hello from the API","content_markdown":"Created with curl."}}}'
Created page "Hello from the API" (id: cmvp00soi0000qe7dmm9pb073, private)
https://app.thenotemaker.com/your-workspace/hello-from-the-api-714e0ca3b5

The page is private to you until you share it. The same answer also comes back as data in result.structuredContent.page (id, title, url, visibility).

5. The same thing in JavaScript

Node 20 or newer, no packages needed. Save it as hello.mjs and run node hello.mjs.

const URL_ = process.env.NOTEMAKER_URL;
const TOKEN = process.env.NOTEMAKER_TOKEN;

let id = 0;
async function tool(name, args) {
  const res = await fetch(URL_, {
    method: "POST",
    headers: {
      Authorization: `Bearer ${TOKEN}`,
      "Content-Type": "application/json",
      Accept: "application/json, text/event-stream",
    },
    body: JSON.stringify({ jsonrpc: "2.0", id: ++id, method: "tools/call", params: { name, arguments: args } }),
  });
  const body = await res.json();
  if (body.error) throw new Error(body.error.message); // sign-in problems
  if (body.result.isError) throw new Error(body.result.content[0].text); // a refused call
  return body.result;
}

const created = await tool("pages_write", { action: "create", title: "Hello from JavaScript", content_markdown: "Created with fetch." });
console.log(created.content[0].text);
const pageId = created.structuredContent.page.id;

const found = await tool("pages", { action: "search", query: "Hello" });
console.log(found.content[0].text);

await tool("pages_write", { action: "delete", page_id: pageId }); // moves it to the trash

6. And in Python

Install the one dependency with pip install requests. Save the script as hello.py and run python hello.py.

import os, requests

URL = os.environ["NOTEMAKER_URL"]
TOKEN = os.environ["NOTEMAKER_TOKEN"]
HEADERS = {
    "Authorization": f"Bearer {TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json, text/event-stream",
}
_id = 0

def tool(name, **arguments):
    global _id
    _id += 1
    body = {"jsonrpc": "2.0", "id": _id, "method": "tools/call", "params": {"name": name, "arguments": arguments}}
    data = requests.post(URL, headers=HEADERS, json=body, timeout=30).json()
    if "error" in data:
        raise RuntimeError(data["error"]["message"])  # sign-in problems
    result = data["result"]
    if result.get("isError"):
        raise RuntimeError(result["content"][0]["text"])  # a refused call
    return result

created = tool("pages_write", action="create", title="Hello from Python", content_markdown="Created with requests.")
print(created["content"][0]["text"])
page_id = created["structuredContent"]["page"]["id"]

found = tool("pages", action="search", query="Hello")
print(found["content"][0]["text"])

tool("pages_write", action="delete", page_id=page_id)  # moves it to the trash

Both scripts print:

Created page "Hello from JavaScript" (id: cmvp01cis0003qe7d7vp21rqq, private)
https://app.thenotemaker.com/your-workspace/hello-from-javascript-b6bcbe814b
- Hello from JavaScript (id: cmvp01cis0003qe7d7vp21rqq)
  Created with fetch.

7. If a call fails

A missing or wrong token answers HTTP 401 with a WWW-Authenticate header. A call the tool refuses (a locked page, a value that breaks a field's rule) answers HTTP 200 with result.isError true and the reason in plain words, and nothing is changed. Public form submissions answer errors as application/problem+json. More in the Agents, trash and errors examples.

Next

Try it in Postman

Prefer a point-and-click client? The NoteMaker API collection in our public Postman workspace has every request from these pages, with tests, an example answer for each and an error case per folder. Fork it into your own workspace, set baseUrl, workspace and token in the environment, and run the folders in order.

API quickstart β€” TheNoteMaker Docs