udServer API

The udServer API provides access for developers to integrate with or automate tasks in udServer.

All API endpoints are prefixed with /api/ (e.g. /api/_user/whoami).

All endpoints return a JSON object containing at minimum a success boolean. If success is false, a message field may provide additional detail.

Common message values:

  • serverfault — internal server error; check server logs
  • writefailure — a write operation failed
  • malformed — request was not in the expected format
  • badcredentials — username or password did not match
  • notfound — requested resource was not found
  • sessionexpired — the session is no longer valid

Authentication is provided via the apikey cookie (set at login) or an apikey field in the JSON body.

Note: There is an additional API at /api/sdk/xxx for udSDK communication that is not publicly documented.


Authentication (OAuth2)

/_oauth/login

Initiates the OAuth2 login flow, redirecting the browser to the configured OAuth provider.

  • Minimum Privilege: Public (no existing session)
  • Expected JSON: { provider: [string], email: [string], redirect: [string] }
    • provider required: The OAuth provider ID
    • email optional: Login hint for the provider
    • redirect optional: URL to redirect to after successful login
  • Response: HTTP redirect to OAuth provider

/_oauth/redirect

OAuth2 callback handler. Completes the login flow and sets the apikey cookie.

  • Minimum Privilege: Public
  • Query Params: code, state
  • Response: HTTP redirect to post-login page with apikey cookie set

/_oauth/logout

Ends the current session and clears the apikey cookie.

  • Minimum Privilege: User
  • Expected JSON: nothing additional
  • Response: HTTP redirect to home page

Current User

/_user/whoami

Returns information about the currently authenticated user.

  • Minimum Privilege: Public (returns limited info if unauthenticated)
  • Query Params: extended optional — if present, includes email and pending invites
  • JSON on Success: { id: [string], globalperms: [int], name: [string], language: [string], expires: [double], lastorgid: [string], needsAuthProvider: [bool], needsEULA: [bool], showWhatsNew: [bool] }
    • If extended: also includes email, emailoptin, invites

/_user/update

Updates the current user's profile, or another user's profile if the caller has the User Edit global permission.

  • Minimum Privilege: User
  • Expected JSON: { userid: [string], realname: [string], language: [string], globalPermissions: [int] }
    • userid optional: Defaults to the current user; requires User Edit global permission to update another user
    • globalPermissions optional: Requires admin-level global permission to set
  • JSON on Success: nothing additional

API Keys

/_user/apikeys/create

Creates a new API key for the current user.

  • Minimum Privilege: User
  • Expected JSON: { name: [string], expiryDays: [int] }
    • name: 1–30 characters
    • expiryDays: 0–720 (0 = no expiry)
  • JSON on Success: { newApiKey: { id: [string] } }

/_user/apikeys/delete

Deletes an API key belonging to the current user.

  • Minimum Privilege: User
  • Expected JSON: { apikey: [string] }
  • JSON on Success: nothing additional

/_user/apikeys/list

Lists all API keys for the current user.

  • Minimum Privilege: User
  • Expected JSON: nothing additional
  • JSON on Success: { apikeys: [array] }
    • Each item: { id: [string], name: [string], expires: [double], created: [double], lastaccess: [double], key: [string] }

Organisations

Organisations are the top-level grouping for users, projects, and assets.

/org/list

Lists all organisations the current user is a member of.

  • Minimum Privilege: User
  • Expected JSON: nothing additional
  • JSON on Success: { orgs: [array] }

/org/create

Creates a new organisation. Requires the "Only Admins Create Orgs" global permission if that setting is enabled.

  • Minimum Privilege: User (or Global Org Edit if restricted)
  • Expected JSON: { name: [string], orgid: [string] }
    • orgid optional: Custom organisation ID
  • JSON on Success: { orgid: [string] }

/:orgid/_get

Returns details of an organisation.

  • Minimum Privilege: Organisation Member
  • Expected JSON: nothing additional
  • JSON on Success: { org: { orgid: [string], name: [string], defaultpermissions: [int64], created: [int64], ispublic: [bool], pendingdelete: [bool], userpermissions: [int64] } }

/:orgid/_update

Updates organisation name or default member permissions.

  • Minimum Privilege: Organisation Owner
  • Expected JSON: { name: [string], defaultpermissions: [int64] }
    • Both fields are optional
  • JSON on Success: nothing additional

/:orgid/_transfer

Transfers ownership of the organisation to another user.

  • Minimum Privilege: Organisation Owner
  • Expected JSON: { userid: [string] }
  • JSON on Success: nothing additional

/:orgid/_icon

Sets the organisation icon.

  • Minimum Privilege: Organisation Owner
  • Expected JSON: multipart/form-data with icon file
  • JSON on Success: nothing additional

/:orgid/_delete

Marks the organisation for deletion.

  • Minimum Privilege: Organisation Owner
  • Expected JSON: nothing additional
  • JSON on Success: nothing additional

/:orgid/_recover

Cancels a pending organisation deletion.

  • Minimum Privilege: Organisation Owner
  • Expected JSON: nothing additional
  • JSON on Success: nothing additional

Organisation Roles

Roles define named sets of permissions that can be assigned to organisation members.

/:orgid/_roles/list

Lists all roles defined in the organisation.

  • Minimum Privilege: Organisation UserList
  • Expected JSON: nothing additional
  • JSON on Success: { roles: [array] }

/:orgid/_roles/update

Creates a new role or updates an existing one.

  • Minimum Privilege: Organisation UserEditRoles
  • Expected JSON: { create: [bool], roleid: [string], name: [string], permissions: [int64], projects: [array] }
    • roleid required if not creating: 4-character role identifier
    • projects optional: Array of project IDs this role applies to
  • JSON on Success: { roleid: [string] } (on create only)

/:orgid/_roles/delete

Deletes a role from the organisation.

  • Minimum Privilege: Organisation UserEditRoles
  • Expected JSON: { roleid: [string] }
    • roleid: 4-character role identifier
  • JSON on Success: nothing additional

Organisation Users

/:orgid/_users/list

Lists users, roles, and pending invites in the organisation.

  • Minimum Privilege: Organisation UserList or UserInvite
  • Expected JSON: nothing additional
  • JSON on Success: { users: [array], roles: [array], invites: [array] }
    • users and roles: Returned if caller has UserList permission
    • invites: Returned if caller has UserInvite permission

/:orgid/_users/remove

Removes a user from the organisation. Users may remove themselves; removing others requires the UserKick permission.

  • Minimum Privilege: User (self) or Organisation UserKick (others)
  • Expected JSON: { userid: [string] }
  • JSON on Success: nothing additional

/:orgid/_users/roles/update

Adds or removes roles for a user in the organisation.

  • Minimum Privilege: Organisation UserAssignRoles
  • Expected JSON: { userid: [string], add: [array], remove: [array] }
    • add optional: Array of role IDs to assign
    • remove optional: Array of role IDs to remove
  • JSON on Success: { roles: [array] } — the user's current roles after the update

/:orgid/_users/invite/create

Invites a user (by email) to the organisation.

  • Minimum Privilege: Organisation UserInvite
  • Expected JSON: { email: [string], roles: [array] }
    • roles optional: Role IDs to assign on acceptance
  • JSON on Success: nothing additional

/:orgid/_users/invite/accept

Accepts a pending invite to an organisation (current user must not already be a member).

  • Minimum Privilege: User
  • Expected JSON: nothing additional
  • JSON on Success: nothing additional

/:orgid/_users/invite/cancel

Cancels a pending invite. Callers with UserInvite permission may cancel any invite; others may only cancel their own.

  • Minimum Privilege: User (own invite) or Organisation UserInvite (any invite)
  • Expected JSON: { email: [string] }
    • email required when cancelling another user's invite
  • JSON on Success: nothing additional

Projects

Projects are containers within an organisation for scenes and files.

/:orgid/_projects/list

Lists all projects in the organisation visible to the current user.

  • Minimum Privilege: Organisation Member
  • Expected JSON: nothing additional
  • JSON on Success: { projects: [array] }
    • Each item: { projid: [string], name: [string], created: [int64], permissions: [int64] }

/:orgid/_projects/create

Creates a new project in the organisation.

  • Minimum Privilege: Organisation ProjectManage
  • Expected JSON: { name: [string], projid: [string] }
    • name required: Minimum 2 characters
    • projid optional: Custom project ID
  • JSON on Success: { projid: [string] }

/:orgid/:projid/_get

Returns details of a project.

  • Minimum Privilege: Organisation ProjectView
  • Expected JSON: nothing additional
  • JSON on Success: { project: { projid: [string], name: [string], created: [int64], permissions: [int64] } }

/:orgid/:projid/_projects/rename

Renames a project.

  • Minimum Privilege: Organisation ProjectManage
  • Expected JSON: { name: [string] }
    • name required: Minimum 2 characters
  • JSON on Success: nothing additional

/:orgid/:projid/_projects/delete

Deletes a project and all its contents.

  • Minimum Privilege: Organisation ProjectManage
  • Expected JSON: nothing additional
  • JSON on Success: nothing additional

/:orgid/:projid/_permission/audit

Audits effective permissions for the project.

  • Minimum Privilege: Organisation UserAssignRoles
  • Expected JSON: nothing additional
  • JSON on Success: nothing additional

Scenes

Scenes are JSON documents stored within a project, used by udStream for 3D visualisation.

/:orgid/:projid/_scene/list

Lists all scenes in a project.

  • Minimum Privilege: Organisation SceneList
  • Query Params: starttime optional — unix timestamp; returns only scenes updated after this time
  • JSON on Success: { scenes: [array] }

/:orgid/:projid/_scene/create

Creates a new scene in a project.

  • Minimum Privilege: Organisation SceneManage
  • Expected JSON: { body: [string] }
    • body: Full scene document as a JSON string
  • JSON on Success: { sceneid: [string], sceneSessionID: [string] }

/:orgid/:projid/:sceneid/_scene/get

Returns the scene document and opens a collaborative session.

  • Minimum Privilege: Organisation SceneAccess
  • Expected JSON: nothing additional
  • JSON on Success: { scene: [object], sceneSessionID: [string] }

/:orgid/:projid/:sceneid/_scene/replace

Replaces the entire scene document.

  • Minimum Privilege: Organisation SceneEdit
  • Expected JSON: { body: [string] }
    • body: New scene document as a JSON string
  • JSON on Success: nothing additional

/:orgid/:projid/:sceneid/_scene/update

Updates scene metadata (e.g. shared visibility).

  • Minimum Privilege: Organisation SceneShare (to update the shared flag)
  • Expected JSON: { shared: [bool] }
    • All fields optional
  • JSON on Success: nothing additional

/:orgid/:projid/:sceneid/_scene/delete

Deletes a scene.

  • Minimum Privilege: Organisation SceneManage
  • Expected JSON: nothing additional
  • JSON on Success: nothing additional

/:orgid/:projid/:sceneid/_scene/sync

Synchronises collaborative editing state. Called periodically by connected clients.

  • Minimum Privilege: Organisation SceneAccess
  • Expected JSON:
    {
      "lastupdate": [double],
      "sceneSessionID": [string],
      "flags": [int],
      "head": { "x": [double], "y": [double], "z": [double], "h": [double], "p": [double], "r": [double] },
      "handLeft": { ... },
      "handRight": { ... },
      "anchor": { "x": [double], "y": [double], "z": [double], "w": [double] },
      "messages": [array],
      "selectedNodes": [array],
      "changes": [object]
    }
    
    • changes optional: Requires SceneEdit permission
  • JSON on Success:
    {
      "viewers": [array],
      "changes": [array],
      "delay": [float],
      "nextupdate": [double]
    }
    

/:orgid/:projid/:sceneid/_scene/thumbnail/save

Saves a thumbnail image for a scene. The image must be a PNG no larger than 320×180 pixels.

  • Minimum Privilege: Organisation SceneEdit
  • Expected JSON: { image: [string] }
    • image: Base64-encoded PNG image data
  • JSON on Success: nothing additional

/:orgid/:projid/:sceneid/_scene/thumbnail/get

Returns the thumbnail image for a scene as a raw PNG.

  • Minimum Privilege: Organisation SceneList
  • Expected JSON: nothing additional
  • Response: Raw PNG binary data (Content-Type: image/png)

Files

/:orgid/:projid/_files/settings

Returns the file storage configuration for a project.

  • Minimum Privilege: Organisation FileSetup
  • Expected JSON: nothing additional
  • JSON on Success: { source: [string], address: [string], region: [string], prefix: [string], accessid: [string], accesssecret: [string] }
    • accesssecret is masked as ***

/:orgid/:projid/_files/update

Updates the file storage configuration for a project.

  • Minimum Privilege: Organisation FileSetup
  • Expected JSON: { source: [string], address: [string], region: [string], prefix: [string], accessid: [string], accesssecret: [string] }
    • address: AWS S3 bucket name (3–63 chars, lowercase alphanumeric, - and . allowed)
    • accesssecret: Pass *** to keep the existing secret unchanged
  • JSON on Success: nothing additional

/:orgid/:projid/_files/list

Lists files in the project storage.

  • Minimum Privilege: Organisation FileList
  • Query Params: folder optional
  • JSON on Success: { files: [array] }

/:orgid/:projid/_file/*

Streams a file from project storage. Supports HTTP range requests.

  • Minimum Privilege: Organisation FileStream
  • Path: File path relative to project storage root
  • Query Params: cell optional (0–7, image tile index), maxres optional (max resolution)
  • Response: Binary file data

/:orgid/:projid/_files/upload/create

Initiates a multipart upload session. The client declares which storage backends it can speak to directly via the supports array; the server responds with the upload method to use and the chunk size to apply. Only supported when project storage is configured (currently AWS S3).

  • Minimum Privilege: Organisation FileManage
  • Expected JSON: { filename: [string], supports: [array] }
    • filename: Destination path within the project storage (e.g. models/scan.las)
    • supports: Backends the client supports uploading to directly, e.g. ["aws"]. Omit or pass [] to force proxied mode.
  • JSON on Success: { uploadId: [string], filename: [string], method: [string], provider: [string], chunkSize: [int] }
    • method: "presigned" — client uploads chunks directly to storage; or "proxied" — client sends chunks through the server
    • provider: Storage provider name when method is "presigned" (e.g. "aws")
    • chunkSize: Bytes per chunk the client should use (100 MB presigned, 32 MB proxied)

/:orgid/:projid/_files/upload/chunk-url

Returns a short-lived presigned URL the client uses to PUT a single chunk directly to storage, bypassing the server entirely. Only call this when upload/create returned method: "presigned".

  • Minimum Privilege: Organisation FileManage
  • Expected JSON: { filename: [string], uploadId: [string], partNumber: [int] }
  • JSON on Success: { url: [string], token: [string] }
    • url: Presigned PUT URL valid for 1 hour. The client PUTs the raw chunk body to this URL with no additional auth headers.
    • token: Reserved for future backends (e.g. Azure block ID). Empty string for AWS S3 — the ETag is returned by storage in the PUT response ETag header and must be collected by the client for use in upload/complete.

/:orgid/:projid/_files/upload/chunk

Uploads a single chunk of a multipart upload through the server (proxied mode). Only call this when upload/create returned method: "proxied". Chunks must be at least 5 MB except for the final part. Metadata is passed via HTTP headers; the raw binary chunk data is the request body.

  • Minimum Privilege: Organisation FileManage
  • Request Headers:
    • X-Filename: Destination path (must match the value returned by upload/create)
    • X-Upload-Id: Upload session ID returned by upload/create
    • X-Part-Number: 1-based part index (1–10000)
  • Request Body: Raw binary chunk data (Content-Type: application/octet-stream)
  • JSON on Success: { partNumber: [int], etag: [string] }
    • etag: MD5 hex digest of the chunk; required when calling upload/complete

/:orgid/:projid/_files/upload/complete

Completes a multipart upload. All parts must be provided in order. The file becomes accessible in project storage once this call succeeds. Works for both presigned and proxied uploads.

  • Minimum Privilege: Organisation FileManage
  • Expected JSON: { filename: [string], uploadId: [string], parts: [array] }
    • parts: Ordered array of { partNumber: [int], etag: [string] } objects, one per uploaded chunk. For presigned uploads the etag is the value from the storage ETag response header (strip surrounding quotes).
  • JSON on Success: nothing additional

/:orgid/:projid/_files/delete

Deletes a single file from project storage. Only supported when project storage is configured as AWS S3.

  • Minimum Privilege: Organisation FileManage
  • Expected JSON: { filename: [string] }
  • JSON on Success: nothing additional

/:orgid/:projid/_files/delete-folder

Deletes all objects under a folder prefix from project storage. S3 has no native folder delete — this lists all objects with the prefix and batch-deletes them. Only supported when project storage is configured as AWS S3.

  • Minimum Privilege: Organisation FileManage
  • Expected JSON: { folder: [string] }
    • folder: The folder prefix to delete. Must end with a trailing / (e.g. models/old-scans/)
  • JSON on Success: { deleted: [int] }
    • deleted: Total number of objects removed

Server Configuration

/config

Returns basic public server configuration.

  • Minimum Privilege: Public
  • Expected JSON: nothing additional
  • Response: Server configuration (plain text)

/_config/full

Returns the full server configuration including general settings, SMTP, and license info.

  • Minimum Privilege: Server Config Edit
  • Expected JSON: nothing additional
  • JSON on Success: { serverurl: [string], supportemail: [string], sessiontimeouthours: [int], userscreatedisabled: [bool], onlyadmincreateorgs: [bool], smtpenabled: [bool], smtpserver: [string], smtpsourceaddress: [string], smtpusername: [string], smtpusetls: [bool], userlimit: [int], userCount: [int], shardCount: [int], shardlimit: [int], serverid: [string], serverExpiry: [double], sessionExpiry: [double], domains: [array] }
    • serverExpiry, sessionExpiry: Unix epoch seconds (double)
    • domains: Array of { domain: [string], sessionlimit: [int], ispremium: [bool] }
    • SMTP password is never returned

/_config/modify

Modifies server configuration settings and saves to disk.

  • Minimum Privilege: Server Config Edit
  • Expected JSON: { sessionTimeoutHours: [int], permissionCacheExpirySeconds: [double], serverurl: [string], supportemail: [string], userscreatebanned: [bool], onlyadmincreateorgs: [bool], smtp: { enabled: [bool], server: [string], sourceaddress: [string], usetls: [bool], username: [string], password: [string] } }
    • All fields optional; omitted fields retain their current value
    • Setting smtp.username to "" clears both username and password
  • JSON on Success: nothing additional

Auth Providers

/_auth/providers/list

Lists configured OAuth providers. Returns full details (including client IDs and endpoints) to callers with Server Config Edit permission; returns only id and name to public callers.

  • Minimum Privilege: Public
  • Expected JSON: nothing additional
  • JSON on Success: { providers: [array] }
    • Public: { id: [string], name: [string] }
    • Admin: also includes clientid, authendpoint, tokenendpoint

/_auth/providers/add

Adds an OAuth provider. If no providers are configured yet, this endpoint is public (to allow initial setup); otherwise requires Server Config Edit.

  • Minimum Privilege: Public (first provider), Server Config Edit (subsequent providers)
  • Expected JSON: { id: [string], name: [string], authendpoint: [string], tokenendpoint: [string], client_id: [string], client_secret: [string] }
    • All fields required, minimum 3 characters each
  • JSON on Success: nothing additional

/_auth/providers/remove

Removes an OAuth provider.

  • Minimum Privilege: Server Config Edit
  • Expected JSON: { id: [string] }
  • JSON on Success: nothing additional

Users (v1)

/v1/user

Returns information about a user.

  • Minimum Privilege: User
  • Expected JSON: { userid: [string] } or { email: [string] }
  • JSON on Success: { user: { userid: [string], realname: [string], email: [string], createdtime: [double], lastlogin: [double], language: [string], globalPermissions: [int] } }
    • email, createdtime, lastlogin, language, globalPermissions: Only returned to the user themselves or callers with User Edit permission

/v1/user/deactivate

Deactivates (blocks) a user account.

  • Minimum Privilege: User Edit
  • Expected JSON: { userid: [string] }
  • JSON on Success: nothing additional

/v1/user/reactivate

Reactivates a previously deactivated user account.

  • Minimum Privilege: User Edit
  • Expected JSON: { userid: [string] } or { username: [string] }
  • JSON on Success: nothing additional

/v1/user/sessions

Lists active sessions for a user.

  • Minimum Privilege: User (own sessions) or User Edit (any user)
  • Expected JSON: { userid: [string], index: [int], count: [int] }
    • userid optional: Defaults to current user
    • index optional: Offset for pagination (default 0)
    • count optional: Results per page (10–50, default 25)
  • JSON on Success: { sessions: [array], total: [int] }
    • Each item: { applicationname: [string], created: [double], lastaccess: [double], remoteaddress: [string] }

Packages

/_packages/create

Creates a new package record and attaches deliverable download links.

  • Minimum Privilege: Server Config Edit
  • Expected JSON: { packagename: [string], versionstring: [string], versionnumber: [int], visibility: [int], releasenotes: [string], deliverables: [array] }
    • versionnumber: Must be > 0
    • visibility: 0 = Public, 1 = Beta
    • releasenotes optional, markdown supported
    • deliverables optional: Array of { variant: [string], fileurl: [string] }
  • JSON on Success: { packageid: [string] }

/_packages/list

Lists available packages.

  • Minimum Privilege: User
  • Expected JSON: { packagename: [string], index: [int], count: [int] }
    • All fields optional
  • JSON on Success: { packages: [array], total: [int] }
    • Each item: { packageid: [string], name: [string], versionstring: [string], versionnumber: [int], created: [int], isavailable: [bool], visibility: [int], releasenotes: [string], deliverables: [array] }
    • isavailable deprecated: no longer used for availability — a package is available when it has a matching deliverable.

/_packages/latest

Returns the latest version of a named package for a given variant. A package resolves only if it has a deliverable matching the requested variant.

  • Minimum Privilege: User
  • Expected JSON: { packagename: [string], packagevariant: [string] }
  • JSON on Success: { package: { packageid: [string], name: [string], versionstring: [string], versionnumber: [int], created: [int], isavailable: [bool], visibility: [int], releasenotes: [string], deliverables: [array] } }
    • isavailable deprecated: always reported, but no longer gates resolution.

/_packages/update

Updates package metadata.

  • Minimum Privilege: Server Config Edit
  • Expected JSON: { packageid: [string], visibility: [int] }
    • visibility optional: 0 = Public, 1 = Beta
  • JSON on Success: nothing additional

Analytics

All analytics endpoints require the Analytics global permission.

/_analytics/overview

Returns high-level server usage statistics.

  • JSON on Success: { users: { total: [int], loggedin: [int], created: [int] }, sessions: [int], scenes: { total: [int], active: [int], deleted: [int] }, workspaces: [int] }

/_analytics/dau

Returns daily active user counts for the last 30 days.

  • JSON on Success: { dataset: [array] } — each item: [date, user_count]

/_analytics/users/top/since/:application/_analytics/users/top/since/:numdays/:application/_analytics/users/top/since/:numdays/:application/:page

Returns top users by session time for an application over the last N days.

  • Path Params: numdays (1–999, default 7), application, page (default 1)
  • JSON on Success: { since: [string], dataset: [array] } — each item: [userid, email, realname, session_seconds]

/_analytics/users/top/between/:start/:end/:application/_analytics/users/top/between/:start/:end/:application/:page

Returns top users by session time for an application between two dates.

  • Path Params: start, end (YYYY-MM-DD), application, page (default 1)
  • JSON on Success: { dataset: [array] } — each item: [userid, email, realname, session_seconds]

/_analytics/apps/usage/between/:start/:end

Returns application usage time per day between two dates.

  • Path Params: start, end (YYYY-MM-DD)
  • JSON on Success: { dataset: [array] } — each item: { name: [string], dates: { [date]: [seconds] } }

/_analytics/platform/usage/between/:start/:end

Returns platform usage time per day between two dates.

  • Path Params: start, end (YYYY-MM-DD)
  • JSON on Success: { dataset: [array] } — each item: { name: [string], dates: { [date]: [seconds] } }

Webhooks

/_webhook/list

Returns all configured webhook endpoints.

  • Minimum Privilege: Server Config Edit
  • Expected JSON: nothing additional
  • JSON on Success: { hooks: [array] }
    • Each item: { url: [string], hooks: [array of string] }
    • hooks: Array of event name strings — "user-create", "user-update", "user-login"

/_webhook/update

Creates, updates, or deletes a webhook endpoint. Passing an empty hooks array removes all entries for that URL.

  • Minimum Privilege: Server Config Edit
  • Expected JSON: { url: [string], hooks: [array of string] }
    • url: Webhook endpoint URL
    • hooks: Array of event names to subscribe to. Pass [] to delete the webhook.
    • Valid event names: "user-create", "user-update", "user-login"
  • JSON on Success: nothing additional