Skip to main content

Overview

The Velt Python SDK exposes two independent backends:
BackendNamespaceUse case
Self-hostingsdk.selfHosting.*Store Velt data in your own MongoDB + AWS S3
REST APIsdk.api.*Call Velt’s REST APIs directly — no database required
Self-hosting backend (sdk.selfHosting.*) simplifies backend implementation by 90%. Instead of writing custom database queries and storage logic, you:
  1. Pass your DB and storage configs to the SDK
  2. Pass the raw request object directly to SDK methods
  3. Return the resulting response object straight to the client
REST API backend (sdk.api.*) provides parity with Velt’s REST APIs. 18 services, typed @dataclass request objects, and raw Velt API responses. No database or AWS configuration needed.

Installation

pip install velt-py

Requirements

  • Python 3.8+
  • Django 4.2.26+ (only if using the self-hosting backend)
  • MongoDB (Percona Server or MongoDB Atlas) for self-hosting
  • requests for REST API calls (installed automatically)
  • Optional velt-py[auth] extra (PyJWT>=2.8.0, cryptography>=42.0.0) — required only for the built-in JWT/JWKS verifier path of verifyToken. Install with pip install 'velt-py[auth]'. Core install (pip install velt-py), the custom-callback verify path, and all non-auth features need no new dependency.

Quick Start

Initialize the SDK

Self-hosting initialization (MongoDB + optional AWS):
from velt_py import VeltSDK

# Initialize with database and AWS config
config = {
    'database': {
        # Option 1: Connection string (recommended for MongoDB Atlas)
        'connection_string': 'mongodb+srv://user:pass@cluster.mongodb.net/velt-db',
        
        # Option 2: Individual components
        # 'host': 'localhost:27017',
        # 'username': 'your_username',
        # 'password': 'your_password',
        # 'auth_database': 'admin',
        # 'database_name': 'velt-db'
    },
    # Optional: AWS S3 config for attachments
    'aws': {
        'bucket_name': 'your-bucket',
        'region': 'us-east-1',
        'access_key_id': 'YOUR_ACCESS_KEY',
        'secret_access_key': 'YOUR_SECRET_KEY'
    },
    # Optional: Custom collection names
    'collections': {
        'comments': 'comment_annotations',
        'reactions': 'reaction_annotations',
        'attachments': 'attachments',
        'users': 'users'
    },
    # Required for token generation; also enables sdk.api.*
    'apiKey': 'YOUR_VELT_API_KEY',
    'authToken': 'YOUR_VELT_AUTH_TOKEN'
}

sdk = VeltSDK.initialize(config)

Configuration

Environment Variables

The SDK reads the following environment variables automatically. These can be used instead of (or in addition to) config dict keys.
VariableConfig key equivalentPurpose
VELT_API_KEYapiKeyVelt API key for authenticating REST API calls
VELT_AUTH_TOKENauthTokenVelt auth token for authenticating REST API calls
VELT_WORKSPACE_IDDefault workspace ID for workspace-scoped operations
VELT_WORKSPACE_AUTH_TOKENAuth token scoped to a specific workspace

Self-Hosting Configuration

Configure MongoDB connection for storing comments, reactions, and user data.
config = {
    'database': {
        # Option 1: Connection string (recommended for MongoDB Atlas)
        'connection_string': 'mongodb+srv://user:pass@cluster.mongodb.net/velt-db',
        
        # Option 2: Individual components (for local MongoDB or custom setup)
        # 'host': 'localhost:27017',
        # 'username': 'your_username',
        # 'password': 'your_password',
        # 'auth_database': 'admin',
        # 'database_name': 'velt-db'
    }
}

Self-Hosting Backend

The SDK provides methods that accept the raw request from the frontend and return the properly formatted response. All self-hosting service classes — the BaseService base class plus seven resolver services — are importable from velt_py.services.self_hosting. As of v0.1.12, RecorderService, NotificationService, and ActivityService are also exported — previously they were wired into SelfHostingBackend but missing from the package’s __all__.
from velt_py.services.self_hosting import (
    BaseService,
    CommentService,
    ReactionService,
    AttachmentService,
    RecorderService,      # newly exported in v0.1.12
    NotificationService,  # newly exported in v0.1.12
    ActivityService,      # newly exported in v0.1.12
    UserService,
)

Comments

getComments

from velt_py import GetCommentResolverRequest

def get_comments(request):
    data = request.json
    comment_request = GetCommentResolverRequest.from_dict(data)
    result = sdk.selfHosting.comments.getComments(comment_request)
    return result
Response
{
    'success': True,
    'statusCode': 200,
    'data': { 'comments': [ ... ] }
}

saveComments

from velt_py import SaveCommentResolverRequest

def save_comments(request):
    data = request.json
    save_request = SaveCommentResolverRequest.from_dict(data)
    result = sdk.selfHosting.comments.saveComments(save_request)
    return result
Response
{ 'success': True, 'statusCode': 200, 'data': { ... } }
As of v0.1.14, when used as a save-resolver handler the inbound event may be a ResolverActions OR a CommentResolverSaveEvent member (or a raw string for forward-compat), and the request may carry targetComment (request context only — never persisted). See the SaveCommentResolverRequest entry under Data Models for these additions.

deleteComment

from velt_py import DeleteCommentResolverRequest

def delete_comment(request):
    data = request.json
    delete_request = DeleteCommentResolverRequest.from_dict(data)
    result = sdk.selfHosting.comments.deleteComment(delete_request)
    return result
Response
{ 'success': True, 'statusCode': 200, 'data': { ... } }

Reactions

getReactions

from velt_py import GetReactionResolverRequest

def get_reactions(request):
    data = request.json
    reaction_request = GetReactionResolverRequest.from_dict(data)
    result = sdk.selfHosting.reactions.getReactions(reaction_request)
    return result
Response
{
    'success': True,
    'statusCode': 200,
    'data': { 'reactions': [ ... ] }
}

saveReactions

from velt_py import SaveReactionResolverRequest

def save_reactions(request):
    data = request.json
    save_request = SaveReactionResolverRequest.from_dict(data)
    result = sdk.selfHosting.reactions.saveReactions(save_request)
    return result
Response
{ 'success': True, 'statusCode': 200, 'data': { ... } }

deleteReaction

from velt_py import DeleteReactionResolverRequest

def delete_reaction(request):
    data = request.json
    delete_request = DeleteReactionResolverRequest.from_dict(data)
    result = sdk.selfHosting.reactions.deleteReaction(delete_request)
    return result
Response
{ 'success': True, 'statusCode': 200, 'data': { ... } }

Users

getUsers

from velt_py import GetUserResolverRequest

def get_users(request):
    data = request.json
    user_request = GetUserResolverRequest.from_dict(data)
    result = sdk.selfHosting.users.getUsers(user_request)
    return result
Response
{
    'success': True,
    'statusCode': 200,
    'data': { 'users': [ { 'userId': 'user-1', 'name': 'John Doe', ... } ] }
}

Attachments

saveAttachment

import json
from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt
from django.views.decorators.http import require_http_methods
from velt_py import SaveAttachmentResolverRequest, DeleteAttachmentResolverRequest
from .velt_sdk import get_velt_sdk

@csrf_exempt
@require_http_methods(["POST"])
def save_attachment(request):
    try:
        file = request.FILES.get('file')
        request_json_str = request.POST.get('request')
        
        if not file or not request_json_str:
            return JsonResponse({
                'success': False,
                'error': 'File and request JSON are required',
                'errorCode': 'INVALID_INPUT',
                'statusCode': 400
            }, status=400)
        
        request_data = json.loads(request_json_str)
        save_request = SaveAttachmentResolverRequest.from_dict(request_data)
        
        sdk = get_velt_sdk()
        result = sdk.selfHosting.attachments.saveAttachment(
            save_request,
            file_data=file.read(),
            file_name=file.name,
            mime_type=file.content_type
        )
        return JsonResponse(result, status=result.get('statusCode', 200))
    except Exception as e:
        return JsonResponse({
            'success': False,
            'error': str(e),
            'errorCode': 'INTERNAL_ERROR',
            'statusCode': 500
        }, status=500)
Response
{ 'success': True, 'statusCode': 200, 'data': { ... } }

deleteAttachment

import json
from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt
from django.views.decorators.http import require_http_methods
from velt_py import DeleteAttachmentResolverRequest
from .velt_sdk import get_velt_sdk

@csrf_exempt
@require_http_methods(["POST"])
def delete_attachment(request):
    try:
        data = json.loads(request.body)
        delete_request = DeleteAttachmentResolverRequest.from_dict(data)
        sdk = get_velt_sdk()
        result = sdk.selfHosting.attachments.deleteAttachment(delete_request)
        return JsonResponse(result, status=result.get('statusCode', 200))
    except Exception as e:
        return JsonResponse({
            'success': False,
            'error': str(e),
            'errorCode': 'INTERNAL_ERROR',
            'statusCode': 500
        }, status=500)
Response
{ 'success': True, 'statusCode': 200, 'data': { ... } }

Token

getToken

  • Generates a Velt auth token for a user. Self-hosting variant.
  • Params: positional — organizationId, userId, email (optional), isAdmin (optional)
  • Returns: VeltSelfHostingResponse
result = sdk.selfHosting.token.getToken(
    organizationId='org-123',
    userId='user-1',
    email='user@example.com',
    isAdmin=False
)
Response
{
    'success': True,
    'statusCode': 200,
    'data': { 'token': 'eyJhbGciOi...' }
}
Note: getToken takes positional / keyword arguments — it does NOT accept a dataclass request object. Signature: getToken(organizationId, userId, email=None, isAdmin=False).

Resolver Token Verification

sdk.selfHosting.verifyToken(headers=None, token=None, **overrides) -> VerifyTokenResult authenticates the credential the Velt frontend forwards to your resolver endpoints. New in v0.1.14. It is opt-in via the resolver_auth config block, framework-agnostic, and fail-closed — it returns a structured VerifyTokenResult and never raises for a verification outcome. It is authentication only: it never consults apiKey, organizationId, or the resolver database; resolver services keep their own scoping. result.claims is informational — assert tenant claims against the resolver payload’s organizationId yourself if you need tenant isolation. The built-in JWT/JWKS verifier requires the optional extra: pip install 'velt-py[auth]'. The custom-callback (verify) path needs no new dependency. Configure resolver_auth in the Resolver Auth config tab.
  • Params:
    • headers — Incoming request headers; the token is extracted from the configured header.
    • token — A raw JWT string, passed directly instead of headers.
    • **overrides — One-off jwt / verify / header / scheme that merge over the configured resolver_auth without changing global config.
  • Returns: VerifyTokenResult — see the Data Models entry for fields.
# In your resolver handler:
result = sdk.selfHosting.verifyToken(headers=request.headers)  # or token='<raw_jwt>'
if not result.verified:
    return HttpResponse(status=401)   # result.errorCode tells you why
# result.claims holds the decoded payload
sdk.selfHosting.comments.saveComments(SaveCommentResolverRequest.from_dict(data))
Error codes (result.errorCode)
CodeWhen
MISSING_TOKENNo token found in header / not passed, empty, or wrong scheme.
EXPIREDToken exp is in the past.
INVALID_SIGNATURESignature did not verify against the resolved key.
CLAIM_MISMATCHissuer, audience, or a required claim failed the check.
ALGORITHM_NOT_ALLOWEDToken alg is not in the configured allowlist.
KEY_RESOLUTION_FAILEDJWKS fetch / public_key / secret could not yield a usable key.
VERIFICATION_FAILEDGeneric verification failure not covered above.
NOT_CONFIGUREDresolver_auth is not configured.
DEPENDENCY_MISSINGBuilt-in verifier used without the velt-py[auth] extra installed.
Token extraction Extracted from the configured header (default Authorization, case-insensitive), stripping the configured scheme prefix (default Bearer); or pass token='<raw_jwt>'. Missing, empty, or wrong-scheme credentials → MISSING_TOKEN. Built-in JWT path — key resolution
  • jwt.secret → symmetric HS256/384/512. A PEM string in secret is rejected to prevent PEM-as-HMAC forgery.
  • jwt.public_key → static RSA/EC key for RS* / ES*.
  • jwt.jwks_url → fetched over HTTPS, cached in-process by (url, kid). A fetch failure, non-2xx response, or unresolvable kidKEY_RESOLUTION_FAILED without raising.
Security properties
  • Fail-closed — never verified=True unless a token was present and fully verified.
  • Algorithm pinning — the allowlist is always required and passed to PyJWT; alg=none is rejected unconditionally even if listed; mixed symmetric + asymmetric allowlists are rejected (HS/RS confusion).
  • HTTPS-only JWKSjwks_url must be https://; a redirect downgrade https→http is rejected; 3xx responses are rejected; cache is scoped by (url, kid), not kid alone.
  • No credential leakage — the token, secret, and claims never appear in error strings or logs.
  • Authentication only — never consults apiKey, organizationId, or the resolver database.
Per-call overrides **overrides kwargs merge over the configured resolver_auth, letting you supply a one-off jwt, verify, header, or scheme without mutating global config. When resolver_auth is not configured verifyToken returns verified=False with errorCode='NOT_CONFIGURED'. It does not raise and does not silently pass. ResolverAuthService Newly exported in velt_py.services.self_hosting.__all__ — the DB-free service backing verifyToken. Direct use is optional.

Framework Examples

SDK Initialization (velt_sdk.py)
from django.conf import settings
from velt_py import VeltSDK

_velt_sdk = None

def get_velt_sdk():
    global _velt_sdk
    if _velt_sdk is None:
        _velt_sdk = VeltSDK.initialize(settings.VELT_SDK_CONFIG)
    return _velt_sdk
API Endpoints (views.py)
import json
from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt
from django.views.decorators.http import require_http_methods
from velt_py import GetCommentResolverRequest, SaveCommentResolverRequest, DeleteCommentResolverRequest
from .velt_sdk import get_velt_sdk

@csrf_exempt
@require_http_methods(["POST"])
def get_comments(request):
    try:
        data = json.loads(request.body)
        comment_request = GetCommentResolverRequest.from_dict(data)
        sdk = get_velt_sdk()
        result = sdk.selfHosting.comments.getComments(comment_request)
        return JsonResponse(result, status=result.get('statusCode', 200))
    except Exception as e:
        return JsonResponse({
            'success': False,
            'error': str(e),
            'errorCode': 'INTERNAL_ERROR',
            'statusCode': 500
        }, status=500)
Configuration (settings.py)
import os

VELT_SDK_CONFIG = {
    'database': {
        'connection_string': os.environ.get('VELT_MONGODB_CONNECTION_STRING'),
    },
    'aws': {
        'bucket_name': os.environ.get('AWS_S3_BUCKET'),
        'region': os.environ.get('AWS_REGION', 'us-east-1'),
        'access_key_id': os.environ.get('AWS_ACCESS_KEY_ID'),
        'secret_access_key': os.environ.get('AWS_SECRET_ACCESS_KEY'),
    },
    'apiKey': os.environ.get('VELT_API_KEY'),
    'authToken': os.environ.get('VELT_AUTH_TOKEN')
}

REST API Backend

The sdk.api.* namespace gives you parity with Velt’s REST APIs across 18 services. Each method takes a typed @dataclass request object and returns the raw Velt API response. You only need apiKey and authToken — no database or AWS config.
from velt_py import VeltSDK

sdk = VeltSDK.initialize({
    'apiKey': 'YOUR_VELT_API_KEY',
    'authToken': 'YOUR_VELT_AUTH_TOKEN'
})

# All 18 services are accessible under sdk.api.*
# e.g. sdk.api.organizations, sdk.api.documents, sdk.api.workspace,
#      sdk.api.workflow ...
Every method returns a dict with either a result key (success) or an error key (failure). See VeltApiResponse.

Organizations

addOrganizations

from velt_py.models.organization import AddOrganizationsRequest

result = sdk.api.organizations.addOrganizations(
    AddOrganizationsRequest(
        organizations=[{'organizationId': 'yourOrganizationId', 'organizationName': 'Your Organization Name'}]
    )
)
Response
{
    'result': {
        'status': 'success',
        'message': 'Organization(s) added successfully.',
        'data': {
            'yourOrganizationId': {
                'success': True,
                'id': '02cf91e5e7a5f4c0b600c84cf248384b',
                'message': 'Added Successfully'
            }
        }
    }
}

getOrganizations

from velt_py.models.organization import GetOrganizationsRequest

result = sdk.api.organizations.getOrganizations(
    GetOrganizationsRequest(
        organizationIds=['yourOrganizationId'],
        pageSize=1000,
        pageToken='pageToken'
    )
)
Response
{
    'result': {
        'status': 'success',
        'message': 'Organization(s) retrieved successfully.',
        'data': [
            {
                'id': 'yourOrganizationId',
                'organizationName': 'Your Organization Name',
                'disabled': False
                # other metadata fields may be included here
            }
            # ... more organizations if multiple were retrieved
        ],
        'nextPageToken': 'pageToken'
    }
}

updateOrganizations

from velt_py.models.organization import UpdateOrganizationsRequest

result = sdk.api.organizations.updateOrganizations(
    UpdateOrganizationsRequest(
        organizations=[{'organizationId': 'yourOrganizationId', 'organizationName': 'Updated Name'}]
    )
)
Response
{
    'result': {
        'status': 'success',
        'message': 'Organization(s) updated successfully.',
        'data': {
            'yourOrganizationId': {
                'success': True,
                'id': '02cf91e5e7a5f4c0b600c84cf248384b',
                'message': 'Updated Successfully'
            }
        }
    }
}

deleteOrganizations

from velt_py.models.organization import DeleteOrganizationsRequest

result = sdk.api.organizations.deleteOrganizations(
    DeleteOrganizationsRequest(organizationIds=['yourOrganizationId1', 'yourOrganizationId2'])
)
Response
{
    'result': {
        'status': 'success',
        'message': 'Organization(s) deleted successfully.',
        'data': {
            'yourOrganizationId1': {
                'success': True,
                'id': '02cf91e5e7a5f4c0b600c84cf248384b',
                'message': 'Deleted Successfully'
            },
            'yourOrganizationId2': {
                'success': False,
                'id': '02cf91e5e7a5f4c0b600c84cf248384b',
                'message': 'Organization does not exist'
            }
        }
    }
}

updateOrganizationDisableState

from velt_py.models.organization import UpdateOrganizationDisableStateRequest

result = sdk.api.organizations.updateOrganizationDisableState(
    UpdateOrganizationDisableStateRequest(
        organizationIds=['yourOrganizationId1', 'yourOrganizationId2'],
        disabled=True
    )
)
Response
{
    'result': {
        'status': 'success',
        'message': 'Updated disable state for Organization(s) successfully.',
        'data': {
            'yourOrganizationId1': {
                'success': True,
                'id': '02cf91e5e7a5f4c0b600c84cf248384b',
                'message': 'Updated disable state for organization Successfully'
            },
            'yourOrganizationId2': {
                'success': False,
                'id': '44e0132f4c6b0d453f18df42d2263b4e',
                'message': 'Organization does not exist'
            }
        }
    }
}

Folders

addFolder

from velt_py.models.folder import AddFolderRequest

result = sdk.api.folders.addFolder(
    AddFolderRequest(
        organizationId='yourOrganizationId',
        folders=[{
            'folderId': 'yourFolderId',
            'folderName': 'yourFolderName',
            'parentFolderId': 'yourParentFolderId'
        }]
    )
)
Response
{
    'result': {
        'status': 'success',
        'message': 'Folder created successfully.',
        'data': {
            'yourFolderId': {
                'success': True,
                'id': 'yourFolderId',
                'message': 'Folder added.'
            }
        }
    }
}

getFolders

from velt_py.models.folder import GetFoldersRequest

result = sdk.api.folders.getFolders(
    GetFoldersRequest(organizationId='yourOrganizationId', folderId='yourFolderId')
)
Response
{
    'result': {
        'status': 'success',
        'message': 'Folders retrieved successfully.',
        'data': [
            {
                'folderId': 'folderId1',
                'folderName': 'Folder 1',
                'organizationId': 'yourOrganizationId',
                'parentFolderId': 'root',
                'createdAt': 1738695077691,
                'lastUpdated': 1738695077691,
                'subFolders': [
                    {
                        'folderId': 'childFolderId1',
                        'folderName': 'Child Folder 1',
                        'parentFolderId': 'folderId1',
                        'createdAt': 1738695615706,
                        'lastUpdated': 1738698727591
                    }
                ]
            }
        ]
    }
}

updateFolder

from velt_py.models.folder import UpdateFolderRequest

result = sdk.api.folders.updateFolder(
    UpdateFolderRequest(
        organizationId='yourOrganizationId',
        folders=[{'folderId': 'yourFolderId', 'folderName': 'yourFolderName', 'parentFolderId': 'yourParentFolderId'}]
    )
)
Response
{
    'result': {
        'status': 'success',
        'message': 'Folder Updated successfully.',
        'data': {
            'yourFolderId': {
                'success': True,
                'id': 'yourFolderId',
                'message': 'Folder Updated.'
            }
        }
    }
}

deleteFolder

from velt_py.models.folder import DeleteFolderRequest

result = sdk.api.folders.deleteFolder(
    DeleteFolderRequest(organizationId='yourOrganizationId', folderId='yourFolderId')
)
Response
{
    'result': {
        'status': 'success',
        'message': 'Folder deleted successfully.',
        'data': { 'yourFolderId': {'success': True} }
    }
}

updateFolderAccess

from velt_py.models.folder import UpdateFolderAccessRequest

result = sdk.api.folders.updateFolderAccess(
    UpdateFolderAccessRequest(
        organizationId='yourOrganizationId',
        folderIds=['yourFolderId'],
        accessType='organizationPrivate'
    )
)
Response
{
    'result': {
        'status': 'success',
        'message': 'Updated access for folders successfully.',
        'data': {
            'yourFolderId': {
                'success': True,
                'accessType': 'organizationPrivate',
                'message': 'Folder access type updated.'
            }
        }
    }
}

Documents

addDocuments

from velt_py.models.document import AddDocumentsRequest

result = sdk.api.documents.addDocuments(
    AddDocumentsRequest(
        organizationId='yourOrganizationId',
        documents=[{'documentId': 'yourDocumentId', 'documentName': 'yourDocumentName'}],
        createOrganization=True,
        folderId='yourFolderId',
        createFolder=True
    )
)
Response
{
    'result': {
        'status': 'success',
        'message': 'Document(s) added successfully.',
        'data': {
            'yourDocumentId': {
                'success': True,
                'id': '8121657101517513',
                'message': 'Added Successfully'
            }
        }
    }
}

getDocuments

from velt_py.models.document import GetDocumentsRequest

result = sdk.api.documents.getDocuments(
    GetDocumentsRequest(
        organizationId='yourOrganizationId',
        documentIds=['yourDocumentId'],
        folderId='yourFolderId'
    )
)
Response
{
    'result': {
        'status': 'success',
        'message': 'Document(s) retrieved successfully.',
        'data': [
            {
                'documentName': 'yourDocumentName',
                'disabled': False,
                'accessType': 'public',
                'id': 'yourDocumentId'
            }
        ],
        'pageToken': 'nextPageToken'
    }
}

updateDocuments

from velt_py.models.document import UpdateDocumentsRequest

result = sdk.api.documents.updateDocuments(
    UpdateDocumentsRequest(
        organizationId='yourOrganizationId',
        documents=[{'documentId': 'yourDocumentId', 'documentName': 'Updated Name'}]
    )
)
Response
{
    'result': {
        'status': 'success',
        'message': 'Document(s) updated successfully.',
        'data': {
            'yourDocumentId': {
                'success': True,
                'id': '8121657101517513',
                'message': 'Updated Successfully'
            }
        }
    }
}

deleteDocuments

from velt_py.models.document import DeleteDocumentsRequest

result = sdk.api.documents.deleteDocuments(
    DeleteDocumentsRequest(
        organizationId='yourOrganizationId',
        documentIds=['yourDocumentId1', 'yourDocumentId2']
    )
)
Response
{
    'result': {
        'status': 'success',
        'message': 'Document(s) deleted successfully.',
        'data': {
            'yourDocumentId1': {
                'success': True,
                'id': '6737987049068973',
                'message': 'Deleted Successfully'
            },
            'yourDocumentId2': {
                'success': True,
                'id': '2131443384150904',
                'message': 'Document does not exist'
            }
        }
    }
}

moveDocuments

from velt_py.models.document import MoveDocumentsRequest

result = sdk.api.documents.moveDocuments(
    MoveDocumentsRequest(
        organizationId='yourOrganizationId',
        documentIds=['yourDocumentId1', 'yourDocumentId2'],
        folderId='target-folder-id'
    )
)
Response
{
    'result': {
        'status': 'success',
        'message': 'Documents moved successfully.'
    }
}

updateDocumentAccess

from velt_py.models.document import UpdateDocumentAccessRequest

result = sdk.api.documents.updateDocumentAccess(
    UpdateDocumentAccessRequest(
        organizationId='yourOrganizationId',
        documentIds=['yourDocumentId'],
        accessType='organizationPrivate'
    )
)
Response
{
    'result': {
        'status': 'success',
        'message': 'Updated access for documents successfully.',
        'data': {
            'yourDocumentId': {
                'success': True,
                'accessType': 'organizationPrivate',
                'message': 'Document access type updated.'
            }
        }
    }
}

updateDocumentDisableState

from velt_py.models.document import UpdateDocumentDisableStateRequest

result = sdk.api.documents.updateDocumentDisableState(
    UpdateDocumentDisableStateRequest(
        organizationId='yourOrganizationId',
        documentIds=['yourDocumentId'],
        disabled=True
    )
)
Response
{
    'result': {
        'status': 'success',
        'message': 'Updated disable state for documents successfully.',
        'data': {
            'yourDocumentId': {
                'success': True,
                'disabled': True,
                'message': 'Document disabled state updated.'
            }
        }
    }
}

migrateDocuments

from velt_py.models.document import MigrateDocumentsRequest

result = sdk.api.documents.migrateDocuments(
    MigrateDocumentsRequest(
        organizationId='yourOrganizationId',
        documentId='old-doc-id',
        newDocumentId='new-doc-id'
    )
)
Response
{
    'result': {
        'status': 'success',
        'message': 'Document migration started successfully.',
        'data': { 'migrationId': 'yourMigrationId' }
    }
}
Note: This call is asynchronous. Poll status via migrateDocumentsStatus.

migrateDocumentsStatus

from velt_py.models.document import MigrateDocumentsStatusRequest

result = sdk.api.documents.migrateDocumentsStatus(
    MigrateDocumentsStatusRequest(
        organizationId='yourOrganizationId',
        migrationId='yourMigrationId'
    )
)
Response
{
    'result': {
        'status': 'success',
        'message': 'Migration status retrieved successfully.',
        'data': {
            'migrationId': 'yourMigrationId',
            'status': 'completed'
        }
    }
}

getDocumentsCount

  • Gets the document count for an organization. Optionally exclude folder docs or scope to a folder.
  • Params: GetDocumentsCountRequest (from velt_py.models.document)
  • Returns: VeltApiResponse
from velt_py.models.document import GetDocumentsCountRequest

result = sdk.api.documents.getDocumentsCount(
    GetDocumentsCountRequest(
        organizationId='org-123',
        excludeFolderDocs=True,
        folderId='folder-1'
    )
)

Users

addUsers

from velt_py.models.user_api import AddUsersRequest

result = sdk.api.users.addUsers(
    AddUsersRequest(
        organizationId='yourOrganizationId',
        users=[{'userId': 'yourUserId1', 'name': 'John Doe', 'email': 'john@example.com', 'accessRole': 'editor'}],
        createOrganization=True
    )
)
Response
{
    'result': {
        'status': 'success',
        'message': 'User(s) processed successfully.',
        'data': {
            'yourUserId1': {
                'success': True,
                'id': '4c250058149d6c9fb8c894c9ef29c790',
                'message': 'User added.'
            }
        }
    }
}

getUsers

  • Retrieves users in an organization or document.
  • Params: GetUsersRequest
  • Returns: GetUsersResponse
  • Now also supports optional includeInvolvedDocuments and searchKey (free-text search) filters.
from velt_py.models.user_api import GetUsersRequest

result = sdk.api.users.getUsers(
    GetUsersRequest(
        organizationId='yourOrganizationId',
        userIds=['yourUserId'],
        documentId='yourDocumentId',
        pageSize=100,
        allDocuments=True,
        groupByDocumentId=True,
        includeInvolvedDocuments=True,
        searchKey='john'
    )
)
Response
{
    'result': {
        'status': 'success',
        'message': 'User(s) retrieved successfully.',
        'data': [
            {'email': 'userEmail@domain.com', 'name': 'userName', 'userId': 'yourUserId'}
        ],
        'nextPageToken': 'pageToken'
    }
}

updateUsers

from velt_py.models.user_api import UpdateUsersRequest

result = sdk.api.users.updateUsers(
    UpdateUsersRequest(
        organizationId='yourOrganizationId',
        users=[{'userId': 'yourUserId1', 'name': 'Jane Doe', 'accessRole': 'viewer'}]
    )
)
Response
{
    'result': {
        'status': 'success',
        'message': 'User(s) processed successfully.',
        'data': {
            'yourUserId1': {
                'success': True,
                'id': '7d87015b055a168b098cf05b870e40ff',
                'message': 'User updated.'
            }
        }
    }
}

deleteUsers

from velt_py.models.user_api import DeleteUsersRequest

result = sdk.api.users.deleteUsers(
    DeleteUsersRequest(
        organizationId='yourOrganizationId',
        userIds=['yourUserId1', 'yourUserId2']
    )
)
Response
{
    'result': {
        'status': 'success',
        'message': 'User(s) deleted successfully.',
        'data': {
            'yourUserId1': {
                'success': True,
                'message': 'User removed.'
            }
        }
    }
}

getUsersCount

  • Gets the user count for an organization. Optionally scope to a document, a user, or all documents.
  • Params: GetUsersCountRequest (from velt_py.models.user_api)
  • Returns: VeltApiResponse
from velt_py.models.user_api import GetUsersCountRequest

result = sdk.api.users.getUsersCount(
    GetUsersCountRequest(organizationId='org-123', allDocuments=True, userId='user-1')
)

getDocUsers

  • Gets document-level users. Optionally filter by user IDs (max 20; max 5 with includeInvolvedDocuments), include involved documents, and paginate.
  • Params: GetDocUsersRequest (from velt_py.models.user_api)
  • Returns: VeltApiResponse
from velt_py.models.user_api import GetDocUsersRequest

result = sdk.api.users.getDocUsers(
    GetDocUsersRequest(organizationId='org-123', userIds=['user-1'], includeInvolvedDocuments=True, pageSize=100)
)

addUserInvite

  • Creates a user invitation (organization, document, or folder).
  • Params: AddUserInviteRequest (from velt_py.models.user_api)
  • Returns: VeltApiResponse
from velt_py.models.user_api import AddUserInviteRequest

result = sdk.api.users.addUserInvite(
    AddUserInviteRequest(email='invitee@example.com', organizationId='org-123', type='org_user')
)

respondToInvite

  • Responds to a user invitation (accept, reject, or withdraw).
  • Params: RespondUserInviteRequest (from velt_py.models.user_api)
  • Returns: VeltApiResponse
from velt_py.models.user_api import RespondUserInviteRequest

result = sdk.api.users.respondToInvite(
    RespondUserInviteRequest(
        email='invitee@example.com', organizationId='org-123', status='ACCEPTED', type='org_user',
        user={'userId': 'user-1', 'name': 'Invitee'}, authToken='invited-user-auth-token'
    )
)

getInvitedUsers

  • Gets invited users for an organization (paginated).
  • Params: GetInvitedUsersRequest (from velt_py.models.user_api)
  • Returns: VeltApiResponse
from velt_py.models.user_api import GetInvitedUsersRequest

invited = sdk.api.users.getInvitedUsers(
    GetInvitedUsersRequest(organizationId='org-123')
)

getUserInvitations

  • Gets invitations for a specific user email (paginated).
  • Params: GetUserInvitationsRequest (from velt_py.models.user_api)
  • Returns: VeltApiResponse
from velt_py.models.user_api import GetUserInvitationsRequest

invitations = sdk.api.users.getUserInvitations(
    GetUserInvitationsRequest(organizationId='org-123', email='invitee@example.com')
)

getInvitedPendingUsersCount

  • Gets the count of pending invited users.
  • Params: GetInvitedPendingUsersCountRequest (from velt_py.models.user_api)
  • Returns: VeltApiResponse
from velt_py.models.user_api import GetInvitedPendingUsersCountRequest

pending = sdk.api.users.getInvitedPendingUsersCount(
    GetInvitedPendingUsersCountRequest(organizationId='org-123', type='org_user')
)

User Groups

addUserGroups

from velt_py.models.user_group import AddUserGroupsRequest

result = sdk.api.userGroups.addUserGroups(
    AddUserGroupsRequest(
        organizationId='yourOrganizationId',
        organizationUserGroups=[{'groupId': 'yourGroupId', 'groupName': 'Engineering'}],
        createOrganization=True
    )
)
Response
{
    'result': {
        'status': 'success',
        'message': 'Organization User Groups added successfully.',
        'data': {
            'yourGroupId': {
                'success': True,
                'id': '77ab6767b022ad0323ba39c24f12cc95',
                'message': 'Organization user group added.'
            }
        }
    }
}

addUsersToGroup

from velt_py.models.user_group import AddUsersToGroupRequest

result = sdk.api.userGroups.addUsersToGroup(
    AddUsersToGroupRequest(
        organizationId='yourOrganizationId',
        organizationUserGroupId='yourGroupId',
        userIds=['yourUserId1', 'yourUserId2']
    )
)
Response
{
    'result': {
        'status': 'success',
        'message': 'Added organization users to group successfully.',
        'data': {
            'yourUserId1': {
                'success': True,
                'organizationUserGroupId': 'yourGroupId',
                'message': 'User added to organization user group.'
            }
        }
    }
}

deleteUsersFromGroup

from velt_py.models.user_group import DeleteUsersFromGroupRequest

result = sdk.api.userGroups.deleteUsersFromGroup(
    DeleteUsersFromGroupRequest(
        organizationId='yourOrganizationId',
        organizationUserGroupId='yourGroupId',
        userIds=['yourUserId1'],
        deleteAll=False
    )
)
Response
{
    'result': {
        'status': 'success',
        'message': 'Deleted users from group successfully.',
        'data': {
            'yourUserId1': {
                'success': True,
                'organizationUserGroupId': 'yourGroupId',
                'message': 'User deleted from organization user group.'
            }
        }
    }
}

Notifications

Filtering unknown fields: updateNotifications accepts an optional filter_unknown_fields: bool = False keyword (backed by velt_py.models.field_allowlists). When True, unknown/custom top-level keys are dropped before the request is sent, while open-typed fields (context, metadata, entityData, user objects) pass through whole. Filtering is fail-open: if it errors, the original payload is sent, so a write is never blocked. addNotifications is not affected — its top-level fields are already fixed. On updateNotifications, isRead / isArchived are not accepted by /v2/notifications/update (the backend strips them anyway), so with the flag on they are dropped client-side.

addNotifications

from velt_py.models.notification_api import AddNotificationsRequest

result = sdk.api.notifications.addNotifications(
    AddNotificationsRequest(
        organizationId='yourOrganizationId',
        documentId='yourDocumentId',
        actionUser={'userId': 'user-1', 'name': 'John Doe', 'email': 'john@example.com'},
        displayHeadlineMessageTemplate='{actionUser} commented on your document',
        displayBodyMessage='Check out the new comment',
        notifyUsers=[{'userId': 'user-2', 'name': 'Jane Doe'}],
        createOrganization=True,
        createDocument=True
    )
)
Response
{
    'result': {
        'status': 'success',
        'message': 'Notification added successfully.',
        'data': {
            'success': True,
            'message': 'Notification added successfully.'
        }
    }
}

getNotifications

from velt_py.models.notification_api import GetNotificationsRequest

result = sdk.api.notifications.getNotifications(
    GetNotificationsRequest(
        organizationId='yourOrganizationId',
        userId='user-2',
        pageSize=10,
        order='desc'
    )
)
Response
{
    'result': {
        'status': 'success',
        'message': 'Notification(s) retrieved successfully.',
        'data': [
            {
                'id': 'notificationId',
                'notificationSource': 'custom',
                'notificationSourceData': {},
                'actionUser': {'email': 'user@example.com', 'name': 'User Name', 'userId': 'yourUserId'},
                'displayBodyMessage': 'This is body message (Secondary message)',
                'displayHeadlineMessageTemplate': 'Template with {actionUser}, {recipientUser}, {customVar}',
                'displayHeadlineMessageTemplateData': {
                    'actionUser': {'email': 'user@example.com', 'name': 'User Name', 'userId': 'yourUserId'},
                    'recipientUser': {'email': 'recipient@example.com', 'name': 'Recipient Name', 'userId': 'recipientUserId'}
                },
                'metadata': {'apiKey': '...', 'documentId': '...', 'organizationId': '...'},
                'notifyUsers': {'yourNotifyUserId': True},
                'notifyUsersByUserId': {'yourNotifyUserById': True},
                'timestamp': 1722409519944
            }
        ],
        'pageToken': 'nextPageToken'
    }
}

updateNotifications

from velt_py.models.notification_api import UpdateNotificationsRequest

result = sdk.api.notifications.updateNotifications(
    UpdateNotificationsRequest(
        organizationId='yourOrganizationId',
        notifications={'5471488637912692': {'isRead': True}}
    )
)
Response
{
    'result': {
        'status': 'success',
        'message': 'Notification(s) updated successfully.',
        'data': {
            '5471488637912692': {
                'success': True,
                'message': 'Notification updated.'
            }
        }
    }
}

deleteNotifications

from velt_py.models.notification_api import DeleteNotificationsRequest

result = sdk.api.notifications.deleteNotifications(
    DeleteNotificationsRequest(
        organizationId='yourOrganizationId',
        notificationIds=['8955243231506071']
    )
)
Response
{
    'result': {
        'status': 'success',
        'message': 'Notification(s) deleted successfully.',
        'data': {
            '8955243231506071': {
                'success': True,
                'message': 'Notification deleted.'
            }
        }
    }
}

getNotificationConfig

from velt_py.models.notification_api import GetNotificationConfigRequest

result = sdk.api.notifications.getNotificationConfig(
    GetNotificationConfigRequest(
        organizationId='org1',
        userId='USER_ID1'
    )
)
Response
{
    'result': {
        'status': 'success',
        'message': 'User config fetched successfully.',
        'data': [
            {
                'config': {'inbox': 'ALL', 'email': 'ALL'},
                'metadata': {
                    'organizationId': 'org1',
                    'apiKey': 'API_KEY',
                    'documentId': 'doc1',
                    'userId': 'USER_ID1'
                }
            }
        ]
    }
}

setNotificationConfig

from velt_py.models.notification_api import SetNotificationConfigRequest

result = sdk.api.notifications.setNotificationConfig(
    SetNotificationConfigRequest(
        organizationId='org1',
        userIds=['USER_ID1'],
        config={'inbox': 'ALL', 'email': 'MINE'}
    )
)
Response
{
    'result': {
        'status': 'success',
        'message': 'User config set successfully.',
        'data': {
            'USER_ID1': {
                'success': True,
                'userId': 'USER_ID1',
                'documentId': 'doc1',
                'message': 'User config set successfully.'
            }
        }
    }
}

Comment Annotations

Filtering unknown fields: The add/update methods below accept an optional filter_unknown_fields: bool = False keyword (backed by velt_py.models.field_allowlists). When True, request entity collections are filtered to only the fields the Velt API accepts, dropping unknown/custom top-level keys before the request is sent. Open-typed fields (context, metadata, entityData, user objects) pass through whole — their nested contents are never filtered. Filtering is fail-open: if it errors, the original payload is sent, so a write is never blocked.

addCommentAnnotations

from velt_py.models.comment_annotation_api import AddCommentAnnotationsRequest

result = sdk.api.commentAnnotations.addCommentAnnotations(
    AddCommentAnnotationsRequest(
        organizationId='yourOrganizationId',
        documentId='yourDocumentId',
        commentAnnotations=[{
            'location': {'id': 'yourLocationId', 'locationName': 'yourLocationName'},
            'commentData': [{
                'commentText': 'Sample Comment',
                'commentHtml': '<div>Sample Comment</div>',
                'from': {'userId': 'yourUserId', 'name': 'yourUserName', 'email': 'yourUserEmail'}
            }]
        }]
    )
)
Response
{
    'result': {
        'status': 'success',
        'message': 'Comment Annotation(s) added successfully.',
        'data': {
            '-O0mpUziLcBwzREvZKs6': {
                'success': True,
                'annotationId': '-O0mpUziLcBwzREvZKs6',
                'commentIds': [126535],
                'message': 'Added Successfully'
            }
        }
    }
}

getCommentAnnotations

from velt_py.models.comment_annotation_api import GetCommentAnnotationsRequest

result = sdk.api.commentAnnotations.getCommentAnnotations(
    GetCommentAnnotationsRequest(
        organizationId='yourOrganizationId',
        documentId='yourDocumentId',
        statusIds=['OPEN'],
        pageSize=10
    )
)
Response
{
    'result': {
        'status': 'success',
        'message': 'Annotation(s) fetched successfully.',
        'data': [
            {
                'annotationId': 'yourAnnotationId',
                'annotationNumber': 2,
                'type': 'comment',
                'createdAt': 1777973713421,
                'lastUpdated': 1777978714209,
                'hasDraftComments': False,
                'context': {'access': {'default': 'velt'}, 'accessFields': ['default:velt']},
                'visibilityConfig': {'type': 'public'},
                'metadata': {'apiKey': '...', 'organizationId': '...', 'documentId': '...'},
                'from': {'userId': 'user123', 'name': 'John Doe', 'email': 'john.doe@example.com'},
                'comments': [
                    {
                        'commentId': 123456,
                        'commentText': 'This is a sample comment text.',
                        'commentHtml': '<p>This is a sample comment text.</p>',
                        'createdAt': 1777973714914,
                        'lastUpdated': '2026-05-05T09:35:15.048Z',
                        'reactionAnnotationIds': ['reactionAnnotationId1'],
                        'from': {'userId': 'user123', 'name': 'John Doe'}
                    }
                ],
                'status': {'id': 'OPEN', 'name': 'Open', 'type': 'default'}
            }
        ],
        'nextPageToken': 'pageToken'
    }
}

getCommentAnnotationsCount

from velt_py.models.comment_annotation_api import GetCommentAnnotationsCountRequest

result = sdk.api.commentAnnotations.getCommentAnnotationsCount(
    GetCommentAnnotationsCountRequest(
        organizationId='ORG_ID',
        documentIds=['DOC_1', 'DOC_2'],
        userId='1.1',
        statusIds=['OPEN', 'IN_PROGRESS']
    )
)
Response
{
    'result': {
        'status': 'success',
        'message': 'Comment count retrieved successfully.',
        'data': {
            'DOC_1': {'total': 4, 'unread': 2},
            'DOC_2': {'total': 2, 'unread': 0}
        }
    }
}

updateCommentAnnotations

from velt_py.models.comment_annotation_api import UpdateCommentAnnotationsRequest

result = sdk.api.commentAnnotations.updateCommentAnnotations(
    UpdateCommentAnnotationsRequest(
        organizationId='yourOrganizationId',
        documentId='yourDocumentId',
        annotationIds=['yourAnnotationId1'],
        updatedData={'status': {'id': 'inprogress', 'name': 'In Progress', 'type': 'ongoing'}}
    )
)
Response
{
    'result': {
        'status': 'success',
        'message': 'Annotations updated successfully.',
        'data': {
            'yourAnnotationId1': {
                'success': True,
                'id': 'yourAnnotationId1',
                'message': 'Annotations updated successfully'
            }
        }
    }
}

deleteCommentAnnotations

from velt_py.models.comment_annotation_api import DeleteCommentAnnotationsRequest

result = sdk.api.commentAnnotations.deleteCommentAnnotations(
    DeleteCommentAnnotationsRequest(
        organizationId='yourOrganizationId',
        documentId='yourDocumentId',
        annotationIds=['yourAnnotationId1', 'yourAnnotationId2']
    )
)
Response
{
    'result': {
        'status': 'success',
        'message': 'Annotations deleted successfully.',
        'data': {
            'yourAnnotationId1': {
                'success': True,
                'id': 'yourAnnotationId',
                'message': 'Deleted Successfully'
            },
            'yourAnnotationId2': {
                'success': False,
                'id': 'yourAnnotationId2',
                'message': 'Annotation not found.'
            }
        }
    }
}

addComments

  • Adds reply comments to an existing annotation.
  • Params: AddCommentsRequest
  • Returns: VeltApiResponse
  • Accepts the optional filter_unknown_fields=True keyword (see the note above).
from velt_py.models.comment_annotation_api import AddCommentsRequest

result = sdk.api.commentAnnotations.addComments(
    AddCommentsRequest(
        organizationId='yourOrganizationId',
        documentId='yourDocumentId',
        annotationId='yourAnnotationId',
        commentData=[{
            'commentText': 'I agree, let me fix this',
            'from': {'userId': 'user-2', 'name': 'Jane Doe'}
        }]
    )
)
Response
{
    'result': {
        'status': 'success',
        'message': 'Comment(s) added successfully.',
        'data': [778115]
    }
}

getComments

from velt_py.models.comment_annotation_api import GetCommentsRequest

result = sdk.api.commentAnnotations.getComments(
    GetCommentsRequest(
        organizationId='yourOrganizationId',
        documentId='yourDocumentId',
        annotationId='yourAnnotationId',
        userIds=['yourUserId']
    )
)
Response
{
    'result': {
        'status': 'success',
        'message': 'Comments retrieved successfully.',
        'data': [
            {
                'commentId': 123456,
                'type': 'text',
                'commentText': 'This is a sample comment text.',
                'commentHtml': '<p>This is a sample comment text.</p>',
                'createdAt': 1777973714914,
                'lastUpdated': '2026-05-05T09:35:15.048Z',
                'reactionAnnotationIds': ['reactionAnnotationId1'],
                'from': {'userId': 'user123', 'name': 'John Doe', 'email': 'john.doe@example.com'}
            }
        ]
    }
}

updateComments

  • Updates fields on individual comments inside an annotation.
  • Params: UpdateCommentsRequest
  • Returns: VeltApiResponse
  • Accepts the optional filter_unknown_fields=True keyword (see the note above).
from velt_py.models.comment_annotation_api import UpdateCommentsRequest

result = sdk.api.commentAnnotations.updateComments(
    UpdateCommentsRequest(
        organizationId='yourOrganizationId',
        documentId='yourDocumentId',
        annotationId='yourAnnotationId',
        commentIds=[607395],
        updatedData={'commentText': 'Updated text', 'commentHtml': '<p>Updated text</p>'}
    )
)
Response
{
    'result': {
        'status': 'success',
        'message': 'Comment updated successfully.',
        'data': {
            '607395': {
                'success': True,
                'id': 607395,
                'message': 'Updated successfully'
            }
        }
    }
}

deleteComments

from velt_py.models.comment_annotation_api import DeleteCommentsRequest

result = sdk.api.commentAnnotations.deleteComments(
    DeleteCommentsRequest(
        organizationId='yourOrganizationId',
        documentId='yourDocumentId',
        annotationId='yourAnnotationId',
        commentIds=[153783, 607395]
    )
)
Response
{
    'result': {
        'status': 'success',
        'message': 'Comments(s) deleted successfully.',
        'data': {
            '153783': {
                'success': True,
                'id': 153783,
                'message': 'Deleted successfully'
            },
            '607395': {
                'success': False,
                'id': 607395,
                'message': 'Not found'
            }
        }
    }
}

Activities

Filtering unknown fields: The add/update methods below accept an optional filter_unknown_fields: bool = False keyword (backed by velt_py.models.field_allowlists). When True, request entity collections are filtered to only the fields the Velt API accepts, dropping unknown/custom top-level keys before the request is sent. Open-typed fields (context, metadata, entityData, user objects) pass through whole — their nested contents are never filtered. Filtering is fail-open: if it errors, the original payload is sent, so a write is never blocked.
result = sdk.api.activities.addActivities(
    AddActivitiesRequest(
        organizationId='org-123', documentId='doc-456',
        activities=[{'featureType': 'comment', 'actionType': 'comment.add', 'actionUser': {'userId': 'user-1'}, 'internalTrackingId': 'abc-123'}]
    ),
    filter_unknown_fields=True,
)
# The 'internalTrackingId' key is removed before the request is sent.

addActivities

from velt_py.models.activity_api import AddActivitiesRequest

result = sdk.api.activities.addActivities(
    AddActivitiesRequest(
        organizationId='org-123',
        documentId='doc-456',
        activities=[{
            'featureType': 'comment',
            'actionType': 'comment.add',
            'actionUser': {'userId': 'user-1', 'name': 'User Name', 'email': 'user@example.com'},
            'displayMessageTemplate': '{{user}} added a comment'
        }]
    )
)
Response
{
    'result': {
        'status': 'success',
        'message': 'Activity(s) added successfully.',
        'data': {
            'success': True,
            'message': 'Activity(s) added successfully.'
        }
    }
}

getActivities

from velt_py.models.activity_api import GetActivitiesRequest

result = sdk.api.activities.getActivities(
    GetActivitiesRequest(
        organizationId='org-123',
        documentId='doc-456',
        featureTypes=['comment'],
        order='desc',
        pageSize=50
    )
)
Response
{
    'result': {
        'status': 'success',
        'message': 'Activity(s) retrieved successfully.',
        'data': [
            {
                'id': 'activity-001',
                'featureType': 'comment',
                'actionType': 'comment.add',
                'actionUser': {'userId': 'user-1', 'email': 'user@example.com', 'name': 'User Name'},
                'targetEntityId': 'annotation-789',
                'displayMessageTemplate': '{{user}} added a comment',
                'displayMessageTemplateData': {'user': {'userId': 'user-1', 'name': 'User Name'}},
                'metadata': {'apiKey': 'yourApiKey', 'documentId': 'doc-456', 'organizationId': 'org-123'},
                'timestamp': 1722409519944
            }
        ],
        'pageToken': 'nextPageToken'
    }
}

updateActivities

from velt_py.models.activity_api import UpdateActivitiesRequest

result = sdk.api.activities.updateActivities(
    UpdateActivitiesRequest(
        organizationId='org-123',
        activities=[{
            'id': 'activity-001',
            'displayMessageTemplate': '{{user}} updated the comment'
        }]
    )
)
Response
{
    'result': {
        'status': 'success',
        'message': 'Activity(s) updated successfully.',
        'data': {
            'activity-001': {
                'success': True,
                'message': 'Activity updated.'
            }
        }
    }
}

deleteActivities

from velt_py.models.activity_api import DeleteActivitiesRequest

result = sdk.api.activities.deleteActivities(
    DeleteActivitiesRequest(
        organizationId='org-123',
        activityIds=['activity-001', 'activity-002']
    )
)
Response
{
    'result': {
        'status': 'success',
        'message': 'Activity(s) deleted successfully.',
        'data': {
            'activity-001': {
                'success': True,
                'message': 'Activity deleted.'
            }
        }
    }
}

Access Control

addPermissions

from velt_py.models.access_control import AddPermissionsRequest

result = sdk.api.accessControl.addPermissions(
    AddPermissionsRequest(
        user={'userId': 'some-user-id'},
        permissions={'resources': [
            {'type': 'organization', 'id': 'YOUR_ORGANIZATION_ID', 'accessRole': 'editor'},
            {'type': 'document', 'id': 'YOUR_DOCUMENT_ID', 'organizationId': 'YOUR_ORGANIZATION_ID', 'accessRole': 'viewer', 'expiresAt': 1728902400}
        ]}
    )
)
Response
{
    'result': {
        'status': 'success',
        'message': 'Permissions added successfully.'
    }
}

getPermissions

from velt_py.models.access_control import GetPermissionsRequest

result = sdk.api.accessControl.getPermissions(
    GetPermissionsRequest(
        organizationId='org1',
        userIds=['1.1'],
        documentIds=['document1']
    )
)
Response
{
    'result': {
        'status': 'success',
        'message': 'User permissions retrieved successfully.',
        'data': {
            '1.1': {
                'folders': {
                    'folder2': {'accessRole': 'editor', 'accessType': 'restricted'}
                },
                'documents': {
                    'document1': {'accessRole': 'viewer', 'accessType': 'restricted'}
                },
                'organization': {
                    'org1': {'accessRole': 'editor'}
                }
            }
        }
    }
}

removePermissions

from velt_py.models.access_control import RemovePermissionsRequest

result = sdk.api.accessControl.removePermissions(
    RemovePermissionsRequest(
        userId='USER_ID',
        permissions={'resources': [
            {'type': 'organization', 'id': 'ORGANIZATION_ID'},
            {'type': 'document', 'id': 'DOCUMENT_ID', 'organizationId': 'ORGANIZATION_ID'}
        ]}
    )
)
Response
{
    'result': {
        'status': 'success',
        'message': 'Permissions removed successfully.'
    }
}

generateSignature

from velt_py.models.access_control import GenerateSignatureRequest

result = sdk.api.accessControl.generateSignature(
    GenerateSignatureRequest(
        permissions=[{
            'userId': 'user123',
            'resourceId': 'document456',
            'type': 'document',
            'hasAccess': True,
            'accessRole': 'viewer',
            'expiresAt': 1759745729823
        }]
    )
)
Response
{
    'result': {
        'status': 'success',
        'message': 'Signature generated successfully.',
        'data': { 'signature': 'a1b2c3d4e5f6...' }
    }
}

generateToken

from velt_py.models.access_control import GenerateTokenRequest

result = sdk.api.accessControl.generateToken(
    GenerateTokenRequest(
        userId='user123',
        userProperties={'isAdmin': False, 'name': 'John Doe', 'email': 'john@example.com'},
        permissions={'resources': [
            {'type': 'organization', 'id': 'org_123', 'accessRole': 'viewer'},
            {'type': 'document', 'id': 'doc_456', 'organizationId': 'org_123', 'accessRole': 'editor', 'expiresAt': 1640995200}
        ]}
    )
)
Response
{
    'result': {
        'status': 'success',
        'message': 'Token generated successfully.',
        'data': { 'token': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...' }
    }
}

CRDT

addCrdtData

from velt_py.models.crdt import AddCrdtDataRequest

result = sdk.api.crdt.addCrdtData(
    AddCrdtDataRequest(
        organizationId='yourOrganizationId',
        documentId='yourDocumentId',
        editorId='my-collab-note',
        data='Hello, collaborative world!',
        type='text'
    )
)
Response
{
    'result': {
        'status': 'success',
        'message': 'CRDT data added successfully.'
    }
}

getCrdtData

from velt_py.models.crdt import GetCrdtDataRequest

result = sdk.api.crdt.getCrdtData(
    GetCrdtDataRequest(
        organizationId='yourOrganizationId',
        documentId='yourDocumentId',
        editorId='my-collab-note'
    )
)
Response
{
    'result': {
        'status': 'success',
        'message': 'CRDT data retrieved successfully.',
        'data': [
            {
                'data': 'Hello, collaborative world!',
                'id': 'my-collab-note',
                'lastUpdate': '2025-01-20T10:30:00.000Z',
                'lastUpdatedBy': 'user-123',
                'sessionId': 'session-abc-456'
            }
        ]
    }
}

updateCrdtData

from velt_py.models.crdt import UpdateCrdtDataRequest

result = sdk.api.crdt.updateCrdtData(
    UpdateCrdtDataRequest(
        organizationId='yourOrganizationId',
        documentId='yourDocumentId',
        editorId='my-collab-note',
        data='Updated collaborative content!',
        type='text'
    )
)
Response
{
    'result': {
        'status': 'success',
        'message': 'CRDT data updated successfully.'
    }
}

deleteCrdtData

  • Deletes CRDT editor data. Optionally target specific editorIds; omit to delete all editors for a document.
  • Params: DeleteCrdtDataRequest (from velt_py.models.crdt)
  • Returns: VeltApiResponse
from velt_py.models.crdt import DeleteCrdtDataRequest

result = sdk.api.crdt.deleteCrdtData(
    DeleteCrdtDataRequest(
        organizationId='org-123',
        documentId='doc-1',
        editorIds=['my-collab-note']
    )
)

Presence

addPresence

from velt_py.models.presence import AddPresenceRequest

result = sdk.api.presence.addPresence(
    AddPresenceRequest(
        organizationId='org-123',
        documentId='doc-456',
        users=[
            {'userId': 'user-1', 'name': 'John Doe', 'email': 'john@example.com', 'status': 'online'},
            {'userId': 'user-2', 'name': 'Jane Doe', 'status': 'away'}
        ]
    )
)
Response
{
    'result': {
        'status': 'success',
        'message': 'Presence added successfully.',
        'data': { 'success': True }
    }
}

updatePresence

from velt_py.models.presence import UpdatePresenceRequest

result = sdk.api.presence.updatePresence(
    UpdatePresenceRequest(
        organizationId='org-123',
        documentId='doc-456',
        users=[{'userId': 'user-1', 'status': 'away'}]
    )
)
Response
{
    'result': {
        'status': 'success',
        'message': 'Presence updated successfully.',
        'data': { 'success': True }
    }
}

deletePresence

from velt_py.models.presence import DeletePresenceRequest

result = sdk.api.presence.deletePresence(
    DeletePresenceRequest(
        organizationId='org-123',
        documentId='doc-456',
        userIds=['user-1', 'user-2']
    )
)
Response
{
    'result': {
        'status': 'success',
        'message': 'Presence deleted successfully.',
        'data': { 'success': True }
    }
}

Livestate

broadcastEvent

from velt_py.models.livestate import BroadcastEventRequest

result = sdk.api.livestate.broadcastEvent(
    BroadcastEventRequest(
        organizationId='org-123',
        documentId='doc-1',
        liveStateDataId='my-live-state',
        data={'status': 'active', 'message': 'Hello World'},
        merge=True
    )
)
Response
{
    'result': {
        'status': 'success',
        'message': 'Event broadcasted successfully.',
        'data': { 'success': True }
    }
}

Recordings

getRecordings

from velt_py.models.recording import GetRecordingsRequest

result = sdk.api.recordings.getRecordings(
    GetRecordingsRequest(
        organizationId='org-123',
        documentId='doc-456',
        recordingIds=['rec-1'],
        pageSize=10,
        pageToken='encryptedPageToken'
    )
)
Response
{
    'result': {
        'status': 'success',
        'message': 'Recorder annotations retrieved successfully.',
        'data': [
            {
                'type': 'recorder',
                'recordingType': 'screen',
                'mode': 'floating',
                'metadata': {
                    'apiKey': 'YOUR_API_KEY',
                    'documentId': 'doc-456',
                    'organizationId': 'org-123'
                },
                'recordedTime': {'duration': 4204.55, 'display': '00:00:04'},
                'displayName': 'Screen Recording 1773814490242.mp4',
                'annotationId': 'ypvmVTROaNU1qP4kq7Cc',
                'attachments': [
                    {
                        'attachmentId': 875113,
                        'url': 'https://storage.googleapis.com/...',
                        'mimeType': 'video/mp4',
                        'name': 'recording_1773814490242.mp4',
                        'type': 'mp4',
                        'size': 103551
                    }
                ],
                'latestVersion': 5
            }
        ],
        'pageToken': 'nextPageToken'
    }
}

Rewriter

askAi

  • Sends a model, prompt, and text to Velt’s AI rewriter and returns the transformed text.
  • Params: AskAiRequest
  • Returns: AskAiResponse
from velt_py.models.rewriter import AskAiRequest

result = sdk.api.rewriter.askAi(
    AskAiRequest(
        model='gpt-4o',
        prompt='Fix the grammar and spelling in the following text.',
        text='Their going to the store to by some apples.'
    )
)
Response
{
    'result': {
        'success': True,
        'text': "They're going to the store to buy some apples."
    }
}
Note: This call may take several seconds and has no client-side timeout. Wrap calls in your own timeout if needed.

GDPR

deleteAllUserData

from velt_py.models.gdpr import DeleteAllUserDataRequest

result = sdk.api.gdpr.deleteAllUserData(
    DeleteAllUserDataRequest(
        userIds=['user-1', 'user-2'],
        organizationIds=['org-123']
    )
)
Response
{
    'status': 'success',
    'message': 'Data deletion process has been initiated.',
    'data': {
        'jobId': 'dsQuvPmIynANgPLLEhCm',
        'tasksCount': 5
    },
    'statusCode': 202
}
Note: This call is asynchronous and returns a jobId. Poll status via getDeleteUserDataStatus.

getAllUserData

from velt_py.models.gdpr import GetAllUserDataRequest

result = sdk.api.gdpr.getAllUserData(
    GetAllUserDataRequest(
        organizationId='org-123',
        userId='user-1',
        pageToken='next-page-token'
    )
)
Response
{
    'result': {
        'status': 'success',
        'message': 'Data fetched successfully.',
        'data': {
            'comments': [],       # Up to 100 items per page.
            'reactions': [],      # Up to 100 items per page.
            'recordings': [],     # Up to 100 items per page.
            'notifications': []   # Up to 100 items per page.
        },
        'nextPageToken': 'bhdwdqwjs298e39e479ddkeuw==329'
    }
}

getDeleteUserDataStatus

from velt_py.models.gdpr import GetDeleteUserDataStatusRequest

result = sdk.api.gdpr.getDeleteUserDataStatus(
    GetDeleteUserDataStatusRequest(jobId='job-id-from-delete-call')
)
Response
{
    'result': {
        'status': 'success',
        'message': 'Data fetched successfully.',
        'data': {
            'isDeleteCompleted': True,
            'tasksLeft': 0,
            'lastTaskCompletedTime': 1748972106739
        }
    }
}

Workspace

createWorkspace

from velt_py.models.workspace import CreateWorkspaceRequest

result = sdk.api.workspace.createWorkspace(
    CreateWorkspaceRequest(
        ownerEmail='owner@example.com',
        workspaceName='My Workspace',
        name='John Doe'
    )
)
Response
{
    'result': {
        'status': 'success',
        'message': 'Workspace created successfully.',
        'data': {
            'id': 'workspace_abc123',
            'name': 'My Workspace',
            'owner': {
                'email': 'owner@example.com',
                'id': 'owner_id_123',
                'name': 'John Doe',
                'avatar': ''
            },
            'authToken': 'eyJhbGciOiJSUzI1NiIs...',
            'apiKeyList': {
                'velt_api_key_1': {
                    'apiKeyName': 'John Doe Test API Key',
                    'id': 'velt_api_key_1',
                    'type': 'testing'
                }
            }
        }
    }
}

getWorkspace

from velt_py.models.workspace import GetWorkspaceRequest

result = sdk.api.workspace.getWorkspace(GetWorkspaceRequest())
Response
{
    'result': {
        'status': 'success',
        'message': 'Workspace retrieved successfully.',
        'data': {
            'id': 'workspace_abc123',
            'name': 'My Workspace',
            'owner': {
                'email': 'owner@example.com',
                'id': 'owner_id_123',
                'name': 'John Doe',
                'avatar': ''
            },
            'authToken': 'eyJhbGciOiJSUzI1NiIs...',
            'apiKeyList': {
                'velt_api_key_1': {
                    'apiKeyName': 'John Doe Test API Key',
                    'id': 'velt_api_key_1',
                    'type': 'testing'
                }
            }
        }
    }
}

createApiKey

from velt_py.models.workspace import CreateApiKeyRequest

result = sdk.api.workspace.createApiKey(
    CreateApiKeyRequest(
        ownerEmail='owner@example.com',
        type='production',
        createAuthToken=True,
        apiKeyName='Production Key',
        allowedDomains=['example.com', '*.example.com']
    )
)
Response
{
    'result': {
        'status': 'success',
        'message': 'API key created successfully.',
        'data': { 'apiKey': 'your_new_api_key' }
    }
}

updateApiKey

from velt_py.models.workspace import UpdateApiKeyRequest

result = sdk.api.workspace.updateApiKey(
    UpdateApiKeyRequest(apiKey='velt_api_key_1', apiKeyName='Renamed Key')
)
Response
{
    'result': {
        'status': 'success',
        'message': 'API key updated successfully.',
        'data': None
    }
}

getApiKeys

from velt_py.models.workspace import GetApiKeysRequest

result = sdk.api.workspace.getApiKeys(
    GetApiKeysRequest(pageSize=50, pageToken='next-page-token')
)
Response
{
    'result': {
        'status': 'success',
        'message': 'API keys retrieved successfully.',
        'data': [
            {'id': 'velt_api_key_1', 'apiKeyName': 'Production Key', 'type': 'production'},
            {'id': 'velt_api_key_2', 'apiKeyName': 'Testing Key', 'type': 'testing'}
        ],
        'nextPageToken': 'eyJsYXN0SWQiOiJ2ZWx0X2FwaV9rZXlfMiJ9'
    }
}

getApiKeyMetadata

  • Gets metadata for the API key the SDK is authenticated with.
  • Params: GetApiKeyMetadataRequest
  • Returns: GetApiKeyMetadataResponse
  • Fixed in v0.1.11: now targets the canonical /v2/workspace/apikeyconfig/get endpoint (was /v2/workspace/apikeymetadata/get, retained as a legacy backend alias). Method signature is unchanged — no call-site change needed.
from velt_py.models.workspace import GetApiKeyMetadataRequest

result = sdk.api.workspace.getApiKeyMetadata(GetApiKeyMetadataRequest())
Response
{
    'result': {
        'status': 'success',
        'message': 'API key metadata retrieved successfully.',
        'data': {
            'defaultDocumentAccessType': 'public',
            'planInfo': {'type': 'sdk test'},
            'ownerEmail': 'owner@example.com'
        }
    }
}

resetAuthToken

from velt_py.models.workspace import ResetAuthTokenRequest

result = sdk.api.workspace.resetAuthToken(
    ResetAuthTokenRequest(apiKey='velt_api_key_1')
)
Response
{
    'result': {
        'status': 'success',
        'message': 'Auth token reset successfully.',
        'data': {
            'apiKey': 'velt_api_key_1',
            'newAuthToken': {
                'token': 'eyJhbGciOiJSUzI1NiIs...',
                'name': 'Default Auth Token',
                'domains': []
            }
        }
    }
}

getAuthTokens

from velt_py.models.workspace import GetAuthTokensRequest

result = sdk.api.workspace.getAuthTokens(
    GetAuthTokensRequest(apiKey='velt_api_key_1')
)
Response
{
    'result': {
        'status': 'success',
        'message': 'Auth tokens retrieved successfully.',
        'data': {
            'apiKey': 'velt_api_key_1',
            'authTokens': [
                {'token': 'eyJhbGciOiJSUzI1NiIs...', 'name': 'Default Auth Token', 'domains': []}
            ]
        }
    }
}

addDomains

from velt_py.models.workspace import AddDomainsRequest

result = sdk.api.workspace.addDomains(
    AddDomainsRequest(domains=['google.com', '*.firebase.com'])
)
Response
{
    'result': {
        'status': 'success',
        'message': 'Domain(s) added successfully to allowed domains.',
        'data': {
            'domainsAdded': ['google.com', '*.firebase.com']
        }
    }
}

deleteDomains

from velt_py.models.workspace import DeleteDomainsRequest

result = sdk.api.workspace.deleteDomains(
    DeleteDomainsRequest(domains=['google.com', '*.firebase.com'])
)
Response
{
    'result': {
        'status': 'success',
        'message': 'Domain(s) removed successfully from allowed domains.',
        'data': {
            'domainsRemoved': ['google.com', '*.firebase.com']
        }
    }
}

getDomains

from velt_py.models.workspace import GetDomainsRequest

result = sdk.api.workspace.getDomains(GetDomainsRequest())
Response
{
    'result': {
        'status': 'success',
        'message': 'Allowed domains retrieved successfully.',
        'data': {
            'allowedDomains': ['localhost', '127.0.0.1', 'example.com']
        }
    }
}

getEmailStatus

from velt_py.models.workspace import GetEmailStatusRequest

result = sdk.api.workspace.getEmailStatus(
    GetEmailStatusRequest(ownerEmail='owner@example.com')
)
Response
{
    'result': {
        'status': 'success',
        'message': 'Email verified and workspace reactivated',
        'data': { 'verified': True }
    }
}
from velt_py.models.workspace import SendLoginLinkRequest

result = sdk.api.workspace.sendLoginLink(
    SendLoginLinkRequest(email='user@example.com', continueUrl='https://app.example.com/dashboard')
)
Response
{
    'result': {
        'status': 'success',
        'message': 'Login link sent successfully.',
        'data': None
    }
}

getEmailConfig

from velt_py.models.workspace import GetEmailConfigRequest

result = sdk.api.workspace.getEmailConfig(GetEmailConfigRequest())
Response
{
    'result': {
        'status': 'success',
        'message': 'Email configuration retrieved successfully.',
        'data': {
            'useEmailService': False,
            'emailServiceConfig': {
                'type': 'default',
                'apiKey': '',
                'fromEmail': '',
                'fromCompany': '',
                'commentTemplateId': '',
                'tagTemplateId': ''
            }
        }
    }
}

updateEmailConfig

from velt_py.models.workspace import UpdateEmailConfigRequest

result = sdk.api.workspace.updateEmailConfig(
    UpdateEmailConfigRequest(
        useEmailService=True,
        emailServiceConfig={'type': 'sendgrid', 'apiKey': 'sg-key', 'fromEmail': 'noreply@example.com'}
    )
)
Response
{
    'result': {
        'status': 'success',
        'message': 'Email configuration updated successfully.',
        'data': None
    }
}

getWebhookConfig

from velt_py.models.workspace import GetWebhookConfigRequest

result = sdk.api.workspace.getWebhookConfig(GetWebhookConfigRequest())
Response
{
    'result': {
        'status': 'success',
        'message': 'Webhook configuration retrieved successfully.',
        'data': {
            'useWebhookService': False,
            'webhookServiceConfig': {
                'authToken': '',
                'rawNotificationUrl': '',
                'processedNotificationUrl': ''
            }
        }
    }
}

updateWebhookConfig

from velt_py.models.workspace import UpdateWebhookConfigRequest

result = sdk.api.workspace.updateWebhookConfig(
    UpdateWebhookConfigRequest(
        useWebhookService=True,
        webhookServiceConfig={
            'authToken': 'webhook-secret',
            'rawNotificationUrl': 'https://example.com/webhook/raw',
            'processedNotificationUrl': 'https://example.com/webhook/processed'
        }
    )
)
Response
{
    'result': {
        'status': 'success',
        'message': 'Webhook configuration updated successfully.',
        'data': None
    }
}

getRequestedDomains

  • Gets requested (pending) domains.
  • Params: GetRequestedDomainsRequest (from velt_py.models.workspace)
  • Returns: VeltApiResponse
from velt_py.models.workspace import GetRequestedDomainsRequest

result = sdk.api.workspace.getRequestedDomains(GetRequestedDomainsRequest())

createDomainRequest

  • Creates a domain access request.
  • Params: CreateDomainRequest (from velt_py.models.workspace)
  • Returns: VeltApiResponse
from velt_py.models.workspace import CreateDomainRequest

result = sdk.api.workspace.createDomainRequest(
    CreateDomainRequest(domain='https://example.com')
)

acceptRejectAdditionalUrlRequest

  • Accepts or rejects an additional-URL request.
  • Params: AcceptRejectAdditionalUrlRequest (from velt_py.models.workspace)
  • Returns: VeltApiResponse
from velt_py.models.workspace import AcceptRejectAdditionalUrlRequest

result = sdk.api.workspace.acceptRejectAdditionalUrlRequest(
    AcceptRejectAdditionalUrlRequest(action='accept', id='request-1', clientDocId='doc-1')
)

copyApiKey

  • Copies configuration from one API key to another (workspace-scoped).
  • Params: CopyApiKeyRequest (from velt_py.models.workspace)
  • Returns: VeltApiResponse
from velt_py.models.workspace import CopyApiKeyRequest

result = sdk.api.workspace.copyApiKey(
    CopyApiKeyRequest(sourceApiKey='velt_api_key_1', targetApiKey='velt_api_key_2')
)

updateApiKeyMetadata

  • Updates API key app configuration (private comments, JWT, default access, AI keys).
  • Params: UpdateApiKeyMetadataRequest (from velt_py.models.workspace)
  • Returns: VeltApiResponse
from velt_py.models.workspace import UpdateApiKeyMetadataRequest

result = sdk.api.workspace.updateApiKeyMetadata(
    UpdateApiKeyMetadataRequest(defaultDocumentAccessType='organizationPrivate')
)

getNotificationConfig

  • Gets the workspace notification service config.
  • Params: GetWorkspaceNotificationConfigRequest (from velt_py.models.workspace)
  • Returns: VeltApiResponse
from velt_py.models.workspace import GetWorkspaceNotificationConfigRequest

result = sdk.api.workspace.getNotificationConfig(GetWorkspaceNotificationConfigRequest())

updateNotificationConfig

  • Updates the workspace notification service config.
  • Params: UpdateWorkspaceNotificationConfigRequest (from velt_py.models.workspace)
  • Returns: VeltApiResponse
from velt_py.models.workspace import UpdateWorkspaceNotificationConfigRequest

result = sdk.api.workspace.updateNotificationConfig(
    UpdateWorkspaceNotificationConfigRequest(useNotificationService=True)
)

getPermissionProviderConfig

  • Gets the permission provider config.
  • Params: GetPermissionProviderConfigRequest (from velt_py.models.workspace)
  • Returns: VeltApiResponse
from velt_py.models.workspace import GetPermissionProviderConfigRequest

result = sdk.api.workspace.getPermissionProviderConfig(GetPermissionProviderConfigRequest())

updatePermissionProviderConfig

  • Updates the permission provider config.
  • Params: UpdatePermissionProviderConfigRequest (from velt_py.models.workspace)
  • Returns: VeltApiResponse
from velt_py.models.workspace import UpdatePermissionProviderConfigRequest

result = sdk.api.workspace.updatePermissionProviderConfig(
    UpdatePermissionProviderConfigRequest(usePermissionProvider=True)
)

getActivityConfig

  • Gets the activity logs config.
  • Params: GetActivityConfigRequest (from velt_py.models.workspace)
  • Returns: VeltApiResponse
from velt_py.models.workspace import GetActivityConfigRequest

result = sdk.api.workspace.getActivityConfig(GetActivityConfigRequest())

updateActivityConfig

  • Updates the activity logs config.
  • Params: UpdateActivityConfigRequest (from velt_py.models.workspace)
  • Returns: VeltApiResponse
from velt_py.models.workspace import UpdateActivityConfigRequest

result = sdk.api.workspace.updateActivityConfig(
    UpdateActivityConfigRequest(activityServiceConfig={'isEnabled': True})
)

getAdvancedWebhookConfig

  • Gets the advanced (Svix) webhook config.
  • Params: GetAdvancedWebhookConfigRequest (from velt_py.models.workspace)
  • Returns: VeltApiResponse
from velt_py.models.workspace import GetAdvancedWebhookConfigRequest

result = sdk.api.workspace.getAdvancedWebhookConfig(GetAdvancedWebhookConfigRequest())

updateAdvancedWebhookConfig

  • Updates the advanced (Svix) webhook config.
  • Params: UpdateAdvancedWebhookConfigRequest (from velt_py.models.workspace)
  • Returns: VeltApiResponse
from velt_py.models.workspace import UpdateAdvancedWebhookConfigRequest

result = sdk.api.workspace.updateAdvancedWebhookConfig(
    UpdateAdvancedWebhookConfigRequest(isEnabled=True)
)

getAdvancedWebhookEndpoints

  • Lists advanced webhook endpoints.
  • Params: GetAdvancedWebhookEndpointsRequest (from velt_py.models.workspace)
  • Returns: VeltApiResponse
from velt_py.models.workspace import GetAdvancedWebhookEndpointsRequest

result = sdk.api.workspace.getAdvancedWebhookEndpoints(GetAdvancedWebhookEndpointsRequest())

createAdvancedWebhookEndpoint

  • Creates an advanced webhook endpoint.
  • Params: CreateAdvancedWebhookEndpointRequest (from velt_py.models.workspace)
  • Returns: VeltApiResponse
from velt_py.models.workspace import CreateAdvancedWebhookEndpointRequest

result = sdk.api.workspace.createAdvancedWebhookEndpoint(
    CreateAdvancedWebhookEndpointRequest(url='https://example.com/webhook')
)

updateAdvancedWebhookEndpoint

  • Updates an advanced webhook endpoint.
  • Params: UpdateAdvancedWebhookEndpointRequest (from velt_py.models.workspace)
  • Returns: VeltApiResponse
from velt_py.models.workspace import UpdateAdvancedWebhookEndpointRequest

result = sdk.api.workspace.updateAdvancedWebhookEndpoint(
    UpdateAdvancedWebhookEndpointRequest(endpointId='endpoint-1', url='https://example.com/webhook/v2')
)

deleteAdvancedWebhookEndpoint

  • Deletes an advanced webhook endpoint.
  • Params: DeleteAdvancedWebhookEndpointRequest (from velt_py.models.workspace)
  • Returns: VeltApiResponse
from velt_py.models.workspace import DeleteAdvancedWebhookEndpointRequest

result = sdk.api.workspace.deleteAdvancedWebhookEndpoint(
    DeleteAdvancedWebhookEndpointRequest(endpointId='endpoint-1')
)

getAdvancedWebhookEndpointSecret

  • Gets an advanced webhook endpoint’s signing secret.
  • Params: GetAdvancedWebhookEndpointSecretRequest (from velt_py.models.workspace)
  • Returns: VeltApiResponse
from velt_py.models.workspace import GetAdvancedWebhookEndpointSecretRequest

result = sdk.api.workspace.getAdvancedWebhookEndpointSecret(
    GetAdvancedWebhookEndpointSecretRequest(endpointId='endpoint-1')
)

ensureWorkspaceAuthToken

  • Ensures a workspace auth token exists (workspace-scoped).
  • Params: EnsureWorkspaceAuthTokenRequest (from velt_py.models.workspace)
  • Returns: VeltApiResponse
from velt_py.models.workspace import EnsureWorkspaceAuthTokenRequest

result = sdk.api.workspace.ensureWorkspaceAuthToken(EnsureWorkspaceAuthTokenRequest())

Workflow

A new service for the Approval Engine / workflow orchestration: definitions, executions, lifecycle events, and step resolution (/v2/workflow/*). 14 methods. Request types are imported from velt_py.models.workflow.
from velt_py.models.workflow import (
    CreateWorkflowDefinitionRequest, GetWorkflowDefinitionRequest, ListWorkflowDefinitionsRequest,
    DispatchExecutionRequest, GetExecutionRequest, ListExecutionsRequest,
    ResolveStepRequest, RecordReviewerDecisionRequest
)

createDefinition

  • Creates a workflow definition.
  • Params: CreateWorkflowDefinitionRequest (from velt_py.models.workflow)
  • Returns: VeltApiResponse
result = sdk.api.workflow.createDefinition(
    CreateWorkflowDefinitionRequest(
        definitionId='doc-approval', name='Document Approval',
        nodes=[{'nodeId': 'review', 'type': 'human', 'config': {'reviewers': [{'userId': 'reviewer-1', 'mandatory': True}]}}],
        edges=[]
    )
)

updateDefinition

  • Updates a workflow definition. Supports optimistic concurrency via ifVersion.
  • Params: UpdateWorkflowDefinitionRequest (from velt_py.models.workflow)
  • Returns: VeltApiResponse
from velt_py.models.workflow import UpdateWorkflowDefinitionRequest

result = sdk.api.workflow.updateDefinition(
    UpdateWorkflowDefinitionRequest(
        definitionId='doc-approval',
        name='Document Approval v2',
        nodes=[{'nodeId': 'review', 'type': 'human', 'config': {'reviewers': [{'userId': 'reviewer-1', 'mandatory': True}]}}],
        edges=[],
        ifVersion=1
    )
)

deleteDefinition

  • Deletes a workflow definition.
  • Params: DeleteWorkflowDefinitionRequest (from velt_py.models.workflow)
  • Returns: VeltApiResponse
from velt_py.models.workflow import DeleteWorkflowDefinitionRequest

result = sdk.api.workflow.deleteDefinition(
    DeleteWorkflowDefinitionRequest(definitionId='doc-approval')
)

getDefinition

  • Gets a workflow definition.
  • Params: GetWorkflowDefinitionRequest (from velt_py.models.workflow)
  • Returns: VeltApiResponse
result = sdk.api.workflow.getDefinition(GetWorkflowDefinitionRequest(definitionId='doc-approval'))

listDefinitions

  • Lists workflow definitions.
  • Params: ListWorkflowDefinitionsRequest (from velt_py.models.workflow)
  • Returns: VeltApiResponse
result = sdk.api.workflow.listDefinitions(ListWorkflowDefinitionsRequest(pageSize=20))

dispatchExecution

  • Dispatches a workflow execution.
  • Params: DispatchExecutionRequest (from velt_py.models.workflow)
  • Returns: VeltApiResponse
result = sdk.api.workflow.dispatchExecution(
    DispatchExecutionRequest(definitionId='doc-approval', idempotencyKey='order-12345', triggerContext={'orderId': '12345'})
)

cancelExecution

  • Cancels a workflow execution.
  • Params: CancelExecutionRequest (from velt_py.models.workflow)
  • Returns: VeltApiResponse
from velt_py.models.workflow import CancelExecutionRequest

result = sdk.api.workflow.cancelExecution(CancelExecutionRequest(executionId='execution-id'))

getExecution

  • Gets a workflow execution.
  • Params: GetExecutionRequest (from velt_py.models.workflow)
  • Returns: VeltApiResponse
result = sdk.api.workflow.getExecution(GetExecutionRequest(executionId='execution-id'))

getExecutionEvents

  • Gets lifecycle events for an execution (paginated).
  • Params: GetExecutionEventsRequest (from velt_py.models.workflow)
  • Returns: VeltApiResponse
from velt_py.models.workflow import GetExecutionEventsRequest

result = sdk.api.workflow.getExecutionEvents(
    GetExecutionEventsRequest(executionId='execution-id', pageSize=50)
)

listExecutions

  • Lists workflow executions.
  • Params: ListExecutionsRequest (from velt_py.models.workflow)
  • Returns: VeltApiResponse
result = sdk.api.workflow.listExecutions(
    ListExecutionsRequest(definitionId='doc-approval', status='running')
)

cancelStep

  • Cancels a step within an execution.
  • Params: CancelStepRequest (from velt_py.models.workflow)
  • Returns: VeltApiResponse
from velt_py.models.workflow import CancelStepRequest

result = sdk.api.workflow.cancelStep(
    CancelStepRequest(executionId='execution-id', stepId='step-id')
)

resolveStep

  • Resolves a step (admin/reviewer override).
  • Params: ResolveStepRequest (from velt_py.models.workflow)
  • Returns: VeltApiResponse
result = sdk.api.workflow.resolveStep(
    ResolveStepRequest(executionId='execution-id', stepId='step-id', action='force-approve', actorId='admin-1')
)

recordAgentResolution

  • Records an agent resolution against a blocking-agent step.
  • Params: RecordAgentResolutionRequest (from velt_py.models.workflow)
  • Returns: VeltApiResponse
from velt_py.models.workflow import RecordAgentResolutionRequest

result = sdk.api.workflow.recordAgentResolution(
    RecordAgentResolutionRequest(executionId='execution-id', stepId='step-id', responseId='response-1', resolution='resolved', actorId='agent-1')
)

recordReviewerDecision

  • Records a reviewer decision against a human step.
  • Params: RecordReviewerDecisionRequest (from velt_py.models.workflow)
  • Returns: VeltApiResponse
result = sdk.api.workflow.recordReviewerDecision(
    RecordReviewerDecisionRequest(executionId='execution-id', stepId='step-id', reviewerId='reviewer-1', decision='approve')
)

Token

getToken

  • Generates a Velt auth token for a user.
  • Params: positional — organizationId, userId, email (optional), isAdmin (optional)
  • Returns: VeltApiResponse
result = sdk.api.token.getToken(
    organizationId='org-123',
    userId='user-1',
    email='user@example.com',
    isAdmin=False
)
Response
{
    'result': {
        'status': 'success',
        'data': { 'token': 'eyJhbGciOi...' }
    }
}
Note: getToken takes positional / keyword arguments — it does NOT accept a dataclass request object. Signature: getToken(organizationId, userId, email=None, isAdmin=False).

Data Isolation

Every sdk.api.* method requires an organizationId in its request payload. Velt’s API enforces data isolation server-side — requests without a valid organizationId will be rejected.

Error Handling

The SDK raises typed exceptions for different failure modes. All exceptions extend VeltSDKError.
ExceptionWhen raised
VeltSDKErrorBase class; catch for any SDK-level error
VeltValidationErrorSDK-level validation (e.g., missing required config); sdk.api.* methods do not validate request payloads locally
VeltTokenErrorToken generation or authentication failure
VeltApiErrorREST API errors (network failures, unexpected responses)
from velt_py.exceptions import VeltSDKError, VeltApiError

try:
    result = sdk.api.organizations.addOrganizations(
        AddOrganizationsRequest(organizations=[{'organizationId': 'org-123'}])
    )
except VeltApiError as e:
    print(f'API error: {e.message}')
except VeltSDKError as e:
    print(f'SDK error: {e.message}')
Import path: from velt_py.exceptions import VeltSDKError, VeltValidationError, VeltTokenError, VeltApiError Common self-hosting error codes returned in the response errorCode field:
  • INVALID_INPUT — Request data is malformed or missing required fields
  • INTERNAL_ERROR — Server-side error during processing
  • NOT_FOUND — Requested resource was not found

Data Models

Python-SDK-specific dataclasses used by the self-hosting backend. These are not in the shared API reference because they are only relevant to sdk.selfHosting.* implementations.

PartialCommentAnnotation

Represents a partial update payload for a comment annotation. Starting in v0.1.10, from, assignedTo, targetTextRange, and resolvedByUserId are first-class typed fields (previously silent pass-through via extra_fields).
from velt_py.models import (
    PartialCommentAnnotation,
    PartialTargetTextRange,
    PartialUser,
    PartialComment,
    BaseMetadata,
)
from velt_py.models.comment import UNSET

@dataclass
class PartialCommentAnnotation:
    annotationId: str
    metadata: Optional[BaseMetadata] = None
    comments: Optional[Dict[str, PartialComment]] = None
    from_: Optional[PartialUser] = None             # 'from' on the wire; from_ avoids Python keyword.
    assignedTo: Optional[PartialUser] = None
    targetTextRange: Optional[PartialTargetTextRange] = None
    resolvedByUserId: Any = UNSET                   # Tri-state: UNSET | None | str. See below.
    extra_fields: Optional[Dict[str, Any]] = None   # Catch-all for customer-configured custom keys.
Field notes
  • from_ — Python alias for the JSON key from (reserved keyword). Serialized as from in the Mongo document.
  • assignedTo — Typed as PartialUser. Omit to leave unchanged; the Mongo write skips the field when None.
  • targetTextRange — Typed PartialTargetTextRange for the selected text snippet a comment is anchored to.
  • resolvedByUserId — See UNSET sentinel for the difference between absent (UNSET) and explicit None.
  • extra_fields — Retained as a catch-all because the frontend contract includes [key: string]: any for customer-configured fieldsToRemove and additionalFields.

PartialReactionAnnotation

Represents a partial update payload for a reaction annotation. Starting in v0.1.12, the reaction-author field is from_ (wire key from), replacing the former user field — aligning with the velt-sdk contract and PartialCommentAnnotation.
from velt_py.models.reaction import PartialReactionAnnotation
from velt_py.models.user import PartialUser

@dataclass
class PartialReactionAnnotation:
    annotationId: str
    metadata: Optional[BaseMetadata] = None
    icon: Optional[str] = None
    from_: Optional[PartialUser] = None             # 'from' on the wire; from_ avoids the Python keyword. Replaces the former 'user' field.
    extra_fields: Optional[Dict[str, Any]] = None   # Catch-all for customer-configured custom keys.
Field notes
  • from_ — Python alias for the JSON key from (reserved keyword); serialized as from. Replaces the former user field (renamed in v0.1.12 to match the velt-sdk contract and the comment models). Constructing with user= no longer works — use from_=.
  • Backward-compatible reads: from_dict() accepts either the canonical from key or the legacy user key (from wins when both are present) and populates from_. to_dict() always emits from. No data migration is required for reaction documents already stored under user.
# Legacy document stored under the old `user` key still resolves:
ann = PartialReactionAnnotation.from_dict({'annotationId': 'r-1', 'icon': '+1', 'user': {'userId': 'u-legacy'}})
ann.from_.userId         # 'u-legacy'
ann.to_dict()['from']    # {'userId': 'u-legacy'}  (re-serialized as `from`)
# Before (v0.1.11 and earlier):
PartialReactionAnnotation(annotationId='r-1', icon='+1', user=PartialUser(userId='u-1'))    # -> {'user': {...}}
# After (v0.1.12):
PartialReactionAnnotation(annotationId='r-1', icon='+1', from_=PartialUser(userId='u-1'))   # -> {'from': {...}}

PartialTargetTextRange

Anchors a comment to a selected text snippet.
from velt_py.models import PartialTargetTextRange

@dataclass
class PartialTargetTextRange:
    text: str = ''        # The selected text content.

UNSET Sentinel

UNSET is a sentinel value exported from velt_py.models.comment. It signals that a field was not included in the incoming request payload and should be skipped entirely during the MongoDB write.
from velt_py.models.comment import UNSET

# Field absent from payload → UNSET → field is NOT written to Mongo
annotation = PartialCommentAnnotation()
# annotation.resolvedByUserId is UNSET → Mongo $set will not include this field

# Field explicitly set to None → None → field IS written as null to Mongo
annotation = PartialCommentAnnotation(resolvedByUserId=None)
# annotation.resolvedByUserId is None → Mongo $set writes null (frontend unresolve action)
ValuePayloadMongo write
UNSETField absentField skipped — no change
NoneField present, value nullField written as null

BaseMetadata

Base metadata attached to every comment annotation. Starting in v0.1.10, sdkVersion and documentMetadata are fully modeled and preserved in MongoDB writes. These fields were previously sent by the frontend on every annotation save but silently dropped.
@dataclass
class BaseMetadata:
    apiKey: Optional[str] = None
    documentId: Optional[str] = None
    clientDocumentId: Optional[str] = None
    organizationId: Optional[str] = None
    clientOrganizationId: Optional[str] = None
    folderId: Optional[str] = None
    veltFolderId: Optional[str] = None
    documentMetadata: Optional[Dict[str, Any]] = None   # New in v0.1.10.
    sdkVersion: Optional[str] = None                    # New in v0.1.10.
No import change is required — BaseMetadata is populated automatically from the incoming request payload. The fix applies transparently to all saveComments calls.

VerifyTokenResult

Structured result returned by sdk.selfHosting.verifyToken. New in v0.1.14. Module: velt_py.models.resolver_auth; exported from velt_py and velt_py.models.
from velt_py.models import VerifyTokenResult

@dataclass
class VerifyTokenResult:
    verified: bool
    claims: Optional[Dict] = None
    error: Optional[str] = None
    errorCode: Optional[str] = None
Field notes
  • verifiedTrue only when a token was present and fully verified, or a custom callback returned non-None claims.
  • claims — Decoded payload when verified; otherwise None.
  • error — Generic, code-based message; never contains the token or secret.
  • errorCode — One of: MISSING_TOKEN, EXPIRED, INVALID_SIGNATURE, CLAIM_MISMATCH, ALGORITHM_NOT_ALLOWED, KEY_RESOLUTION_FAILED, VERIFICATION_FAILED, NOT_CONFIGURED, DEPENDENCY_MISSING.

CommentResolverSaveEvent

Enum of comment save-resolver actions the frontend forwards to your save handler. New in v0.1.14. A (str, Enum) exported from velt_py and velt_py.models; wire values are byte-identical to the upstream frontend enum.
from velt_py import CommentResolverSaveEvent
from velt_py.models import CommentResolverSaveEvent  # same class
MemberWire value
STATUS_CHANGEcomment_annotation.status_change
PRIORITY_CHANGEcomment_annotation.priority_change
ASSIGNcomment_annotation.assign
ACCESS_MODE_CHANGEcomment_annotation.access_mode_change
CUSTOM_LIST_CHANGEcomment_annotation.custom_list_change
APPROVEcomment_annotation.approve
ACCEPTcomment.accept
REJECTcomment.reject
SUGGESTION_ACCEPTcomment_annotation.suggestion_accept
SUGGESTION_REJECTcomment_annotation.suggestion_reject
REACTION_ADDcomment.reaction_add
REACTION_DELETEcomment.reaction_delete
SUBSCRIBEcomment_annotation.subscribe
UNSUBSCRIBEcomment_annotation.unsubscribe
Parse orderSaveCommentResolverRequest.from_dict tries ResolverActions FIRST (preserving every existing value), then CommentResolverSaveEvent, then keeps the raw string for unknown future values. DistinctnessCommentResolverSaveEvent.REACTION_ADD (comment.reaction_add) is distinct from ResolverActions.REACTION_ADD (reaction.add, the reaction-resolver action); the parse order routes each correctly.

SaveCommentResolverRequest

The full shared shape is documented in the API reference. This entry covers only the v0.1.14 additions — additive; existing payloads parse byte-identically.
from velt_py import SaveCommentResolverRequest, CommentResolverSaveEvent

request = SaveCommentResolverRequest.from_dict(data)
if request.targetComment is not None:
    print(request.targetComment.commentId)   # request context — NOT written to MongoDB
sdk.selfHosting.comments.saveComments(request)
Field notes
  • targetComment: Optional[PartialComment] — The comment the action occurred on, resolved by the frontend from commentId. from_dict parses it fail-open (a malformed/partial dict never raises). to_dict emits it only when not None. saveComments NEVER persists it (request context only).
  • event: Optional[Union[ResolverActions, CommentResolverSaveEvent, str]] — Widened. Every existing ResolverActions value still parses to the same member. Parse order: ResolverActions first, then CommentResolverSaveEvent, then raw string for unknown future values.

Resources