# txt — Full API & SDK Reference # Generated: 2026-10-14T04:47:36.887Z # Base URL: https://api.txt.mn =========================================================================== ## 0. Mental model — remote text filesystem =========================================================================== txt notes and attachments are files. Cloud sync (dots) exposes them as a read/write HTTP filesystem for other apps (CLI, React Native, MCP, desktop, agents). Attachment bytes stay in the user's private dots blob; txt manages their workspace metadata and links. Stable developer routes use /api/v1. Existing /api/me and /api/files routes remain supported for installed clients. GET /api/v1 is the live discovery document. v1 adds scoped/expiring keys, cursor pagination, CORS, DB-backed quotas, X-Request-ID, If-Match conditional writes, and Idempotency-Key replay. list / readdir GET /api/me | /api/me/files | /api/me/folders skills GET /api/v1/skills read GET /api/me/files/:id | …/raw write PUT /api/me/files/:id create POST /api/me/files upload bytes POST /api/me/files/upload?name=FILE_NAME import URL POST /api/me/files/import temp link POST /api/me/files/:id/share identities GET|PATCH /api/v1/identities ideate GET|POST /api/v1/ideation | POST /api/v1/files/:id/ideate render POST /api/v1/artifacts unlink DELETE /api/me/files/:id stat HEAD /api/me/files/:id | …/raw connect GET /api/me/files/:id/connections Every file and folder can carry: context human/agent-readable purpose, scope, people, and constraints tags normalized reusable labels for deterministic connections Performance contract: - Directory listings NEVER include file bodies (only size + mtime). - GET file/raw returns ETag + Last-Modified. - If-None-Match → 304 (empty body) when the revision is unchanged. - Folder GET defaults to metadata; pass ?include=content for bodies. - Versions list omits bodies unless ?include=content. Human API page: https://api.txt.mn/api Interactive docs: https://api.txt.mn/api/playground Developer dashboard: https://api.txt.mn/api/dashboard Short agent doc: https://api.txt.mn/llms.txt Mint a key: https://txt.mn/sync (vanity redirect to the working sync page) =========================================================================== ## 1. Authentication =========================================================================== All API endpoints accept authentication in two forms: 1. Browser session cookie (set automatically when signed in with dots at https://api.txt.mn/auth/sign-in) 2. Bearer API key: Authorization: Bearer txt_ First-party native clients may instead send a dots OAuth Authorization Code + PKCE access token as Bearer auth. Store it in Keychain/secure storage and refresh it without discarding offline edits. Generate API keys at https://txt.mn/sync or via POST /api/me/keys (session). Keys are prefixed with "txt_" and hashed at rest. Key creation accepts scopes plus expiresInDays (1, 7, 30, 90, 365, or null). Available scopes: files:read, files:write, folders:read, folders:write, collaboration:read, collaboration:write, shares:read, shares:write, ai:use. Raw keys are returned once. Rotation preserves scope/expiry; revocation is immediate. =========================================================================== ## 2. REST API Reference =========================================================================== All responses are JSON unless noted. v1 infrastructure errors return { error: { code, message, requestId } }; legacy route errors retain { error: string } for compatibility. Every v1 response includes X-Request-ID. --------------------------------------------------------------------------- ### 2.1 User & File Tree (directory listing) --------------------------------------------------------------------------- GET /api/me Returns the file tree — metadata only, no bodies. Response: { user: { id, email, name }, folders: [ { id, name, context, tags, fileCount, createdAt, updatedAt, endpoint, files: [...] } ], rootFiles: [ { id, name, context, tags, type, size, createdAt, updatedAt, endpoint, raw } ] } GET /api/me/files Flat file index (preferred by desktop / SDK). Metadata only. POST /api/me/files Create a file. Body: { name, content?, context?, tags?, fileType?, folderId?, availability? } availability is "cloud" or "cloud+local" (default). A local-only file is intentionally outside the cloud API until a client uploads it. DELETE /api/me/files/:id Unlink a file. --------------------------------------------------------------------------- ### 2.2 Files (read / write) --------------------------------------------------------------------------- GET /api/me/files/:id Returns full file metadata and content. content is null for dots-backed attachments; use /raw to download their bytes. Headers: ETag, Last-Modified, Cache-Control: private, no-cache If-None-Match → 304 when unchanged. Response: { id, name, content, context, tags, type, availability, folderId, size, createdAt, updatedAt } HEAD /api/me/files/:id Stat only (ETag, Content-Length, no body). GET /api/me/files/:id/raw Raw bytes (no JSON) with the stored Content-Type. Same ETag / 304 / HEAD behavior as JSON GET. POST /api/me/files/upload?name=FILE_NAME&folderId=OPTIONAL_ID Upload any non-empty raw body up to 100 MB. Content-Length is checked when supplied; the actual body length is always enforced. Content-Type is preserved. The response metadata includes storage:"dots" and raw:/api/v1/files/:id/raw. Stable route: /api/v1/files/upload. POST /api/me/files/import Import one public HTTPS resource into private dots storage. Body: { url, name?, folderId?, context?, tags? }. Redirects and private-network destinations are blocked; the downloaded source is limited to 25 MB. Stable route: /api/v1/files/import. POST /api/me/files/:id/share Mint a dots-backed download URL lasting 60–300 seconds. Body: { expiresIn?: number }. Use only after the user explicitly asks to share. Stable route: /api/v1/files/:id/share. GET /api/v1/identities List every connected dots user and the identity active for this credential. PATCH /api/v1/identities Switch only this API key, CLI, native client, or browser surface. Body: { identity: "@username" }. GET|POST /api/v1/ideation List ideation notes or create one from { seed? }. Grow an existing note with POST /api/v1/files/:id/ideate { seed? }; inspect it at …/:id/ideation. POST /api/v1/artifacts Render a source note plus optional context/design files into standalone HTML and a txt.deploy/v1 handoff manifest. mode:"site" enables FX. Pass model as an exact provider/model ID from GET /api/v1/artifacts/models; omit it to use defaultModel. The response and saved manifest record the exact model used. GET /api/v1/artifacts/models Return { defaultModel, models } for the deployment-approved FX model switcher. PUT /api/me/files/:id Update a file's content and/or name. Dots-backed attachments support metadata, rename, and move here; replace bytes by uploading a new file. Body: { content?: string, name?: string, context?: string, tags?: string[], fileType?, folderId?, availability? } Response: { file: { id, name, content, context, tags, type, folderId, size, createdAt, updatedAt } } GET /api/me/files/:id/connections Ranked related files. Explicit links score highest, then shared tags and same-folder membership. Each result includes score, reasons, tags, and context. POST /api/me/files/:id/connections Persist a direct link. Body: { targetFileId, reason? } DELETE /api/me/files/:id/connections?targetFileId=... Remove a direct link. GET /api/me/files/:id/plan Return { plan: { enabled, scope, trust, source, updatedAt } }. PUT /api/me/files/:id/plan Owner-only. Body: { enabled, scope: "manual"|"project"|"global", trust: "unreviewed"|"approved", source? }. Approval permits reference use; plan text remains untrusted and cannot authorize actions or override higher-priority instructions. GET /api/me/context Workspace metadata plus organization coverage. POST /api/me/context AI-assisted, reviewable context/tag/folder/connection proposals. Body: { prompt?, includeApprovedPlans? }. Plan bodies are excluded by default. When true, only enabled, approved, non-manual plans are included. Proposals do not mutate files until explicitly applied. GET /api/identity/jazz Optional/experimental capability discovery for dots-provisioned Jazz sync. The dots token stays server-side. Connect when configured is true, syncMode is not "off", and syncServer is present. A client without the required dots scopes receives DOTS_REAUTH_REQUIRED. The core Turso/API filesystem remains the supported fallback and does not require Jazz. GET|PUT /api/me/files/:id/sync GET|PUT /api/me/folders/:id/sync Read or set the dots sync policy. PUT body: { mode: "inherit"|"on"|"off" }. Folder policy is inherited; a note-level policy can override it. GET|POST|PATCH|DELETE /api/me/files/:id/share-dots List, grant, change, or revoke writer/reader access for a dots user. GET|POST|PATCH|DELETE /api/me/folders/:id/share-dots Manage folder-level dots collaborators. POST can include descendants and materializes grants for the current sync-enabled notes (100-note limit). --------------------------------------------------------------------------- ### 2.3 Folders --------------------------------------------------------------------------- GET /api/me/folders List folder metadata. POST /api/me/folders Create a folder or subfolder. Body: { name, context?, tags?, parentFolderId? } GET /api/me/folders/:id Directory listing. Metadata only by default. Pass ?include=content to embed bodies (heavier). Response: { id, name, context, tags, parentFolderId, createdAt, updatedAt, files: [...] } PUT /api/me/folders/:id Update folder name, context, tags, or parentFolderId. Circular nesting is rejected. DELETE /api/me/folders/:id Delete the folder and promote direct files and subfolders one level. --------------------------------------------------------------------------- ### 2.4 Version History --------------------------------------------------------------------------- GET /api/me/files/:id/versions List immutable versions, newest first (metadata by default). Pass ?include=content for bodies. Response includes version_number, content_hash, byte_size, author, source, label, and created_at. POST /api/me/files/:id/versions Commit an immutable version. Body: { content?, label?, source?, commitId? }. Omit content to snapshot the server working copy. commitId makes retries idempotent. Writers may commit; readers may only list/fetch. GET /api/me/files/:id/versions/:versionId Fetch one immutable version including content. --------------------------------------------------------------------------- ### 2.5 Comments (multiplayer) --------------------------------------------------------------------------- GET /api/files/:id/comments Browser-session only. Response fields include id, file_id, user_id, user_email, user_name, body, selection_start, selection_end, selected_text, resolved, resolved_by, resolved_at, created_at, and updated_at. Polls every 5 s in the web app UI. POST /api/files/:id/comments Body: { body, selectionStart?, selectionEnd?, selectedText? }. Response: { comment: {...} } PATCH /api/files/:id/comments Resolve or re-open a comment. Body: { commentId, resolved }. DELETE /api/files/:id/comments Query: ?commentId=... --------------------------------------------------------------------------- ### 2.6 Suggestions (track-changes) --------------------------------------------------------------------------- GET /api/files/:id/suggestions Browser-session only. Response fields include original_text, suggested_text, selection_start, selection_end, status, reviewer, and timestamps. status is one of: pending | accepted | rejected POST /api/files/:id/suggestions Propose a change without modifying the live file. Body: { originalText?, suggestedText, selectionStart, selectionEnd }. Response: { suggestion: {...} } PATCH /api/files/:id/suggestions Accept or reject a suggestion. Body: { suggestionId, status: "accepted" | "rejected" }. --------------------------------------------------------------------------- ### 2.7 API Keys --------------------------------------------------------------------------- GET /api/me/keys Response: { keys: [ { id, label, token_prefix, created_at, last_used_at } ] } POST /api/me/keys Body: { label?: string } Response: { id, label, token: "txt_...", token_prefix } IMPORTANT: the full token is only returned once — store it securely. PATCH /api/me/keys Rotate an existing key. Body: { id: string } Response: { id, label, token: "txt_...", token_prefix, rotated_from } IMPORTANT: the old key is revoked and the replacement token is shown once. DELETE /api/me/keys Body: { id: string } --------------------------------------------------------------------------- ### 2.8 AI credentials and usage --------------------------------------------------------------------------- Human configuration: https://api.txt.mn/ai GET /api/me/ai User-activated provider preference, usage, and credential metadata only. AI is off when provider is null. Accepts a browser session or Bearer txt_ key. Never returns provider secrets. PUT /api/me/ai Select an already-configured user-funded provider: { provider: "gateway"|"openai"|"anthropic" } GET|PUT|DELETE /api/me/ai/credentials Browser-session-only write-only vault. Provider credentials are verified, AES-256-GCM encrypted, user/provider-bound, and never returned. Do not ask an agent to collect, print, save, or rotate a human's provider key. POST /api/ai/assist Uses the account preference and rejects request-scoped X-Txt-AI-Key headers. Accepts text, action/customPrompt, fileName, scope (selection|document), and targetFormat (preserve|markdown|plain-text|html|json|yaml|mermaid|fountain). Selection scope returns replacement text. Document scope returns a complete transformed document; AI Gateway document transforms run through fx. txt-cli BYOK bypasses this endpoint and calls the chosen provider directly. --------------------------------------------------------------------------- ### 2.9 Public links --------------------------------------------------------------------------- POST /api/shares Create a live capability link from { fileId, mode, password? }. The server reads the canonical file; callers do not upload a second content snapshot. Modes may be editable, readonly, password, or password-readonly. Defaults to a compact random txt.mn URL. Optional name creates a chosen alias; linkStyle selects short or named. Returns publicUrl, shortUrl, namedUrl, tokenUrl, and a separate nav.link tracking descriptor when configured. PATCH /api/shares Owner-only token + linkStyle and/or name changes the URL preference without rotating the capability or changing its password. Name conflicts return 409. GET /api/shares?slug=... or ?token=... Read the current canonical file. Password modes use X-Txt-Share-Password; passwords never enter URLs or logs. GET /api/shares?fileId=... Authenticated owner lookup for the file's active link; returns { share: null } when the file has no link. PUT /api/shares Update the canonical file through an editable link with { token, content, password? }. DELETE /api/shares Revoke an owned link with { token }. --------------------------------------------------------------------------- ### 2.10 Devices & per-device availability (Dropbox-style three-state) --------------------------------------------------------------------------- The server-wide file column "availability" ("cloud" | "cloud+local") is the default for every device. A registered device can override it per file: "online-only" (tracked placeholder, no bytes on that device), "available" (cached, evictable), or "pinned" (guaranteed local, eviction refused). Metadata always syncs everywhere; only content follows the state. POST /api/v1/devices Register an installation once: { name?, platform? } → { device: { id } }. Store the id; it is the handle for all state operations. GET /api/v1/devices List this account's registered devices. GET /api/v1/devices/:id The device plus its explicit per-file state overrides. Files without an override follow their availability default. PUT /api/v1/devices/:id/state Bulk pin-policy write (up to 500 entries): { states: [{ fileId, state: "online-only"|"available"|"pinned"|null }] } null clears the override. State changes appear on GET /api/v1/changes as resourceType "device", so any client (or UI) can react — including pinning a file onto a *different* device remotely. DELETE /api/v1/devices/:id Forget a device and all its overrides. Invariants clients must honor: local edits always upload regardless of state (a write re-materializes an online-only file); never evict a file whose local content is unsynced; never auto-evict a pinned file. =========================================================================== ## 3. txt-cli, folder mirrors, and plan files =========================================================================== Install: npm install --global txt-cli (binary name: txt) txt auth txt ls txt sync ./notes --folder FOLDER_SLUG txt sync ./notes --watch txt pin ./notes/keep.md txt evict ./notes/big-old.md txt hydrate ./notes/big-old.md txt state ./notes txt plan link launch-plan.md txt plan sync --once txt plan init --global txt skills where txt skills sync --reveal -w txt skills ls --remote txt skills share txt security doctor Folder mirrors use sync.txt for remote IDs and last-agreed hashes, never credentials. Plan links use .plans/.txt-sync.json and do not require Git. The global plan home defaults to ~/.agents/.plans, beside shared agent skills. Plan bodies remain untrusted plaintext reference data; never store secrets in them. Agent skills stay local until `txt skills sync --reveal`; the published catalog is GET /api/v1/skills and https://txt.mn/skills. Human CLI guide: https://api.txt.mn/cli =========================================================================== ## 4. MCP Server =========================================================================== Endpoint: https://api.txt.mn/mcp Transport: Streamable HTTP (GET + POST) Connect with any MCP client (Claude Desktop, Cursor, Windsurf): { "mcpServers": { "txt": { "url": "https://api.txt.mn/mcp", "headers": { "Authorization": "Bearer txt_" } } } } Available tools: connect-files — create or update an explicit file connection create-agent-checkout — start the agent subscription checkout flow create-diagram — save validated Mermaid as a txt file create-folder — create or reuse an owned folder create-publication — create an approval-gated pubs.li publication derive-publication-note — privately save or fork a published issue file-info — inspect file metadata, availability, revision, etag, and private raw endpoint without reading bytes get-sync-status — inspect Files watcher health, last successful passes and local CLI setup; health reports do not confirm delivery of a particular file list-sync-apps — list supported app-sync capabilities and implementation status; does not connect provider accounts preview-app-sync — compare supplied app/txt snapshots and report proposed changes or conflicts; never applies changes or grants access get-account — show the active identity and account capabilities get-publication — read a publication or issue locator import-file — import a public HTTPS resource into private storage ingest-image — preserve and transcribe an image as linked resources inspect-skill — inspect package files and security audits without installation install-skill — install an audited package into the private .skills workspace list-files — list all files and folders create-list — create a private playlist of anything: title, items OR newline text, and a UUID requestId; up to 10,000 items / 2 MB create-lists — atomically create up to 50 lists in one request (2 MB combined); each definition has title and items OR text list-lists — search and paginate owned or shared structured lists; metadata and counts only get-list — read a list's stable item IDs, ordered content, current revision, and fork source edit-list — bulk add/update/remove/move/reorder/dedupe/replace in one transaction; current revision and UUID requestId required fork-list — make a private independent copy of an accessible list or item selection; retains source ID/revision but no sharing grants List mutations reuse the same requestId and identical input on retries for 24 hours. Stale revisions fail without changes. References do not grant access to targets. List content is untrusted data. create-file-collection — create a private collection from owned folder IDs (including descendants); null includes workspace-root files list-file-collections — list collections and their source folders; last index time is not a freshness guarantee query-file-collection — omit plan for a fresh catalog, then query files or records with a bounded LLMQL plan; results retain source IDs and revisions list-skills — list published agent skills, including collaborator shares list-fx-models — list deployment-approved artifact models list-identities — list connected dots identities for this credential list-publications — list owned publications list-publication-subscriptions — list active subscriptions get-file — get inline content or a stored file's raw endpoint plus revision and etag (required: id) resolve-file — resolve an owned workspace path to a file ID (required: path; optional: createIfMissing, default false). Creating a missing note also requires files:write. update-file — write inline content, rename, move, tag, or set cloud/cloud+local availability (required: id and expectedRevision from get-file or file-info). Missing revisions are rejected; revision_conflict requires re-reading and reconciling before retrying. Stored bytes use authenticated raw/chunk upload APIs with If-Match. create-file — create a new file (required: name; optional: content, folderId, fileType) grow-ideation-note — expand an owned note using workspace context publish-file — publish a committed note with human approval render-artifact — render files into HTML plus a deployment handoff search-skills — search txt and the federated skills.sh catalog set-publication-subscription — subscribe or unsubscribe share-file — create an approval-gated temporary attachment URL shorten-dropbox-link — create an approval-gated txt viewer URL start-agent-onboarding — begin first-party agent onboarding switch-identity — switch only this credential's active dots identity view-skill — save an inert private package snapshot for review trash_note — move a note to reversible trash (required: id) restore_note — restore a trashed note (required: id) purge_trashed_note — permanently delete an already-trashed note with explicit confirmation get-clue — inspect aclue's brain state and suggestions run_aclue — explicitly run aclue self-reasoning (required confirmation: RUN ACLUE) Files is a shared filesystem for people and agents. MCP, HTTP, the web app, and local folder sync use the same file IDs and revisions. Local agents run txt files sync --folder --watch --json on the target machine after authenticating. Omit --watch for one pass. Local edits upload; cloud/agent edits download; concurrent edits keep conflict copies. Offline continuous watchers retry after connectivity returns. A hosted MCP call cannot start a local watcher. Cloud write success is not local delivery confirmation. Use get-sync-status for watcher health and check local actions for delivery. =========================================================================== ## 5. SDK — TypeScript / JavaScript / React Native =========================================================================== TypeScript source (copy-paste or import): https://api.txt.mn/sdk Pre-built ESM bundle (no build step): https://api.txt.mn/sdk.js --------------------------------------------------------------------------- ### 5.1 Install --------------------------------------------------------------------------- Option A — copy the TypeScript source into your project: curl https://api.txt.mn/sdk > lib/txt-sdk.ts Option B — dynamic import in Node / Deno / browser: const { TxtClient } = await import("https://api.txt.mn/sdk.js") Option C — npm (if published): npm install txt-sdk # or pnpm add / yarn add --------------------------------------------------------------------------- ### 5.2 Basic usage --------------------------------------------------------------------------- import { TxtClient } from "./txt-sdk" const txt = new TxtClient({ baseUrl: "https://api.txt.mn", apiKey: "txt_...", }) // List all files const tree = await txt.list() // Read a file const file = await txt.getFile("file_id") console.log(file.content) // Write to a file await txt.updateFile("file_id", { content: "Hello from the SDK!" }) // Get raw text (no JSON) const raw = await txt.getRaw("file_id") --------------------------------------------------------------------------- ### 5.3 Real-time sync (ETag polling) --------------------------------------------------------------------------- // Uses If-None-Match — unchanged polls return 304 (no body) const stop = txt.sync("file_id", (content, file) => { console.log("File updated:", content) }, 5000) // Stop syncing stop() // Watch multiple files at once const stopAll = txt.syncMany( ["file_a", "file_b"], (fileId, content) => console.log(fileId, content), ) --------------------------------------------------------------------------- ### 5.4 React hook (web + React Native) --------------------------------------------------------------------------- import { TxtClient, useTxtFile } from "./txt-sdk" const client = new TxtClient({ baseUrl: "https://api.txt.mn", apiKey: "txt_..." }) function NoteScreen({ fileId }) { const { content, loading, error, update } = useTxtFile(client, fileId) if (loading) return return ( update(text)} multiline /> ) } --------------------------------------------------------------------------- ### 5.5 React Native — quick notes app pattern --------------------------------------------------------------------------- // 1. Store the API key securely import * as SecureStore from "expo-secure-store" await SecureStore.setItemAsync("txt_key", "txt_...") const key = await SecureStore.getItemAsync("txt_key") // 2. Create the client const txt = new TxtClient({ baseUrl: "https://api.txt.mn", apiKey: key }) // 3. List notes on mount useEffect(() => { txt.list().then(tree => setFiles(tree.rootFiles)) }, []) // 4. Sync a single note live useEffect(() => { if (!activeFileId) return return txt.sync(activeFileId, (content) => setNote(content)) }, [activeFileId]) // 5. Save on blur / debounce const save = useDebouncedCallback( (content) => txt.updateFile(activeFileId, { content }), 800, ) --------------------------------------------------------------------------- ### 5.6 Comments & suggestions from code --------------------------------------------------------------------------- // Post a comment anchored to selected text await txt.createComment(fileId, "Check this phrasing", "selected text here") // Propose a change without editing the live doc await txt.createSuggestion(fileId, "old text", "new text") // Accept a suggestion (applies the diff to the file) await txt.reviewSuggestion(fileId, suggestionId, "accepted") =========================================================================== ## 6. SDK Source =========================================================================== // SDK source not available — fetch from https://api.txt.mn/sdk