# Ela > Notes that remember. How to use Ela, connect an agent, and call the HTTP API. Search returns handles, provenance, and coverage — never full bodies. - [Quickstart](https://docs.elanotes.com/index.md): Open Ela, search your notes, or call the HTTP API. - [Web](https://docs.elanotes.com/web.md): The Next.js Ela app. Three panes. Talks only through the HTTP API when pointed at one. - [Desktop](https://docs.elanotes.com/desktop.md): Unsigned Ela desktop. Local markdown vault first. Optional HTTP replica. - [CLI](https://docs.elanotes.com/cli.md): notes is a first-class API client through @elanotes/sdk. - [MCP local](https://docs.elanotes.com/mcp-local.md): Stdio MCP over a local markdown vault and SQLite FTS5. - [MCP cloud](https://docs.elanotes.com/mcp-cloud.md): Streamable HTTP MCP on the same host and auth as /v1. - [Create, edit, and delete notes](https://docs.elanotes.com/using-notes.md): How to create a note in Ela, edit it in the app or on disk, and delete or archive it. Your markdown folder is the source of truth. - [Search](https://docs.elanotes.com/using-search.md): Search returns handles, provenance, and coverage — never full note bodies. Zero results is a valid answer. - [Privacy](https://docs.elanotes.com/privacy.md): Notes in private/ stay on your machine. The cloud never sees them — not in results, logs, or caches. - [Agents](https://docs.elanotes.com/agents.md): Connect Ela over MCP, HTTP, or the notes CLI. Search returns handles and coverage, not file dumps. - [API overview](https://docs.elanotes.com/api/overview.md): Host path, auth, errors, filters, field masks, pagination, rate limits, idempotency, custom methods, and deprecations. - [Errors](https://docs.elanotes.com/api/errors.md): Stable reason codes, hints, and help anchors used by the HTTP envelope. - [TypeScript SDK](https://docs.elanotes.com/sdk-ts.md): @elanotes/sdk — generated types plus a thin openapi-fetch client. - [Python SDK](https://docs.elanotes.com/sdk-python.md): elanotes — typed httpx client generated from the committed OpenAPI document. - [Changelog](https://docs.elanotes.com/changelog.md): Public API and docs changes for the v1 agentic contract. - [Process liveness](https://docs.elanotes.com/api-reference/meta/process-liveness.md): Unauthenticated liveness probe. Does not check Postgres, the vault working copy, or blob store. - [OpenAPI 3.1 document](https://docs.elanotes.com/api-reference/meta/openapi-31-document.md): Unauthenticated machine-readable contract for the routes this process currently serves. Same document as contracts/openapi/elanotes.v1.json when the drift check is green. - [MCP stream (GET)](https://docs.elanotes.com/api-reference/mcp/mcp-stream-get.md): Streamable HTTP MCP on the same host as `/v1`, with the same auth plugin. Body and status follow the MCP transport (JSON or SSE), not the notes error envelope. Tools are the cloud read registry over the bound vault; agents write notes through HTTP `/v1`, not MCP. - [MCP JSON-RPC (POST)](https://docs.elanotes.com/api-reference/mcp/mcp-json-rpc-post.md): Streamable HTTP MCP on the same host as `/v1`, with the same auth plugin. Body and status follow the MCP transport (JSON or SSE), not the notes error envelope. Tools are the cloud read registry over the bound vault; agents write notes through HTTP `/v1`, not MCP. - [MCP session delete](https://docs.elanotes.com/api-reference/mcp/mcp-session-delete.md): Streamable HTTP MCP on the same host as `/v1`, with the same auth plugin. Body and status follow the MCP transport (JSON or SSE), not the notes error envelope. Tools are the cloud read registry over the bound vault; agents write notes through HTTP `/v1`, not MCP. - [List attachments](https://docs.elanotes.com/api-reference/attachments/list-attachments.md): Attachments indexed for the bound vault. No pagination or type filter on this route. - [Upload an attachment](https://docs.elanotes.com/api-reference/attachments/upload-an-attachment.md): multipart/form-data field `file` (one file). Requires VAULT_PATH. Returns 201 `{ name, sha256 }`. 413 when over the byte cap; 415 when the type is disallowed. Not a JSON body. - [Get attachment metadata and URL](https://docs.elanotes.com/api-reference/attachments/get-attachment-metadata-and-url.md): Presigned URL when the blob store is configured; 503 if BLOB_* is missing. Query sha256 when the file_name is ambiguous (409 lists candidate hashes). - [AuthKit public config](https://docs.elanotes.com/api-reference/auth/authkit-public-config.md): Unauthenticated bootstrap for native PKCE. Returns the WorkOS client_id, optional organization_id, and the iOS redirect URI. 404 when WORKOS_CLIENT_ID is unset. - [Exchange AuthKit tokens](https://docs.elanotes.com/api-reference/auth/exchange-authkit-tokens.md): Unauthenticated token proxy for native PKCE. Proxies authorization_code and refresh_token grants to WorkOS with the server-held API key. Public clients must not hold WORKOS_API_KEY. Counts as a write for rate limit. - [List folders](https://docs.elanotes.com/api-reference/folders/list-folders.md): Sorted vault-relative folder paths, including inferred parents and empty folders declared on the cloud path. No folder_id, color, or depth query. Date folders (YYYY-MM-DD) used as daily-note homes are ordinary paths here. - [Create a folder](https://docs.elanotes.com/api-reference/folders/create-a-folder.md): Body `{ path }`. Nesting is at most one level (parent/child). With `VAULT_PATH`, creates a directory. Without it (cloud / Postgres-only), persists the path in `vault_folders` so GET lists empty folders. Write permission when auth is on. Does not take folder_id. - [Delete a folder](https://docs.elanotes.com/api-reference/folders/delete-a-folder.md): Body `{ path }`. Recursive delete of that directory. Identity is path, not folder_id. Write permission when auth is on. Empty cloud folders delete from `vault_folders`; folders that contain notes still need a working copy. - [Rename a folder](https://docs.elanotes.com/api-reference/folders/rename-a-folder.md): Body `{ path, name }` — folder identity is the existing path; `name` is a single segment. No update_mask. Write permission when auth is on. Empty cloud folders rename in `vault_folders`; folders that contain notes still need a working copy. - [Grep note lines](https://docs.elanotes.com/api-reference/search/grep-note-lines.md): Literal or regex line matches with coverage. Query params: pattern, optional path_glob, case_insensitive, literal, filter, order_by, page_size, page_token, min_seq. Legacy limit stays accepted. Handles plus line text only; not a substitute for GET /v1/notes/{note}. - [Search notes](https://docs.elanotes.com/api-reference/search/search-notes.md): Returns ranked handles with provenance, coverage, ranker_version, and index_version — never full bodies. Scoped to the bearer vault. Query params: q, optional filter (AIP-160 pre-rank scope), order_by, page_size, page_token, min_seq. Legacy limit stays accepted. Silent partial results are a failure;… - [Index status](https://docs.elanotes.com/api-reference/vault/index-status.md): index_version, ranker_version, layer sequences, and counts for the bound vault. Use these versions to interpret search determinism. - [Vault summary](https://docs.elanotes.com/api-reference/vault/vault-summary.md): Note counts, orphans, broken wikilinks, top hubs, excluded folders, and discovered properties for the bound vault. - [List notes](https://docs.elanotes.com/api-reference/notes/list-notes.md): Lists notes in the bound vault. Canonical list params are filter (AIP-160), order_by, page_size, and page_token; the response emits next_page_token. Legacy prefix, cursor, limit, and archived stay accepted and next_cursor stays emitted through v1. GET /v1/daily and /v1/tasks are not routes — use fil… - [Read a note by slug](https://docs.elanotes.com/api-reference/notes/read-a-note-by-slug.md): Line-sliced read of one note. Query params: start_line, end_line, cursor, version_id. Pin version_id when editing. `{note}` is the slug (or id on some review paths), not a folder-qualified path. - [List note links](https://docs.elanotes.com/api-reference/notes/list-note-links.md): Wikilink, embed, tag, and supersedes edges. Query params: direction (forward|back|both), depth (1–3), kinds (comma-separated). - [Read raw note content](https://docs.elanotes.com/api-reference/notes/read-raw-note-content.md): Full markdown body plus path, version_id, and content_hash. Use this when you need the whole file; prefer the line-sliced read for retrieval. - [Create or upsert a note](https://docs.elanotes.com/api-reference/writes/create-or-upsert-a-note.md): Body `{ path, content, agent_id, expect_version_id?, create_only? }`. `Idempotency-Key` header is required. Upserts by path and returns a write receipt (`applied` or `queued`). When `status = applied`, `note` is the GET resource without `lines`. 409 on version move (`reason=VERSION_MOVED`, current_v… - [Delete a note](https://docs.elanotes.com/api-reference/writes/delete-a-note.md): Query `agent_id` and optional `expect_version_id`. `Idempotency-Key` required. Receipt, not 204. Tombstones rather than hard-delete. - [Partial-update a note](https://docs.elanotes.com/api-reference/writes/partial-update-a-note.md): AIP-134/161 PATCH. Query `update_mask` is required and comma-separated (`title`, `content`, `folder`, `tags`, `status`, `frontmatter.`). Body is the partial resource plus `agent_id` and optional `expect_version_id`. Missing or unknown mask is 400 `INVALID_UPDATE_MASK`. Write-plane: review, budg… - [Replace a unique substring](https://docs.elanotes.com/api-reference/writes/replace-a-unique-substring.md): Deprecated slash-form custom method. Use POST /v1/notes/{note}:edit. Body `{ version_id, old_string, new_string, agent_id }`. `Idempotency-Key` required. 409 if version moved; 422 if old_string is missing or ambiguous (`reason=EDIT_AMBIGUOUS`, candidate_lines in ErrorInfo.metadata). - [Move a note to a new path](https://docs.elanotes.com/api-reference/writes/move-a-note-to-a-new-path.md): Deprecated slash-form custom method. Use POST /v1/notes/{note}:move. Body `{ new_path, agent_id, expect_version_id? }`. `Idempotency-Key` required. - [Rename a note slug](https://docs.elanotes.com/api-reference/writes/rename-a-note-slug.md): Deprecated slash-form custom method. Use POST /v1/notes/{note}:rename. Body `{ new_slug, agent_id, expect_version_id?, update_links? }`. `new_slug` is a filename, not a path. - [Replace a unique substring](https://docs.elanotes.com/api-reference/writes/replace-a-unique-substring-1.md): AIP-136 custom method. Body `{ version_id, old_string, new_string, agent_id }`. `Idempotency-Key` required. 409 if version moved; 422 if old_string is missing or ambiguous. - [Move a note to a new path](https://docs.elanotes.com/api-reference/writes/move-a-note-to-a-new-path-1.md): AIP-136 custom method. Body `{ new_path, agent_id, expect_version_id? }`. `new_path` must end in .md and stay inside the vault. - [Rename a note slug](https://docs.elanotes.com/api-reference/writes/rename-a-note-slug-1.md): AIP-136 custom method. Body `{ new_slug, agent_id, expect_version_id?, update_links? }`. `new_slug` is a filename, not a path — use :move to change folders. - [Restore a prior version](https://docs.elanotes.com/api-reference/review/restore-a-prior-version.md): Deprecated slash-form custom method. Use POST /v1/notes/{note}:rollback. Body `{ version_id }` writes that version's content as a new version. - [List note versions](https://docs.elanotes.com/api-reference/review/list-note-versions.md): Deprecated slash-form revision list. Use GET /v1/notes/{note}:listRevisions. Accepts filter, order_by, page_size, page_token. Each version includes AIP-162 `revision_id` / `revision_create_time` plus v1 `version_id` / `id` / `created_at` aliases. - [List note revisions](https://docs.elanotes.com/api-reference/review/list-note-revisions.md): AIP-136 custom method. Same filter, order_by, page_size, and page_token contract as the deprecated /versions list. Each version includes AIP-162 `revision_id` / `revision_create_time` plus v1 `version_id` / `id` / `created_at` aliases. - [Roll back to a prior revision](https://docs.elanotes.com/api-reference/review/roll-back-to-a-prior-revision.md): AIP-136 / AIP-162 custom method. Body `{ version_id }` writes that revision's content as a new version (optimistic concurrency on the current version). - [Get write settings](https://docs.elanotes.com/api-reference/review/get-write-settings.md): Reviewer permission when auth is on. Returns `{ write_policy, write_budget }` for the bound vault. - [Replace write settings](https://docs.elanotes.com/api-reference/review/replace-write-settings.md): Deprecated full PUT replace of `{ write_policy, write_budget }`. Prefer PATCH /v1/vault/write-settings?update_mask=. Reviewer permission when auth is on. - [Partial-update write settings](https://docs.elanotes.com/api-reference/review/partial-update-write-settings.md): AIP-134/161 PATCH. Query `update_mask` must be `write_policy`, `write_budget`, or both. Missing or unknown mask is 400 `INVALID_UPDATE_MASK`. Reviewer permission when auth is on. - [List pending writes](https://docs.elanotes.com/api-reference/review/list-pending-writes.md): Reviewer permission when auth is on. Canonical list params are filter (write fields: status, kind, agent_id, created_at, decided_at), order_by, page_size, page_token. Legacy status stays accepted. GET /v1/writes/{id} follows a queued receipt (AIP-131). - [Get a pending write](https://docs.elanotes.com/api-reference/review/get-a-pending-write.md): AIP-131 Get. Reviewer permission when auth is on. Follow a queued Create/Update receipt by pending_id. - [Approve a pending write](https://docs.elanotes.com/api-reference/review/approve-a-pending-write.md): Deprecated slash-form custom method. Use POST /v1/writes/{id}:approve. Reviewer permission when auth is on. 409 if the write was already decided. - [Reject a pending write](https://docs.elanotes.com/api-reference/review/reject-a-pending-write.md): Deprecated slash-form custom method. Use POST /v1/writes/{id}:reject. Reviewer permission when auth is on. 409 if the write was already decided. - [Approve a pending write](https://docs.elanotes.com/api-reference/review/approve-a-pending-write-1.md): AIP-136 custom method. Reviewer permission when auth is on. 409 if the write was already decided. - [Reject a pending write](https://docs.elanotes.com/api-reference/review/reject-a-pending-write-1.md): AIP-136 custom method. Reviewer permission when auth is on. 409 if the write was already decided. - [Query note properties](https://docs.elanotes.com/api-reference/query/query-note-properties.md): POST-only property aggregation (filters, sort, group_by, aggregate). The list path is GET /v1/notes?filter= (AIP-160). This route is not a tags or daily-notes endpoint. - [Store a replica checkpoint](https://docs.elanotes.com/api-reference/sync/store-a-replica-checkpoint.md): Full replace of the replica checkpoint. Write permission when auth is on. Rejects unsealed E2EE snapshots. - [E2EE replica status](https://docs.elanotes.com/api-reference/sync/e2ee-replica-status.md): Whether private notes are enabled for this vault, plus the salt and recovery notice. Replica plane; not a notes CRUD route. - [Enable private notes](https://docs.elanotes.com/api-reference/sync/enable-private-notes.md): One-way opt-in. Body must acknowledge the canonical recovery notice. 409 if already enabled. Write permission when auth is on. - [Pull replica ops](https://docs.elanotes.com/api-reference/sync/pull-replica-ops.md): Device replica log after `after_seq`. 409 when the cursor is behind compaction (`reason=SYNC_COMPACTED`, after_seq and compacted_through_seq in ErrorInfo.metadata). Not a notes list. - [Push replica ops](https://docs.elanotes.com/api-reference/sync/push-replica-ops.md): Ingest sealed replica ops from a device. Write permission when auth is on. Rejects unsealed E2EE ops. - [Replica snapshot](https://docs.elanotes.com/api-reference/sync/replica-snapshot.md): Current replica snapshot for hydrate. Replica plane only. - [List tags](https://docs.elanotes.com/api-reference/tags/list-tags.md): Rolls up frontmatter tags (inline arrays and YAML block sequences) to { name, note_count } plus coverage. Optional filter scopes which notes contribute. Body #hashtags are not tags. ## OpenAPI Specs - [openapi](/openapi.json)