# jot A collaborative text editor. Documents are plain text, edited in real time by people in a browser and by agents over HTTP. Both go through the same operational-transform path, so text written here appears live in any editor that has the document open — character by character if you stream it. ## Authentication Create a key at https://jot.hyper.video/settings/keys, then send it as a bearer token: Authorization: Bearer jot_sk_... Requests with no key act as an anonymous browser session. Anyone with a document's URL can read and write it unless its visibility is "private". ## Endpoints Base: https://jot.hyper.video/api/v1/documents (alias: https://jot.hyper.video/api/docs) POST / Create. Body: {text?, language?, title?, visibility?} -> 201 {id, url, version} GET / List documents you own. -> {documents:[...]} 401 if no key was sent, rather than an empty list — an empty list would be indistinguishable from a key that never arrived. GET /:id Read. Accept: text/plain (default) or application/json PUT /:id Replace the whole document. Body: text, or {text} PATCH /:id Surgical edit. Body is one of: {"append": "..."} {"insert": {"at": 120, "text": "..."}} {"replace": {"from": 10, "to": 20, "text": "..."}} POST /:id/append Append. Body: text, or {text} POST /:id/stream Append a streaming body, flushed every ~60ms. This is the one to use for model output. GET /:id/events Server-sent events: an initial "snapshot", then an "update" per change. PATCH /:id/settings Body: {visibility?, title?, readOnly?} visibility and readOnly are owner only; title needs write access, like the language. DELETE /:id Owner only. GET /:id/comments Margin comments, in document order. ?context=200 adds "before"/"after" text around each anchor. -> {id, version, comments:[...]} POST /:id/comments Add a comment anchored to a text range. Body: {"body": "...", "quote": "exact text"} or {"body": "...", "from": 10, "to": 42, "at": } "quote" anchors to the first occurrence of that exact text — use it instead of computing offsets. Optional "author" names the card. -> 201 {id, comment} PATCH /:id/comments/:cid Body: {"resolved": true|false} DELETE /:id/comments/:cid Comment author or document owner only. ## Notes - PUT computes a minimal diff, so replacing a document does not disturb other people's cursors or flash the whole text. - Documents are capped at 512 KB. A single edit may add at most 64 KB. - A private document answers 404 to anyone who cannot read it. - A well-formed id nobody has written to reads as an *empty* document, not a 404 — documents are addressed by name, so any valid id can be written to. Check "version": 0 (or the x-jot-version header, which text/plain reads also carry) before concluding a document is genuinely empty rather than mistyped. - Every error body carries "docs" pointing back here, and every response to this API carries a Link: rel="service-desc" header saying the same. - Writes answer with a RateLimit-Policy header describing the quota you are held to: 40 creates and 200 other writes per 60s, keyed per API key. There is deliberately no RateLimit-Remaining — the limiter does not report one, and a guess is worse than nothing. On 429, Retry-After is authoritative. - A document its owner has locked ("readOnly": true) still reads normally, but every write answers 403 {"error":"read_only"} for everyone except the owner. Retrying will not help; the owner has to unlock it. - Language is detected from the content when nobody has chosen one; setting it explicitly wins from then on. - Comments need only read access — they work on a locked document, which is the intended review flow: a human shares a read-only jot, you comment on it. Comment anchors are transformed through every edit server-side, so the from/to you read back always describe the current text. If the anchored text is deleted entirely the comment survives with "orphaned": true and its original excerpt. Each comment carries the quoted excerpt it was anchored to. ## Examples curl -X POST https://jot.hyper.video/api/v1/documents \ -H "Authorization: Bearer $JOT_KEY" \ -H "content-type: application/json" \ -d '{"text":"# Notes\n","language":"markdown"}' curl https://jot.hyper.video/api/v1/documents/ curl -X POST https://jot.hyper.video/api/v1/documents//stream \ -H "Authorization: Bearer $JOT_KEY" --data-binary @output.txt ## MCP A Model Context Protocol server is available at https://jot.hyper.video/mcp over streamable HTTP, authenticated with the same bearer key. Tools: create_document, read_document, append_to_document, replace_document, list_documents, list_comments, add_comment, resolve_comment. Send "Accept: application/json, text/event-stream" — the streamable HTTP transport requires both, and answers -32000 "Not Acceptable" without them. The server returns usage guidance in the "instructions" field of the initialize result, so an MCP client will normally surface it to the model without anyone fetching this file. Streaming, surgical PATCH edits, settings, SSE and DELETE are HTTP-only. DELETE in particular is deliberately not a tool: it is permanent, and an agent should not be one mistaken call away from destroying someone's document.