hubKnowledge Base
Knowledge Base/API Documentation
v1.0 — phase 1· 120 endpoints · 21 resource groups · 7 roles · 4 permission levels

REST API Reference

Resource-oriented URLs. JSON-encoded responses. ABAC permissions on every grant. Hash-chained audit log. All endpoints are prefixed with /api/v1.

API Conventions

Base path/api/v1/
AuthenticationAuthorization: Bearer <JWT> on every non-PUBLIC endpoint (ZITADEL or Keycloak)
Dev bypassWith DEV_BYPASS_AUTH=true: Bearer dev-bypass (admin) or Bearer lt_<N> (user N)
Content typeapplication/json for bodies; multipart/form-data for file uploads
Paginationpage (1-based) + size query params → { items, total, page, page_size, pages }
Error format{ "detail": "<message>", "error_code": "<CODE>" } with appropriate HTTP status
Soft deletesDELETE performs soft-delete; rows remain in DB with deleted=true
TimestampsISO 8601 UTC on every datetime field
IDsAll resource IDs are 64-bit integers
API explorerSwagger UI: /api/docs · ReDoc: /api/redoc · OpenAPI JSON: /api/openapi.json

Authentication Header

# Every non-PUBLIC endpoint requires this header Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9... # Obtained via the OIDC PKCE flow (ZITADEL or Keycloak) # Service accounts: exchange the IdP JSON key for a JWT

Pagination Envelope

{ "items": [...], "total": 142, "page": 1, "page_size": 20, "pages": 8 }

Endpoint Reference

favorite

Health

2 endpoints
MethodPath
GET/api/v1/health
GET/api/v1/health/ready
lock_open

Authentication & Profile

9 endpoints
MethodPath
POST/api/v1/auth/callback
POST/api/v1/auth/logout
GET/api/v1/auth/me
PUT/api/v1/auth/me
GET/api/v1/auth/me/notifications/preferences
PUT/api/v1/auth/me/notifications/preferences
POST/api/v1/auth/me/2fa/enable
POST/api/v1/auth/me/2fa/verify
DELETE/api/v1/auth/me/2fa
group

Users

4 endpoints
MethodPath
GET/api/v1/users
GET/api/v1/users/{user_id}
PUT/api/v1/users/{user_id}/role
DELETE/api/v1/users/{user_id}
domain

Organizations

6 endpoints
MethodPath
GET/api/v1/organizations/me
PUT/api/v1/organizations/me
GET/api/v1/organizations/me/stats
GET/api/v1/organizations
GET/api/v1/organizations/me/idp-role-mapping
PUT/api/v1/organizations/me/idp-role-mapping
corporate_fare

Departments

5 endpoints
MethodPath
GET/api/v1/departments
GET/api/v1/departments/{dept_id}
POST/api/v1/departments
PUT/api/v1/departments/{dept_id}
DELETE/api/v1/departments/{dept_id}
description

Documents

22 endpoints
MethodPath
GET/api/v1/documents
POST/api/v1/documents
POST/api/v1/documents/batch
GET/api/v1/documents/batch/{batch_id}
GET/api/v1/documents/starred
GET/api/v1/documents/{document_id}
PUT/api/v1/documents/{document_id}
DELETE/api/v1/documents/{document_id}
PATCH/api/v1/documents/{document_id}/status
POST/api/v1/documents/{document_id}/upload
GET/api/v1/documents/{document_id}/download
POST/api/v1/documents/{document_id}/lock
POST/api/v1/documents/{document_id}/unlock
POST/api/v1/documents/{document_id}/star
DELETE/api/v1/documents/{document_id}/star
GET/api/v1/documents/{document_id}/retention
PUT/api/v1/documents/{document_id}/retention
DELETE/api/v1/documents/{document_id}/retention
POST/api/v1/documents/{document_id}/normalize
GET/api/v1/documents/{document_id}/thumbnail
GET/api/v1/documents/{document_id}/ai-suggestions
POST/api/v1/documents/{document_id}/apply-ai-suggestions
folder

Folders

8 endpoints
MethodPath
GET/api/v1/folders
POST/api/v1/folders
GET/api/v1/folders/{folder_id}
PUT/api/v1/folders/{folder_id}
DELETE/api/v1/folders/{folder_id}
GET/api/v1/folders/{folder_id}/children
POST/api/v1/folders/{folder_id}/move
GET/api/v1/folders/{folder_id}/path
admin_panel_settings

Permissions

8 endpoints
MethodPath
GET/api/v1/permissions/document/{document_id}
GET/api/v1/permissions/folder/{folder_id}
POST/api/v1/permissions/document
POST/api/v1/permissions/folder
PUT/api/v1/permissions/{permission_id}
DELETE/api/v1/permissions/{permission_id}
GET/api/v1/permissions/my/document/{document_id}
GET/api/v1/permissions/my/folder/{folder_id}
account_tree

Workflows

5 endpoints
MethodPath
POST/api/v1/workflows
GET/api/v1/workflows/{workflow_id}
POST/api/v1/workflows/{workflow_id}/steps/{step_id}/approve
POST/api/v1/workflows/{workflow_id}/steps/{step_id}/reject
DELETE/api/v1/workflows/{workflow_id}
chat_bubble

Comments

5 endpoints
MethodPath
GET/api/v1/comments/document/{document_id}
POST/api/v1/comments/document/{document_id}
PUT/api/v1/comments/{comment_id}
DELETE/api/v1/comments/{comment_id}
POST/api/v1/comments/{comment_id}/resolve
label

Tags

9 endpoints
MethodPath
GET/api/v1/tags
POST/api/v1/tags
GET/api/v1/tags/{tag_id}
PUT/api/v1/tags/{tag_id}
DELETE/api/v1/tags/{tag_id}
GET/api/v1/tags/autocomplete
GET/api/v1/documents/{document_id}/tags
POST/api/v1/documents/{document_id}/tags
DELETE/api/v1/documents/{document_id}/tags
psychology

Chat & AI

4 endpoints
MethodPath
POST/api/v1/chat/document/{document_id}
GET/api/v1/chat/sessions
GET/api/v1/ai/documents/{document_id}
POST/api/v1/ai/reindex/{document_id}
mail

Invitations

3 endpoints
MethodPath
POST/api/v1/users/invite
GET/api/v1/invitations/{token}
POST/api/v1/invitations/{token}/use
notifications

Notifications

3 endpoints
MethodPath
GET/api/v1/notifications/unread-count
GET/api/v1/notifications
POST/api/v1/notifications/{notification_id}/read
schema

Document Types & Schemas

10 endpoints
MethodPath
GET/api/v1/document-types
POST/api/v1/document-types
GET/api/v1/document-types/{code}
PUT/api/v1/document-types/{code}
DELETE/api/v1/document-types/{code}
GET/api/v1/document-types/{code}/schemas
POST/api/v1/document-types/{code}/schemas
GET/api/v1/document-types/{code}/policies
POST/api/v1/document-types/{code}/policies
DELETE/api/v1/document-types/{code}/policies/{policy_id}
inventory

Audit Logs

2 endpoints
MethodPath
GET/api/v1/audit-logs/timeline
GET/api/v1/audit-logs/verify
cloud_download

Audit Exports

2 endpoints
MethodPath
POST/api/v1/audit-exports
GET/api/v1/audit-exports/{export_id}
swap_horiz

WebSockets

2 endpoints
MethodPath
WS/api/v1/ws/collaborate/{document_id}?token=<jwt>
WS/api/v1/ws/notifications?token=<jwt>

Role Hierarchy

Roles are ordered. Higher roles inherit every capability of lower roles. The numeric `level` is what the auth dependency compares against on every request.

RoleLevelScope
SUPER_ADMIN100Cross-organization administration, audit verification
ADMIN80Full org management, role changes, legal holds, audit exports
MANAGER60Department management, invite users, create workflows
EDITOR40Create and edit documents, grant up to WRITE permission
USER30Standard document access per explicit permission grants
VIEWER20Read-only access to documents granted to them
GUEST10Minimal / public-only access

Permission Levels

Document and folder access is controlled by explicit grants, evaluated after role checks. Four levels — capabilities accumulate going down.

Levelviewcommenteditsharemanage
READ
COMMENT
WRITE
ADMIN

Permission Resolution Waterfall

  1. Document exists? — 404 if not.
  2. Owner shortcut — always allowed (bypasses ABAC conditions).
  3. Public document — READ allowed.
  4. Direct document permission grant.
  5. Folder permission grant (when no direct grant).
  6. Department permission grant (when the user has a department).
  7. Expiry check — denied if `expires_at` is in the past.
  8. ABAC conditions — `ip_range`, `time_window`, `require_mfa`.

Cache key: vyxlo:permissions:{user_id}:read:{doc_id} with a 5-minute TTL. Always invalidated on grant/revoke; bypassed when an ABAC RequestContext is in play.

Data Models

Document Object

{ "id": 1042, "title": "Q4 Financial Report", "file_name": "q4-2025-financials.pdf", "file_size_bytes": 2048000, "mime_type": "application/pdf", "status": "APPROVED", // DRAFT|IN_REVIEW|APPROVED|PUBLISHED|ARCHIVED "document_type": "FINANCIAL", "sensitivity": "CONFIDENTIAL", "owner_id": 5, "organization_id": 2, "department_id": 8, "folder_id": 17, "current_version_number": 3, "view_count": 24, "download_count": 6, "comment_count": 4, "page_count": 18, "word_count": 4200, "checksum": "a3f2b1...", // SHA-256 for tamper detection "retention_until": "2027-12-31T23:59:59Z", "is_locked": false, "locked_by_id": null, "is_starred": true, "tags": ["finance", "Q4", "board"], "ai_processed": true, "ai_classification": "FINANCIAL_REPORT", "ai_confidence": 0.97, "ai_summary": "Quarterly financial results showing 18% revenue growth...", "ai_keywords": ["revenue", "Q4", "board"], "ai_entities": { "people": [...], "organizations": [...], "dates": [...] }, "ai_suggested_sensitivity": "CONFIDENTIAL", "chunk_index_status": "INDEXED", // NOT_INDEXED|QUEUED|INDEXED|FAILED "chunk_indexed_at": "2026-01-15T10:32:00Z", "created_at": "2026-01-14T09:00:00Z", "updated_at": "2026-01-15T11:00:00Z" }

Permission Grant Object (with ABAC conditions)

{ "id": 301, "level": "WRITE", // NONE|READ|COMMENT|WRITE|ADMIN "resource_type": "document", // "document" or "folder" "resource_id": 1042, "target_user_id": 12, "target_department_id": null, // grant to dept = all members inherit "expires_at": "2026-06-30T23:59:59Z", // null = permanent "note": "Temporary write access for Q4 close", "conditions": { "ip_range": ["10.0.0.0/8", "192.168.1.0/24"], "time_window": { "start": "09:00", "end": "18:00", "tz": "Asia/Dubai", "days": ["Mon","Tue","Wed","Thu","Fri"] }, "require_mfa": true }, "created_at": "2026-01-10T08:00:00Z" }

All ABAC conditions are AND-ed. conditions: null means unrestricted. Document owners always bypass ABAC conditions.

Workflow Object

{ "id": 88, "document_id": 1042, "name": "Q1 Report Approval", "status": "IN_PROGRESS", // PENDING|IN_PROGRESS|APPROVED|REJECTED|CANCELLED "created_by_id": 5, "expires_at": "2026-12-31T00:00:00Z", "created_at": "2026-01-15T12:00:00Z", "steps": [ { "id": 201, "step_number": 1, "assignee_id": 9, "description": "Legal review", "status": "APPROVED", // WAITING|PENDING|APPROVED|REJECTED "comment": "Looks good.", "decided_at": "2026-01-16T09:30:00Z" }, { "id": 202, "step_number": 2, "assignee_id": 3, "description": "Finance sign-off", "status": "PENDING", "comment": null, "decided_at": null } ] }

Audit Log Entry (hash-chained)

{ "id": 415221, "actor_user_id": 12, "action": "DOCUMENT_DOWNLOADED", "resource_type": "document", "resource_id": 1042, "ip_address": "203.0.113.42", "user_agent": "Mozilla/5.0 ...", "request_id": "req_8a4f...", "metadata": { "version": 3, "duration_ms": 184 }, "previous_hash": "9e47b1c0...", "hash": "f12a4d77...", // SHA-256(prev_hash + canonical_payload) "created_at": "2026-04-21T14:32:11Z" }

Each row’s hash commits to the previous row’s previous_hash. GET /audit-logs/verify walks the chain and returns first_tampered_id if any row has been altered.

Share Link Object

{ "id": 55, "token": "sl_abc123xyz", "url": "https://app.vyxlo.com/share/sl_abc123xyz", "document_id": 1042, "permission_level": "READ", "created_by_id": 5, "expires_at": "2026-02-01T23:59:59Z", "is_password_protected": true, "allowed_emails": ["partner@acme.com", "auditor@ext.com"], "access_count": 3, "is_active": true, "created_at": "2026-01-15T14:00:00Z" }

Real-Time Protocols

WSWebSocket — Document Collaboration

Authenticated using the OIDC JWT (passed as a query param or `Authorization` header).

ws://host/api/v1/ws/collaborate/{document_id}?token=<jwt> // Client → server: { "type": "presence", "action": "join" } { "type": "cursor", "position": { "line": 5, "col": 10 } } // Server → client: { "type": "presence", "users": [{ "id": 42, "name": "Alice" }] } { "type": "comment", "comment_id": 5, "action": "created" } { "type": "status_change", "new_status": "IN_REVIEW" }

WSWebSocket — Notifications

Per-user notification stream. Each event carries a running `unread_count`, so the client never has to re-poll.

ws://host/api/v1/ws/notifications?token=<jwt> // Server → client: { "type": "notification", "id": 101, "title": "Document shared with you", "body": "Alice shared 'Q4 Report' with you", "unread_count": 3 }

SSEServer-Sent Events — Document Q&A

The chat endpoint streams the LLM response token by token (text/event-stream). Citations and the token count arrive on the final `done` event.

POST /api/v1/chat/document/{document_id} { "question": "What are the key findings?" } // SSE stream response: data: {"token": "The "} data: {"token": "key "} data: {"token": "findings..."} ... data: {"done": true, "session_id": 42, "citations": [...], "token_count": 87}

File Downloads — Presigned URLs

File bytes never flow through the VyXlo API server. The download endpoint returns a 15-minute presigned MinIO URL; the client fetches the file directly from object storage. This scales to very large files without API server memory pressure.

GET /api/v1/documents/1042/download Authorization: Bearer <access_token> // Response: { "url": "https://minio.example.com/bucket/q4-financials.pdf?X-Amz-Expires=900...", "expires_in": 900 } // Client fetches directly from MinIO — zero API server bandwidth

Error Reference

Every error follows the same shape: {"detail": "...", "error_code": "..."} with the appropriate HTTP status.

StatusClassWhen
400BadRequestExceptionMalformed request or business rule violation
401UnauthorizedExceptionMissing or invalid JWT
403ForbiddenExceptionAuthenticated but insufficient permission (or ABAC condition failed)
404ResourceNotFoundExceptionEntity not found, or belongs to a different organization
409ConflictExceptionState conflict (locked document, duplicate slug, active workflow exists)
410GoneExpired token or share link
422Validation ErrorPydantic schema validation failed (invalid enum, missing required field)
500Internal Server ErrorUnexpected server error — request_id is in server logs