Skip to main content

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

RoleCan manage membersCan edit docsCan 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

FieldRequiredDefaultDescription
titleNo"Untitled"Document title
iconNonullEmoji or icon string
cover_urlNonullCover image URL
workspace_idNonullPlace inside a workspace (user must be a member)
visibilityNo"private"private | workspace | public
doc_astNo{"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"