{"components":{"headers":{"IdempotentReplayed":{"description":"`true` when the response is a stored result of an earlier request with the same Idempotency-Key.","schema":{"enum":["true"],"type":"string"}},"RetryAfter":{"description":"Seconds to wait before retrying. Sent on 429, on 409 IDEMPOTENCY_IN_PROGRESS and on temporary 503s.","schema":{"type":"integer"}}},"parameters":{"At":{"description":"Moment in time (RFC 3339).","in":"query","name":"at","required":true,"schema":{"format":"date-time","type":"string"}},"Embedding":{"description":"Your own query embedding — base64 of little-endian float32 values.","in":"query","name":"embedding","schema":{"contentEncoding":"base64","type":"string"}},"ExternalId":{"description":"Your identifier (1–512 bytes, no control characters), URL-encoded.","in":"path","name":"eid","required":true,"schema":{"maxLength":512,"minLength":1,"type":"string"}},"GroupBy":{"description":"`vault` adds a per-vault breakdown (`by_vault`).","in":"query","name":"group_by","schema":{"default":"metric","enum":["metric","vault"],"type":"string"}},"IdempotencyKey":{"description":"Makes retries of this write safe; see \"Idempotency\" above.","in":"header","name":"Idempotency-Key","required":false,"schema":{"maxLength":255,"minLength":1,"type":"string"}},"NoteId":{"description":"Note id (UUID).","in":"path","name":"id","required":true,"schema":{"type":"string"}},"Page":{"description":"1-based page. Values above 100000 or non-integers → 400 INVALID_PAGE.","in":"query","name":"page","schema":{"default":1,"maximum":100000,"minimum":1,"type":"integer"}},"Since":{"description":"Period start, exclusive (RFC 3339). Default — the beginning.","in":"query","name":"since","schema":{"format":"date-time","type":"string"}},"Stream":{"description":"`1` streams progress as server-sent events (text/event-stream).","in":"query","name":"stream","schema":{"enum":["1"],"type":"string"}},"SubjectFilter":{"description":"Only notes of this end user (1–256 bytes, no control characters;\notherwise `400 INVALID_SUBJECT`). Absent or empty — all notes of the\nvault.\n","in":"query","name":"subject_id","schema":{"maxLength":256,"type":"string"}},"TenantId":{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}},"Until":{"description":"Period end, inclusive (RFC 3339). Default — now.","in":"query","name":"until","schema":{"format":"date-time","type":"string"}},"WebhookDeliveryHeader":{"description":"Delivery id; the same on retries — deduplicate on it.","in":"header","name":"X-DB-Delivery","required":true,"schema":{"format":"uuid","type":"string"}},"WebhookEventHeader":{"description":"Event name.","in":"header","name":"X-DB-Event","required":true,"schema":{"type":"string"}},"WebhookSignatureHeader":{"description":"`sha256=` + hex HMAC-SHA256 of `\u003cX-DB-Timestamp\u003e.\u003craw body\u003e` with the webhook secret.","in":"header","name":"X-DB-Signature","required":true,"schema":{"type":"string"}},"WebhookTimestampHeader":{"description":"Unix time of this attempt, seconds.","in":"header","name":"X-DB-Timestamp","required":true,"schema":{"type":"string"}}},"responses":{"BadGateway":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"An upstream call failed (LEARN_FAILED from the LLM, FETCH_FAILED for a URL)."},"BadRequest":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Invalid request (BAD_REQUEST, INVALID_PAGE, MISSING_VAULT, INVALID_IDEMPOTENCY_KEY, INVALID_URL, BLOCKED_URL, INVALID_SUBJECT, INVALID_SCOPES, INVALID_EVENTS, INVALID_WEBHOOK_URL, …)."},"Conflict":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Conflict (TITLE_CONFLICT, EXTERNAL_ID_CONFLICT, IDEMPOTENCY_IN_PROGRESS). Only IDEMPOTENCY_IN_PROGRESS carries Retry-After.","headers":{"Retry-After":{"$ref":"#/components/headers/RetryAfter"}}},"Forbidden":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Account suspended (ACCOUNT_SUSPENDED), vault cap reached (VAULT_LIMIT_REACHED), webhook cap reached (WEBHOOK_LIMIT_REACHED) or the vault key may not do this (INSUFFICIENT_SCOPE)."},"InternalError":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Server error (INTERNAL_ERROR or an operation-specific *_FAILED code)."},"NotFound":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Not found (NOT_FOUND, VAULT_NOT_FOUND, PLAN_NOT_FOUND, NOT_FOUND_AT_TIME)."},"PayloadTooLarge":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Request body too large (BODY_TOO_LARGE), a note too large (NOTE_TOO_LARGE), storage full (STORAGE_LIMIT_REACHED) or a vault too large to export (EXPORT_TOO_LARGE)."},"PaymentRequired":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"The account balance is used up (BALANCE_EXHAUSTED); reads still work."},"ServiceUnavailable":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Unavailable. SERVICE_BUSY, VAULT_UNAVAILABLE and EMBEDDER_UNAVAILABLE\nafter an embedder failure are temporary and carry Retry-After.\nEMBEDDER_UNAVAILABLE without an embedder configured, LEARN_UNAVAILABLE\nand LEARN_FAILED (feature not configured) are permanent for this\nserver and have no Retry-After.\n","headers":{"Retry-After":{"$ref":"#/components/headers/RetryAfter"}}},"TooManyRequests":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Rate limit exceeded (RATE_LIMITED).","headers":{"Retry-After":{"$ref":"#/components/headers/RetryAfter"}}},"Unauthorized":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Missing or invalid credentials (UNAUTHORIZED, AUTH_MISSING, AUTH_INVALID)."},"UnprocessableEntity":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"IDEMPOTENCY_KEY_MISMATCH, NOT_HTML, EMPTY_CONTENT."}},"schemas":{"Account":{"properties":{"features":{"description":"What this server has switched on.","properties":{"learn":{"description":"LLM routes (`/learn`, `/learn/from-vault`, `POST /memories`, suggest-tags, reanalyze) are available.","type":"boolean"},"note_expiry":{"description":"Notes past `expires_at` are moved to the trash. `false` — `expires_at` is stored but nothing acts on it.","type":"boolean"},"sync_preview":{"description":"`POST /sync` understands `dry_run`. A server without this flag ignores `dry_run` and writes the files — check it before asking for a preview.","type":"boolean"}},"required":["note_expiry","learn","sync_preview"],"type":"object"},"limits":{"properties":{"graph_rag_per_min":{"type":"integer"},"learn_per_min":{"type":"integer"},"rebuild_per_min":{"type":"integer"},"requests_per_min":{"description":"0 — unlimited.","type":"integer"},"storage_bytes":{"description":"null — unlimited.","format":"int64","type":["integer","null"]},"vault_create_per_min":{"type":"integer"},"vaults":{"description":"null — unlimited.","type":["integer","null"]}},"required":["storage_bytes","vaults","requests_per_min","learn_per_min","graph_rag_per_min","rebuild_per_min","vault_create_per_min"],"type":"object"},"name":{"type":"string"},"plan":{"$ref":"#/components/schemas/Plan"},"status":{"$ref":"#/components/schemas/TenantStatus"},"tenant_id":{"format":"uuid","type":"string"},"vaults_used":{"type":"integer"}},"required":["tenant_id","name","plan","status","limits"],"type":"object"},"AddMemoriesRequest":{"properties":{"messages":{"items":{"$ref":"#/components/schemas/MemoryMessage"},"maxItems":200,"minItems":1,"type":"array"},"metadata":{"additionalProperties":true,"description":"Written into the created notes.","type":"object"},"subject_id":{"maxLength":256,"minLength":1,"type":"string"}},"required":["subject_id","messages"],"type":"object"},"AddMemoriesResponse":{"properties":{"created":{"items":{"$ref":"#/components/schemas/Note"},"type":"array"},"errors":{"items":{"properties":{"action_id":{"type":"string"},"error":{"type":"string"}},"required":["action_id","error"],"type":"object"},"type":"array"},"pending_actions":{"description":"Actions left for approval.","type":"integer"},"pending_plan_id":{"description":"Plan with the actions left for approval.","type":"string"},"subject_id":{"type":"string"},"updated":{"items":{"$ref":"#/components/schemas/Note"},"type":"array"}},"required":["subject_id","created","updated","pending_actions"],"type":"object"},"ApplyLinksResult":{"properties":{"links_made":{"items":{"type":"string"},"type":["array","null"]},"requested_count":{"type":"integer"}},"required":["links_made","requested_count"],"type":"object"},"AutoLinkSuggestion":{"properties":{"link_type":{"type":"string"},"reason":{"type":"string"},"shared_tags":{"items":{"type":"string"},"type":"array"},"source_id":{"type":"string"},"source_title":{"type":"string"},"target_id":{"type":"string"},"target_title":{"type":"string"},"weight":{"type":"number"}},"required":["source_id","source_title","target_id","target_title","link_type","weight","reason"],"type":"object"},"BatchDeleteRequest":{"properties":{"external_ids":{"items":{"maxLength":512,"minLength":1,"type":"string"},"maxItems":500,"minItems":1,"type":"array"}},"required":["external_ids"],"type":"object"},"BatchDeleteResponse":{"properties":{"deleted":{"items":{"type":"string"},"type":"array"},"not_found":{"items":{"type":"string"},"type":"array"}},"required":["deleted","not_found"],"type":"object"},"BatchNoteItem":{"allOf":[{"$ref":"#/components/schemas/ExternalNoteRequest"},{"properties":{"external_id":{"maxLength":512,"minLength":1,"type":"string"}},"required":["external_id"],"type":"object"}]},"BatchNoteResult":{"properties":{"created":{"type":"boolean"},"error":{"description":"Set when this item failed.","type":"string"},"external_id":{"type":"string"},"id":{"format":"uuid","type":"string"},"title":{"description":"Actual title (may carry a suffix).","type":"string"}},"required":["external_id","created"],"type":"object"},"BatchNotesRequest":{"properties":{"notes":{"description":"External ids must be unique within the request.","items":{"$ref":"#/components/schemas/BatchNoteItem"},"maxItems":500,"minItems":1,"type":"array"}},"required":["notes"],"type":"object"},"BatchNotesResponse":{"properties":{"results":{"items":{"$ref":"#/components/schemas/BatchNoteResult"},"type":"array"}},"required":["results"],"type":"object"},"ChunkInput":{"properties":{"chunk_index":{"type":"integer"},"content":{"type":"string"},"embedding":{"items":{"type":"number"},"type":"array"},"end_char":{"type":"integer"},"start_char":{"type":"integer"}},"required":["chunk_index","content"],"type":"object"},"ConsolidateRequest":{"properties":{"max_notes":{"type":"integer"},"scope":{"default":"all","enum":["all","tag"],"type":"string"},"similarity_min":{"maximum":1,"minimum":0,"type":"number"},"tag":{"description":"Required when scope=tag.","type":"string"}},"type":"object"},"ConsolidationReport":{"properties":{"capped":{"type":"boolean"},"duplicates":{"items":{"properties":{"a":{"$ref":"#/components/schemas/GraphNode"},"b":{"$ref":"#/components/schemas/GraphNode"},"similarity":{"type":"number"}},"required":["a","b","similarity"],"type":"object"},"type":["array","null"]},"scanned":{"type":"integer"},"scope":{"type":"string"},"scope_value":{"type":"string"},"similarity_min":{"type":"number"}},"required":["scope","scanned","capped","similarity_min","duplicates"],"type":"object"},"CreateLinkRequest":{"properties":{"context":{"type":"string"},"link_type":{"default":"reference","description":"e.g. reference, extends, contradicts, inspired_by, example_of, related_to.","type":"string"},"source_id":{"type":"string"},"target_id":{"type":"string"},"weight":{"description":"0 or absent — 1.0.","type":"number"}},"required":["source_id","target_id"],"type":"object"},"CreateMCPTokenRequest":{"properties":{"auto_capture":{"description":"Ask the agent to save every exchange.","type":"boolean"},"name":{"minLength":1,"type":"string"},"vault_id":{"format":"uuid","type":"string"}},"required":["name"],"type":"object"},"CreateNoteRequest":{"properties":{"content":{"minLength":1,"type":"string"},"expires_at":{"format":"date-time","type":"string"},"external_id":{"maxLength":512,"minLength":1,"type":"string"},"file_path":{"type":"string"},"metadata":{"additionalProperties":true,"type":"object"},"priority":{"description":"0 or absent — default 5.","maximum":10,"minimum":0,"type":"integer"},"subject_id":{"description":"End user this note belongs to (empty — shared).","maxLength":256,"type":"string"},"tags":{"items":{"type":"string"},"type":"array"},"title":{"minLength":1,"type":"string"}},"required":["title","content"],"type":"object"},"CreateVaultKeyRequest":{"properties":{"expires_at":{"description":"Must be in the future.","format":"date-time","type":"string"},"name":{"maxLength":200,"type":"string"},"scopes":{"items":{"$ref":"#/components/schemas/VaultKeyScope"},"minItems":1,"type":"array"}},"required":["scopes"],"type":"object"},"CreateVaultRequest":{"properties":{"embedder":{"description":"Provider id from `GET /api/v1/embedders`, or just its kind (`openai`, `ollama`) when unambiguous. Omitted — the default provider.","type":"string"},"name":{"minLength":1,"type":"string"},"seed_welcome":{"description":"Fill the vault with a few linked example notes.","type":"boolean"}},"required":["name"],"type":"object"},"CreateWebhookRequest":{"properties":{"events":{"items":{"$ref":"#/components/schemas/WebhookEventName"},"minItems":1,"type":"array"},"secret":{"description":"Generated when absent.","minLength":16,"type":"string"},"url":{"description":"https URL on a public address.","format":"uri","maxLength":2048,"type":"string"},"vault_id":{"format":"uuid","type":"string"}},"required":["url","events"],"type":"object"},"CreatedVaultKey":{"allOf":[{"$ref":"#/components/schemas/VaultKey"},{"properties":{"key":{"description":"The plain key (`dbk_…`); shown only once.","type":"string"}},"required":["key"],"type":"object"}]},"DeletedNote":{"properties":{"created_at":{"format":"date-time","type":"string"},"deleted_at":{"format":"date-time","type":"string"},"excerpt":{"type":"string"},"expires_at":{"format":"date-time","type":"string"},"id":{"format":"uuid","type":"string"},"title":{"type":"string"},"updated_at":{"format":"date-time","type":"string"}},"required":["id","title","deleted_at","created_at","updated_at","excerpt"],"type":"object"},"Embedder":{"properties":{"available":{"type":"boolean"},"default":{"type":"boolean"},"dimensions":{"type":"integer"},"id":{"description":"`kind:model` — the value for `embedder` when creating a vault.","type":"string"},"kind":{"enum":["openai","ollama"],"type":"string"},"model":{"type":"string"}},"required":["id","kind","model","dimensions","default","available"],"type":"object"},"EmbeddingStatus":{"properties":{"chunks_failed":{"type":"integer"},"chunks_pending":{"type":"integer"},"chunks_total":{"type":"integer"},"done":{"description":"Nothing waits for vectors.","type":"boolean"},"embedder":{"type":"string"},"notes_failed":{"description":"Live notes the embedder rejected for good.","type":"integer"},"notes_pending":{"description":"Live notes without a current vector.","type":"integer"},"notes_total":{"description":"Live notes (the trash is not counted).","type":"integer"},"vault_id":{"format":"uuid","type":"string"}},"required":["vault_id","embedder","notes_total","notes_pending","notes_failed","chunks_total","chunks_pending","chunks_failed","done"],"type":"object"},"Error":{"properties":{"code":{"$ref":"#/components/schemas/ErrorCode"},"current_bytes":{"description":"With STORAGE_LIMIT_REACHED.","format":"int64","type":"integer"},"error":{"description":"Human-readable message.","type":"string"},"hint":{"type":"string"},"limit":{"description":"With VAULT_LIMIT_REACHED.","type":"integer"},"limit_bytes":{"NOTE_TOO_LARGE and EXPORT_TOO_LARGE.":null,"description":"With STORAGE_LIMIT_REACHED","format":"int64","type":"integer"},"topup_url":{"description":"With BALANCE_EXHAUSTED.","type":"string"}},"required":["error","code"],"type":"object"},"ErrorCode":{"description":"| Code | Status | Meaning |\n|---|---|---|\n| BAD_REQUEST | 400 | Invalid parameters or JSON. |\n| INVALID_PAGE | 400 | `page` is not an integer in 1..100000. |\n| MISSING_VAULT | 400 | `X-Vault-ID` is missing (or the MCP token has no vault). |\n| INVALID_IDEMPOTENCY_KEY | 400 | Idempotency-Key is not 1–255 printable ASCII characters. |\n| INVALID_URL | 400 | Not an http(s) URL. |\n| BLOCKED_URL | 400 | The URL resolves to a private or internal address. |\n| TOPIC_FAILED | 400 | Topic synthesis failed. |\n| FROM_VAULT_FAILED | 400 | Synthesis from notes failed. |\n| INVALID_SCOPES | 400 | Vault key scopes must be a non-empty subset of read, write, learn. |\n| INVALID_SUBJECT | 400 | `subject_id` is missing (where required) or not 1–256 bytes without control characters. |\n| INVALID_EVENTS | 400 | Webhook events must be a non-empty subset of the known events. |\n| INVALID_WEBHOOK_URL | 400 | Webhook URL is not https, or resolves to a private or internal address. |\n| INVALID_EMBEDDER | 400 | `embedder` is not one of `GET /api/v1/embedders`. |\n| UNAUTHORIZED | 401 | Missing or invalid API key. |\n| AUTH_MISSING | 401 | MCP: no Bearer token. |\n| AUTH_INVALID | 401 | MCP: invalid or revoked token. |\n| BALANCE_EXHAUSTED | 402 | Balance is used up: writes and paid operations are blocked, reads work. |\n| ACCOUNT_SUSPENDED | 403 | Account is suspended. |\n| VAULT_LIMIT_REACHED | 403 | The plan's vault cap is reached. |\n| INSUFFICIENT_SCOPE | 403 | The vault key lacks the route's scope, is bound to another vault, or the route needs the account key. |\n| WEBHOOK_LIMIT_REACHED | 403 | The account already has 20 webhooks. |\n| SESSION_MISMATCH | 403 | Legacy SSE MCP: the session belongs to another token. |\n| NOT_FOUND | 404 | Resource not found. |\n| VAULT_NOT_FOUND | 404 | Vault not found for this account. |\n| PLAN_NOT_FOUND | 404 | Learn plan not found, expired or already executed. |\n| NOT_FOUND_AT_TIME | 404 | The note did not exist at that moment. |\n| TITLE_CONFLICT | 409 | A live note already has this title. |\n| EXTERNAL_ID_CONFLICT | 409 | A live note already has this external_id. |\n| IDEMPOTENCY_IN_PROGRESS | 409 | A request with this Idempotency-Key is still running. |\n| SOURCES_CHANGED | 409 | Reconstruct: a source note changed or was deleted after the preview. |\n| EMBEDDER_IMMUTABLE | 409 | A vault's embedder cannot be changed. |\n| BODY_TOO_LARGE | 413 | Request body exceeds the limit (10 MiB; 50 MiB for /sync and /notes/batch). |\n| STORAGE_LIMIT_REACHED | 413 | Storage limit reached; delete notes or empty the trash. |\n| EXPORT_TOO_LARGE | 413 | The vault is too large to export in one response (`limit_bytes`); page through the notes instead. |\n| NOTE_TOO_LARGE | 413 | Title + content exceed the per-note limit (`limit_bytes`, 900 KB by default) or do not fit in the full-text index; split the note. |\n| IDEMPOTENCY_KEY_MISMATCH | 422 | The Idempotency-Key was used for a different request. |\n| NOT_HTML | 422 | The URL did not return an HTML page. |\n| EMPTY_CONTENT | 422 | No readable text at the URL. |\n| RATE_LIMITED | 429 | Rate limit exceeded; see Retry-After. |\n| INTERNAL_ERROR | 500 | Unexpected server error. |\n| LEARN_FAILED | 500/502/503 | Learn pipeline or LLM call failed. |\n| NO_STREAM | 500 | Streaming is not supported by the connection. |\n| TEMPORAL_LOOKUP_FAILED, TEMPORAL_GRAPH_FAILED, TEMPORAL_SEARCH_FAILED, TEMPORAL_SNAPSHOT_FAILED, HISTORY_LOOKUP_FAILED | 500 | Point-in-time query failed. |\n| TOKEN_CREATE_FAILED, TOKEN_LIST_FAILED, TOKEN_REVOKE_FAILED | 500 | MCP token operation failed. |\n| VAULT_LOOKUP_FAILED | 500 | MCP: vault lookup failed. |\n| FETCH_FAILED | 502 | Fetching the URL failed. |\n| SERVICE_BUSY | 503 | Server is busy; see Retry-After. |\n| VAULT_UNAVAILABLE | 503 | The vault is temporarily unavailable. |\n| EMBEDDER_UNAVAILABLE | 503 | No embedder for this vault (not configured on the server; no Retry-After), or it failed (Retry-After). |\n| LEARN_UNAVAILABLE | 503 | The LLM feature is not configured. |\n","enum":["BAD_REQUEST","INVALID_PAGE","MISSING_VAULT","INVALID_IDEMPOTENCY_KEY","INVALID_URL","BLOCKED_URL","TOPIC_FAILED","FROM_VAULT_FAILED","INVALID_SCOPES","INVALID_SUBJECT","INVALID_EVENTS","INVALID_WEBHOOK_URL","INVALID_EMBEDDER","UNAUTHORIZED","AUTH_MISSING","AUTH_INVALID","BALANCE_EXHAUSTED","ACCOUNT_SUSPENDED","VAULT_LIMIT_REACHED","INSUFFICIENT_SCOPE","WEBHOOK_LIMIT_REACHED","SESSION_MISMATCH","NOT_FOUND","VAULT_NOT_FOUND","PLAN_NOT_FOUND","NOT_FOUND_AT_TIME","TITLE_CONFLICT","EXTERNAL_ID_CONFLICT","LINK_EXISTS","IDEMPOTENCY_IN_PROGRESS","SOURCES_CHANGED","EMBEDDER_IMMUTABLE","BODY_TOO_LARGE","STORAGE_LIMIT_REACHED","NOTE_TOO_LARGE","EXPORT_TOO_LARGE","IDEMPOTENCY_KEY_MISMATCH","NOT_HTML","EMPTY_CONTENT","RATE_LIMITED","INTERNAL_ERROR","LEARN_FAILED","NO_STREAM","TEMPORAL_LOOKUP_FAILED","TEMPORAL_GRAPH_FAILED","TEMPORAL_SEARCH_FAILED","TEMPORAL_SNAPSHOT_FAILED","HISTORY_LOOKUP_FAILED","TOKEN_CREATE_FAILED","TOKEN_LIST_FAILED","TOKEN_REVOKE_FAILED","VAULT_LOOKUP_FAILED","FETCH_FAILED","SERVICE_BUSY","VAULT_UNAVAILABLE","EMBEDDER_UNAVAILABLE","LEARN_UNAVAILABLE"],"type":"string"},"ExportNote":{"properties":{"content":{"type":"string"},"created_at":{"format":"date-time","type":"string"},"deleted_at":{"format":"date-time","type":"string"},"expires_at":{"format":"date-time","type":"string"},"external_id":{"type":["string","null"]},"file_path":{"type":"string"},"id":{"type":"string"},"metadata":{"$ref":"#/components/schemas/Metadata"},"priority":{"type":"integer"},"subject_id":{"type":["string","null"]},"tags":{"items":{"type":"string"},"type":["array","null"]},"title":{"type":"string"},"updated_at":{"format":"date-time","type":"string"}},"type":"object"},"ExternalNoteRequest":{"properties":{"content":{"minLength":1,"type":"string"},"metadata":{"additionalProperties":true,"type":"object"},"subject_id":{"description":"End user this note belongs to (empty — shared).","maxLength":256,"type":"string"},"tags":{"items":{"type":"string"},"type":"array"},"title":{"minLength":1,"type":"string"}},"required":["title","content"],"type":"object"},"FromVaultRequest":{"properties":{"delete_sources":{"type":"boolean"},"mode":{"default":"plan","enum":["plan","auto","create"],"type":"string"},"op":{"default":"synthesize","enum":["synthesize","reconstruct"],"type":"string"},"proposal":{"$ref":"#/components/schemas/Proposal"},"sensitivity":{"$ref":"#/components/schemas/Sensitivity"},"source":{"properties":{"ids":{"items":{"type":"string"},"type":"array"},"scope":{"default":"all","enum":["ids","tag","all","topic"],"type":"string"},"tag":{"type":"string"},"tags":{"items":{"type":"string"},"type":"array"},"topic":{"type":"string"}},"type":"object"},"style":{"default":"digest","enum":["digest","faq","study_guide","supplement"],"type":"string"},"subject_id":{"description":"Reconstruct: only this end user's notes.","maxLength":256,"minLength":1,"type":"string"},"supplement":{"type":"string"},"target_id":{"description":"Reconstruct: which of the sources is kept (default: first of ids / oldest by tag).","type":"string"}},"type":"object"},"FromVaultResponse":{"properties":{"created":{"$ref":"#/components/schemas/Note"},"deleted_source_ids":{"description":"Reconstruct: the merged notes moved to the trash.","items":{"type":"string"},"type":"array"},"deleted_sources":{"description":"Source notes moved to the trash.","type":"integer"},"proposal":{"$ref":"#/components/schemas/Proposal"},"updated":{"$ref":"#/components/schemas/Note"}},"type":"object"},"FullGraph":{"properties":{"edges":{"items":{"$ref":"#/components/schemas/GraphEdge"},"type":["array","null"]},"nodes":{"items":{"$ref":"#/components/schemas/GraphNode"},"type":["array","null"]},"total_nodes":{"type":"integer"},"truncated":{"type":"boolean"}},"required":["nodes","edges","total_nodes","truncated"],"type":"object"},"GraphEdge":{"properties":{"link_type":{"type":"string"},"source":{"type":"string"},"target":{"type":"string"},"weight":{"type":"number"}},"required":["source","target","link_type","weight"],"type":"object"},"GraphNeighbor":{"properties":{"direction":{"enum":["outbound","inbound"],"type":"string"},"id":{"type":"string"},"is_manual":{"type":"boolean"},"link_id":{"type":"string"},"link_type":{"type":"string"},"shared_tags":{"items":{"type":"string"},"type":"array"},"title":{"type":"string"},"weight":{"type":"number"}},"required":["id","title","link_id","link_type","weight","is_manual","direction"],"type":"object"},"GraphNode":{"properties":{"id":{"type":"string"},"title":{"type":"string"}},"required":["id","title"],"type":"object"},"GraphRAGRequest":{"description":"Exactly one of `q` and `embedding`.","properties":{"embedding":{"description":"Your own query vector (the vault's `embedding_dims`).","items":{"type":"number"},"type":"array"},"expand_neighbors":{"type":"boolean"},"q":{"description":"The query as text; the server embeds it with the vault's embedder.","type":"string"},"subject_id":{"description":"Only this end user's notes (seeds and neighbours).","maxLength":256,"minLength":1,"type":"string"},"tags":{"description":"Notes must have all of these tags (seeds and neighbours).","items":{"type":"string"},"type":"array"},"top_n":{"default":5,"maximum":50,"minimum":1,"type":"integer"}},"type":"object"},"GraphResponse":{"properties":{"neighbors":{"items":{"$ref":"#/components/schemas/GraphNeighbor"},"type":["array","null"]},"node":{"$ref":"#/components/schemas/GraphNode"}},"required":["node","neighbors"],"type":"object"},"Health":{"properties":{"admin_enabled":{"type":"boolean"},"checks":{"additionalProperties":{"properties":{"configured":{"type":"boolean"},"error":{"type":"string"},"ok":{"type":"boolean"},"version":{"type":"string"}},"type":"object"},"description":"Present with `deep=1`.","type":"object"},"db":{"enum":["ok","error"],"type":"string"},"multi_tenant":{"type":"boolean"},"status":{"enum":["ok","error"],"type":"string"}},"required":["status","db","multi_tenant","admin_enabled"],"type":"object"},"LearnActionOverride":{"properties":{"add_section":{"type":"string"},"content":{"type":"string"},"tags":{"items":{"type":"string"},"type":"array"},"target_id":{"type":"string"},"title":{"type":"string"},"type":{"type":"string"}},"type":"object"},"LearnAutoResult":{"properties":{"executed_action_ids":{"items":{"type":"string"},"type":["array","null"]},"plan":{"$ref":"#/components/schemas/LearnPlan"},"result":{"$ref":"#/components/schemas/LearnExecutionResult"}},"required":["plan","executed_action_ids","result"],"type":"object"},"LearnExecutionResult":{"properties":{"collisions_handled":{"type":"integer"},"contradicted":{"items":{"type":"string"},"type":"array"},"created":{"items":{"type":"string"},"type":"array"},"errors":{"items":{"properties":{"action_id":{"type":"string"},"error":{"type":"string"}},"required":["action_id","error"],"type":"object"},"type":"array"},"extended":{"items":{"type":"string"},"type":"array"},"link_suggestions":{"items":{"$ref":"#/components/schemas/AutoLinkSuggestion"},"type":"array"},"links_made":{"items":{"type":"string"},"type":"array"},"skipped":{"items":{"type":"string"},"type":"array"}},"type":"object"},"LearnImpliedChange":{"properties":{"add_section":{"type":"string"},"confidence":{"type":"number"},"link_type":{"type":"string"},"reason":{"type":"string"},"target_id":{"type":"string"},"target_title":{"type":"string"},"type":{"enum":["outdate","extend","link"],"type":"string"}},"required":["type","target_id"],"type":"object"},"LearnLinkSuggestion":{"properties":{"link_type":{"type":"string"},"target_id":{"type":"string"},"target_title":{"type":"string"}},"required":["target_id","target_title","link_type"],"type":"object"},"LearnPlan":{"properties":{"actions":{"items":{"$ref":"#/components/schemas/PlannedAction"},"type":["array","null"]},"completion_tokens":{"type":"integer"},"model":{"type":"string"},"plan_id":{"type":"string"},"prompt_tokens":{"type":"integer"},"subject_id":{"description":"The plan was made within this end user's memory.","type":"string"}},"required":["plan_id","actions"],"type":"object"},"LearnRequest":{"properties":{"after":{"description":"For rebuild_links — `next_after` of the previous call.","type":"string"},"approved":{"description":"For execute — ids of plan actions to apply.","items":{"type":"string"},"type":"array"},"approved_links":{"description":"For apply_links.","items":{"$ref":"#/components/schemas/AutoLinkSuggestion"},"type":"array"},"limit":{"default":100,"description":"For rebuild_links.","maximum":200,"minimum":1,"type":"integer"},"mode":{"default":"plan","enum":["plan","execute","auto","apply_links","rebuild_links"],"type":"string"},"overrides":{"additionalProperties":{"$ref":"#/components/schemas/LearnActionOverride"},"description":"For execute — per action id, fields to change before applying.","type":"object"},"plan_id":{"description":"For execute.","type":"string"},"sensitivity":{"$ref":"#/components/schemas/Sensitivity"},"subject_id":{"description":"For plan and auto — learn within one end user's memory: related\nnotes are searched, extended and created only among that\nsubject's notes. For execute the subject comes from the stored\nplan.\n","maxLength":256,"type":"string"},"text":{"description":"Required for plan and auto.","type":"string"}},"type":"object"},"LearnRun":{"properties":{"approved_action_ids":{"items":{"type":"string"},"type":"array"},"completion_tokens":{"type":"integer"},"created_at":{"format":"date-time","type":"string"},"duration_ms":{"type":"integer"},"error":{"type":"string"},"id":{"type":"string"},"mode":{"type":"string"},"model":{"type":"string"},"plan":{"description":"The plan as produced (JSON)."},"prompt_tokens":{"type":"integer"},"result":{"description":"The execution result (JSON)."},"status":{"enum":["ok","partial","error"],"type":"string"},"subject_id":{"type":"string"},"text_length":{"type":"integer"},"text_preview":{"type":"string"}},"required":["id","mode","text_length","prompt_tokens","completion_tokens","duration_ms","status","created_at"],"type":"object"},"Link":{"properties":{"context":{"type":"string"},"created_at":{"format":"date-time","type":"string"},"id":{"type":"string"},"is_manual":{"type":"boolean"},"link_type":{"type":"string"},"source_id":{"type":"string"},"target_id":{"type":"string"},"weight":{"type":"number"}},"required":["id","source_id","target_id","link_type","weight","is_manual","created_at"],"type":"object"},"MCPToken":{"properties":{"auto_capture":{"type":"boolean"},"created_at":{"format":"date-time","type":"string"},"id":{"type":"string"},"last_used_at":{"format":"date-time","type":["string","null"]},"name":{"type":"string"},"prefix":{"type":"string"},"revoked":{"type":"boolean"},"vault_id":{"type":["string","null"]}},"required":["id","prefix","name","vault_id","auto_capture","created_at","last_used_at","revoked"],"type":"object"},"MCPTokenCreated":{"properties":{"auto_capture":{"type":"boolean"},"created_at":{"format":"date-time","type":"string"},"id":{"type":"string"},"name":{"type":"string"},"prefix":{"type":"string"},"token":{"description":"The secret; shown only once.","type":"string"},"vault_id":{"type":["string","null"]}},"required":["id","token","prefix","name","vault_id","auto_capture","created_at"],"type":"object"},"MemoryListResponse":{"properties":{"notes":{"items":{"$ref":"#/components/schemas/Note"},"type":"array"},"subject_id":{"type":"string"},"total":{"type":"integer"}},"required":["subject_id","notes","total"],"type":"object"},"MemoryMessage":{"properties":{"content":{"minLength":1,"type":"string"},"role":{"default":"user","description":"E.g. `user`, `assistant`.","type":"string"}},"required":["content"],"type":"object"},"MemorySearchResponse":{"properties":{"mode":{"enum":["text","hybrid"],"type":"string"},"results":{"items":{"$ref":"#/components/schemas/SearchResult"},"type":"array"},"subject_id":{"type":"string"}},"required":["subject_id","mode","results"],"type":"object"},"Metadata":{"additionalProperties":true,"description":"Arbitrary JSON object stored with the note.","type":["object","null"]},"Note":{"properties":{"content":{"type":"string"},"created_at":{"format":"date-time","type":"string"},"embedding_current":{"description":"The stored embedding matches the current title and content.","type":"boolean"},"embedding_updated_at":{"format":"date-time","type":["string","null"]},"expires_at":{"description":"TTL: when it passes, the note moves to the trash within `NOTE_EXPIRY_INTERVAL` (5 min by default) and `note.deleted` is sent. Absent — never expires.","format":"date-time","type":"string"},"external_id":{"type":["string","null"]},"file_path":{"type":"string"},"id":{"format":"uuid","type":"string"},"metadata":{"$ref":"#/components/schemas/Metadata"},"priority":{"description":"1 (highest) – 10. Search (/search, MCP search_notes, subject memories) multiplies the ranking score by 1 + 0.025 × (5 − priority): ×1.1 for 1, ×1.0 for 5, ×0.875 for 10. text_score/vector_score stay raw; final_score is the weighted score.","maximum":10,"minimum":1,"type":"integer"},"subject_id":{"description":"End user this note belongs to; null — a shared note of the vault.","maxLength":256,"type":["string","null"]},"tags":{"items":{"type":"string"},"type":"array"},"title":{"type":"string"},"updated_at":{"format":"date-time","type":"string"}},"required":["id","title","content","metadata","priority","embedding_updated_at","embedding_current","created_at","updated_at","external_id","subject_id"],"type":"object"},"NoteList":{"properties":{"limit":{"type":"integer"},"notes":{"items":{"$ref":"#/components/schemas/Note"},"type":["array","null"]},"page":{"type":"integer"},"total":{"type":"integer"}},"required":["notes","total","page","limit"],"type":"object"},"NoteRevision":{"properties":{"changed_at":{"format":"date-time","type":"string"},"content":{"type":"string"},"expires_at":{"format":"date-time","type":"string"},"file_path":{"type":"string"},"note_id":{"type":"string"},"operation":{"enum":["update","delete"],"type":"string"},"priority":{"type":"integer"},"tags":{"items":{"type":"string"},"type":"array"},"title":{"type":"string"}},"required":["note_id","content","operation","changed_at"],"type":"object"},"Plan":{"enum":["payg","partner"],"type":"string"},"PlannedAction":{"properties":{"add_section":{"type":"string"},"confidence":{"maximum":1,"minimum":0,"type":"number"},"content":{"type":"string"},"forced_by":{"type":"string"},"id":{"type":"string"},"implies_changes":{"items":{"$ref":"#/components/schemas/LearnImpliedChange"},"type":"array"},"link_to":{"items":{"$ref":"#/components/schemas/LearnLinkSuggestion"},"type":"array"},"link_type":{"type":"string"},"needs_confirmation":{"type":"boolean"},"new_content":{"type":"string"},"old_excerpt":{"type":"string"},"original_create":{"properties":{"content":{"type":"string"},"tags":{"items":{"type":"string"},"type":"array"},"title":{"type":"string"}},"required":["title","content"],"type":"object"},"reasoning":{"type":"string"},"tags":{"items":{"type":"string"},"type":"array"},"target_id":{"type":"string"},"target_title":{"type":"string"},"title":{"type":"string"},"type":{"enum":["CREATE","EXTEND","CONTRADICT","DUPLICATE","LINK_ONLY"],"type":"string"}},"required":["id","type","confidence","reasoning"],"type":"object"},"Proposal":{"properties":{"content":{"type":"string"},"content_pruned":{"type":"string"},"op":{"description":"Set on reconstruct previews.","enum":["reconstruct"],"type":"string"},"source_ids":{"items":{"type":"string"},"type":["array","null"]},"source_versions":{"additionalProperties":{"format":"date-time","type":"string"},"description":"Reconstruct: `updated_at` of each source at preview time, checked when applying.","type":"object"},"target_id":{"description":"Reconstruct: the note that receives the result.","type":"string"},"title":{"type":"string"},"truncated":{"type":"boolean"},"used_notes":{"type":"integer"}},"required":["title","content"],"type":"object"},"RebuildLinksResult":{"properties":{"auto_created":{"type":"integer"},"next_after":{"description":"Cursor for the next batch; null when done.","type":["string","null"]},"processed":{"type":"integer"},"total":{"type":"integer"}},"required":["processed","auto_created","total","next_after"],"type":"object"},"SearchResponse":{"properties":{"degraded":{"enum":["text_only"],"type":"string"},"mode":{"enum":["text","vector","hybrid"],"type":"string"},"results":{"items":{"$ref":"#/components/schemas/SearchResult"},"type":"array"},"total":{"type":"integer"}},"required":["results","total","mode"],"type":"object"},"SearchResult":{"properties":{"excerpt":{"type":"string"},"external_id":{"type":["string","null"]},"final_score":{"description":"Ranking score, including the note priority weight (see Note.priority).","type":"number"},"id":{"type":"string"},"snippet":{"description":"The most relevant passage for the query (/search).","type":"string"},"tags":{"items":{"type":"string"},"type":["array","null"]},"text_score":{"type":"number"},"title":{"type":"string"},"vector_score":{"type":"number"}},"required":["id","title","external_id","excerpt","tags","final_score"],"type":"object"},"Sensitivity":{"description":"How eagerly links are created automatically.","enum":["low","medium","high"],"type":"string"},"SourceResult":{"properties":{"created":{"type":"boolean"},"note_id":{"type":"string"},"title":{"type":"string"}},"required":["note_id","title","created"],"type":"object"},"StaleNote":{"properties":{"content":{"type":"string"},"id":{"type":"string"},"title":{"type":"string"}},"required":["id","title"],"type":"object"},"SubjectDeleteResult":{"properties":{"chunks":{"format":"int64","type":"integer"},"learn_plans":{"format":"int64","type":"integer"},"learn_runs":{"format":"int64","type":"integer"},"notes":{"format":"int64","type":"integer"},"revisions":{"format":"int64","type":"integer"},"subject_id":{"type":"string"},"webhook_deliveries":{"format":"int64","type":"integer"}},"required":["subject_id","notes","revisions","chunks","learn_runs","learn_plans","webhook_deliveries"],"type":"object"},"SubjectSummary":{"properties":{"notes":{"description":"Live notes.","type":"integer"},"subject_id":{"type":"string"},"trashed":{"description":"Notes in the trash.","type":"integer"},"updated_at":{"description":"Latest change to any of the subject's notes.","format":"date-time","type":"string"}},"required":["subject_id","notes","trashed","updated_at"],"type":"object"},"SyncFile":{"properties":{"content":{"description":"Markdown with optional front matter.","type":"string"},"path":{"type":"string"}},"required":["path","content"],"type":"object"},"SyncFileResult":{"properties":{"action":{"description":"What happened to the file (with `dry_run` — what would happen).\n`unchanged` — the note already has exactly this text, tags and\nfront matter.\n","enum":["create","update","unchanged","error"],"type":"string"},"duplicate_of":{"description":"Path of an earlier file in this request with the same title: both\nbecome one note, with the content of the later file.\n","type":"string"},"error":{"type":"string"},"path":{"type":"string"},"title":{"description":"The title the file's note is matched by.","type":"string"}},"required":["path","title","action"],"type":"object"},"SyncRequest":{"properties":{"dry_run":{"default":false,"description":"Write nothing; report what each file would do.","type":"boolean"},"files":{"items":{"$ref":"#/components/schemas/SyncFile"},"minItems":1,"type":"array"},"links_only":{"default":false,"description":"Do not touch the notes; only turn the files' `[[wikilinks]]` into\nlinks. Cannot be combined with `dry_run`.\n","type":"boolean"},"mode":{"default":"upsert","enum":["upsert"],"type":"string"}},"required":["files"],"type":"object"},"SyncResponse":{"properties":{"created":{"type":"integer"},"dry_run":{"type":"boolean"},"errors":{"items":{"properties":{"error":{"type":"string"},"path":{"type":"string"}},"required":["path","error"],"type":"object"},"type":"array"},"files":{"items":{"$ref":"#/components/schemas/SyncFileResult"},"type":"array"},"links_created":{"description":"New links made from `[[wikilinks]]`. Links that already existed are not counted.","type":"integer"},"skipped":{"type":"integer"},"unchanged":{"description":"Of `updated`, the files whose note already had the same content.","type":"integer"},"updated":{"description":"Files whose note already existed — including the unchanged ones.","type":"integer"}},"required":["created","updated","unchanged","skipped","links_created","dry_run","files","errors"],"type":"object"},"Tag":{"properties":{"id":{"type":"string"},"name":{"type":"string"}},"required":["id","name"],"type":"object"},"Tenant":{"properties":{"api_key":{"description":"Only when creating.","type":"string"},"created_at":{"format":"date-time","type":"string"},"id":{"format":"uuid","type":"string"},"name":{"type":"string"},"plan":{"$ref":"#/components/schemas/Plan"},"status":{"$ref":"#/components/schemas/TenantStatus"},"storage_limit_bytes":{"description":"null — by plan; 0 — unlimited.","format":"int64","type":["integer","null"]}},"required":["id","name","status","plan","storage_limit_bytes","created_at"],"type":"object"},"TenantCredentials":{"properties":{"api_key":{"type":"string"},"vault_id":{"description":"Default vault; empty if none.","type":"string"}},"required":["api_key","vault_id"],"type":"object"},"TenantExport":{"properties":{"exported_at":{"format":"date-time","type":"string"},"tenant_id":{"type":"string"},"vaults":{"items":{"$ref":"#/components/schemas/VaultExport"},"type":"array"}},"required":["tenant_id","exported_at","vaults"],"type":"object"},"TenantStatus":{"enum":["active","read_only","suspended"],"type":"string"},"UpdateEmbeddingRequest":{"properties":{"embedding":{"items":{"type":"number"},"minItems":1,"type":"array"},"embedding_updated_at":{"format":"date-time","type":"string"}},"required":["embedding"],"type":"object"},"UpdateNoteRequest":{"properties":{"content":{"type":"string"},"expires_at":{"description":"A new TTL; `null` removes it (the note never expires). Absent — unchanged.","format":"date-time","type":["string","null"]},"external_id":{"description":"Empty string unbinds the external id.","maxLength":512,"type":"string"},"file_path":{"type":"string"},"metadata":{"additionalProperties":true,"type":"object"},"priority":{"type":"integer"},"subject_id":{"description":"Move the note to another end user; empty string makes it shared.","maxLength":256,"type":"string"},"tags":{"description":"Replaces the tag set.","items":{"type":"string"},"type":"array"},"title":{"type":"string"}},"type":"object"},"UpdateVaultRequest":{"description":"At least one field.","properties":{"embedder":{"description":"Must equal the current embedder (it cannot be changed: `409 EMBEDDER_IMMUTABLE`).","type":"string"},"link_sensitivity":{"$ref":"#/components/schemas/Sensitivity"},"name":{"maxLength":255,"type":"string"}},"type":"object"},"UpdateWebhookRequest":{"properties":{"active":{"type":"boolean"},"events":{"items":{"$ref":"#/components/schemas/WebhookEventName"},"minItems":1,"type":"array"},"rotate_secret":{"type":"boolean"},"url":{"format":"uri","maxLength":2048,"type":"string"}},"type":"object"},"UpsertChunksRequest":{"properties":{"chunks":{"items":{"$ref":"#/components/schemas/ChunkInput"},"minItems":1,"type":"array"}},"required":["chunks"],"type":"object"},"Usage":{"properties":{"by_vault":{"description":"With `group_by=vault`. `vault_id` null — usage not tied to a vault (account level or a deleted vault).","items":{"properties":{"counts":{"$ref":"#/components/schemas/UsageCounts"},"vault_id":{"type":["string","null"]},"vault_name":{"type":["string","null"]}},"required":["vault_id","vault_name","counts"],"type":"object"},"type":"array"},"counts":{"$ref":"#/components/schemas/UsageCounts"},"period_end":{"format":"date-time","type":"string"},"period_start":{"format":"date-time","type":"string"},"tenant_id":{"type":"string"}},"required":["tenant_id","period_start","period_end","counts"],"type":"object"},"UsageCounts":{"additionalProperties":{"format":"int64","type":"integer"},"description":"Metric → total for the period. Metrics without records are absent.\n`embeddings_tokens`, `llm_input_tokens`, `llm_output_tokens` — tokens;\n`api_calls` — REST and MCP requests; `search_queries` — executed\nsearches (REST /search, /chunks/search, /search/graph-rag and MCP\nsearch tools); `storage_mb_hours` — stored MiB × hours.\n","properties":{"api_calls":{"format":"int64","type":"integer"},"embeddings_tokens":{"format":"int64","type":"integer"},"llm_input_tokens":{"format":"int64","type":"integer"},"llm_output_tokens":{"format":"int64","type":"integer"},"search_queries":{"format":"int64","type":"integer"},"storage_mb_hours":{"format":"int64","type":"integer"}},"type":"object"},"Vault":{"properties":{"created_at":{"format":"date-time","type":"string"},"embedder":{"description":"Embedding provider id (`kind:model`) from `GET /api/v1/embedders`.\nVaults created before providers could be chosen keep their old\nvalue (e.g. `openai`), which means the server's default provider.\n","type":"string"},"embedding_dims":{"description":"Dimensions of the vault's vectors.","type":"integer"},"id":{"format":"uuid","type":"string"},"link_sensitivity":{"$ref":"#/components/schemas/Sensitivity"},"name":{"type":"string"},"schema_name":{"type":"string"},"tenant_id":{"format":"uuid","type":"string"}},"required":["id","tenant_id","name","schema_name","embedder","embedding_dims","link_sensitivity","created_at"],"type":"object"},"VaultDataExport":{"properties":{"exported_at":{"format":"date-time","type":"string"},"vault":{"$ref":"#/components/schemas/VaultExport"}},"required":["exported_at","vault"],"type":"object"},"VaultExport":{"properties":{"deleted_notes":{"items":{"$ref":"#/components/schemas/ExportNote"},"type":["array","null"]},"links":{"items":{"properties":{"context":{"type":"string"},"link_type":{"type":"string"},"source_id":{"type":"string"},"target_id":{"type":"string"},"weight":{"type":"number"}},"type":"object"},"type":["array","null"]},"name":{"type":"string"},"notes":{"items":{"$ref":"#/components/schemas/ExportNote"},"type":["array","null"]},"revisions":{"items":{"properties":{"changed_at":{"format":"date-time","type":"string"},"content":{"type":"string"},"note_id":{"type":"string"},"operation":{"type":"string"},"tags":{},"title":{"type":["string","null"]}},"type":"object"},"type":["array","null"]},"tags":{"items":{"$ref":"#/components/schemas/Tag"},"type":["array","null"]},"vault_id":{"type":"string"}},"required":["vault_id","name","notes","deleted_notes","revisions","links","tags"],"type":"object"},"VaultKey":{"properties":{"created_at":{"format":"date-time","type":"string"},"expires_at":{"format":"date-time","type":["string","null"]},"id":{"format":"uuid","type":"string"},"last_used_at":{"description":"Updated at most once a minute.","format":"date-time","type":["string","null"]},"name":{"type":"string"},"prefix":{"description":"First characters of the key, for display (`dbk_1a2b3c4d…`).","type":"string"},"revoked_at":{"format":"date-time","type":["string","null"]},"scopes":{"items":{"$ref":"#/components/schemas/VaultKeyScope"},"type":"array"},"vault_id":{"format":"uuid","type":"string"}},"required":["id","vault_id","name","prefix","scopes","expires_at","created_at","last_used_at","revoked_at"],"type":"object"},"VaultKeyScope":{"enum":["read","write","learn"],"type":"string"},"Webhook":{"properties":{"active":{"type":"boolean"},"created_at":{"format":"date-time","type":"string"},"disabled_reason":{"type":["string","null"]},"events":{"items":{"$ref":"#/components/schemas/WebhookEventName"},"type":"array"},"failure_count":{"description":"Deliveries in a row that exhausted their retries.","type":"integer"},"id":{"format":"uuid","type":"string"},"secret":{"description":"Signing secret; only in the create response and after `rotate_secret`.","type":"string"},"updated_at":{"format":"date-time","type":"string"},"url":{"format":"uri","type":"string"},"vault_id":{"description":"Only this vault's events; null — all vaults.","format":"uuid","type":["string","null"]}},"required":["id","vault_id","url","events","active","failure_count","disabled_reason","created_at","updated_at"],"type":"object"},"WebhookDelivery":{"properties":{"attempts":{"type":"integer"},"created_at":{"format":"date-time","type":"string"},"delivered_at":{"format":"date-time","type":["string","null"]},"event":{"type":"string"},"id":{"description":"Also sent as `X-DB-Delivery`.","format":"uuid","type":"string"},"last_error":{"type":["string","null"]},"last_status_code":{"type":["integer","null"]},"next_attempt_at":{"format":"date-time","type":"string"},"payload":{"$ref":"#/components/schemas/WebhookPayload"},"status":{"description":"`skipped` — the webhook was disabled before this delivery was sent; it will not be sent later.","enum":["pending","sending","delivered","failed","skipped"],"type":"string"},"webhook_id":{"format":"uuid","type":"string"}},"required":["id","webhook_id","event","payload","status","attempts","next_attempt_at","last_status_code","last_error","created_at","delivered_at"],"type":"object"},"WebhookEventName":{"enum":["note.created","note.updated","note.deleted","learn.completed","contradiction.detected","quota.warning","subject.deleted"],"type":"string"},"WebhookPayload":{"description":"Body of every webhook delivery.","properties":{"data":{"additionalProperties":true,"description":"Event-specific; see the `webhooks` section.","type":"object"},"event":{"description":"Event name, e.g. `note.created`, or `webhook.test`.","type":"string"},"occurred_at":{"format":"date-time","type":"string"},"vault_id":{"description":"Null for account-level events (quota.warning).","format":"uuid","type":["string","null"]}},"required":["event","vault_id","occurred_at","data"],"type":"object"}},"securitySchemes":{"AdminKey":{"description":"Internal: operator/billing service only.","in":"header","name":"X-Admin-API-Key","type":"apiKey"},"ApiKey":{"description":"Account API key.","in":"header","name":"X-API-Key","type":"apiKey"},"McpBearer":{"description":"MCP token from `POST /api/v1/mcp/tokens`.","scheme":"bearer","type":"http"},"VaultId":{"description":"Id of the vault to work in (a vault of the same account).","in":"header","name":"X-Vault-ID","type":"apiKey"},"VaultKey":{"description":"Vault key (`dbk_…`) from `POST /api/v1/vaults/{id}/keys`, bound to one\nvault and limited by its scopes (read, write, learn). `X-Vault-ID` is\noptional; if sent it must name the key's vault.\n","in":"header","name":"X-API-Key","type":"apiKey"}}},"info":{"description":"Semantic memory for AI agents and the products built on them: notes with\nfull-text, vector and hybrid search, a link graph, point-in-time history,\nLLM-driven learning and an MCP endpoint.\n\n## Authentication\n\n* **Vault data** (`/api/v1/notes`, `/search`, `/learn`, …) — `X-API-Key`\n  (account key) and `X-Vault-ID` (the vault to work in), or a **vault key**\n  (`dbk_…`) in `X-API-Key`. A vault key is bound to one vault, so\n  `X-Vault-ID` is optional with it (if sent, it must name the same vault,\n  otherwise `403 INSUFFICIENT_SCOPE`).\n* **Account level** (`/api/v1/vaults`, `/api/v1/account`, `/api/v1/usage`,\n  `/api/v1/webhooks`) — `X-API-Key` with the account key only. Vault keys\n  are refused here with `403 INSUFFICIENT_SCOPE`.\n* **MCP** (`/mcp`) — `Authorization: Bearer \u003ctoken\u003e`, where the token is\n  either an MCP token from `POST /api/v1/mcp/tokens` (full access to one\n  vault) or a vault key (`dbk_…`), which limits the session to the key's\n  scopes. See **MCP** below.\n* **Admin** (`/api/v1/admin/*`) — `X-Admin-API-Key`; internal, used by the\n  operator and the billing service only.\n\n### Vault keys and scopes\n\nVault keys are issued by `POST /api/v1/vaults/{id}/keys` (the plain key is\nreturned once) with a set of scopes:\n\n* `read` — every `GET`, plus the read-only `POST /search/graph-rag` and\n  `POST /consolidate`;\n* `learn` — LLM routes: `POST /learn`, `/learn/from-vault`,\n  `/learn/source`, `/memories`, `/notes/{id}/reanalyze`,\n  `/notes/{id}/suggest-tags`;\n* `write` — every other write.\n\nA request outside the key's scopes gets `403 INSUFFICIENT_SCOPE`. Vault\nkeys can never manage MCP tokens. A revoked or expired key gets\n`401 UNAUTHORIZED`.\n\n## MCP\n\n`https://api.digital-brain.io/mcp` is a Model Context Protocol server\n(streamable HTTP transport) for Claude Code, Claude Desktop, Cursor and any\nother MCP client. Every call works in the vault the token is bound to.\n\n```\nclaude mcp add --transport http digital-brain --scope user \\\n  https://api.digital-brain.io/mcp --header \"Authorization: Bearer \u003ctoken\u003e\"\n```\n\nCursor (`~/.cursor/mcp.json`):\n`{\"mcpServers\":{\"digital-brain\":{\"url\":\"https://api.digital-brain.io/mcp\",\n\"headers\":{\"Authorization\":\"Bearer \u003ctoken\u003e\"}}}}`.\n\n* An **MCP token** sees every tool. With `auto_capture: true` the server\n  also tells the agent to record each exchange (`record_interaction`).\n* A **vault key** sees only the tools of its scopes: `read` — search,\n  reading, graph, history, `list_notes`; `write` — adding, updating,\n  deleting and restoring notes, links; `learn` — LLM tools (`learn_text`,\n  `suggest_tags`, …). A read-only key gives an agent memory it cannot\n  change. A call outside the scopes returns a tool error\n  `INSUFFICIENT_SCOPE`.\n* Every tool carries MCP annotations (`readOnlyHint`, `destructiveHint`,\n  `idempotentHint`), so clients can auto-approve reads.\n* A failed call is a tool result with `isError: true` and a message that\n  says what to do (not found, invalid id, missing argument, rate limit,\n  storage full).\n* The same plan limits apply as on REST; LLM tools share the `learn`\n  class. `GET /api/v1/mcp/selftest` checks the connection from your\n  backend.\n\n## Errors\n\nEvery error is JSON `{\"error\": \"\u003chuman message\u003e\", \"code\": \"\u003cERROR_CODE\u003e\"}`.\nBranch on `code`, not on the message. Some errors carry extra fields\n(`hint`, `topup_url`, `limit_bytes`, `current_bytes`, `limit`). The list of\ncodes is in the `ErrorCode` schema.\n\n## Rate limits\n\nLimits are per account and depend on the plan (see `GET /api/v1/account`):\na general data class, a stricter `learn` class for LLM routes, `graph-rag`,\nlink rebuilds and vault creation. Over the limit the server answers\n`429 RATE_LIMITED` with a `Retry-After` header (seconds). Repeated invalid\nkeys from one IP are limited too.\n\n`Retry-After` (seconds) comes with every response that is worth\nretrying: `429 RATE_LIMITED`, `409 IDEMPOTENCY_IN_PROGRESS`,\n`503 SERVICE_BUSY`, `503 VAULT_UNAVAILABLE` and `503 EMBEDDER_UNAVAILABLE`\nwhen the embedder failed. A 503 that describes the server's setup — no\nembedder configured, `LEARN_UNAVAILABLE`, `LEARN_FAILED` for a missing\nlink builder — has no `Retry-After`: retrying will not help.\n\n## Idempotency\n\nWrites (`POST`, `PUT`, `PATCH`, `DELETE` on vault data routes, and\n`POST /api/v1/vaults`) accept an `Idempotency-Key` header (1–255 printable\nASCII characters, scoped to the account):\n\n* The first request with a key runs normally. Its response is stored for\n  24 hours unless the status is 5xx or 429, the response was streamed, or\n  the body is larger than 1 MiB.\n* A retry with the same key and the same request (method, path with query,\n  vault and body) returns the stored response without running it again,\n  with the header `Idempotent-Replayed: true`.\n* The same key with a different request → `422 IDEMPOTENCY_KEY_MISMATCH`.\n* A retry while the first request is still running →\n  `409 IDEMPOTENCY_IN_PROGRESS` with `Retry-After`.\n* After a 5xx or 429 the key is released: the retry runs the request.\n* Streaming requests (`?stream=1` or `Accept: text/event-stream`) are not\n  covered.\n\nRoutes that return a secret once (vault keys, webhooks, `POST\n/api/v1/mcp/tokens`) ignore `Idempotency-Key`: a stored response would keep\nthe secret for 24 hours.\n\n## End-user memory\n\nOne vault can hold the memory of many end users of your product. Tag a\nnote with `subject_id` (your user id) and filter with `?subject_id=` on\nlist, search, chunk search and graph routes: only that subject's notes are\nreturned. Without the filter, all notes of the vault are visible. `POST\n/learn` and `POST /memories` with a `subject_id` only read and change that\nsubject's notes. `DELETE /api/v1/subjects/{subject_id}` erases everything\nstored for a subject.\n\n## Webhooks\n\n`POST /api/v1/webhooks` subscribes a URL to events (see the `webhooks`\nsection of this document for the payloads). Each delivery is a `POST`\nwith a JSON body `{event, vault_id, occurred_at, data}` and the headers\n`X-DB-Event`, `X-DB-Delivery` (delivery id — deduplicate on it; delivery\nis at-least-once), `X-DB-Timestamp` (Unix seconds) and `X-DB-Signature`\n= `sha256=` + hex HMAC-SHA256 of `\u003ctimestamp\u003e.\u003craw body\u003e` keyed with the\nwebhook secret. Reject deliveries whose timestamp is too old. A non-2xx\nanswer is retried up to 8 times over about 22.5 hours; after 5 deliveries\nin a row exhaust their retries the webhook is disabled\n(`active: false`, `disabled_reason`). Disabling a webhook marks its unsent\ndeliveries `skipped` — they are not sent after re-enabling; deleting a\nwebhook deletes its deliveries.\n\n## Optional routes\n\n`/api/v1/learn` (and `/learn/runs`), `/api/v1/learn/from-vault`,\n`POST /api/v1/memories`, `/api/v1/notes/{id}/reanalyze` and\n`/api/v1/notes/{id}/suggest-tags` exist only when the server has an LLM\nconfigured; otherwise they return 404 (`/api/v1/learn/source` makes no LLM\ncall and is always there). Vector search needs an embedder for the vault;\nwithout one, vector modes answer `503 EMBEDDER_UNAVAILABLE`.\n","title":"Digital Brain API","version":"1.0.0"},"openapi":"3.1.0","paths":{"/api/v1/account":{"get":{"description":"Available even when the account is suspended or read-only.","operationId":"getAccount","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Account"}}},"description":"The account."},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"ApiKey":[]}],"summary":"Plan, status and limits of the account","tags":["Account \u0026 Usage"]}},"/api/v1/admin/note-expiry":{"get":{"description":"Internal: operator only (X-Admin-API-Key). Changes nothing. How many\nlive notes already have `expires_at` in the past and would move to the\ntrash on the first TTL pass once `NOTE_EXPIRY_INTERVAL` is set, and how\nmany expire within 7 days — in total and per vault (only vaults with\nsuch notes, most overdue first).\n","operationId":"adminNoteExpiryPreview","responses":{"200":{"content":{"application/json":{"schema":{"properties":{"enabled":{"type":"boolean"},"interval":{"description":"NOTE_EXPIRY_INTERVAL, e.g. 0s or 5m0s.","type":"string"},"overdue_notes":{"type":"integer"},"overdue_vaults":{"type":"integer"},"skipped_vaults":{"description":"Vaults that could not be read (the list is incomplete).","type":"integer"},"upcoming_7d_notes":{"type":"integer"},"vaults":{"items":{"properties":{"oldest_overdue_expires_at":{"format":"date-time","type":["string","null"]},"overdue":{"type":"integer"},"tenant_id":{"format":"uuid","type":"string"},"upcoming_7d":{"type":"integer"},"vault_id":{"format":"uuid","type":"string"},"vault_name":{"type":"string"}},"required":["overdue","upcoming_7d","oldest_overdue_expires_at"],"type":"object"},"type":"array"}},"required":["enabled","interval","overdue_notes","overdue_vaults","upcoming_7d_notes","vaults","skipped_vaults"],"type":"object"}}},"description":"Preview."},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"AdminKey":[]}],"summary":"Dry run of note TTL","tags":["Admin"],"x-internal":true}},"/api/v1/admin/tenants":{"get":{"description":"Internal: operator/billing service only (X-Admin-API-Key).","operationId":"adminListTenants","responses":{"200":{"content":{"application/json":{"schema":{"properties":{"tenants":{"items":{"$ref":"#/components/schemas/Tenant"},"type":"array"}},"required":["tenants"],"type":"object"}}},"description":"Accounts."},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"AdminKey":[]}],"summary":"List accounts","tags":["Admin"],"x-internal":true},"post":{"description":"Internal: operator/billing service only (X-Admin-API-Key). The response contains the API key.","operationId":"adminCreateTenant","requestBody":{"content":{"application/json":{"schema":{"properties":{"name":{"type":"string"}},"required":["name"],"type":"object"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Tenant"}}},"description":"Created (with `api_key`)."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"AdminKey":[]}],"summary":"Create an account","tags":["Admin"],"x-internal":true}},"/api/v1/admin/tenants/{id}":{"delete":{"description":"Internal: operator/billing service only (X-Admin-API-Key).","operationId":"adminDeleteTenant","responses":{"204":{"description":"Deleted."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"AdminKey":[]}],"summary":"Delete an account and all its vaults","tags":["Admin"],"x-internal":true},"get":{"description":"Internal: operator/billing service only (X-Admin-API-Key).","operationId":"adminGetTenant","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Tenant"}}},"description":"The account."},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"AdminKey":[]}],"summary":"Get an account","tags":["Admin"],"x-internal":true},"parameters":[{"$ref":"#/components/parameters/TenantId"}]},"/api/v1/admin/tenants/{id}/api-key":{"get":{"description":"Internal: operator/billing service only (X-Admin-API-Key).","operationId":"adminGetTenantApiKey","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TenantCredentials"}}},"description":"Credentials."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"AdminKey":[]}],"summary":"Current API key and default vault","tags":["Admin"],"x-internal":true},"parameters":[{"$ref":"#/components/parameters/TenantId"}]},"/api/v1/admin/tenants/{id}/export":{"get":{"description":"Internal: operator/billing service only (X-Admin-API-Key). All or\nnothing: a vault that cannot be read fails the export with `500`\ninstead of returning a partial one.\n","operationId":"adminExportTenant","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TenantExport"}}},"description":"Export."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"}},"security":[{"AdminKey":[]}],"summary":"Export all vault data of an account (GDPR)","tags":["Admin"],"x-internal":true},"parameters":[{"$ref":"#/components/parameters/TenantId"}]},"/api/v1/admin/tenants/{id}/plan":{"parameters":[{"$ref":"#/components/parameters/TenantId"}],"patch":{"description":"Internal: operator/billing service only (X-Admin-API-Key). `storage_limit_bytes`: null — by plan, 0 — unlimited.","operationId":"adminSetTenantPlan","requestBody":{"content":{"application/json":{"schema":{"properties":{"plan":{"$ref":"#/components/schemas/Plan"},"storage_limit_bytes":{"format":"int64","minimum":0,"type":["integer","null"]}},"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Tenant"}}},"description":"The updated account."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"AdminKey":[]}],"summary":"Set plan and storage limit override","tags":["Admin"],"x-internal":true}},"/api/v1/admin/tenants/{id}/rotate-api-key":{"parameters":[{"$ref":"#/components/parameters/TenantId"}],"post":{"description":"Internal: operator/billing service only (X-Admin-API-Key).","operationId":"adminRotateTenantApiKey","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TenantCredentials"}}},"description":"New credentials."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"AdminKey":[]}],"summary":"Issue a new API key (the old one stops working)","tags":["Admin"],"x-internal":true}},"/api/v1/admin/tenants/{id}/status":{"parameters":[{"$ref":"#/components/parameters/TenantId"}],"patch":{"description":"Internal: operator/billing service only (X-Admin-API-Key).","operationId":"adminSetTenantStatus","requestBody":{"content":{"application/json":{"schema":{"properties":{"status":{"$ref":"#/components/schemas/TenantStatus"}},"required":["status"],"type":"object"}}},"required":true},"responses":{"204":{"description":"Updated."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"AdminKey":[]}],"summary":"Set account status","tags":["Admin"],"x-internal":true}},"/api/v1/admin/tenants/{id}/storage":{"get":{"description":"Internal: operator/billing service only (X-Admin-API-Key).","operationId":"adminGetTenantStorage","responses":{"200":{"content":{"application/json":{"schema":{"properties":{"current_bytes":{"format":"int64","type":"integer"},"limit_bytes":{"description":"0 means unlimited.","format":"int64","type":"integer"},"recorded_at":{"format":"date-time","type":"string"},"tenant_id":{"type":"string"},"unlimited":{"type":"boolean"}},"required":["tenant_id","current_bytes","limit_bytes","unlimited","recorded_at"],"type":"object"}}},"description":"Storage."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"AdminKey":[]}],"summary":"Live storage use and limit","tags":["Admin"],"x-internal":true},"parameters":[{"$ref":"#/components/parameters/TenantId"}]},"/api/v1/admin/tenants/{id}/usage":{"get":{"description":"Internal: operator/billing service only (X-Admin-API-Key). Same shape as `GET /api/v1/usage`.","operationId":"adminGetTenantUsage","parameters":[{"$ref":"#/components/parameters/Since"},{"$ref":"#/components/parameters/Until"},{"$ref":"#/components/parameters/GroupBy"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Usage"}}},"description":"Usage."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"AdminKey":[]}],"summary":"Account usage for billing","tags":["Admin"],"x-internal":true},"parameters":[{"$ref":"#/components/parameters/TenantId"}]},"/api/v1/chunks/search":{"get":{"description":"`q` only — hybrid with a server-side query embedding; `embedding` only —\nvector; both — hybrid with your embedding. Read-only accounts get text\nchunk search (`X-Search-Degraded: text_only`).\n","operationId":"searchChunks","parameters":[{"in":"query","name":"q","schema":{"type":"string"}},{"$ref":"#/components/parameters/Embedding"},{"in":"query","name":"limit","schema":{"default":10,"maximum":50,"minimum":1,"type":"integer"}},{"$ref":"#/components/parameters/SubjectFilter"}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/SearchResult"},"type":"array"}}},"description":"Matching chunks, best first.","headers":{"X-Search-Degraded":{"schema":{"type":"string"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Search note chunks","tags":["Search"]}},"/api/v1/chunks/{id}/embedding":{"put":{"operationId":"updateChunkEmbedding","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateEmbeddingRequest"}}},"required":true},"responses":{"204":{"description":"Stored."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/PaymentRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Store a chunk embedding computed by the caller","tags":["Chunks \u0026 Embeddings"]}},"/api/v1/consolidate":{"post":{"description":"Nothing is changed. Learn rate class.","operationId":"consolidate","parameters":[{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConsolidateRequest"}}},"required":false},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConsolidationReport"}}},"description":"Duplicate pairs, most similar first."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/PaymentRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Find likely duplicate notes (read-only report)","tags":["Learn"]}},"/api/v1/embedders":{"get":{"description":"The providers configured on this server. `default` is used by vaults\ncreated without `embedder` and by all vaults created before providers\ncould be chosen. `available: false` — known, but without a key or\naddress: vaults on it work without vector search\n(`503 EMBEDDER_UNAVAILABLE`).\n","operationId":"listEmbedders","responses":{"200":{"content":{"application/json":{"schema":{"properties":{"embedders":{"items":{"$ref":"#/components/schemas/Embedder"},"type":"array"}},"required":["embedders"],"type":"object"}}},"description":"Providers, the default first."},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"ApiKey":[]}],"summary":"Embedding providers a vault can use","tags":["Vaults"]}},"/api/v1/embeddings/stale":{"get":{"operationId":"listStaleEmbeddings","parameters":[{"in":"query","name":"limit","schema":{"default":100,"maximum":1000,"minimum":1,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/StaleNote"},"type":"array"}}},"description":"Notes to (re)embed."},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Notes whose embedding is missing or outdated","tags":["Chunks \u0026 Embeddings"]}},"/api/v1/graph":{"get":{"operationId":"getFullGraph","parameters":[{"description":"Maximum nodes.","in":"query","name":"limit","schema":{"default":2000,"maximum":5000,"minimum":1,"type":"integer"}},{"$ref":"#/components/parameters/SubjectFilter"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FullGraph"}}},"description":"Nodes and the edges between them; `truncated` when not everything fits."},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"The whole vault graph (for visualisation)","tags":["Graph"]}},"/api/v1/learn":{"post":{"description":"Modes:\n* `plan` (default) — analyse `text`, return a plan of actions (CREATE,\n  EXTEND, CONTRADICT, DUPLICATE, LINK_ONLY); nothing is written.\n* `execute` — apply `approved` actions of a stored `plan_id` (plans\n  expire; each plan executes once).\n* `auto` — plan and execute high-confidence actions; the rest stays as a\n  plan.\n* `apply_links` — create links from `approved_links`.\n* `rebuild_links` — rebuild automatic links for a batch of notes\n  (`limit`, cursor `after` → `next_after`); separate rebuild rate class.\n\nWith `?stream=1`, `plan` and `auto` stream progress as server-sent\nevents (`event: \u003cname\u003e`, `data: \u003cjson\u003e`), ending with `plan_done` or\n`error`. Learn rate class.\n","operationId":"learn","parameters":[{"$ref":"#/components/parameters/IdempotencyKey"},{"$ref":"#/components/parameters/Stream"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LearnRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/LearnPlan"},{"$ref":"#/components/schemas/LearnExecutionResult"},{"$ref":"#/components/schemas/LearnAutoResult"},{"$ref":"#/components/schemas/ApplyLinksResult"},{"$ref":"#/components/schemas/RebuildLinksResult"}]}},"text/event-stream":{"schema":{"type":"string"}}},"description":"Shape depends on `mode`."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/PaymentRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Turn text into curated notes (LLM)","tags":["Learn"]}},"/api/v1/learn/from-vault":{"post":{"description":"**`op=synthesize`** (default) writes a NEW note from the sources and\nleaves them as they are. `source.scope`: `ids`, `tag` (`tag` or\n`tags`), `all`, or `topic` (the model writes from its own knowledge\nabout `source.topic`). With `delete_sources`, source notes move to the\ntrash after creation.\n\n**`op=reconstruct`** rewrites the selected notes in place: one note is\nrewritten (clearer structure, no facts lost); several are merged into\none that replaces them. The target (`target_id`, default the first of\n`source.ids`, or the oldest for `scope=tag`) keeps its id — incoming\nlinks, external_id and history stay — and gets the new title and text;\nthe other sources go to the trash (restorable), their manual links and\ntags are copied onto the target, and `metadata.merged_from` lists them.\nThe target's previous version stays in its history. Only\n`scope=ids|tag`, at most 20 notes, all of one end user (or all shared;\n`subject_id` restricts to one). The preview carries `target_id` and\n`source_versions`; applying it after any source changed is\n`409 SOURCES_CHANGED` with nothing written. Applying emits\n`learn.completed` (`mode: reconstruct`, target in `extended`, merged\nnotes in `deleted`) and is recorded in `/learn/runs`.\n\n`mode`: `plan` (default, returns a `proposal`, meters the LLM call),\n`auto` (proposal applied at once), `create` (apply a `proposal` you\npass back — no LLM call). `?stream=1` (not for `create`) streams\n`summarizing`, `summarized`, `done` or `error` events. Learn rate class.\n","operationId":"learnFromVault","parameters":[{"$ref":"#/components/parameters/IdempotencyKey"},{"$ref":"#/components/parameters/Stream"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FromVaultRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FromVaultResponse"}},"text/event-stream":{"schema":{"type":"string"}}},"description":"Proposal and/or created note."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/PaymentRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Learn from existing notes — synthesize a new note or reconstruct the selected ones (LLM)","tags":["Learn"]}},"/api/v1/learn/runs":{"get":{"operationId":"listLearnRuns","parameters":[{"in":"query","name":"limit","schema":{"default":20,"maximum":200,"minimum":1,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"runs":{"items":{"$ref":"#/components/schemas/LearnRun"},"type":"array"}},"required":["runs"],"type":"object"}}},"description":"Runs, newest first."},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Recent learn runs (audit log)","tags":["Learn"]}},"/api/v1/learn/runs/{id}":{"get":{"operationId":"getLearnRun","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LearnRun"}}},"description":"The run."},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"One learn run","tags":["Learn"]}},"/api/v1/learn/source":{"post":{"description":"Fetches the page, extracts readable text and stores it as a note tagged\n`source` (no LLM). The same URL again updates that note. Private and\ninternal addresses are refused. Learn rate class.\n","operationId":"learnFromUrl","parameters":[{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"content":{"application/json":{"schema":{"properties":{"url":{"format":"uri","type":"string"}},"required":["url"],"type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SourceResult"}}},"description":"Existing source note updated."},"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SourceResult"}}},"description":"Source note created."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/PaymentRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"429":{"$ref":"#/components/responses/TooManyRequests"},"502":{"$ref":"#/components/responses/BadGateway"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Save a web page as a note","tags":["Learn"]}},"/api/v1/links":{"post":{"description":"Manual links survive automatic re-analysis.","operationId":"createLink","parameters":[{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateLinkRequest"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Link"}}},"description":"Created."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/PaymentRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Create a manual link between two notes","tags":["Links"]}},"/api/v1/links/{id}":{"delete":{"operationId":"deleteLink","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/IdempotencyKey"}],"responses":{"204":{"description":"Deleted."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Delete a link","tags":["Links"]}},"/api/v1/mcp/info":{"get":{"operationId":"getMcpInfo","responses":{"200":{"content":{"application/json":{"schema":{"properties":{"auth":{"enum":["bearer"],"type":"string"},"enabled":{"description":"Whether the legacy SSE transport is enabled. `false` does not mean MCP is off: `endpoint` works regardless.","type":"boolean"},"endpoint":{"description":"Path of the main MCP endpoint on this host (`/mcp`).","type":"string"},"multi_tenant":{"type":"boolean"},"port":{"description":"Port of the legacy SSE transport.","type":"string"},"transport":{"description":"The main transport; always on.","enum":["streamable_http"],"type":"string"}},"required":["transport","endpoint","enabled","port","multi_tenant","auth"],"type":"object"}}},"description":"Settings for building an MCP client configuration."},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"MCP connection settings","tags":["MCP"]}},"/api/v1/mcp/selftest":{"get":{"operationId":"mcpSelftest","responses":{"200":{"content":{"application/json":{"schema":{"properties":{"server":{"properties":{"name":{"type":"string"},"version":{"type":"string"}},"type":"object"},"tenant_ok":{"type":"boolean"},"tool_names":{"items":{"type":"string"},"type":"array"},"tools":{"type":"integer"},"vault_ok":{"type":"boolean"}},"required":["server","tools","tool_names","tenant_ok","vault_ok"],"type":"object"}}},"description":"Server identity, tools and access checks."},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Check what an MCP agent would see","tags":["MCP"]}},"/api/v1/mcp/tokens":{"get":{"operationId":"listMcpTokens","responses":{"200":{"content":{"application/json":{"schema":{"properties":{"tokens":{"items":{"$ref":"#/components/schemas/MCPToken"},"type":"array"}},"required":["tokens"],"type":"object"}}},"description":"Tokens (without secrets)."},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"MCP tokens of the account","tags":["MCP"]},"post":{"description":"The token is bound to `vault_id` if given, otherwise to the vault in `X-Vault-ID`. The secret is returned only once.","operationId":"createMcpToken","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateMCPTokenRequest"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MCPTokenCreated"}}},"description":"Created. Store `token` now."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/PaymentRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Issue an MCP token","tags":["MCP"]}},"/api/v1/mcp/tokens/{id}":{"delete":{"operationId":"revokeMcpToken","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/IdempotencyKey"}],"responses":{"204":{"description":"Revoked."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Revoke an MCP token","tags":["MCP"]}},"/api/v1/memories":{"get":{"description":"With `q` — search among this subject's notes only (hybrid when an\nembedder is available, otherwise text) → `{subject_id, mode,\nresults}`. Without `q` — the subject's notes, newest first →\n`{subject_id, notes, total}`.\n","operationId":"getMemories","parameters":[{"in":"query","name":"subject_id","required":true,"schema":{"maxLength":256,"minLength":1,"type":"string"}},{"in":"query","name":"q","schema":{"type":"string"}},{"in":"query","name":"limit","schema":{"default":10,"maximum":50,"minimum":1,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/MemorySearchResponse"},{"$ref":"#/components/schemas/MemoryListResponse"}]}}},"description":"Search results or the list of notes."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Memory of one end user","tags":["Memory"]},"post":{"description":"`/learn` in `auto` mode within one subject's memory: facts from the\nmessages become notes with this `subject_id`; only this subject's\nnotes are considered for extending. Low-confidence and CONTRADICT\nactions are not applied — they stay in `pending_plan_id` (approve with\n`POST /learn` `mode=execute`). Exists only when the server has an LLM\nconfigured. Learn rate class; needs the `learn` scope.\n","operationId":"addMemories","parameters":[{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddMemoriesRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddMemoriesResponse"}}},"description":"Notes created and updated."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/PaymentRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Remember a conversation of an end user (LLM)","tags":["Memory"]}},"/api/v1/notes":{"get":{"operationId":"listNotes","parameters":[{"$ref":"#/components/parameters/Page"},{"in":"query","name":"limit","schema":{"default":20,"maximum":100,"minimum":1,"type":"integer"}},{"description":"`created` orders by creation time; anything else by last update (newest first).","in":"query","name":"sort","schema":{"enum":["updated","created"],"type":"string"}},{"$ref":"#/components/parameters/SubjectFilter"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NoteList"}}},"description":"One page of notes."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"List live notes","tags":["Notes"]},"post":{"operationId":"createNote","parameters":[{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateNoteRequest"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Note"}}},"description":"Created (or the stored result of an earlier request with the same Idempotency-Key).","headers":{"Idempotent-Replayed":{"$ref":"#/components/headers/IdempotentReplayed"}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/PaymentRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Create a note","tags":["Notes"]}},"/api/v1/notes/alive":{"get":{"operationId":"aliveNotes","parameters":[{"description":"Comma-separated note UUIDs (at most 200 are checked; non-UUIDs are ignored).","in":"query","name":"ids","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"alive":{"items":{"format":"uuid","type":"string"},"type":"array"}},"required":["alive"],"type":"object"}}},"description":"The subset of ids that are live notes."},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Which of the given note ids still exist","tags":["Notes"]}},"/api/v1/notes/batch":{"post":{"description":"Each item is an upsert keyed by `external_id` (same semantics as\n`PUT /notes/external/{eid}`, including automatic ` (2)` title\nsuffixes). Items fail independently: a failed item has `error` set.\nBodies up to 50 MiB are accepted.\n","operationId":"batchUpsertNotes","parameters":[{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BatchNotesRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BatchNotesResponse"}}},"description":"Per-item results in request order."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/PaymentRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Upsert up to 500 notes by external id","tags":["External IDs"]}},"/api/v1/notes/batch-delete":{"post":{"description":"Allowed even when storage is full or the account is read-only.","operationId":"batchDeleteNotes","parameters":[{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BatchDeleteRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BatchDeleteResponse"}}},"description":"Which ids were deleted and which were not found."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Move up to 500 notes to the trash by external id","tags":["External IDs"]}},"/api/v1/notes/deleted":{"delete":{"operationId":"emptyTrash","parameters":[{"$ref":"#/components/parameters/IdempotencyKey"}],"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"purged":{"format":"int64","type":"integer"}},"required":["purged"],"type":"object"}}},"description":"Number of notes purged."},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Permanently delete every note in the trash","tags":["Notes"]},"get":{"operationId":"listDeletedNotes","parameters":[{"$ref":"#/components/parameters/Page"},{"in":"query","name":"limit","schema":{"default":50,"maximum":200,"minimum":1,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"limit":{"type":"integer"},"notes":{"items":{"$ref":"#/components/schemas/DeletedNote"},"type":"array"},"page":{"type":"integer"},"total":{"type":"integer"}},"required":["notes","total","page","limit"],"type":"object"}}},"description":"One page of deleted notes, newest deletion first."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"List notes in the trash","tags":["Notes"]}},"/api/v1/notes/external/{eid}":{"delete":{"operationId":"deleteNoteByExternalId","parameters":[{"$ref":"#/components/parameters/IdempotencyKey"}],"responses":{"204":{"description":"Deleted."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Move a note to the trash by external id","tags":["External IDs"]},"get":{"operationId":"getNoteByExternalId","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Note"}}},"description":"The note."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Get a note by external id","tags":["External IDs"]},"parameters":[{"$ref":"#/components/parameters/ExternalId"}],"put":{"description":"Creates the note (201) or updates it (200). If the title is taken by a\ndifferent note, a suffix ` (2)`, ` (3)`, … is added; the response holds\nthe actual title.\n","operationId":"upsertNoteByExternalId","parameters":[{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExternalNoteRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Note"}}},"description":"Updated (or unchanged)."},"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Note"}}},"description":"Created."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/PaymentRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Create or update a note by external id","tags":["External IDs"]}},"/api/v1/notes/stats":{"get":{"operationId":"getNoteStats","responses":{"200":{"content":{"application/json":{"schema":{"properties":{"tags":{"description":"Distinct tags.","type":"integer"},"total":{"description":"Live notes.","type":"integer"},"words":{"description":"Words across live notes.","format":"int64","type":"integer"}},"required":["total","words","tags"],"type":"object"}}},"description":"Counts for live notes."},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Vault statistics","tags":["Notes"]}},"/api/v1/notes/{id}":{"delete":{"description":"Moves the note to the trash, or removes it permanently with `hard=true`.","operationId":"deleteNote","parameters":[{"$ref":"#/components/parameters/IdempotencyKey"},{"in":"query","name":"hard","schema":{"default":false,"type":"boolean"}}],"responses":{"204":{"description":"Deleted."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Delete a note","tags":["Notes"]},"get":{"operationId":"getNote","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Note"}}},"description":"The note."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Get a note","tags":["Notes"]},"parameters":[{"$ref":"#/components/parameters/NoteId"}],"put":{"description":"Only the fields present are changed. Editing title or content resets the embedding until it is recomputed.","operationId":"updateNote","parameters":[{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateNoteRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Note"}}},"description":"The updated note."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/PaymentRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Update a note (partial)","tags":["Notes"]}},"/api/v1/notes/{id}/at":{"get":{"operationId":"getNoteAt","parameters":[{"$ref":"#/components/parameters/At"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NoteRevision"}}},"description":"The note's state at `at`."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"A note as it was at a moment","tags":["Temporal"]},"parameters":[{"$ref":"#/components/parameters/NoteId"}]},"/api/v1/notes/{id}/chunks":{"parameters":[{"$ref":"#/components/parameters/NoteId"}],"post":{"description":"Chunks are created automatically on write; use this only to supply your own chunking (optionally with embeddings).","operationId":"upsertNoteChunks","parameters":[{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpsertChunksRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"count":{"type":"integer"}},"required":["count"],"type":"object"}}},"description":"Number of chunks stored."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/PaymentRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Replace the chunks of a note","tags":["Chunks \u0026 Embeddings"]}},"/api/v1/notes/{id}/embedding":{"parameters":[{"$ref":"#/components/parameters/NoteId"}],"put":{"operationId":"updateNoteEmbedding","parameters":[{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateEmbeddingRequest"}}},"required":true},"responses":{"204":{"description":"Stored."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/PaymentRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Store a note embedding computed by the caller","tags":["Chunks \u0026 Embeddings"]}},"/api/v1/notes/{id}/graph":{"get":{"operationId":"getNoteGraph","parameters":[{"$ref":"#/components/parameters/SubjectFilter"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GraphResponse"}}},"description":"The note and its links in both directions."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"A note and its direct neighbours","tags":["Graph"]},"parameters":[{"$ref":"#/components/parameters/NoteId"}]},"/api/v1/notes/{id}/graph-at":{"get":{"operationId":"getNoteGraphAt","parameters":[{"$ref":"#/components/parameters/At"}],"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"at":{"format":"date-time","type":"string"},"neighbors":{"items":{"$ref":"#/components/schemas/GraphNeighbor"},"type":["array","null"]},"note_id":{"type":"string"}},"required":["note_id","at","neighbors"],"type":"object"}}},"description":"Links that existed at `at`."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"A note's neighbours at a moment","tags":["Temporal"]},"parameters":[{"$ref":"#/components/parameters/NoteId"}]},"/api/v1/notes/{id}/history":{"get":{"operationId":"getNoteHistory","responses":{"200":{"content":{"application/json":{"schema":{"properties":{"count":{"type":"integer"},"note_id":{"type":"string"},"revisions":{"items":{"$ref":"#/components/schemas/NoteRevision"},"type":["array","null"]}},"required":["note_id","revisions","count"],"type":"object"}}},"description":"Revisions."},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Every stored revision of a note","tags":["Temporal"]},"parameters":[{"$ref":"#/components/parameters/NoteId"}]},"/api/v1/notes/{id}/reanalyze":{"parameters":[{"$ref":"#/components/parameters/NoteId"}],"post":{"description":"Learn rate class. Returns links created automatically and mid-confidence suggestions.","operationId":"reanalyzeNote","parameters":[{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"content":{"application/json":{"schema":{"properties":{"sensitivity":{"$ref":"#/components/schemas/Sensitivity"}},"type":"object"}}},"required":false},"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"auto_created":{"description":"Ids of links created.","items":{"type":"string"},"type":"array"},"link_suggestions":{"items":{"$ref":"#/components/schemas/AutoLinkSuggestion"},"type":"array"},"processed":{"type":"integer"}},"required":["auto_created","link_suggestions","processed"],"type":"object"}}},"description":"Result of the rebuild."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/PaymentRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Rebuild automatic links of one note","tags":["Learn"]}},"/api/v1/notes/{id}/restore":{"parameters":[{"$ref":"#/components/parameters/NoteId"}],"post":{"description":"If a live note already has the same title, pass a new `title` in the body.","operationId":"restoreNote","parameters":[{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"content":{"application/json":{"schema":{"properties":{"title":{"description":"Restore under this title instead.","type":"string"}},"type":"object"}}},"required":false},"responses":{"204":{"description":"Restored."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/PaymentRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Restore a note from the trash","tags":["Notes"]}},"/api/v1/notes/{id}/similar":{"get":{"operationId":"similarNotes","parameters":[{"in":"query","name":"limit","schema":{"default":10,"maximum":50,"minimum":1,"type":"integer"}},{"$ref":"#/components/parameters/SubjectFilter"}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/SearchResult"},"type":"array"}}},"description":"Similar notes, most similar first."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Notes most similar to this one (by embedding)","tags":["Search"]},"parameters":[{"$ref":"#/components/parameters/NoteId"}]},"/api/v1/notes/{id}/suggest-tags":{"parameters":[{"$ref":"#/components/parameters/NoteId"}],"post":{"description":"Learn rate class. Suggestions exclude tags the note already has; `known` marks tags that already exist in the vault.","operationId":"suggestTags","parameters":[{"$ref":"#/components/parameters/IdempotencyKey"}],"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"existing_tags":{"items":{"type":"string"},"type":["array","null"]},"suggested_tags":{"items":{"properties":{"known":{"type":"boolean"},"reason":{"type":"string"},"tag":{"type":"string"}},"required":["tag","reason","known"],"type":"object"},"type":"array"}},"required":["suggested_tags"],"type":"object"}}},"description":"Suggested tags."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/PaymentRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"429":{"$ref":"#/components/responses/TooManyRequests"},"502":{"$ref":"#/components/responses/BadGateway"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Suggest tags for a note (LLM)","tags":["Learn"]}},"/api/v1/openapi.json":{"get":{"operationId":"getOpenApiSpec","responses":{"200":{"content":{"application/json":{"schema":{"type":"object"}}},"description":"The OpenAPI 3.1 document as JSON."}},"security":[],"summary":"This OpenAPI document","tags":["Meta"]}},"/api/v1/search":{"get":{"description":"`text` — full-text (Ukrainian-aware); `vector` — semantic (needs an\nembedder or your own `embedding`); `hybrid` — both, fused. When the\naccount is read-only, vector/hybrid without your own embedding run as\ntext search and the response says `degraded: text_only` (also the\n`X-Search-Degraded` header).\n","operationId":"search","parameters":[{"description":"Query text. Required for text and hybrid.","in":"query","name":"q","schema":{"type":"string"}},{"in":"query","name":"mode","schema":{"default":"text","enum":["text","vector","hybrid"],"type":"string"}},{"in":"query","name":"limit","schema":{"default":10,"maximum":50,"minimum":1,"type":"integer"}},{"$ref":"#/components/parameters/Embedding"},{"description":"Comma-separated; results must have all of them.","in":"query","name":"tags","schema":{"type":"string"}},{"description":"Only notes whose external_id starts with this prefix.","in":"query","name":"external_prefix","schema":{"type":"string"}},{"description":"Drop results whose final score is lower.","in":"query","name":"min_score","schema":{"type":"number"}},{"$ref":"#/components/parameters/SubjectFilter"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchResponse"}}},"description":"Results, best first.","headers":{"X-Search-Degraded":{"description":"`text_only` when a vector/hybrid search ran as text search.","schema":{"type":"string"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Search notes","tags":["Search"]}},"/api/v1/search/at":{"get":{"operationId":"searchAt","parameters":[{"in":"query","name":"q","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/At"},{"in":"query","name":"limit","schema":{"default":10,"maximum":100,"minimum":1,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"at":{"format":"date-time","type":"string"},"mode":{"enum":["text"],"type":"string"},"note":{"type":"string"},"q":{"type":"string"},"results":{"items":{"$ref":"#/components/schemas/SearchResult"},"type":["array","null"]},"total":{"type":"integer"}},"required":["q","at","mode","results","total"],"type":"object"}}},"description":"Results (text mode only — embeddings are not versioned)."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Full-text search over the vault as it was at a moment","tags":["Temporal"]}},"/api/v1/search/graph-rag":{"post":{"description":"Top-N notes by similarity to the query plus, with `expand_neighbors`,\nthe notes linked to them (both directions). Send the query as text\n(`q` — the server embeds it with the vault's embedder, metered like\n`/search`: `embeddings_tokens` and `search_queries`) or as your own\nvector (`embedding`, dimensions of the vault) — exactly one of them,\notherwise `400`. `subject_id` and `tags` filter like in `/search`, and\nthey apply to the neighbours too.\n\nA read-only account (balance used up) may call it — it only reads:\nwith `q` the seeds are found by full-text search instead of paying for\na query embedding, and the response has `X-Search-Degraded: text_only`\n(the seeds then carry `text_score`). An unavailable embedder is\n`503 EMBEDDER_UNAVAILABLE` (with `Retry-After` when it is a transient\nfailure). Separate `graph-rag` rate class.\n","operationId":"graphRag","parameters":[{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GraphRAGRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/SearchResult"},"type":"array"}}},"description":"Seeds (by score) and then their neighbours (score 0).","headers":{"X-Search-Degraded":{"description":"`text_only` — the seeds were found by full-text search (read-only account).","schema":{"enum":["text_only"],"type":"string"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/PaymentRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Vector search expanded through the link graph","tags":["Search"]}},"/api/v1/subjects":{"get":{"description":"Every `subject_id` that has at least one note in the vault (live or in\nthe trash), with note counts and the time of the latest change,\nmost recently changed first.\n","operationId":"listSubjects","parameters":[{"$ref":"#/components/parameters/Page"},{"in":"query","name":"limit","schema":{"default":50,"maximum":200,"minimum":1,"type":"integer"}},{"description":"Only subject ids that start with this string.","in":"query","name":"prefix","schema":{"maxLength":256,"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"limit":{"type":"integer"},"page":{"type":"integer"},"subjects":{"items":{"$ref":"#/components/schemas/SubjectSummary"},"type":"array"},"total":{"type":"integer"}},"required":["subjects","total","page","limit"],"type":"object"}}},"description":"One page of end users."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"List the end users of a vault","tags":["Memory"]}},"/api/v1/subjects/{subject_id}":{"delete":{"description":"Permanently deletes the subject's notes in this vault (live and in the\ntrash) with their revisions, chunks and links, its learn runs and\nunapproved plans, and stored webhook deliveries about its notes. Then\nsends one `subject.deleted` event. Zero counts when there was nothing\n— repeating is safe.\n","operationId":"deleteSubject","parameters":[{"$ref":"#/components/parameters/IdempotencyKey"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubjectDeleteResult"}}},"description":"What was deleted."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/PaymentRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Erase everything stored for an end user","tags":["Memory"]},"parameters":[{"description":"End user id, URL-encoded.","in":"path","name":"subject_id","required":true,"schema":{"maxLength":256,"minLength":1,"type":"string"}}]},"/api/v1/sync":{"post":{"description":"Upserts notes by title parsed from each file (front matter, `#tags`,\n`[[wikilinks]]` become metadata, tags and links). Bodies up to 50 MiB\nare accepted. Per-file failures are listed in `errors`; `files` says\nwhat happened to each file.\n\nNotes are matched by **title** (front matter `title`, else the first\n`# heading`, else the file name), so importing the same files again\nupdates the same notes instead of duplicating them, and two files with\nthe same title end up as one note (`duplicate_of`). Re-importing a\nfile keeps the note's priority and lifetime (`expires_at`).\n\nA `[[wikilink]]` is resolved the way Obsidian does it: by note title,\nthen by the file the note was imported from (`[[File name]]`,\n`[[Folder/File name]]`), then by a front matter alias (`aliases`);\ncase is ignored, `#heading` and `|label` are dropped. A link to\nsomething that is not a note (an image, a page not written yet) is\nskipped.\n\n`dry_run: true` writes nothing and answers what the import would do —\nshow it to a person before importing. A file over the note size limit\nis a per-file error there; the real import rejects the whole request\nwith `413 NOTE_TOO_LARGE`.\n\nA large vault goes in several requests. A `[[wikilink]]` to a note\nfrom a later request cannot be resolved when its file is imported, so\nfinish with `links_only: true` for the files that have links: it\ncreates the missing links and leaves the notes untouched.\n","operationId":"syncFiles","parameters":[{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SyncRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SyncResponse"}}},"description":"Import summary."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/PaymentRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Import Markdown files (Obsidian-style)","tags":["Notes"]}},"/api/v1/tags":{"get":{"operationId":"listTags","responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/Tag"},"type":"array"}}},"description":"Tags ordered by name."},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"All tags in the vault","tags":["Tags"]}},"/api/v1/tags/notes/count":{"get":{"operationId":"countNotesByTags","parameters":[{"description":"Comma-separated tag names.","in":"query","name":"tags","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"total":{"type":"integer"}},"required":["total"],"type":"object"}}},"description":"Count."},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Number of distinct notes having any of the tags","tags":["Tags"]}},"/api/v1/tags/{name}/notes":{"get":{"operationId":"notesByTag","parameters":[{"in":"path","name":"name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/Note"},"type":"array"}}},"description":"Notes."},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Notes with a tag","tags":["Tags"]}},"/api/v1/usage":{"get":{"description":"Counter metrics summed over `(since, until]`. Available even when the account is suspended.","operationId":"getUsage","parameters":[{"$ref":"#/components/parameters/Since"},{"$ref":"#/components/parameters/Until"},{"$ref":"#/components/parameters/GroupBy"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Usage"}}},"description":"Usage."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"ApiKey":[]}],"summary":"Consumption of the account for a period","tags":["Account \u0026 Usage"]}},"/api/v1/vault/snapshot":{"get":{"operationId":"getVaultSnapshot","parameters":[{"$ref":"#/components/parameters/At"},{"$ref":"#/components/parameters/Page"},{"in":"query","name":"limit","schema":{"default":50,"maximum":200,"minimum":1,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"at":{"format":"date-time","type":"string"},"limit":{"type":"integer"},"notes":{"items":{"$ref":"#/components/schemas/GraphNode"},"type":["array","null"]},"page":{"type":"integer"},"total":{"type":"integer"}},"required":["at","notes","total","page","limit"],"type":"object"}}},"description":"One page of notes as of `at`."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"summary":"Notes that existed at a moment","tags":["Temporal"]}},"/api/v1/vaults":{"get":{"operationId":"listVaults","parameters":[{"description":"Filter by name.","in":"query","name":"q","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"vaults":{"items":{"$ref":"#/components/schemas/Vault"},"type":"array"}},"required":["vaults"],"type":"object"}}},"description":"Vaults."},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"ApiKey":[]}],"summary":"Vaults of the account","tags":["Vaults"]},"post":{"description":"Limited by the plan's vault cap (`403 VAULT_LIMIT_REACHED`) and a separate creation rate.\n\n`embedder` picks the embedding provider from `GET /api/v1/embedders`\n(full id like `ollama:nomic-embed-text`, or just the kind when the\nserver has one provider of that kind; omitted — the default one).\nThe vault's vectors get that provider's dimensions and all its\nembedding (notes, chunks, search, learn, links, graph-rag) goes\nthrough it. An unknown embedder is `400 INVALID_EMBEDDER`. The\nembedder cannot be changed in place later (`409 EMBEDDER_IMMUTABLE`);\n`POST /api/v1/vaults/{id}/copy` makes a copy with another embedder.\n","operationId":"createVault","parameters":[{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateVaultRequest"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Vault"}}},"description":"Created."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/PaymentRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"ApiKey":[]}],"summary":"Create a vault","tags":["Vaults"]}},"/api/v1/vaults/{id}":{"delete":{"operationId":"deleteVault","responses":{"204":{"description":"Deleted."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"ApiKey":[]}],"summary":"Delete a vault and all its data","tags":["Vaults"]},"parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}],"patch":{"description":"`embedder` cannot be changed in place: a different value is\n`409 EMBEDDER_IMMUTABLE` (use `POST /api/v1/vaults/{id}/copy` with that\nembedder); the same value is accepted and ignored.\n","operationId":"updateVault","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateVaultRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Vault"}}},"description":"The updated vault."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/PaymentRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"ApiKey":[]}],"summary":"Rename a vault or change its link sensitivity","tags":["Vaults"]}},"/api/v1/vaults/{id}/copy":{"parameters":[{"description":"Source vault id.","in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}],"post":{"description":"The way to change a vault's embedding provider. Creates a new vault\nwith `embedder` and copies the source's content into it: notes (the\ntrash included) with the same ids, tags, links, chunks, note and link\nhistory, learn runs — without vectors. The embed worker then embeds the\ncopy with the new provider in the background (billed as usual\n`embeddings_tokens`); progress is `GET /api/v1/vaults/{id}/embedding-status`.\n\nThe source is not changed and keeps working the whole time (search,\nkeys, MCP tokens, webhooks stay bound to it). When the copy reports\n`done: true`, point clients to the new vault id, issue its keys and\ndelete the old vault. Changes made in the source after the copy are\nnot carried over.\n\nCounts toward the plan's vault cap (`403 VAULT_LIMIT_REACHED`) and the\nvault creation rate. Needs free storage about the size of the source\n(`413 STORAGE_LIMIT_REACHED`). An embedder that is not configured on\nthe server is `409 EMBEDDER_UNAVAILABLE`.\n","operationId":"copyVault","parameters":[{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"content":{"application/json":{"schema":{"properties":{"embedder":{"description":"Provider id or kind from GET /api/v1/embedders.","type":"string"},"name":{"description":"Name of the copy; default — the source name with the embedder id.","maxLength":255,"type":"string"}},"required":["embedder"],"type":"object"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"properties":{"copied":{"properties":{"links":{"type":"integer"},"notes":{"description":"Notes copied","the trash included.":null,"type":"integer"},"tags":{"type":"integer"}},"required":["notes","links","tags"],"type":"object"},"embedding":{"$ref":"#/components/schemas/EmbeddingStatus"},"source_id":{"format":"uuid","type":"string"},"vault":{"$ref":"#/components/schemas/Vault"}},"required":["vault","source_id","copied","embedding"],"type":"object"}}},"description":"The copy."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/PaymentRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"ApiKey":[]}],"summary":"Copy a vault with another embedder","tags":["Vaults"]}},"/api/v1/vaults/{id}/embedding-status":{"get":{"description":"How many notes and chunks still wait for vectors — the progress of a\ncopy with another embedder or of a large import. `done` — nothing is\nwaiting (items the embedder rejected for good are counted in\n`*_failed` and do not wait).\n","operationId":"getVaultEmbeddingStatus","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmbeddingStatus"}}},"description":"Progress."},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"ApiKey":[]}],"summary":"Embedding progress of a vault","tags":["Vaults"]},"parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}]},"/api/v1/vaults/{id}/export":{"get":{"description":"Everything stored in the vault as one JSON document: live notes, the\ntrash, every revision, links and tags. The notes import back with\n`POST /api/v1/notes/batch` (by `external_id`) or `POST /api/v1/sync`.\nEither the whole vault or an error — never a partial export.\nA vault with more than 64 MiB of note text (live notes, the trash and\nevery revision) is refused with `413 EXPORT_TOO_LARGE`: page through\n`GET /api/v1/notes`, `GET /api/v1/notes/deleted` and\n`GET /api/v1/notes/{id}/history` instead. Exports run a few at a time;\nwhen all slots are busy the answer is `503 SERVICE_BUSY` with\nRetry-After.\n","operationId":"exportVault","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VaultDataExport"}}},"description":"The vault's data."},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"ApiKey":[]}],"summary":"Export a whole vault","tags":["Vaults"]},"parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}]},"/api/v1/vaults/{id}/keys":{"get":{"description":"All keys of the vault, revoked ones included, newest first; without plain values.","operationId":"listVaultKeys","responses":{"200":{"content":{"application/json":{"schema":{"properties":{"keys":{"items":{"$ref":"#/components/schemas/VaultKey"},"type":"array"}},"required":["keys"],"type":"object"}}},"description":"Keys."},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"ApiKey":[]}],"summary":"Keys of a vault","tags":["Vault keys"]},"parameters":[{"description":"Vault id.","in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}],"post":{"description":"The plain key (`dbk_…`) is in `key` and is returned only here; later\nonly `prefix` is shown. See \"Vault keys and scopes\".\n","operationId":"createVaultKey","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateVaultKeyRequest"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatedVaultKey"}}},"description":"Created; `key` is shown once."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/PaymentRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"ApiKey":[]}],"summary":"Issue a vault key","tags":["Vault keys"]}},"/api/v1/vaults/{id}/keys/{keyID}":{"delete":{"description":"The key stops working from the next request.","operationId":"revokeVaultKey","responses":{"204":{"description":"Revoked."},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"ApiKey":[]}],"summary":"Revoke a vault key","tags":["Vault keys"]},"parameters":[{"description":"Vault id.","in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}},{"in":"path","name":"keyID","required":true,"schema":{"format":"uuid","type":"string"}}]},"/api/v1/webhooks":{"get":{"operationId":"listWebhooks","responses":{"200":{"content":{"application/json":{"schema":{"properties":{"webhooks":{"items":{"$ref":"#/components/schemas/Webhook"},"type":"array"}},"required":["webhooks"],"type":"object"}}},"description":"Webhooks, newest first, without secrets."},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"ApiKey":[]}],"summary":"Webhooks of the account","tags":["Webhooks"]},"post":{"description":"`secret` (at least 16 characters) is generated when absent and is\nreturned only here and on `PATCH` with `rotate_secret`. With\n`vault_id` only that vault's events are sent; `quota.warning` is sent\neither way. Up to 20 webhooks per account.\n","operationId":"createWebhook","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateWebhookRequest"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Webhook"}}},"description":"Created; includes `secret`."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/PaymentRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"ApiKey":[]}],"summary":"Subscribe a URL to events","tags":["Webhooks"]}},"/api/v1/webhooks/{id}":{"delete":{"operationId":"deleteWebhook","responses":{"204":{"description":"Deleted."},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"ApiKey":[]}],"summary":"Delete a webhook and its delivery log","tags":["Webhooks"]},"parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}],"patch":{"description":"Only the fields present are changed. `active: true` enables a disabled\nwebhook and resets its failure counter. `active: false` marks its\nunsent deliveries `skipped`: after re-enabling, only new events are\nsent. `rotate_secret: true` returns the new `secret` in the response.\n","operationId":"updateWebhook","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateWebhookRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Webhook"}}},"description":"The updated webhook."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/PaymentRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"ApiKey":[]}],"summary":"Change, enable, disable a webhook or rotate its secret","tags":["Webhooks"]}},"/api/v1/webhooks/{id}/deliveries":{"get":{"description":"Newest first. Finished deliveries are kept for 30 days.","operationId":"listWebhookDeliveries","parameters":[{"in":"query","name":"limit","schema":{"default":50,"maximum":100,"minimum":1,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"deliveries":{"items":{"$ref":"#/components/schemas/WebhookDelivery"},"type":"array"}},"required":["deliveries"],"type":"object"}}},"description":"Deliveries."},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"ApiKey":[]}],"summary":"Recent deliveries of a webhook","tags":["Webhooks"]},"parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}]},"/api/v1/webhooks/{id}/test":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}],"post":{"description":"Queues a `webhook.test` event for this webhook regardless of its\nevents. The result appears in `GET /webhooks/{id}/deliveries`. On a\ndisabled webhook the delivery is `skipped` right away.\n","operationId":"testWebhook","responses":{"202":{"content":{"application/json":{"schema":{"properties":{"delivery":{"$ref":"#/components/schemas/WebhookDelivery"}},"required":["delivery"],"type":"object"}}},"description":"Queued."},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/PaymentRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"security":[{"ApiKey":[]}],"summary":"Queue a test delivery","tags":["Webhooks"]}},"/health":{"get":{"operationId":"getHealth","parameters":[{"description":"`1` also checks pgvector and the embedder (cached for a minute).","in":"query","name":"deep","schema":{"enum":["1"],"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Health"}}},"description":"Healthy."},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Health"}}},"description":"Database or a deep check failed."}},"security":[],"summary":"Liveness and dependency check","tags":["Meta"]}},"/mcp":{"post":{"description":"Model Context Protocol endpoint (streamable HTTP). Send JSON-RPC 2.0\nmessages (`initialize`, `tools/list`, `tools/call`, …) with\n`Accept: application/json, text/event-stream`. The server returns\n`Mcp-Session-Id` on `initialize`; send it back on later calls. `GET`\nopens the server-sent event stream, `DELETE` ends the session. The\ntoken decides the vault; rate limits and billing match the REST API.\nWith an exhausted balance (`read_only`) the transport keeps working,\nas REST reads do: read tools and `delete_note` succeed (searches run\nas text search, without a paid query embedding), write and LLM tools\nreturn a tool error starting with `BALANCE_EXHAUSTED`.\n","operationId":"mcpRequest","requestBody":{"content":{"application/json":{"schema":{"description":"A JSON-RPC 2.0 request or notification.","type":"object"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"type":"object"}},"text/event-stream":{"schema":{"type":"string"}}},"description":"JSON-RPC response, as JSON or as an event stream."},"202":{"description":"Notification accepted."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"security":[{"McpBearer":[]}],"summary":"MCP streamable-HTTP transport","tags":["MCP"]}}},"security":[{"ApiKey":[],"VaultId":[]},{"VaultKey":[]}],"servers":[{"url":"https://api.digital-brain.io"},{"url":"http://localhost:8080"}],"tags":[{"description":"Create, read, update and delete notes; trash and import.","name":"Notes"},{"description":"Notes addressed by the caller's own identifiers.","name":"External IDs"},{"description":"Full-text, vector and hybrid search.","name":"Search"},{"description":"Links between notes as a graph.","name":"Graph"},{"description":"The state of notes and links at a past moment.","name":"Temporal"},{"description":"Manual links between notes.","name":"Links"},{"description":"Tags and notes by tag.","name":"Tags"},{"description":"For callers that compute embeddings themselves.","name":"Chunks \u0026 Embeddings"},{"description":"LLM-driven curation. Available when the server has an LLM configured.","name":"Learn"},{"description":"Vaults of the account (X-API-Key only).","name":"Vaults"},{"description":"Keys bound to one vault with scopes (account key only).","name":"Vault keys"},{"description":"Memory of your end users, scoped by subject_id.","name":"Memory"},{"description":"Signed event notifications (account key only).","name":"Webhooks"},{"description":"MCP endpoint and its tokens.","name":"MCP"},{"description":"Plan, limits and consumption (X-API-Key only).","name":"Account \u0026 Usage"},{"description":"Service information (no authentication).","name":"Meta"},{"description":"Internal: operator/billing service only (X-Admin-API-Key).","name":"Admin","x-internal":true}],"webhooks":{"contradictionDetected":{"post":{"description":"A learn plan found new text contradicting a note (kind `contradict`) or making it outdated (kind `outdate`).","operationId":"onContradictionDetected","parameters":[{"$ref":"#/components/parameters/WebhookEventHeader"},{"$ref":"#/components/parameters/WebhookDeliveryHeader"},{"$ref":"#/components/parameters/WebhookTimestampHeader"},{"$ref":"#/components/parameters/WebhookSignatureHeader"}],"requestBody":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/WebhookPayload"},{"properties":{"data":{"properties":{"action_id":{"type":"string"},"kind":{"enum":["contradict","outdate"],"type":"string"},"note_id":{"type":"string"},"old_excerpt":{"type":"string"},"plan_id":{"type":"string"},"reason":{"type":"string"},"subject_id":{"type":"string"}},"type":"object"}},"type":"object"}]}}}},"responses":{"2XX":{"description":"Accepted."}},"summary":"contradiction.detected","tags":["Webhooks"]}},"learnCompleted":{"post":{"description":"A learn run applied actions: REST `/learn` execute and auto,\n`POST /memories`, the MCP tools `learn_text` and `record_interaction`\n(mode `auto`, empty `run_id`), and reconstructions (`/learn/from-vault\nop=reconstruct`, MCP `reconstruct_notes`; mode `reconstruct`, the\ntarget in `extended`, merged notes in `deleted`).\n","operationId":"onLearnCompleted","parameters":[{"$ref":"#/components/parameters/WebhookEventHeader"},{"$ref":"#/components/parameters/WebhookDeliveryHeader"},{"$ref":"#/components/parameters/WebhookTimestampHeader"},{"$ref":"#/components/parameters/WebhookSignatureHeader"}],"requestBody":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/WebhookPayload"},{"properties":{"data":{"properties":{"contradicted":{"items":{"type":"string"},"type":"array"},"created":{"items":{"type":"string"},"type":"array"},"deleted":{"description":"Reconstruct: notes merged into the target and moved to the trash.","items":{"type":"string"},"type":"array"},"errors":{"type":"integer"},"extended":{"items":{"type":"string"},"type":"array"},"mode":{"type":"string"},"plan_id":{"type":"string"},"run_id":{"type":"string"},"status":{"type":"string"},"subject_id":{"type":"string"}},"type":"object"}},"type":"object"}]}}}},"responses":{"2XX":{"description":"Accepted."}},"summary":"learn.completed","tags":["Webhooks"]}},"noteEvent":{"post":{"description":"Sent in the same transaction as the change, whatever the path (REST,\nMCP, learn, sync). Restoring from the trash is `note.created`.\n`note.updated` fires when the title, content, metadata, external_id,\nsubject_id or the set of tags changes — at most one event per note\nper transaction (a note created with tags is only `note.created`;\nwriting the same set of tags again is no event). Embedding and\npriority changes are not events.\n","operationId":"onNoteEvent","parameters":[{"$ref":"#/components/parameters/WebhookEventHeader"},{"$ref":"#/components/parameters/WebhookDeliveryHeader"},{"$ref":"#/components/parameters/WebhookTimestampHeader"},{"$ref":"#/components/parameters/WebhookSignatureHeader"}],"requestBody":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/WebhookPayload"},{"properties":{"data":{"properties":{"external_id":{"type":["string","null"]},"id":{"format":"uuid","type":"string"},"subject_id":{"type":["string","null"]},"title":{"type":"string"}},"required":["id","title","external_id","subject_id"],"type":"object"}},"type":"object"}]}}}},"responses":{"2XX":{"description":"Accepted. Any other answer is retried."}},"summary":"note.created, note.updated, note.deleted","tags":["Webhooks"]}},"quotaWarning":{"post":{"description":"Storage use crossed 80% or 100% of the limit; at most once per threshold per UTC day. `vault_id` is null.","operationId":"onQuotaWarning","parameters":[{"$ref":"#/components/parameters/WebhookEventHeader"},{"$ref":"#/components/parameters/WebhookDeliveryHeader"},{"$ref":"#/components/parameters/WebhookTimestampHeader"},{"$ref":"#/components/parameters/WebhookSignatureHeader"}],"requestBody":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/WebhookPayload"},{"properties":{"data":{"properties":{"limit_bytes":{"format":"int64","type":"integer"},"threshold_percent":{"enum":[80,100],"type":"integer"},"used_bytes":{"format":"int64","type":"integer"},"used_percent":{"type":"integer"}},"type":"object"}},"type":"object"}]}}}},"responses":{"2XX":{"description":"Accepted."}},"summary":"quota.warning","tags":["Webhooks"]}},"subjectDeleted":{"post":{"description":"An end user's memory was erased (one event instead of a note.deleted per note).","operationId":"onSubjectDeleted","parameters":[{"$ref":"#/components/parameters/WebhookEventHeader"},{"$ref":"#/components/parameters/WebhookDeliveryHeader"},{"$ref":"#/components/parameters/WebhookTimestampHeader"},{"$ref":"#/components/parameters/WebhookSignatureHeader"}],"requestBody":{"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/WebhookPayload"},{"properties":{"data":{"properties":{"notes":{"format":"int64","type":"integer"},"subject_id":{"type":"string"}},"type":"object"}},"type":"object"}]}}}},"responses":{"2XX":{"description":"Accepted."}},"summary":"subject.deleted","tags":["Webhooks"]}}}}