API Endpoints
Canonical API contract for the Omni edge proxy and modern PKMS routes.
This page documents the routes exposed by omni-edge-proxy/src/index.ts:33-348 and the modern PKMS routes registered in omni-edge-proxy/src/routes/pkms.ts:1150-1679.
Use Legacy Notes Compatibility for the workspace-scoped compatibility routes that the current desktop client still uses for note CRUD.
Authentication and headers
Most PKMS routes require:
Authorization: Bearer <token>The proxy accepts several token forms through the shared auth pipeline described in omni-edge-proxy/src/index.ts:75-97 and omni-edge-proxy/src/routes/pkms.ts:319-336.
CORS-allowed headers
The edge proxy explicitly allows these request headers:
Content-Type
Authorization
X-Appwrite-Project
X-Appwrite-Key
X-Proxy-Decrypt
X-Client-KeySee omni-edge-proxy/src/index.ts:35-41.
Response decryption controls
PKMS responses are only transformed when the caller opts in with:
X-Proxy-Decrypt: trueYou may also provide a client key directly:
X-Client-Key: <client-key>Behavior from omni-edge-proxy/src/routes/pkms.ts:122-153 and omni-edge-proxy/src/routes/pkms.ts:222-233:
- If
X-Proxy-Decryptis nottrue, the proxy returns the stored response unchanged. - If
X-Proxy-Decrypt: trueis present, the proxy resolves a client key. - Client key precedence is:
X-Client-Key- escrowed key resolved through
getClientKeyinomni-edge-proxy/src/index.ts:75-97
- If no client key is available, the response is still returned unchanged.
The response transformer can decrypt:
- envelope objects with
format: "omni.om.encrypted" - encrypted blob strings shaped like
iv:tag:ciphertext - nested arrays and objects containing those values
See omni-edge-proxy/src/routes/pkms.ts:137-220.
Route inventory
| Method | Path | Description |
|---|---|---|
GET | /health | Health probe. |
GET | /v1/me | Verify the current token and report whether escrowed client key material exists. |
POST | /api/v1/webhooks/r1xG2bFatcOoQS0A28AQZ/sync | Firebase-backed sync and wrapped-key restoration webhook. |
POST | /api/v1/webhooks/E6K9u35uZUEIJVnp2NivP/sync | Firebase-backed onboarding and client-key escrow webhook. |
GET | /v1/workspaces | List workspaces. |
POST | /v1/workspaces | Create a workspace. |
GET | /v1/workspaces/:workspaceId | Fetch one workspace. |
POST | /v1/documents | Create a unified PKMS document. |
PATCH | /v1/documents/:id | Partially update a unified document. |
DELETE | /v1/documents/:id?workspace_id=... | Delete a unified document. |
POST | /v1/documents/query | Query documents with semantic-first orchestration and keyword fallback. |
GET | /v1/workspaces/:workspaceId/documents | List document summaries for a workspace. |
POST | /v1/workspaces/:workspaceId/documents | Create a workspace-scoped unified document. |
GET | /v1/workspaces/:workspaceId/documents/:documentId | Fetch a unified document plus blocks and markdown. |
PUT | /v1/workspaces/:workspaceId/documents/:documentId | Replace/update a workspace-scoped unified document. |
DELETE | /v1/workspaces/:workspaceId/documents/:documentId | Delete a workspace-scoped unified document. |
POST | /v1/workspaces/:workspaceId/chats | Create a new chat session thread. |
PATCH | /v1/workspaces/:workspaceId/chats/:threadId | Update chat thread title or metadata. |
GET | /v1/workspaces/:workspaceId/chats/:threadId/messages | Fetch messages for a chat session. |
POST | /v1/workspaces/:workspaceId/chats/:threadId/messages | Append a message to a chat session thread. |
GET | /v1/workspaces/:workspaceId/index/status | Read legacy derived-index status. |
GET | /v1/workspaces/:workspaceId/index/raw | Read the raw derived block index. |
POST | /v1/workspaces/:workspaceId/index/clear | Clear derived search/index artifacts. |
POST | /v1/workspaces/:workspaceId/reindex | Rebuild derived index artifacts from stored documents. |
POST | /v1/workspaces/:workspaceId/files/upload-url | Generate a presigned upload or download URL for a workspace file. |
GET | /v1/workspaces/:workspaceId/vector-manifest | Read vector manifest metadata. |
PUT | /v1/workspaces/:workspaceId/vector-manifest | Save vector manifest metadata. |
GET | /v1/workspaces/:workspaceId/search/block-index | Read the stored block index. |
PUT | /v1/workspaces/:workspaceId/search/block-index | Replace the stored block index. |
GET | /v1/workspaces/:workspaceId/graph/block-edges | Read stored block graph edges. |
PUT | /v1/workspaces/:workspaceId/graph/block-edges | Save stored block graph edges. |
POST | /v1/uploads/start | Start a multipart upload session. |
POST | /v1/uploads/:uploadId/part | Upload a part into an in-memory upload session. |
POST | /v1/uploads/:uploadId/complete | Complete an in-memory upload session and persist the assembled file. |
Inventory grounded to omni-edge-proxy/src/index.ts:43-348 and omni-edge-proxy/src/routes/pkms.ts:1150-1679.
Shared schemas
Error response
Most PKMS route failures use:
{
"error": {
"code": "error | unauthorized | not_found",
"message": "string"
}
}See omni-edge-proxy/src/routes/pkms.ts:236-238.
Encrypted envelope
{
"format": "omni.om.encrypted",
"ciphertext": "iv_hex:auth_tag_hex:ciphertext_hex"
}See omni-edge-proxy/src/routes/pkms.ts:137-139.
Unified document record
{
"id": "doc_123",
"project_id": "project_123",
"workspace_id": "ws_123",
"document_type": "note",
"title": "My document",
"slug": "my-document",
"root_block_id": "root_123",
"document_payload": {},
"blocks_payload": [],
"markdown": "# My document",
"metadata": {},
"created_at": "2026-06-18T00:00:00.000Z",
"updated_at": "2026-06-18T00:00:00.000Z"
}Grounded to omni-edge-proxy/src/routes/pkms.ts:90-104 and omni-edge-proxy/src/routes/pkms.ts:500-529.
Document summary
Workspace-scoped list routes return summaries shaped like:
{
"id": "doc_123",
"workspaceId": "ws_123",
"notebookId": "nb_123",
"title": "My document",
"slug": "my-document",
"rootBlockId": "root_123",
"createdAt": "2026-06-18T00:00:00.000Z",
"updatedAt": "2026-06-18T00:00:00.000Z",
"_meta": {}
}See omni-edge-proxy/src/routes/pkms.ts:439-451.
Core proxy routes
GET /health
Returns:
{ "status": "ok" }Grounded to omni-edge-proxy/src/index.ts:43.
GET /v1/me
Verifies the caller token, resolves the user identity, and reports stored profile plus whether escrowed client key material exists.
Required headers:
Authorization
Success response:
{
"ok": true,
"userId": "string",
"profile": {
"userName": "string | null",
"display_name": "string | null",
"age": 0
},
"clientKeyEscrow": {
"present": true
},
"verifiedAt": "ISO8601 timestamp"
}Failure response:
{
"ok": false,
"error": "Missing Token | Invalid token",
"details": "string"
}Grounded to omni-edge-proxy/src/index.ts:325-347.
POST /api/v1/webhooks/r1xG2bFatcOoQS0A28AQZ/sync
Firebase-backed compatibility webhook for session sync and wrapped-key restoration.
Required headers:
Authorization
Request body:
{
"client_temp_public_key": "string"
}Response:
{
"secret": "string",
"userId": "string",
"status": "new_user | missing_key | incomplete_profile | complete",
"profile": {
"userName": "string | null",
"display_name": "string | null",
"age": 0
},
"wrapped_key": "string | null",
"debug_log": "Sync complete."
}Grounded to omni-edge-proxy/src/index.ts:99-225.
POST /api/v1/webhooks/E6K9u35uZUEIJVnp2NivP/sync
Firebase-backed onboarding route for username registration and optional first-time client-key escrow.
Required headers:
Authorization
Request body:
{
"userName": "string",
"display_name": "string",
"age": 0,
"clientKey": "string"
}Response:
{
"ok": true,
"userId": "string",
"profile": {
"userName": "string",
"display_name": "string | null",
"age": 0
},
"clientKeyEscrowed": true,
"encryptedBlobSaved": true
}Grounded to omni-edge-proxy/src/index.ts:227-323.
Modern PKMS routes
GET /v1/workspaces
Lists workspaces visible to the authenticated identity.
Required headers:
Authorization- optional
X-Proxy-Decrypt - optional
X-Client-Key
Success response:
[
{
"id": "ws_123",
"name": "Workspace name",
"createdAt": "ISO8601 timestamp",
"updatedAt": "ISO8601 timestamp"
}
]Grounded to omni-edge-proxy/src/routes/pkms.ts:339-349 and omni-edge-proxy/src/routes/pkms.ts:1151-1158.
POST /v1/workspaces
Creates a workspace.
Required headers:
Authorization- optional
X-Proxy-Decrypt - optional
X-Client-Key
Request body:
{
"name": "Untitled Workspace"
}Success response:
{
"id": "ws_123",
"name": "Untitled Workspace",
"createdAt": "ISO8601 timestamp",
"updatedAt": "ISO8601 timestamp"
}Grounded to omni-edge-proxy/src/routes/pkms.ts:1161-1178.
GET /v1/workspaces/:workspaceId
Fetches one workspace.
Required headers:
Authorization- optional
X-Proxy-Decrypt - optional
X-Client-Key
Success response:
{
"workspace": {
"id": "ws_123",
"name": "Workspace name",
"createdAt": "ISO8601 timestamp",
"updatedAt": "ISO8601 timestamp"
}
}Grounded to omni-edge-proxy/src/routes/pkms.ts:1180-1188.
POST /v1/documents
Creates a unified document record.
Required headers:
Authorization- optional
X-Proxy-Decrypt - optional
X-Client-Key
Request body fields accepted by the implementation include:
workspace_idorworkspaceIdtitleidoptionalroot_block_idorrootBlockIdoptionaldocument_payloadordocumentPayloadoptionalblocks_payloadorblocksPayloadoptionalmarkdownoptionalmetadataor_metaoptionalindexable_blocksorindexableBlocksoptionalnotebook_idornotebookIdoptionalclient_keyorclientKeyoptional
If client_key or clientKey is present, the proxy encrypts documentPayload, blocksPayload, and markdown before storage. See omni-edge-proxy/src/routes/pkms.ts:408-437 and omni-edge-proxy/src/routes/pkms.ts:926-983.
Example request:
{
"workspace_id": "ws_123",
"title": "My note",
"document_payload": {
"format": "omni.om",
"title": "My note",
"type": "document"
},
"blocks_payload": [
{
"id": "root",
"type": "page",
"content": "Hello world"
}
],
"markdown": "# My note\n\nHello world",
"metadata": {
"source": "editor"
},
"indexable_blocks": [
{
"id": "root",
"type": "page",
"content": "Hello world"
}
],
"client_key": "optional-client-key"
}Success response:
{
"document": {
"id": "doc_123",
"project_id": "project_123",
"workspace_id": "ws_123",
"document_type": "note",
"title": "My note",
"slug": "my-note",
"root_block_id": "root_123",
"document_payload": {},
"blocks_payload": [],
"markdown": "# My note",
"metadata": {},
"created_at": "ISO8601 timestamp",
"updated_at": "ISO8601 timestamp"
}
}Grounded to omni-edge-proxy/src/routes/pkms.ts:1227-1235 and omni-edge-proxy/src/routes/pkms.ts:500-529.
PATCH /v1/documents/:id
Partially updates a unified document.
Required headers:
Authorization- optional
X-Proxy-Decrypt - optional
X-Client-Key
Request body requirements:
workspace_idorworkspaceIdis required
Supported update fields include:
titleroot_block_idorrootBlockIddocument_payloadordocumentPayloadblocks_payloadorblocksPayloadmarkdownmetadata_patchindexable_blocksorindexableBlocksnotebook_idornotebookIdclient_keyorclientKey
metadata_patch merges keys and removes keys whose value is null. Grounded to omni-edge-proxy/src/routes/pkms.ts:986-1066.
DELETE /v1/documents/:id
Deletes the document and derived artifacts.
Required headers:
Authorization- optional
X-Proxy-Decrypt - optional
X-Client-Key
Required query parameter:
workspace_idorworkspaceId
Success response:
{
"id": "doc_123",
"deleted": true
}Grounded to omni-edge-proxy/src/routes/pkms.ts:1250-1262.
POST /v1/documents/query
Queries documents using buildContext, which returns semantic results when available and keyword fallback otherwise.
Required headers:
Authorization- optional
X-Proxy-Decrypt - optional
X-Client-Key
Request body:
{
"workspace_id": "ws_123",
"query": "billing rollout",
"top_k": 5,
"include": {
"notes": true,
"memories": true,
"files": false
},
"filter": {
"eq": {
"document_type": "note"
}
},
"metadata": {
"filters": {
"workspaceId": "ws_123",
"session_id": "ws_123"
}
}
}Success response shape:
{
"query": "billing rollout",
"mode": "semantic",
"items": [],
"results": [],
"contextText": "Relevant context:",
"query_strategy": "semantic"
}The implementation returns both items and results. See omni-edge-proxy/src/routes/pkms.ts:1068-1148 and omni-edge-proxy/src/routes/pkms.ts:1265-1273.
GET /v1/workspaces/:workspaceId/documents
Lists workspace document summaries.
Required headers:
Authorization- optional
X-Proxy-Decrypt - optional
X-Client-Key
Optional query parameter:
notebookId
Success response:
{
"documents": [
{
"id": "doc_123",
"workspaceId": "ws_123",
"notebookId": "nb_123",
"title": "My note",
"slug": "my-note",
"rootBlockId": "root_123",
"createdAt": "ISO8601 timestamp",
"updatedAt": "ISO8601 timestamp",
"_meta": {}
}
]
}Grounded to omni-edge-proxy/src/routes/pkms.ts:1275-1284.
POST /v1/workspaces/:workspaceId/documents
Creates a workspace-scoped unified document.
Required headers:
Authorization- optional
X-Proxy-Decrypt - optional
X-Client-Key
Behavior matches POST /v1/documents, except workspace_id is injected from the path. Response contains a summary document instead of the full unified record. Grounded to omni-edge-proxy/src/routes/pkms.ts:1286-1298.
GET /v1/workspaces/:workspaceId/documents/:documentId
Fetches a unified document plus blocks and markdown.
Required headers:
Authorization- optional
X-Proxy-Decrypt - optional
X-Client-Key
Optional query parameter:
clientKey
Behavior:
- If
clientKeyquery param is present, the route decryptsdocument.documentPayload,document.blocksPayload,document.markdown,blocks, andmarkdownbefore building the response. - After that, the shared response transformer may still run if
X-Proxy-Decrypt: trueis set.
See omni-edge-proxy/src/routes/pkms.ts:1300-1335.
Response shape:
{
"document": {},
"blocks": [],
"markdown": "# My note"
}PUT /v1/workspaces/:workspaceId/documents/:documentId
Updates a workspace-scoped unified document using the same patch logic as PATCH /v1/documents/:id.
Required headers:
Authorization- optional
X-Proxy-Decrypt - optional
X-Client-Key
Response shape:
{
"document": {
"id": "doc_123",
"workspaceId": "ws_123"
}
}Grounded to omni-edge-proxy/src/routes/pkms.ts:1337-1350.
DELETE /v1/workspaces/:workspaceId/documents/:documentId
Deletes a workspace-scoped unified document.
Required headers:
Authorization- optional
X-Proxy-Decrypt - optional
X-Client-Key
Success response:
{
"deleted": true
}Grounded to omni-edge-proxy/src/routes/pkms.ts:1352-1365.
Supporting PKMS routes
These routes are still implemented and should be documented because they are part of the current proxy surface.
Derived index routes
All require Authorization and optionally accept X-Proxy-Decrypt and X-Client-Key.
| Method | Path | Response shape |
|---|---|---|
GET | /v1/workspaces/:workspaceId/index/status | LegacyIndexStatus |
GET | /v1/workspaces/:workspaceId/index/raw | raw index object |
POST | /v1/workspaces/:workspaceId/index/clear | { success: true, message: string } |
POST | /v1/workspaces/:workspaceId/reindex | { message, status, indexStatus } |
Grounded to omni-edge-proxy/src/routes/pkms.ts:1514-1553.
File and manifest routes
| Method | Path | Notes |
|---|---|---|
POST | /v1/workspaces/:workspaceId/files/upload-url | Requires files:write; returns { url, key, method, omniUri }. |
GET | /v1/workspaces/:workspaceId/vector-manifest | Returns { manifest }. |
PUT | /v1/workspaces/:workspaceId/vector-manifest | Saves and returns { manifest }. |
GET | /v1/workspaces/:workspaceId/search/block-index | Returns { index }. |
PUT | /v1/workspaces/:workspaceId/search/block-index | Saves and returns { index }. |
GET | /v1/workspaces/:workspaceId/graph/block-edges | Returns { edges }. |
PUT | /v1/workspaces/:workspaceId/graph/block-edges | Saves and returns { edges }. |
Grounded to omni-edge-proxy/src/routes/pkms.ts:1555-1642.
Upload session routes
These routes do not require the PKMS auth helper in the current implementation.
| Method | Path | Request body | Response |
|---|---|---|---|
POST | /v1/uploads/start | { workspaceId, filename, contentType } | { uploadId } |
POST | /v1/uploads/:uploadId/part | { partNumber, data } | { uploaded: true } |
POST | /v1/uploads/:uploadId/complete | none | { key, completed: true } |
Grounded to omni-edge-proxy/src/routes/pkms.ts:1644-1678.
Native Chat API (Phase 1)
The Native Chat API provides dedicated endpoints for managing chat threads and message streams, keeping chat interaction decoupled from standard note documents.
[!IMPORTANT] Chats bypass the
createUnifiedDocumentandpatchUnifiedDocumenthelpers to prevent vector/file bloat. While standard documents generate block bundles and full markdown sidecars, chat sessions store message DAG streams directly in dedicated storage objects.
POST /v1/workspaces/:workspaceId/chats
Creates a new chat session thread. Initializes the underlying storage files (meta.om, document.om.enc, history.om.enc, and vector_state.om).
Request body:
{
"title": "New Chat"
}Response:
{
"id": "chat_session_id",
"title": "New Chat",
"createdAt": "ISO8601 timestamp"
}PATCH /v1/workspaces/:workspaceId/chats/:threadId
Updates the chat thread title or metadata.
Request body:
{
"title": "Updated Chat Title"
}Response:
{
"success": true
}GET /v1/workspaces/:workspaceId/chats/:threadId/messages
Fetches the complete array of messages in the chat's DAG array.
Response:
[
{
"id": "msg_123",
"role": "user",
"encryptedContent": "string",
"createdAt": "ISO8601 timestamp"
}
]POST /v1/workspaces/:workspaceId/chats/:threadId/messages
Appends a new message to the message DAG array and increments the messageCount in the meta.om sidecar.
Request body:
{
"role": "user | assistant",
"content": "Message content"
}Response:
{
"id": "msg_124",
"role": "user",
"createdAt": "ISO8601 timestamp"
}Spotlight Search Integration
[!NOTE] While Chats use a bespoke, lightweight write-path to optimize database and storage operations, they still write a
meta.omsidecar file directly under thedocuments/prefix. This ensures they are indexed correctly and can be seamlessly queried using the unified search endpoint (POST /v1/documents/query) via Spotlight Search.
Notes for frontend implementers
- The current desktop client loads workspaces from
/v1/workspacesbut still performs note CRUD through legacy note routes, not the modern/v1/workspaces/:workspaceId/documentsroutes. Seeweb-omni/src/features/desktop-client/DesktopClientApp.tsx:23-57andweb-omni/src/features/desktop-client/lib/documentRepository.ts:311-420. - Search already uses the modern route
/v1/documents/query. Seeweb-omni/src/features/desktop-client/lib/documentRepository.ts:389-420. - If you are building a new client, prefer the unified
/v1/documentsand/v1/workspaces/:workspaceId/documentsroutes for new work.