Documentation Index
Fetch the complete documentation index at: https://docs.ivory.finance/llms.txt
Use this file to discover all available pages before exploring further.
Authentication
All editor endpoints require two headers — the Kong API gateway key and your Ivory JWT:
X-API-Key: <your-api-key>
Authorization: Bearer <jwt>
Obtain a JWT with POST /v1/auth/login before calling any editor endpoint.
Workspaces
Workspaces are optional containers that group documents and let you share access with a team in one step. A document placed in a workspace with visibility: 'workspace' is automatically visible to all workspace members.
Workspace roles
| Role | Can manage members | Can edit docs | Can read docs |
|---|
admin | ✓ | ✓ | ✓ |
editor | ✗ | ✓ | ✓ |
viewer | ✗ | ✗ | ✓ |
Only the workspace creator can delete the workspace.
List workspaces
Returns all workspaces where the user is creator or member, ordered by updated_at descending.
curl https://api.ivory.finance/v1/editor/workspaces \
-H "X-API-Key: $IVORY_API_KEY" \
-H "Authorization: Bearer $IVORY_JWT"
[
{
"id": "ws_01JK3MNP...",
"tenant_id": "user_abc123",
"name": "Research Team",
"description": "Shared equity research workspace",
"icon": "🏢",
"created_by": "user_abc123",
"created_at": "2026-01-15T10:00:00Z",
"updated_at": "2026-03-10T14:22:00Z",
"my_role": "admin"
}
]
Create workspace
curl -X POST https://api.ivory.finance/v1/editor/workspaces \
-H "X-API-Key: $IVORY_API_KEY" \
-H "Authorization: Bearer $IVORY_JWT" \
-H "Content-Type: application/json" \
-d '{
"name": "Q2 2026 Research",
"description": "Earnings season analysis workspace",
"icon": "📊"
}'
Returns 201 with the created workspace object. The creator is implicitly admin.
Get workspace
Returns workspace details plus the full member list.
curl https://api.ivory.finance/v1/editor/workspaces/ws_01JK3MNP \
-H "X-API-Key: $IVORY_API_KEY" \
-H "Authorization: Bearer $IVORY_JWT"
{
"id": "ws_01JK3MNP...",
"name": "Research Team",
"members": [
{ "user_id": "user_abc123", "role": "admin", "invited_by": null, "created_at": "2026-01-15T10:00:00Z" },
{ "user_id": "user_def456", "role": "editor", "invited_by": "user_abc123", "created_at": "2026-02-01T09:00:00Z" }
]
}
Update workspace
Requires admin role. Send only the fields you want to change.
curl -X PATCH https://api.ivory.finance/v1/editor/workspaces/ws_01JK3MNP \
-H "X-API-Key: $IVORY_API_KEY" \
-H "Authorization: Bearer $IVORY_JWT" \
-H "Content-Type: application/json" \
-d '{ "name": "Q2 2026 Research — Final", "icon": "✅" }'
Delete workspace
Returns 204. Only the workspace creator can delete. Cascades to all workspace documents.
curl -X DELETE https://api.ivory.finance/v1/editor/workspaces/ws_01JK3MNP \
-H "X-API-Key: $IVORY_API_KEY" \
-H "Authorization: Bearer $IVORY_JWT"
Add / update member
role must be one of admin, editor, viewer. Upserts — if the user is already a member their role is updated.
curl -X POST https://api.ivory.finance/v1/editor/workspaces/ws_01JK3MNP/members \
-H "X-API-Key: $IVORY_API_KEY" \
-H "Authorization: Bearer $IVORY_JWT" \
-H "Content-Type: application/json" \
-d '{ "user_id": "user_xyz789", "role": "editor" }'
Remove member
Returns 204. Requires admin role.
curl -X DELETE \
"https://api.ivory.finance/v1/editor/workspaces/ws_01JK3MNP/members/user_xyz789" \
-H "X-API-Key: $IVORY_API_KEY" \
-H "Authorization: Bearer $IVORY_JWT"
Documents
List documents
Returns all documents visible to the current user (owner, explicit member, workspace member, or public). Use the optional workspace_id query param to filter to a specific workspace.
# All accessible documents
curl "https://api.ivory.finance/v1/editor/documents" \
-H "X-API-Key: $IVORY_API_KEY" \
-H "Authorization: Bearer $IVORY_JWT"
# Filter by workspace
curl "https://api.ivory.finance/v1/editor/documents?workspace_id=ws_01JK3MNP" \
-H "X-API-Key: $IVORY_API_KEY" \
-H "Authorization: Bearer $IVORY_JWT"
doc_ast is not returned in the list — use GET /v1/editor/documents/{doc_id} to fetch the full content.
[
{
"id": "doc_01JK4...",
"tenant_id": "user_abc123",
"workspace_id": "ws_01JK3MNP...",
"title": "Apple FY2025 Deep Dive",
"icon": "🍎",
"visibility": "workspace",
"word_count": 1842,
"created_by": "user_abc123",
"updated_by_type": "user",
"updated_by_id": "user_abc123",
"created_at": "2026-02-10T09:00:00Z",
"updated_at": "2026-03-15T16:45:00Z",
"my_role": "owner"
}
]
Create document
| Field | Required | Default | Description |
|---|
title | No | "Untitled" | Document title |
icon | No | null | Emoji or icon string |
cover_url | No | null | Cover image URL |
workspace_id | No | null | Place inside a workspace (user must be a member) |
visibility | No | "private" | private | workspace | public |
doc_ast | No | {"type":"doc","content":[]} | Initial content as Tiptap JSON |
curl -X POST https://api.ivory.finance/v1/editor/documents \
-H "X-API-Key: $IVORY_API_KEY" \
-H "Authorization: Bearer $IVORY_JWT" \
-H "Content-Type: application/json" \
-d '{
"title": "NVDA Q4 2025 Analysis",
"icon": "💡",
"workspace_id": "ws_01JK3MNP...",
"visibility": "private",
"doc_ast": {
"type": "doc",
"content": [
{
"type": "heading",
"attrs": { "level": 1 },
"content": [{ "type": "text", "text": "NVDA Q4 2025" }]
}
]
}
}'
Returns 201 with the full document object including id (UUID). The document is immediately indexed in OpenSearch asynchronously.
Get document
Returns the full document including doc_ast. The my_role field reflects the caller’s effective access level.
Public documents return my_role: "viewer" for unauthenticated users. Always check my_role before allowing edits in your UI.
curl "https://api.ivory.finance/v1/editor/documents/doc_01JK4..." \
-H "X-API-Key: $IVORY_API_KEY" \
-H "Authorization: Bearer $IVORY_JWT"
{
"id": "doc_01JK4...",
"title": "NVDA Q4 2025 Analysis",
"visibility": "workspace",
"doc_ast": {
"type": "doc",
"content": [
{
"type": "heading",
"attrs": { "level": 1 },
"content": [{ "type": "text", "text": "NVDA Q4 2025" }]
}
]
},
"word_count": 412,
"updated_by_type": "agent",
"updated_by_id": "orchestrator",
"my_role": "owner"
}
Update document
Requires at least editor role. Send only the fields you want to change.
When visibility changes, the OpenSearch index is updated automatically:
private / workspace → removed from the public index
public → added to the public index so anyone can find it via semantic search
Agent writes — pass updated_by_type: "agent" and updated_by_id: "<agent-name>" to tag the change for the audit trail.
# Update title and visibility
curl -X PATCH "https://api.ivory.finance/v1/editor/documents/doc_01JK4..." \
-H "X-API-Key: $IVORY_API_KEY" \
-H "Authorization: Bearer $IVORY_JWT" \
-H "Content-Type: application/json" \
-d '{
"title": "NVDA Q4 2025 — Final",
"visibility": "workspace"
}'
# Write doc_ast (agent update)
curl -X PATCH "https://api.ivory.finance/v1/editor/documents/doc_01JK4..." \
-H "X-API-Key: $IVORY_API_KEY" \
-H "Authorization: Bearer $IVORY_JWT" \
-H "Content-Type: application/json" \
-d '{
"doc_ast": { "type": "doc", "content": [...] },
"updated_by_type": "agent",
"updated_by_id": "orchestrator"
}'
Delete document (soft)
Returns 204. Requires owner role. Sets is_deleted=true — hidden from all list/get endpoints but not physically removed.
curl -X DELETE "https://api.ivory.finance/v1/editor/documents/doc_01JK4..." \
-H "X-API-Key: $IVORY_API_KEY" \
-H "Authorization: Bearer $IVORY_JWT"
Document sharing
Share a document directly with individual users without adding them to a workspace. Requires owner role.
Add / update member
role must be owner, editor, commenter, or viewer.
curl -X POST "https://api.ivory.finance/v1/editor/documents/doc_01JK4.../members" \
-H "X-API-Key: $IVORY_API_KEY" \
-H "Authorization: Bearer $IVORY_JWT" \
-H "Content-Type: application/json" \
-d '{ "user_id": "user_xyz789", "role": "editor" }'
Remove member
Returns 204.
curl -X DELETE \
"https://api.ivory.finance/v1/editor/documents/doc_01JK4.../members/user_xyz789" \
-H "X-API-Key: $IVORY_API_KEY" \
-H "Authorization: Bearer $IVORY_JWT"
Version snapshots
Versions are point-in-time snapshots of doc_ast. Use them to implement “save a named version” and “restore version” in your UI.
List versions
curl "https://api.ivory.finance/v1/editor/documents/doc_01JK4.../versions" \
-H "X-API-Key: $IVORY_API_KEY" \
-H "Authorization: Bearer $IVORY_JWT"
[
{ "id": "ver_...", "version_num": 3, "label": "Final draft", "created_by_type": "user", "created_by_id": "user_abc123", "created_at": "2026-03-20T11:00:00Z" },
{ "id": "ver_...", "version_num": 2, "label": null, "created_by_type": "agent", "created_by_id": "orchestrator", "created_at": "2026-03-19T09:30:00Z" },
{ "id": "ver_...", "version_num": 1, "label": "Initial", "created_by_type": "user", "created_by_id": "user_abc123", "created_at": "2026-03-18T08:00:00Z" }
]
Create snapshot
Requires editor role. If doc_ast is omitted, the current document content is snapshotted automatically.
curl -X POST "https://api.ivory.finance/v1/editor/documents/doc_01JK4.../versions" \
-H "X-API-Key: $IVORY_API_KEY" \
-H "Authorization: Bearer $IVORY_JWT" \
-H "Content-Type: application/json" \
-d '{ "label": "Before AI rewrite" }'
Returns 201 with the new version including version_num (auto-incrementing integer).
Get snapshot
Returns the full snapshot including doc_ast. To restore: load the snapshot’s doc_ast and call PATCH /v1/editor/documents/{doc_id} with it.
curl "https://api.ivory.finance/v1/editor/documents/doc_01JK4.../versions/3" \
-H "X-API-Key: $IVORY_API_KEY" \
-H "Authorization: Bearer $IVORY_JWT"