For agents and developers
Pinpal Notes API and MCP.
The MCP server for assistants, a REST API for your own code, the same sign-in and the same token. A short version for agents is at llms.txt.
Pinpal Notes connector address
https://notes.mypinpal.com/mcpPaste it into Claude or ChatGPT as a custom connector and sign in with Apple or Google. Step by step · API and MCP reference
Pinpal Notes is a simple notes app. A person writes in the app. Their agent connects and reads and writes the same notes: shopping lists, recipes, training plans, whatever comes up. There are two ways in, and both use the same sign-in and the same personal token.
- MCP server:
https://notes.mypinpal.com/mcp. For Claude and every other MCP client. Nothing to install. - REST API:
https://notes.mypinpal.com/api/v1. For your own code.
A short copy of this page lives at /llms.txt.
Getting started in Claude
Add Pinpal Notes to Claude once, and Claude can read and write your notes in any chat.
- In Claude, open Customize, then Connectors.
- Press + and choose Add custom connector.
- Name it Pinpal Notes and paste
https://notes.mypinpal.com/mcp. Press Add. - Press Connect and sign in with Apple or Google, the same account as in the app.
- Ask Claude something like "put milk and bread on my shopping list".
It works the same in Claude on the web, on desktop and on your phone. Claude plans can add custom connectors, and the free plan allows one. You can see and revoke the connection in the app under Account.
In Claude Code, add it from the terminal, then run /mcp to sign in:
claude mcp add --transport http pinpal-notes https://notes.mypinpal.com/mcp
MCP server and tools
Server URL: https://notes.mypinpal.com/mcp (Streamable HTTP).
Any MCP client that supports OAuth connects on its own: a call without a
token answers 401 and points at
/.well-known/oauth-protected-resource,
the client registers itself and sends the person to sign in. A token from
the app's Account works too, as Authorization: Bearer TOKEN.
list_folders: the person's folders, with how many notes each holds.create_folder: a new folder, when the person asks or nothing fits.list_notes: list notes in one folder or all, active, archived or all.read_note: one note with its Markdown body, its folder and its files.create_note: a new note in a folder, title and Markdown body.edit_note: change the title, the whole body, the star, or move it to another folder.archive_note: archive or unarchive a note.read_file: one of the note's files by number; a text file comes back as text, a picture as the picture.attach_file: add a file to the note, as text or base64; it gets the next number.delete_note: delete a note. It moves to Recently deleted in the person's app, with its files, and can be restored there for 30 days.
The tools follow the same rules as the REST API below: everything works on the free plan, and only a new note past the person's 20 free notes needs their subscription.
REST API quickstart
If you are an agent acting for a person: tell them you want to connect to Pinpal Notes, then do this.
- If you can speak MCP, use the MCP server instead; it handles sign-in for you.
- If you have an OAuth
client_id, open the authorize URL (below). They sign in with Apple or Google. You exchange the code for a token. - If you do not, ask them to open Pinpal Notes, go to Account, create a token, and paste it to you.
- Call
GET /api/v1/mewith that token. If it returns the person, you are connected. - List the folders, then list, read, create, and edit the notes in them. They write on the phone. You write too.
curl https://notes.mypinpal.com/api/v1/me \ -H "Authorization: Bearer TOKEN"
Authentication
Every call to /api/v1 needs a personal API token as a Bearer
token. The token is scoped to one person. They can revoke it in the app
under Account. A pasted token, and a token from an app that does not
refresh, does not expire on its own; an app that registered for refresh
tokens gets one that lives an hour and renews it.
Authorization: Bearer TOKEN
Pinpal Notes is free for up to 20 active notes (archived and deleted ones do not count). Only creating a note past that needs the person's subscription; it answers 402 with free_limit_reached and a message to relay to the person. Reading, editing, folders, files, archiving and deleting always work.
GET /me
Connect check. Who this token belongs to.
GET https://notes.mypinpal.com/api/v1/me Authorization: Bearer TOKEN
{
"id": "…",
"email": "…",
"name": "…"
}
DELETE /me
Revoke this token. Call it before you store a new one on reconnect,
so Account does not fill with dead rows. A token that is already gone
answers 401, which is the same end state.
DELETE https://notes.mypinpal.com/api/v1/me Authorization: Bearer TOKEN
{ "ok": true }
GET /folders
The person's folders, newest activity first. Every note lives in exactly
one. noteCount counts the active notes; colors is
the palette a new folder may use.
GET https://notes.mypinpal.com/api/v1/folders Authorization: Bearer TOKEN
{
"folders": [
{
"id": "…",
"name": "Recipes",
"color": "#4F8FD6",
"noteCount": 12,
"createdAt": "2026-09-01T09:00:00.000Z",
"updatedAt": "2026-09-11T12:00:00.000Z"
}
],
"colors": ["#F2724B", "#E0B252", "…"]
}
POST /folders
Make a folder. Body { name, color? }. Make one only when the person asks or no folder fits. Returns the
folder, 201.
POST https://notes.mypinpal.com/api/v1/folders
Authorization: Bearer TOKEN
Content-Type: application/json
{ "name": "Training" }
GET /notes
List notes. Query folder (an id or the exact name) for one
folder, every folder without it, and filter=active|archived|all
(default active). Starred first, then newest edit.
preview is a short plain-text snippet of the body, not the
full Markdown.
GET https://notes.mypinpal.com/api/v1/notes?folder=Recipes&filter=active Authorization: Bearer TOKEN
{
"notes": [
{
"id": "…",
"folderId": "…",
"title": "Shopping",
"preview": "Milk",
"archived": false,
"important": false,
"fileCount": 0,
"updatedAt": "2026-09-11T12:00:00.000Z"
}
]
}
GET /notes/:id
One note, including the Markdown body, its folder and its files.
GET https://notes.mypinpal.com/api/v1/notes/NOTE_ID Authorization: Bearer TOKEN
{
"id": "…",
"folderId": "…",
"title": "Shopping",
"body": "- [ ] Milk\n- [ ] Eggs",
"archived": false,
"important": false,
"fileCount": 1,
"files": [
{
"id": "…",
"number": 1,
"name": "receipt.jpg",
"contentType": "image/jpeg",
"size": 182400,
"url": "/api/v1/notes/NOTE_ID/files/1",
"author": { "kind": "user", "name": "Maja" },
"createdAt": "2026-09-11T12:00:00.000Z"
}
],
"createdAt": "2026-09-01T09:00:00.000Z",
"updatedAt": "2026-09-11T12:00:00.000Z"
}
POST /notes
Create a note. Body { title?, body?, folder? }, where
folder is an id or the exact name; without it the note goes in
the oldest folder. Missing fields become empty strings. Past the 20 free notes, without a subscription, this answers 402.
POST https://notes.mypinpal.com/api/v1/notes
Authorization: Bearer TOKEN
Content-Type: application/json
{ "title": "Dinner", "body": "- [ ] Roast a chicken", "folder": "Recipes" }
Returns the full note, 201.
PATCH /notes/:id
Update a note. Send only the fields you want to change:
title, body, archived,
important, folder (moves the note).
PATCH https://notes.mypinpal.com/api/v1/notes/NOTE_ID
Authorization: Bearer TOKEN
Content-Type: application/json
{ "body": "- [x] Roast a chicken" }
Returns the full note.
POST /notes/:id/archive
Hide a note from the active list. Same as PATCH with archived: true.
POST https://notes.mypinpal.com/api/v1/notes/NOTE_ID/archive Authorization: Bearer TOKEN
POST /notes/:id/unarchive
Put an archived note back on the active list.
POST https://notes.mypinpal.com/api/v1/notes/NOTE_ID/unarchive Authorization: Bearer TOKEN
DELETE /notes/:id
Delete a note. It moves, with its files, to Recently deleted in the person's app and is gone from every call here. The person can restore it there for 30 days, or delete it for good; after that it is purged. No call here empties Recently deleted.
DELETE https://notes.mypinpal.com/api/v1/notes/NOTE_ID Authorization: Bearer TOKEN
{ "ok": true, "recentlyDeleted": true, "deletedAt": "2026-10-02T09:00:00.000Z", "purgesAt": "2026-11-01T09:00:00.000Z" }
Files
A note can carry files: a photo, a receipt, a PDF, a Markdown or JSON file. Each gets a number in the note, never reused, so a person can say "file 1". At most 10 MB a file. Only the person removes a file, in the app.
GET https://notes.mypinpal.com/api/v1/notes/NOTE_ID/files POST https://notes.mypinpal.com/api/v1/notes/NOTE_ID/files GET https://notes.mypinpal.com/api/v1/notes/NOTE_ID/files/1
Attach as multipart with a file field, or as raw bytes:
curl https://notes.mypinpal.com/api/v1/notes/NOTE_ID/files \ -H "Authorization: Bearer TOKEN" \ -F "file=@receipt.jpg" curl https://notes.mypinpal.com/api/v1/notes/NOTE_ID/files \ -H "Authorization: Bearer TOKEN" \ -H "Content-Type: text/markdown" \ -H "X-File-Name: plan.md" \ --data-binary @plan.md
Returns the file, 201. The bytes come back with their own type and name.
Markdown
body is Markdown. The person never sees the syntax; the app
renders it. When you write, use:
**bold**and*italic*- bulletsand1. numbered- [ ]unchecked and- [x]checked checklist items
Errors
401missing or bad token ({"error":"Unauthorized"})402free plan full: a new note past the 20 free ones without a subscription ({"error":"free_limit_reached","limit":20,"message":"..."}); relay the message, do not retry400invalid JSON body on PATCH404no such note
OAuth 2.0
An app can obtain a token without a paste. The person signs in on
notes.mypinpal.com; your server swaps the code for the same kind of
personal API token. Discovery:
/.well-known/oauth-authorization-server.
GET https://notes.mypinpal.com/oauth/authorize
?client_id=…
&redirect_uri=…
&response_type=code
&state=…
&code_challenge=…
&code_challenge_method=S256
POST https://notes.mypinpal.com/oauth/token
grant_type=authorization_code
code=…
redirect_uri=…
client_id=…
client_secret=…
code_verifier=…
→ { "access_token": "…", "token_type": "Bearer", "scope": "notes" }
PKCE S256 is supported. Optional label on authorize names the
token in Account (for example Agent Heim · Freja).
A client that registered with "grant_types": ["authorization_code", "refresh_token"]
also gets expires_in (an hour) and a refresh_token.
grant_type=refresh_token swaps it for a new pair; each refresh
token works once. Revoking the connection in Account ends both.
MCP clients and other public apps register themselves at
POST /oauth/register (dynamic client registration) and must
use PKCE S256; they get no secret. Building an app with its own server and
a client secret? Email hello@mypinpal.com
for a client_id. Agent Heim
is already registered.