Overview
The Velt Python SDK exposes two independent backends:
| Backend | Namespace | Use case |
|---|
| Self-hosting | sdk.selfHosting.* | Store Velt data in your own MongoDB + AWS S3 |
| REST API | sdk.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:
- Pass your DB and storage configs to the SDK
- Pass the raw request object directly to SDK methods
- 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
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)
REST API-only initialization (no database needed):from velt_py import VeltSDK
# Minimal config for REST API backend only
config = {
'apiKey': 'YOUR_VELT_API_KEY',
'authToken': 'YOUR_VELT_AUTH_TOKEN'
}
sdk = VeltSDK.initialize(config)
# All sdk.api.* services are now available
result = sdk.api.organizations.getOrganizations(...)
The database section is optional when using only sdk.api.*. Set VELT_API_KEY and VELT_AUTH_TOKEN environment variables as an alternative to passing credentials in the config dict.
Configuration
Environment Variables
The SDK reads the following environment variables automatically. These can be used instead of (or in addition to) config dict keys.
| Variable | Config key equivalent | Purpose |
|---|
VELT_API_KEY | apiKey | Velt API key for authenticating REST API calls |
VELT_AUTH_TOKEN | authToken | Velt auth token for authenticating REST API calls |
VELT_WORKSPACE_ID | — | Default workspace ID for workspace-scoped operations |
VELT_WORKSPACE_AUTH_TOKEN | — | Auth token scoped to a specific workspace |
Self-Hosting Configuration
Database
AWS (Attachments)
Collections
User Schema
Resolver Auth
Complete Example
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'
}
}
Configure AWS S3 for storing file attachments.config = {
'aws': {
'bucket_name': 'your-bucket-name',
'region': 'us-east-1',
'access_key_id': 'YOUR_AWS_ACCESS_KEY',
'secret_access_key': 'YOUR_AWS_SECRET_KEY'
}
}
Customize collection names for storing Velt data.config = {
'collections': {
'comments': 'comment_annotations', # Default: 'comment_annotations'
'reactions': 'reaction_annotations', # Default: 'reaction_annotations'
'attachments': 'attachments', # Default: 'attachments'
'users': 'users' # Default: 'users'
}
}
Map your user schema fields to Velt’s expected fields if your database uses different field names.config = {
'user_schema': {
'userId': 'userId', # Your field name for user ID
'name': 'name', # Your field name for display name
'photoUrl': 'photoUrl', # Your field name for avatar URL
'email': 'email', # Your field name for email
'color': 'color', # Your field name for user color
'textColor': 'textColor', # Your field name for text color
'isAdmin': 'isAdmin', # Your field name for admin flag
'initial': 'initial' # Your field name for user initial
}
}
Optional resolver_auth block enabling sdk.selfHosting.verifyToken. The built-in JWT verifier requires pip install 'velt-py[auth]'; the custom verify callback needs no new dependency.config = {
'resolver_auth': {
# Built-in JWT verifier (HS256 example):
'jwt': {
'secret': 'your-hmac-secret', # HS* — or for RS*/ES*:
# 'public_key': '-----BEGIN PUBLIC KEY-----...',
# 'jwks_url': 'https://your-idp/.well-known/jwks.json',
'algorithms': ['HS256'], # REQUIRED allowlist
'issuer': 'https://your-idp', # optional, enforced when set
'audience': 'velt', # optional, enforced when set
'leeway': 30, # optional clock skew (seconds)
# 'require': ['exp'], # optional: reject tokens missing these claims
},
# OR a custom escape hatch (takes priority over `jwt`):
# 'verify': lambda token, headers: my_decode(token), # return claims dict or None
}
}
See Resolver Token Verification for full detail. Full configuration with database, AWS, collections, and user schema.from velt_py import VeltSDK
config = {
'database': {
'connection_string': 'mongodb+srv://user:pass@cluster.mongodb.net/velt-db',
},
'aws': {
'bucket_name': 'your-bucket-name',
'region': 'us-east-1',
'access_key_id': 'YOUR_AWS_ACCESS_KEY',
'secret_access_key': 'YOUR_AWS_SECRET_KEY'
},
'collections': {
'comments': 'comment_annotations',
'reactions': 'reaction_annotations',
'attachments': 'attachments',
'users': 'users'
},
'user_schema': {
'userId': 'userId',
'name': 'name',
'photoUrl': 'photoUrl',
'email': 'email',
'color': 'color',
'textColor': 'textColor',
'isAdmin': 'isAdmin',
'initial': 'initial'
},
'apiKey': 'YOUR_VELT_API_KEY',
'authToken': 'YOUR_VELT_AUTH_TOKEN'
}
sdk = VeltSDK.initialize(config)
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,
)
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': [ ... ] }
}
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.
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)
import json
from flask import request, jsonify
from velt_py import SaveAttachmentResolverRequest
@app.route('/api/velt/attachments/save', methods=['POST'])
def save_attachment():
try:
file = request.files.get('file')
request_json = request.form.get('request')
if not file or not request_json:
return jsonify({
'success': False,
'error': 'File and request JSON are required',
'errorCode': 'INVALID_INPUT',
'statusCode': 400
}), 400
request_data = json.loads(request_json)
save_request = SaveAttachmentResolverRequest.from_dict(request_data)
result = sdk.selfHosting.attachments.saveAttachment(
save_request,
file_data=file.read(),
file_name=file.filename,
mime_type=file.content_type
)
return jsonify(result), result.get('statusCode', 200)
except Exception as e:
return jsonify({'success': False, 'error': str(e), 'errorCode': 'INTERNAL_ERROR', 'statusCode': 500}), 500
import json
from fastapi import Request, UploadFile, File, Form
from fastapi.responses import JSONResponse
from velt_py import SaveAttachmentResolverRequest
@app.post('/api/velt/attachments/save')
async def save_attachment(file: UploadFile = File(...), request: str = Form(...)):
try:
request_data = json.loads(request)
save_request = SaveAttachmentResolverRequest.from_dict(request_data)
file_bytes = await file.read()
result = sdk.selfHosting.attachments.saveAttachment(
save_request,
file_data=file_bytes,
file_name=file.filename,
mime_type=file.content_type
)
return JSONResponse(content=result, status_code=result.get('statusCode', 200))
except Exception as e:
return JSONResponse(content={'success': False, 'error': str(e), 'errorCode': 'INTERNAL_ERROR', 'statusCode': 500}, status_code=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)
from flask import request, jsonify
from velt_py import DeleteAttachmentResolverRequest
@app.route('/api/velt/attachments/delete', methods=['POST'])
def delete_attachment():
try:
data = request.json
delete_request = DeleteAttachmentResolverRequest.from_dict(data)
result = sdk.selfHosting.attachments.deleteAttachment(delete_request)
return jsonify(result), result.get('statusCode', 200)
except Exception as e:
return jsonify({'success': False, 'error': str(e), 'errorCode': 'INTERNAL_ERROR', 'statusCode': 500}), 500
from fastapi import Request
from fastapi.responses import JSONResponse
from velt_py import DeleteAttachmentResolverRequest
@app.post('/api/velt/attachments/delete')
async def delete_attachment(request: Request):
try:
data = await request.json()
delete_request = DeleteAttachmentResolverRequest.from_dict(data)
result = sdk.selfHosting.attachments.deleteAttachment(delete_request)
return JSONResponse(content=result, status_code=result.get('statusCode', 200))
except Exception as e:
return JSONResponse(content={'success': False, 'error': str(e), 'errorCode': 'INTERNAL_ERROR', 'statusCode': 500}, status_code=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)
| Code | When |
|---|
MISSING_TOKEN | No token found in header / not passed, empty, or wrong scheme. |
EXPIRED | Token exp is in the past. |
INVALID_SIGNATURE | Signature did not verify against the resolved key. |
CLAIM_MISMATCH | issuer, audience, or a required claim failed the check. |
ALGORITHM_NOT_ALLOWED | Token alg is not in the configured allowlist. |
KEY_RESOLUTION_FAILED | JWKS fetch / public_key / secret could not yield a usable key. |
VERIFICATION_FAILED | Generic verification failure not covered above. |
NOT_CONFIGURED | resolver_auth is not configured. |
DEPENDENCY_MISSING | Built-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 kid → KEY_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 JWKS —
jwks_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')
}
from flask import Flask, request, jsonify
from velt_py import VeltSDK, GetCommentResolverRequest, SaveCommentResolverRequest, DeleteCommentResolverRequest
app = Flask(__name__)
sdk = VeltSDK.initialize({
'database': { 'connection_string': 'mongodb+srv://...' }
})
@app.route('/api/velt/comments/get', methods=['POST'])
def get_comments():
data = request.json
comment_request = GetCommentResolverRequest.from_dict(data)
result = sdk.selfHosting.comments.getComments(comment_request)
return jsonify(result), result.get('statusCode', 200)
from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse
from velt_py import VeltSDK, GetCommentResolverRequest
app = FastAPI()
sdk = VeltSDK.initialize({
'database': { 'connection_string': 'mongodb+srv://...' }
})
@app.post('/api/velt/comments/get')
async def get_comments(request: Request):
data = await request.json()
comment_request = GetCommentResolverRequest.from_dict(data)
result = sdk.selfHosting.comments.getComments(comment_request)
return JSONResponse(content=result, status_code=result.get('statusCode', 200))
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.'
}
}
}
}
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.
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'
}
}
}
}
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'
}
}
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}
}
}
}
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'
}
}
}
}
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.'
}
}
}
}
- 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]
}
}
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'}
}
]
}
}
- 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'
}
}
}
}
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'
}
}
- 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 }
}
}
sendLoginLink
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')
)
- 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.
| Exception | When raised |
|---|
VeltSDKError | Base class; catch for any SDK-level error |
VeltValidationError | SDK-level validation (e.g., missing required config); sdk.api.* methods do not validate request payloads locally |
VeltTokenError | Token generation or authentication failure |
VeltApiError | REST 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.
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': {...}}
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)
| Value | Payload | Mongo write |
|---|
UNSET | Field absent | Field skipped — no change |
None | Field present, value null | Field written as null |
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
verified — True 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.
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
| Member | Wire value |
|---|
STATUS_CHANGE | comment_annotation.status_change |
PRIORITY_CHANGE | comment_annotation.priority_change |
ASSIGN | comment_annotation.assign |
ACCESS_MODE_CHANGE | comment_annotation.access_mode_change |
CUSTOM_LIST_CHANGE | comment_annotation.custom_list_change |
APPROVE | comment_annotation.approve |
ACCEPT | comment.accept |
REJECT | comment.reject |
SUGGESTION_ACCEPT | comment_annotation.suggestion_accept |
SUGGESTION_REJECT | comment_annotation.suggestion_reject |
REACTION_ADD | comment.reaction_add |
REACTION_DELETE | comment.reaction_delete |
SUBSCRIBE | comment_annotation.subscribe |
UNSUBSCRIBE | comment_annotation.unsubscribe |
Parse order — SaveCommentResolverRequest.from_dict tries ResolverActions FIRST (preserving every existing value), then CommentResolverSaveEvent, then keeps the raw string for unknown future values.
Distinctness — CommentResolverSaveEvent.REACTION_ADD (comment.reaction_add) is distinct from ResolverActions.REACTION_ADD (reaction.add, the reaction-resolver action); the parse order routes each correctly.
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