Connect scripts and AI tools

Let scripts and AI agents read, create and append to notes with an API token kept in an environment variable.

Applies to Requires an API token · macOS or Linux shell, Python 3

These recipes use only the four requests in the Markdown API: list, read as Markdown, create and append. Anything else — overwriting, deleting, searching note bodies — isn’t available through the API.

Keep the token safe

  1. In the profile menu → Account security → API tokens, create one token per purpose (for example, “lab log script” or “MacBook Claude Code”). If one leaks, you revoke just that one.
  2. Put it in your shell profile (~/.zshrc or similar) as an environment variable: export COMMONNOTE_TOKEN="cnk_…"
  3. Have scripts and tools read that variable. Never write the token into a code file.
Tokens never expire. Revoke tokens you’re done with or haven’t used in a while (check “Last used” in the list). Never paste a token into a chat window or an AI conversation.

Shell: append a line to a note

Useful for collecting measurements or a work log in one note. The JSON is built with python3 so line breaks and quotes stay safe.

NOTE_ID="<note-id>"
LINE="- $(date '+%Y-%m-%d %H:%M') Centrifugation done, supernatant stored"

python3 -c 'import json,sys; print(json.dumps({"markdown": sys.argv[1]}))' "$LINE" |
curl -sS -X POST -H "Authorization: Bearer $COMMONNOTE_TOKEN" \
  -H "Content-Type: application/json" --data-binary @- \
  "https://commonnote.app/api/v1/notes/$NOTE_ID/append"

Python: upload a file as a note, save notes to files

Standard library only.

import json, os, pathlib, urllib.parse, urllib.request

BASE = "https://commonnote.app/api/v1"
TOKEN = os.environ["COMMONNOTE_TOKEN"]

def call(method, path, body=None, accept="application/json"):
    req = urllib.request.Request(
        BASE + path, method=method,
        data=json.dumps(body).encode() if body is not None else None,
        headers={"Authorization": f"Bearer {TOKEN}",
                 "Content-Type": "application/json", "Accept": accept})
    with urllib.request.urlopen(req) as res:
        text = res.read().decode()
        return json.loads(text) if accept == "application/json" else text

# 1) Upload a Markdown file as a new note
md = pathlib.Path("report.md").read_text(encoding="utf-8")
created = call("POST", "/notes", {"markdown": md})
print(created["url"])

# 2) Save recent notes with "weekly" in the title to files
for note in call("GET", "/notes?limit=20&q=" + urllib.parse.quote("weekly"))["notes"]:
    if note["locked"]:
        continue
    body = call("GET", f"/notes/{note['id']}", accept="text/markdown")
    pathlib.Path(f"{note['id']}.md").write_text(body, encoding="utf-8")
  • On a 429, wait the number of seconds in the Retry-After header and retry. The limit is 300 requests per minute per token.
  • Password-locked notes always return 423 to an API token, even while they’re unlocked in the app, so skip them as above.
  • Each request’s markdown must be 2 MB or less.

Hand it to an AI coding agent (such as Claude Code)

Agents that run commands in your terminal, like Claude Code, can use this API directly. Pass the token only as an environment variable in the shell where the agent runs, and tell the agent the variable’s name — never the value.

  1. In the terminal where you’ll run the agent, check that COMMONNOTE_TOKEN is set without printing it — for example, test -n "$COMMONNOTE_TOKEN" && echo set.
  2. Ask the agent something like: Use the CommonNote Markdown API (https://commonnote.app/api/v1). The token is in the COMMONNOTE_TOKEN environment variable; send it as an Authorization: Bearer header and never print it or write it to a file. Read my recent notes with "meeting" in the title as Markdown and pull out the action items.
  3. To keep the result, add “create a new note with it” (POST /notes) or “append it to note <id>” (/append).
An agent can reach every note your account can see. Make a separate token for the agent and revoke it when the work is done. The API has no delete or overwrite, so an agent can’t remove a note or replace it wholesale.