The API
Everything in a workspace, over HTTP: notes and their contents, the conversations on them, history and undo, search. A program can do what you can do, and never more.
A first call
Make a key under Your account → API keys, then ask who you are. Every call carries the key as a bearer token, and nothing else authenticates — a browser session is not a way in.
curl https://goscribi.com/api/v1/workspaces \
-H "Authorization: Bearer $GO_SCRIBI_KEY"
That answers with the workspaces the key reaches, each with its id and what
the key may do there. Every other address is inside one:
/api/v1/w/<workspace>/…
curl https://goscribi.com/api/v1/w/1/notes \
-H "Authorization: Bearer $GO_SCRIBI_KEY"
Three kinds of credential
- A personal key —
gsk_live_… - Yours, acting as you, in the workspaces you choose. Made under Your account → API keys. It is shown once; we keep a fingerprint and not the key. Only you can revoke it — not an administrator — and it keeps working in your other workspaces if one shuts its door.
- An application key —
gsa_live_… - A program that is a member of one workspace in its own right, with its own permission and its own name in every note's history. Made by an administrator under Settings → Integrations. It survives the person who set it up leaving, and removing the application is the whole of revoking it. Its keys have no level of their own: each can do exactly what the application can. A program that needs less is an application with a lower permission.
- An OAuth connection —
gso_… -
For a client that should never hold a copy of your key: it asks, you press
Allow, and it gets a token for one workspace. This is what
https://goscribi.com/mcpuses. End it under Your account → API keys.
What a credential may do
A credential never grants anything. A personal key or an OAuth connection is a ceiling: it can only lower what its person already has. A read/write key held by somebody with read on a folder is still read there. An application's keys are not levelled — what the application may do is set on the application.
| On a key | As an OAuth scope | What it can do |
|---|---|---|
read | read | Look at everything it can reach, and change nothing. |
comment | comment | And join the conversation on a note, without changing the note. |
create | write | And write, make and delete, wherever the holder can. |
The two vocabularies are deliberate: write is the word an OAuth
client expects, and create is the word this application uses for
the same rung.
When a workspace says no
An administrator can shut two doors, and neither of them revokes anything — a key belongs to the person who made it.
- A workspace can refuse personal keys altogether (Settings → Integrations). Its own applications keep working; OAuth connections do not.
- One member's keys can be shut out of one workspace (Settings → People → that person). Their keys keep working everywhere else they reach.
Either way the workspace simply becomes absent to that credential, with a sentence saying which door it was — unless the key never named the workspace at all, in which case it is told nothing, because "never given" and "does not exist" must not be tellable apart.
Errors
Every refusal has the same three fields, and the documentation
is a link back to this page, at the anchor for that code.
{
"error": "conflict",
"message": "Somebody else changed this note first. Read it again and decide again.",
"documentation": "https://goscribi.com/docs/api#conflict"
}
404 is the refusal, not 403. Anything you cannot read is absent. 403 only ever means you can already see the thing and may not change it — which is why it can afford to say which of three reasons it was.
- No credential, or not one that is still live. Send `Authorization: Bearer <key>`. Every reason fails the same way on purpose — revoked, expired, mistyped, or never ours — because a caller who learns which one learns whether a key exists.
-
not_found404 - Absent, or absent to you. The refusal for anything you may not read: a note, a workspace, a conversation. It is deliberately the same answer as something that was never there. A key that names a workspace it may no longer reach is told why; one that never named it is told nothing at all.
-
forbidden403 - You can see this and may not change it. The only refusal that admits a thing exists, and it is only ever used where you could already read it.
-
read_only_key403 - The credential's ceiling is read. Not the workspace's doing and not your permissions: the key itself says read. Make a read/write one under Your account → API keys.
-
workspace_locked403 - The workspace is over its note limit. Reading still works, and so does deleting — that is the way out. The message carries the two numbers and where to change plan.
-
cannot_comment403 - This credential may read the conversation and not add to it. Comment level is its own rung between read and write. A read key is told the conversation does not exist at all; this is what a reader who may see it but not answer gets.
-
kind_is_fixed422 - A note's kind cannot change once it is made. Its contents are a body or rows, and one does not become the other by relabelling. Between a checklist, a map and a board the interface can make a NEW note of the other kind from this one, and the message says where. Sending the kind it already has is not a change, and is accepted.
-
not_yours403 - Somebody else's words, or a thread somebody else has replied to. You may edit only your own comment. An administrator may delete anybody's and may never edit one.
-
conflict409 - The note moved while you were deciding. Sent a `lock_version` and it was stale. Read the note again and decide again — a program's write is never merged into somebody else's, because a program did not type anything to merge.
-
invalid422 - The record refused it. The message is the record's own, in full, so it names the field.
-
missing_parameter422 - A parameter this call cannot do without was absent. `POST /notes` wants its `note` object; the message names what was missing.
-
over_the_note_limit422 - Making a note when the workspace is full. The same numbers as `workspace_locked`, answered earlier because creating is the one write that cannot be allowed to half-happen.
-
over_the_storage_limit422 - Uploading a file the workspace has no room for. The sibling of `over_the_note_limit`, counted in bytes rather than notes. Separate from `invalid` because a program can do something about this one: the message carries how much is used and how much the plan allows, and deleting a file makes room at once rather than overnight.
-
limit_reached403 - The plan's allowance for something is used up. Answered when a workspace already has as many repeating tasks as its plan allows. It names the allowance, so a program can say which plan is in the way rather than reporting a bare refusal — and stopping one makes room at once.
-
column_not_empty422 - A board column that still holds cards. Nothing is cascaded here. Move the cards, then delete the column.
-
too_many_requests429 - Too many requests for one credential. 300 a minute per credential, and 60 a minute on `/subjects`. The answer carries `Retry-After: 60`.
-
no_workspace404 - An MCP connection that reaches no workspace, or more than one. Only `/mcp` answers this. Point the client at `/mcp/w/<id>`; the message lists the workspaces the connection can see.
The reference
Every endpoint, what it needs, what it takes and what it answers with. The list is generated from the application's own routes, so it cannot quietly fall behind them.
- Notes A note is text, a checklist, a board or a map. These are the calls that make, read, change and bin one, whichever kind it is.
- Checklist rows The rows of a checklist: their text, their own notes, what is ticked, and where each one sits in the tree.
- Board columns and cards A board is cards in columns. Cards carry a description, an assignee, a due date and an estimate; columns carry a WIP limit and which one finishes.
- Map nodes The nodes of a mind map: the same tree a checklist has, with a side and a colour.
- Comments The conversations on a note — what somebody asked about a particular sentence, and everything said back. A thread is a conversation; a reply is one message in it.
- Repeating tasks What comes back, and when. Rules are RFC 5545 `RRULE` strings — the ones every calendar exchanges — so a rule you already have can be handed over unchanged, and one you are given can be fed to a calendar.
- Building a tree in one call Make a folder tree and the notes in it in one request, all or nothing. Name things with your own reference ids so a note can go in a folder the same call is about to make, try it without doing it, and send an idempotency key so a lost reply cannot build it twice.
- Note properties Fields on a note itself — a review date, a status, where it came from — rather than words inside it. Every one is optional, and everything here is keyed by a property's KEY, which never changes when it is renamed.
- History and undo Every write leaves a version. These read them, read what the note SAID at one of them, and take back a change.
- Finding things Search, subjects, folders and templates: the calls a program makes before it knows which note it wants.
- Claude, and other agents An MCP server on top of the same API, so a client that speaks MCP can work in a workspace without anybody copying a key. The tools are shaped like things people ask for rather than one per endpoint.
- Workspaces and limits Which workspaces a credential reaches, what it may do in one, and what the plan allows.
Things that are true of every call
- Paging
-
Lists take
pageandper_page— fifty by default, a hundred at most, and twenty-five on/search, which takes noper_pageat all. The paging fields sit beside the collection rather than around it:{"notes": […], "page": 1, "per_page": 50, "total": 120, "pages": 3}. There are no cursors and noLinkheader. - Times and dates
-
Every time is UTC, ISO 8601:
2026-09-16T00:05:17Z. A date that is a date — a card's due date, a diary entry's day — isYYYY-MM-DD. - Writing to a note somebody else might be writing to
-
Every note carries a
lock_version. Send it back with a change and a stale one is refused withconflict; leave it out and the last write wins. Every write to a note's contents — a row, a card, a node — advances it and records a version. - A delete is a bin
-
DELETE /notes/:idanswers 200 with"deleted": trueand a sentence saying it can be put back for thirty days. Removing a row, a card or a node is an ordinary write, and answers with the whole note. - Markdown, and what a reader saw
-
Bodies come back as Markdown. Add
?text=trueto a single note or a single version and every Markdown field gains a plain-text twin —text, ornote_texton a row, card or node. That is the string a comment's quote is anchored against, so a program matching comments wants it. - Putting a picture or a document in a note
-
Bodies are text, and a
data:address in one is refused — a file in a text column is copied into every version the note keeps and counted against nothing. Send the bytes instead, toPOST /notes/:note_id/files: multipart infile, which streams and is allowed the plan's whole upload allowance, or base64 indatawith afilename, which is capped lower because it is held in memory. The answer carriesmarkdown—— ready to paste. Uploading does not change the note. Write that Markdown into the body yourself, withPATCH /notes/:id, or nobody will ever see the file. That is deliberate: an upload is not an edit somebody made, so it costs no version and cannot surprise whoever is typing into the note at the time. The type is decided by the bytes, never by the filename or what you call it, and SVG, HTML and XML are refused whatever they are named, because they can carry scripts and we serve from our own origin. - Rate limits
-
300 requests a minute per credential, and 60 a minute on
/subjects. Over it,too_many_requestsandRetry-After: 60. - Versions of the API
-
One,
/api/v1. We may add fields and error codes without changing it, so a client should ignore what it does not recognise. Anything that would break a working program gets a new version.
Claude, and other agents
There is an MCP server on top of all of this, at
https://goscribi.com/mcp. Paste that into a client that speaks
MCP, press Allow, and it has the same reach a key would give it — no secret
to copy. It discovers where to ask by reading the
WWW-Authenticate header on a 401, which points at
/.well-known/oauth-protected-resource.