Reference
API reference
A REST API over your notes, drafts, literature notes and media. JSON in, JSON out, one token.
The REST API gives you full read and write access to the same data your account has inside the app. Every
endpoint lives under https://thinkernotes.com/api/v1, accepts and returns JSON, and is scoped to
the account that owns the token, so there's no way for a token to see or change another user's data.
Authentication
Send your API token as a bearer header on every request. See Getting started to create one.
Authorization: Bearer tn_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Notes
The core content type: a single atomic idea, with text and tags. It's called Insight inside the
app, and note everywhere in the API.
| Method | Path | Description |
|---|---|---|
GET | /notes | List notes, most recent first. Add ?query= to search text and tags, ?limit= to cap results (default 10, max 50). |
GET | /notes/:id | Fetch one note's full text, tags and linked note ids. |
POST | /notes | Create a note. |
PATCH | /notes/:id | Update a note's text or tags. |
DELETE | /notes/:id | Delete a note. |
Create and update take a note object:
| Field | Type | Required | Description |
|---|---|---|---|
text | string | Yes | The note's content, at least 10 characters. |
tags | array of strings | No | Replaces the note's tags. |
curl https://thinkernotes.com/api/v1/notes \
-H "Authorization: Bearer tn_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{ "note": { "text": "The obstacle is the way", "tags": ["stoicism"] } }'
require "net/http"
require "json"
uri = URI("https://thinkernotes.com/api/v1/notes")
request = Net::HTTP::Post.new(uri, "Content-Type" => "application/json")
request["Authorization"] = "Bearer tn_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
request.body = { note: { text: "The obstacle is the way", tags: ["stoicism"] } }.to_json
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
puts response.body
const response = await fetch("https://thinkernotes.com/api/v1/notes", {
method: "POST",
headers: {
"Authorization": "Bearer tn_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"Content-Type": "application/json",
},
body: JSON.stringify({
note: { text: "The obstacle is the way", tags: ["stoicism"] },
}),
});
const note = await response.json();
console.log(note);
import requests
response = requests.post(
"https://thinkernotes.com/api/v1/notes",
headers={"Authorization": "Bearer tn_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"},
json={"note": {"text": "The obstacle is the way", "tags": ["stoicism"]}},
)
print(response.json())
A note, as returned by GET /notes/:id, POST /notes or PATCH
/notes/:id:
{
"id": 42,
"text": "The obstacle is the way",
"tags": ["stoicism"],
"created_at": "2026-08-02T10:14:00Z",
"linked_note_ids": []
}
GET /notes returns the same shape without linked_note_ids, as an array, with
text truncated into an excerpt field.
Drafts
Quick, unstructured inbox notes, the raw material before it becomes a note.
| Method | Path | Description |
|---|---|---|
GET | /drafts | List drafts, most recent first. ?query= and ?limit= supported. |
GET | /drafts/:id | Fetch one draft's full text. |
POST | /drafts | Create a draft. Body: { "draft": { "text": "..." } }. |
PATCH | /drafts/:id | Update a draft's text. |
DELETE | /drafts/:id | Delete a draft. |
Literature notes
Notes taken against a piece of media, like a book, an article or a podcast.
| Method | Path | Description |
|---|---|---|
GET | /literature_notes | List literature notes, most recent first. ?query= and ?limit= supported. |
GET | /literature_notes/:id | Fetch one literature note's full text. |
POST | /literature_notes | Create a literature note. Body: { "literature_note": { "text": "...", "media_id": 1 } }. The media_id has to belong to you. |
PATCH | /literature_notes/:id | Update the text or re-attach to a different media item. |
DELETE | /literature_notes/:id | Delete a literature note. |
Media
A source you're taking literature notes on, like a book, an article or a podcast.
| Method | Path | Description |
|---|---|---|
GET | /media | List media, most recent first. ?query= matches title and author, ?limit= caps results. |
GET | /media/:id | Fetch one media item. |
POST | /media | Create a media item. |
PATCH | /media/:id | Update a media item. |
DELETE | /media/:id | Delete a media item. |
Create and update take a media object:
| Field | Type | Required | Description |
|---|---|---|---|
title | string | Yes | Must be unique within your account. |
author | string | No | |
kind | string | No | One of book, podcast, article, other. Defaults to book. |
status | string | No | One of not_started, in_progress, finished. |
url | string | No |
Errors
| Status | Cause |
|---|---|
401 Unauthorized | Missing or invalid bearer token |
404 Not Found | The record doesn't exist, or belongs to another account |
422 Unprocessable Entity | Validation failed, the response body has an errors array |
204 No Content | A DELETE succeeded |
Want read-only, assistant-facing access instead of full read and write? Take a look at the MCP server. Same data, just no write tools.