> ## Documentation Index
> Fetch the complete documentation index at: https://velt.dev/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Overview

## Overview

Velt organizes your collaborative data in a clear hierarchy. This structure helps control Velt feature data access with precision.
The hierarchy is: Organization → Folders → Documents → Locations.

Here are the core concepts:

* [Organizations](#organizations): The top-level container for everything. Think of it as your customer's entire account (e.g., Meta). It holds all their users, groups, and collaborative data.

* [Folders](#folders): A way to group and organize documents, just like in a file system. Folders can contain other folders and documents, inheriting permissions.

* [Documents](#documents): The primary collaborative space. This is where features like comments, presence, and cursors come alive. A document could be a design file, a dashboard, a spreadsheet, or a specific page in your app.

* [Locations](#locations): An optional, granular subspace within a document. If a document is a slide deck, a location is a single slide. If a document is a video, a location could be a specific timestamp.

* [Users](#users): Your end users who use your app.

* [Access Control](#access-control): The rules that control who can access what Velt feature data.

* [Authentication](#authenticate-a-user): The process of authenticating a user in Velt.

## Organizations

### Overview

An **Organization** is the top-level entity.

* It contains folders, documents, locations and users.
* Think of an `organization` as the account belonging to a company (e.g., Company A). This account may have several `users` (Company A employees). A `document` will be any file created within the organization (e.g., document, spreadsheet, slides, etc.). A `location` will be any child section within the document (e.g., slide within a presentation).

### Properties

* By default, Users within the organization can access all of it's resources like folder, documents, contact list etc. This can be modified using access control settings.
* A user can be added to multiple organizations but can only log in to one organization at a time.
* Access to resources can be restricted by setting controls at the individual resource level.

### APIs

### Frontend APIs

#### Sign in User into an Organization

* Sign in the user into an organization using [these options](/key-concepts/overview#sign-in-a-user).
* User needs to sign in to an organization in order to perform CRUD operations on it.

### Backend APIs

#### Create Organization

* When the user signs into an organization it will be created automatically if it doesn't exist.
* Explicitly create an organization using the REST API. [Learn more](/api-reference/rest-apis/v2/organizations/add-organizations)

#### Update Organization

* Update organization using the REST API. [Learn more](/api-reference/rest-apis/v2/organizations/update-organizations)

#### Delete Organization

* Delete organization using the REST API. [Learn more](/api-reference/rest-apis/v2/organizations/delete-organizations)
* It will delete all the data (folders, documents, locations and users) within the organization.

#### Get Organization

* Get organization and it's metadata using the REST API. [Learn more](/api-reference/rest-apis/v2/organizations/get-organizations-v2)

#### Disable Organization

* Disable CRUD access to an organization using the REST API. [Learn more](/api-reference/rest-apis/v2/organizations/update-organization-disable-state)

#### Provision Access to an Organization

* Provision access to an organization using [access control APIs](/key-concepts/overview#access-control)

## Folders

### Overview

Folders help you organize documents in a hierarchical way, like a traditional file system.

### Properties

* Folders can contain both documents and subfolders.
* Folders use the same permission model as Organizations and Documents.
* By default, folders inherits the permission from it's organization.
* A user can be added to multiple Folders but can only initialize one Folder at a time.
* By default, all Folder users have access to all Folder resources including sub folders, documents, locations and user contacts.
* Access to individual resources within the Folder **cannot** be restricted by setting controls at the individual resource level.
* Access of the Folder cascades to all resources within the Folder.

### APIs

### Frontend APIs

#### Subscribe to a folder

* Subscribe to a folder and its documents using the `setDocuments` method.
* Subscribe to all documents in the folder or a specific set of documents. If you want to subscribe to specific documents in the folder then you can pass upto 30 documents at a time.

<Note>
  **Filtering Behavior:** When using `setDocuments` with the `allDocuments` flag, the method automatically filters out documents the user doesn't have access to instead of failing the entire operation. The folder document limit is set to 50 documents when using `allDocuments: true`. Any documents the user doesn't have access to are silently filtered from the result.
</Note>

<Tabs>
  <Tab title="React / Next.js">
    **Using Hooks:**

    ```jsx expandable theme={null}
    const { setDocuments } = useSetDocuments();

    {/* Subscribe to a folder and all its documents */}
    const rootDocument = [
      {
        id: 'document-1',
        metadata: {
          documentName: 'Document 1'
        }
      }
    ];

    setDocuments(
      rootDocument,
      {
        folderId: 'folder1',
        allDocuments: true
      }
    );


    {/* Subscribe to a folder and some documents */}
    const documents = [
      {
        id: 'document-1',
        metadata: {
          documentName: 'Document 1'
        }
      },
      {
        id: 'document-2',
        metadata: {
          documentName: 'Document 2'
        }
      }
    ];

    setDocuments(
      documents,
      {
        folderId: 'folder1',
      }
    );
    ```

    **Using API:**

    ```jsx expandable theme={null}
    {/* Subscribe to a folder and all its documents */}
    await client.setDocuments(
      rootDocument,
      {
        folderId: 'folder1',
        allDocuments: true
      }
    );

    {/* Subscribe to a folder and some documents */}
    await client.setDocuments(
      documents,
      {
        folderId: 'folder1',
      }
    );
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```js expandable theme={null}
    // Subscribe to a folder and all its documents
    const rootDocument = [
      {
        id: 'document-1',
        metadata: {
          documentName: 'Document 1'
        }
      }
    ];

    await Velt.setDocuments(
      rootDocument,
      {
        folderId: 'folder1',
        allDocuments: true
      }
    );

    // Subscribe to a folder and some documents

    const documents = [
      {
        id: 'document-1',
        metadata: {
          documentName: 'Document 1'
        }
      },
      {
        id: 'document-2',
        metadata: {
          documentName: 'Document 2'
        }
      }
    ];

    await Velt.setDocuments(
      documents,
      {
        folderId: 'folder1',
      }
    );
    ```
  </Tab>
</Tabs>

#### Fetch folder metadata

* Retrieve folder metadata and its subfolders using either `organizationId` or `folderId`, with support for pagination.

<Tabs>
  <Tab title="React / Next.js">
    ```jsx expandable theme={null}
    // Get all folders for a specific organization
    const folderMetadata = await client.fetchFolders({
      organizationId: 'org1'
    });

    // Get a specific folder's metadata with its immediate subfolders
    const folderMetadata = await client.fetchFolders({
      organizationId: 'org1',
      folderId: 'folder1'
    });

    console.log(folderMetadata); // { data: { folder1: { ... } }, nextPageToken: '...' }
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```js expandable theme={null}
    // Get all folders for a specific organization
    const folderMetadata = await Velt.fetchFolders({
      organizationId: 'org1'
    });

    // Get a specific folder's metadata with its immediate subfolders
    const folderMetadata = await Velt.fetchFolders({
      organizationId: 'org1',
      folderId: 'folder1'
    });

    console.log(folderMetadata); // { data: { folder1: { ... } }, nextPageToken: '...' }
    ```
  </Tab>
</Tabs>

### Backend APIs

#### Create Folder

* Create a folder using the REST API. [Learn more](/api-reference/rest-apis/v2/folders/add-folder)

#### Update Folder

* Update folder using the REST API. [Learn more](/api-reference/rest-apis/v2/folders/update-folder)

#### Move Documents to Folder

* Move documents to a folder using the REST API. [Learn more](/api-reference/rest-apis/v2/documents/move-documents)

#### Delete Folder

* Delete folder using the REST API. [Learn more](/api-reference/rest-apis/v2/folders/delete-folder)
* It will delete all the data (subfolders, documents, locations and users) within the folder.

#### Get Folder

* Get folder and it's metadata using the REST API. [Learn more](/api-reference/rest-apis/v2/folders/get-folders)

#### Update Folder Access Type

* Update the access type of a folder using the REST API. [Learn more](/api-reference/rest-apis/v2/folders/update-folder-access)

#### Provision Access to a Folder

Provision access to a folder using [access control APIs](/key-concepts/overview#access-control)

## Documents

### Overview

A **Document** is a collaborative space within an Organization where users work together in real time. Each document includes:

* Feature data (such as Comments, Presence, Cursors, etc.)
* Locations
* Users (distinct from Organization users; see Access Control for details)

For example, in a slide presentation app, the whole slide deck would be a single document.

### Properties

* Anyone connected to the same `documentId` can see and interact with each other's activity, like presence, cursors, comments etc.
* Users can subscribe to a single document or multiple documents at the same time.
* Document inherits the permission from it's organization and parent folder.
* A user can be added to multiple Documents.
* You can set Document level access control to override the Organization's access control it inherited but not the Folder's access control.

<Note>
  **Document Access Priority:** Document-level access settings now take priority over folder-level access settings. If a document has its own explicit access configuration, those settings will be used. If the document doesn't have explicit access settings, it will inherit from its parent folder or organization.
</Note>

### APIs

### Frontend APIs

#### Subscribe to Documents

* Use this to set and subscribe to one or multiple documents at the same time.
* You can specify 30 documents at a time.
* The first document in the list will be considered as the root document.
* For features like comments, notifications, recorder, reactions etc. you will be able to read and write to multiple documents at the same time.
* For features like cursors, presence, huddle, live state sync etc. it will default to the root document.
* Sidebar will automatically show data from all the documents.

<Warning>
  **Access Filtering:** The `setDocuments` method now filters out documents the user doesn't have access to instead of failing the entire operation. Previously, if any document in the array was inaccessible, the entire query would fail. Now only accessible documents are subscribed, and inaccessible ones are silently filtered out.
</Warning>

**Params:**

* `documents`: [Document\[\]](/api-reference/sdk/models/data-models#document)
* `options?`: [SetDocumentsRequestOptions](/api-reference/sdk/models/data-models#setdocumentsrequestoptions)

<Tabs>
  <Tab title="React / Next.js">
    **Using Hooks:**

    ```jsx theme={null}
    const documents = [
      {
        id: 'document-1',
        metadata: {
          documentName: 'Document 1'
        }
      },
      {
        id: 'document-2',
        metadata: {
          documentName: 'Document 2'
        }
      }
    ];
    const { setDocuments } = useSetDocuments();
    setDocuments(documents);
    ```

    **Using API:**

    ```jsx theme={null}
    const documents = [
      {
        id: 'document-1',
        metadata: {
          documentName: 'Document 1'
        }
      },
      {
        id: 'document-2',
        metadata: {
          documentName: 'Document 2'
        }
      }
    ];
    await client.setDocuments(documents);
    ```
  </Tab>

  <Tab title="Other Frameworks">
    **Using API:**

    ```js theme={null}
    const documents = [
      {
        id: 'document-1',
        metadata: {
          documentName: 'Document 1'
        }
      },
      {
        id: 'document-2',
        metadata: {
          documentName: 'Document 2'
        }
      }
    ];
    await Velt.setDocuments(documents);
    ```
  </Tab>
</Tabs>

**With Options:**

<Tabs>
  <Tab title="React / Next.js">
    **Subscribe to all documents in a folder:**

    ```jsx theme={null}
    const { setDocuments } = useSetDocuments();

    setDocuments(
      [{ id: 'document-1', metadata: { documentName: 'Document 1' } }],
      {
        folderId: 'my-folder-id',
        allDocuments: true
      }
    );
    ```

    **Filter by location and specify a root document:**

    ```jsx theme={null}
    const { setDocuments } = useSetDocuments();

    setDocuments(
      [
        { id: 'document-1', metadata: { documentName: 'Document 1' } },
        { id: 'document-2', metadata: { documentName: 'Document 2' } }
      ],
      {
        locationId: 'scene-1',
        rootDocumentId: 'document-2'
      }
    );
    ```

    **Override the debounce window:**

    ```jsx theme={null}
    const { setDocuments } = useSetDocuments();

    setDocuments(
      [{ id: 'document-1', metadata: { documentName: 'Document 1' } }],
      {
        debounceTime: 300
      }
    );
    ```

    **Filter by context fields:**

    ```jsx theme={null}
    const { setDocuments } = useSetDocuments();

    setDocuments(
      [{ id: 'document-1', metadata: { documentName: 'Document 1' } }],
      {
        context: {
          customField: 'value'
        }
      }
    );
    ```
  </Tab>

  <Tab title="Other Frameworks">
    **Subscribe to all documents in a folder:**

    ```js theme={null}
    await Velt.setDocuments(
      [{ id: 'document-1', metadata: { documentName: 'Document 1' } }],
      {
        folderId: 'my-folder-id',
        allDocuments: true
      }
    );
    ```

    **Filter by location and specify a root document:**

    ```js theme={null}
    await Velt.setDocuments(
      [
        { id: 'document-1', metadata: { documentName: 'Document 1' } },
        { id: 'document-2', metadata: { documentName: 'Document 2' } }
      ],
      {
        locationId: 'scene-1',
        rootDocumentId: 'document-2'
      }
    );
    ```

    **Override the debounce window:**

    ```js theme={null}
    await Velt.setDocuments(
      [{ id: 'document-1', metadata: { documentName: 'Document 1' } }],
      {
        debounceTime: 300
      }
    );
    ```

    **Filter by context fields:**

    ```js theme={null}
    await Velt.setDocuments(
      [{ id: 'document-1', metadata: { documentName: 'Document 1' } }],
      {
        context: {
          customField: 'value'
        }
      }
    );
    ```
  </Tab>
</Tabs>

##### **Read/Write data from multiple documents on the same page**

* If you want to display data (eg: comments) from multiple documents on the same page, add `data-velt-document-id` attribute to the container that contains the `document`.
* It will be used to identify which part of the DOM belongs to which document.

```html theme={null}
<div class="document-container" data-velt-document-id="document-1">
  ...
</div>

<div class="document-container" data-velt-document-id="document-2">
  ...
</div>

<div class="document-container" data-velt-document-id="document-3">
  ...
</div>
```

#### Filter comments by context

You can filter which comments are loaded when subscribing to documents by passing a `context.access` parameter to `setDocuments()`. This is useful when you only want to fetch specific comments **within a document** that the user has access to.

Learn more about the [Feature Level Access Control](/key-concepts/overview#aset-feature-level-permissions-using-access-context-custom-metadata).

<Tabs>
  <Tab title="React / Next.js">
    ```jsx theme={null}
    const { client } = useVeltClient();

    client.setDocuments(documents, {
        context: {
            access: {
                entityId: ['numberOfVisitors'],
                dashboardId: ['myDashboard'],
            }
        },
    });
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```js theme={null}
    Velt.setDocuments(documents, {
        context: {
            access: {
                entityId: ['numberOfVisitors'],
                dashboardId: ['myDashboard'],
            }
        },
    });
    ```
  </Tab>
</Tabs>

#### Subscribe to Documents from Other Organizations

* By default, users can only access documents within their own organization.
* Enable cross-organization access by passing the target `organizationId` in the options parameter to `setDocument`/`setDocuments` (see Hook & API Example below).
* Ensure that the user has access to the target document in the target organization.

<Tabs>
  <Tab title="React / Next.js">
    **Using Hook:**

    ```jsx expandable theme={null}
    {/* Single Document */}
    useSetDocument("DOCUMENT_ID", {
      organizationId: 'ANOTHER_ORGANIZATION_ID'
    });

    {/* Multiple Documents */}
    const documents = [
      {
        id: 'document-1',
        metadata: {
          documentName: 'Document 1'
        }
      },
      {
        id: 'document-2',
        metadata: {
          documentName: 'Document 2'
        }
      }
    ];
    useSetDocuments(documents, {
      organizationId: 'ANOTHER_ORGANIZATION_ID'
    });
    ```

    **Using API:**

    ```jsx theme={null}
    {/* Single Document */}
    await client.setDocument("DOCUMENT_ID", {
      organizationId: 'ANOTHER_ORGANIZATION_ID'
    });

    {/* Multiple Documents */}
    const documents = [
      {
        id: 'document-1',
        metadata: {
          documentName: 'Document 1'
        }
      },
      {
        id: 'document-2',
        metadata: {
          documentName: 'Document 2'
        }
      }
    ];
    await client.setDocuments(documents, {
      organizationId: 'ANOTHER_ORGANIZATION_ID'
    });
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```javascript expandable theme={null}
    {/* Single Document */}
    await Velt.setDocument(DOCUMENT_ID, {
      organizationId: 'ANOTHER_ORGANIZATION_ID'
    });

    {/* Multiple Documents */}
    const documents = [
      {
        id: 'document-1',
        metadata: {
          documentName: 'Document 1'
        }
      },
      {
        id: 'document-2',
        metadata: {
          documentName: 'Document 2'
        }
      }
    ];
    await Velt.setDocuments(documents, {
      organizationId: 'ANOTHER_ORGANIZATION_ID'
    });
    ```
  </Tab>
</Tabs>

#### Set Root Document

* Set the root document.
* This is useful when you have multiple documents subscribed in your app and you want change the root document during the session.

<Tabs>
  <Tab title="React / Next.js">
    ```jsx theme={null}
    await client.setRootDocument({id:'DOCUMENT_ID'})
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```javascript theme={null}
    await Velt.setRootDocument({id:'DOCUMENT_ID'})
    ```
  </Tab>
</Tabs>

#### Unsubscribe from Documents

* Use this to unsubscribe from all documents at once.

<Tabs>
  <Tab title="React / Next.js">
    **Using Hooks:**

    ```jsx theme={null}
    useUnsetDocuments();
    ```

    **Using API:**

    ```jsx theme={null}
    await client.unsetDocuments();
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx theme={null}
    await Velt.unsetDocuments();
    ```
  </Tab>
</Tabs>

#### Get Document Metadata

* Use this to get the metadata of a Document.
* This is useful when you want to display the document name in your app or any custom metadata that you have set.
* This returns a subscription with [`DocumentMetadata`](/api-reference/sdk/models/data-models#documentmetadata) object.

<Tabs>
  <Tab title="React / Next.js">
    ```jsx theme={null}
    client.getDocumentMetadata().subscribe((documentMetadata) => {
      console.log("Current document metadata: ", documentMetadata);
    });
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx theme={null}
    Velt.getDocumentMetadata().subscribe((documentMetadata) => {
        console.log("Current document metadata: ", documentMetadata);
    });
    ```
  </Tab>
</Tabs>

#### [Fetch Documents](/api-reference/sdk/api/api-methods#fetchdocuments)

* Fetch documents by organization, folder, or specific document IDs.
* Use `allDocuments: true` to fetch all documents for an organization or a specific folder.
* Supports pagination via `nextPageToken` in the response.
* When specifying individual `documentIds`, you can **pass up to 30 IDs at a time**.

<Warning>
  This is a one-time fetch, not a realtime subscription. You will need to call again to refresh results.
</Warning>

**Params:**

* `request`: [FetchDocumentsRequest](/api-reference/sdk/models/data-models#fetchdocumentsrequest)
* Returns: [FetchDocumentsResponse](/api-reference/sdk/models/data-models#fetchdocumentsresponse)

<Tabs>
  <Tab title="React / Next.js">
    ```ts theme={null}
    // Gets all documents for given org id
    await client.fetchDocuments({ organizationId: 'org1', allDocuments: true });

    // Gets all documents for the given folderId
    await client.fetchDocuments({ organizationId: 'org1', folderId: 'folder1', allDocuments: true });

    // Gets specified documents
    await client.fetchDocuments({ organizationId: 'org1', documentIds: ['doc1', 'doc2'] });
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```js theme={null}
    // Gets all documents for given org id
    await Velt.fetchDocuments({ organizationId: 'org1', allDocuments: true });

    // Gets all documents for the given folderId
    await Velt.fetchDocuments({ organizationId: 'org1', folderId: 'folder1', allDocuments: true });

    // Gets specified documents
    await Velt.fetchDocuments({ organizationId: 'org1', documentIds: ['doc1', 'doc2'] });
    ```
  </Tab>
</Tabs>

### Backend APIs

#### Create Document

* Create a document using the REST API. [Learn more](/api-reference/rest-apis/v2/documents/add-documents)

#### Update Document

* Update document using the REST API. [Learn more](/api-reference/rest-apis/v2/documents/update-documents)

#### Delete Document

* Delete document using the REST API. [Learn more](/api-reference/rest-apis/v2/documents/delete-documents)
* It will delete all the data (locations and users) within the document.

#### Get Document

* Get document and it's metadata using the REST API. [Learn more](/api-reference/rest-apis/v2/documents/get-documents-v2)

#### Update Document Access Type

* Update the access type of a document using the REST API. [Learn more](/api-reference/rest-apis/v2/documents/update-document-access)

#### Provision Access to a Document

Provision access to a document using [access control APIs](/key-concepts/overview#access-control)

#### Disable Document

* Disable CRUD access to a document using the REST API. [Learn more](/api-reference/rest-apis/v2/documents/update-document-disable-state)

#### Legacy APIs

##### **Subscribe to a Single Document**

* Use this to initialize and subscribe to a single Document.
* Once you set the document, you will start receiving realtime updates from the document.
* **Params:**
  * `documentId`: The unique identifier for the document.
  * `metadata`: (optional) This is a key/value pair object where you can set metadata about the document such as `documentName`. documentName is a special field that we use to display the document name in some Velt Components.

<Tabs>
  <Tab title="React / Next.js">
    **Using Hooks:**

    ```jsx theme={null}
    useSetDocument('unique-document-id', {documentName: 'Document Name'});
    ```

    **Using API:**

    ```jsx theme={null}
    await client.setDocument('unique-document-id', {documentName: 'Document Name'});
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx theme={null}
    await Velt.setDocument('unique-document-id', {documentName: 'Document Name'});
    ```
  </Tab>
</Tabs>

##### **Unsubscribe from a Single Document**

* Use this to unsubscribe from the root Document
* Once you unset the document, you will no longer receive realtime updates from the document.
* For some parts of your app, you may not need Velt. In such cases, you can unset the document.

<Tabs>
  <Tab title="React / Next.js">
    **Using Hooks:**

    ```jsx theme={null}
    useUnsetDocumentId();
    ```

    **Using API:**

    ```jsx theme={null}
    await client.unsetDocumentId();
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx theme={null}
    await Velt.unsetDocumentId();
    ```
  </Tab>
</Tabs>

## Locations

### Overview

**Locations** are optional subspaces (JSON object) within a document, providing finer partitioning of data.

Locations can represent:

* Pages
* Sections
* Video frames
* Data points on maps/charts
* Any other contextual area

For instance:

* In a slide presentation, the entire slide presentation will be a document each individual slide will be a location.
* In a dashboard, the entire dashboard is a document but various filters applied will be locations;
* In a video player, the entire video will be the document and timestamps will be locations.

<Tip> If a **Document** is like a house, a **Location** is like a room within the house. </Tip>

### Properties

* Any user with access to the document will have access to all locations in the document.
* Access controls cannot be set at the location level.
* Locations automatically generate location groups in the sidebar and organizes the comments within the group.
* The location object has these fields:
  * `id` (required): A unique identifier for the location that can be used to reference it later
  * `locationName` (recommended): A human-readable name displayed in Velt components like the `VeltCommentsSideBar`
  * You can add any number of custom fields to the location object.

### APIs

### Frontend APIs

#### Subscribe to Locations

* Use this to set and subscribe to one or multiple locations at the same time.
* The first location in the list will be considered as the root location.
* Features will by default add data to the root location unless you use the location boundaries.
* Sidebar will automatically show data from all the documents.

**Params:**

* `locations`: [Location\[\]](/api-reference/sdk/models/data-models#location)
* `options?`: [SetLocationsRequestOptions](/api-reference/sdk/models/data-models#setlocationsrequestoptions)
  * `rootLocationId`: The id of the location that will be set as the root location. If you don't specify this, the first location will be set as the root location.
  * `appendLocation`: If you want to append new locations to the existing locations, set this to `true`.

<Tabs>
  <Tab title="React / Next.js">
    **Using Hooks:**

    ```jsx theme={null}
    const locations = [
      {id:'location1', locationName:'Location 1'},
      {id:'location2', locationName:'Location 2'}
    ];
    const { setLocations } = useSetLocations();
    setLocations(locations);
    ```

    **Using API:**

    ```jsx theme={null}
      await client.setLocations([
        {id:'location1', locationName:'Location 1'},
        {id:'location2', locationName:'Location 2'}
      ], {rootLocationId: 'location2'}); // By default 1st location will be set as root location unless rootLocationId is specified.

      // Append new locations
      await client.setLocations([
        {id:'location3', locationName:'Location 3'},
        {id:'location4', locationName:'Location 4'}
      ], {appendLocation: true})
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```js theme={null}
      await Velt.setLocations([
        {id:'location1', locationName:'Location 1'},
        {id:'location2', locationName:'Location 2'}
      ], {rootLocationId: 'location2'}); // By default 1st location will be set as root location unless rootLocationId is specified.

      // Append new locations
      await Velt.setLocations([
        {id:'location3', locationName:'Location 3'},
        {id:'location4', locationName:'Location 4'}
      ], {appendLocation: true})
    ```
  </Tab>
</Tabs>

##### Read/Write data from multiple locations on the same page using Location Boundaries

* If you want to display data (eg: comments) from multiple locations on the same page, add `data-velt-location-id` attribute to the container that contains the `location`.
* It will be used to identify which part of the DOM belongs to which location.
* This ensures that the comment added within the location is associated with the correct location.

```html theme={null}
<div class="location-container" data-velt-location-id="location-1">
  ...
</div>

<div class="location-container" data-velt-location-id="location-2">
  ...
</div>

<div class="location-container" data-velt-location-id="location-3">
  ...
</div>
```

#### Set Root Location

* Set the root location.
* This is useful when you have multiple locations subscribed in your app and you want change the root location during the session.

<Tabs>
  <Tab title="React / Next.js">
    ```jsx theme={null}
    await client.setRootLocation({id:'LOCATION_ID'})
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```javascript theme={null}
    await Velt.setRootLocation({id:'LOCATION_ID'})
    ```
  </Tab>
</Tabs>

#### Unsubscribe from Locations

* Unset locations by ids or all of them if you don't specify any parameters.

<Tabs>
  <Tab title="React / Next.js">
    ```jsx theme={null}
    // remove specific locations
    await client.unsetLocationsIds(['location1', 'location2', 'location3'])

    // remove all locations
    await client.unsetLocationsIds()
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx theme={null}
    // remove specific locations
    await Velt.unsetLocationsIds(['location1', 'location2', 'location3'])

    // remove all locations
    await Velt.unsetLocationsIds()
    ```
  </Tab>
</Tabs>

#### Legacy APIs

##### **Subscribe to a Single Location**

* Use this to initialize and subscribe to a single Location.

<Tabs>
  <Tab title="React / Next.js">
    **Using Hooks:**

    ```jsx theme={null}
    useSetLocation({
      'id': 'locationId1',
      'locationName': 'MainVideoPlayer',
      'videoFrame': '120'
    })
    ```

    **Using API:**

    ```jsx theme={null}
    client.setLocation({
      'id': 'locationId1',
      'locationName': 'MainVideoPlayer',
      'videoFrame': '120'
    })
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx theme={null}
    Velt.setLocation({
      'id': 'locationId1',
      'locationName': 'MainVideoPlayer',
      'videoFrame': '120'
    })
    ```
  </Tab>
</Tabs>

##### **Subscribe to Multiple Locations**

* Use this to subscribe to multiple locations at the same time.
* Add additional locations on the page by using set location with the `true` parameter.

<Tabs>
  <Tab title="React / Next.js">
    **Using Hooks:**

    ```jsx expandable theme={null}
    useSetLocation({
      'id': 'locationId1',
      'locationName': 'MainVideoPlayer',
      'videoFrame': '120'
      // You can keep adding more field to make the location very specific.
      // The field names can be anything.
    })

    useSetLocation({
      'id': 'locationId1',
      'locationName': 'MainVideoPlayer',
      'videoFrame': '120'
      // You can keep adding more field to make the location very specific.
      // The field names can be anything.
    }, true)
    ```

    **Using API:**

    ```jsx theme={null}
    client.setLocation({
      'id': 'locationId1',
      'locationName': 'MainVideoPlayer',
      'videoFrame': '120'
      // You can keep adding more field to make the location very specific.
      // The field names can be anything.
    });

    client.setLocation({
      'id': 'locationId2',
      'locationName': 'MainVideoPlayer2',
      'videoFrame': '120'
      // You can keep adding more field to make the location very specific.
      // The field names can be anything.
    }, true);
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx expandable theme={null}
    Velt.setLocation({
      'id': 'locationId1',
      'locationName': 'MainVideoPlayer',
      'videoFrame': '120'
      // You can keep adding more field to make the location very specific.
      // The field names can be anything.
    });

    Velt.setLocation({
      'id': 'locationId2',
      'locationName': 'MainVideoPlayer2',
      'videoFrame': '120'
      // You can keep adding more field to make the location very specific.
      // The field names can be anything.
    }, true);
    ```
  </Tab>
</Tabs>

## Users

### Overview

* A `User` is anyone authenticated with the Velt SDK.
* After authentication, a user's profile appears in Velt's collaboration features. For example, their name is shown next to their comments, in `@mentions`, and alongside their avatar in presence and cursor features.

### Contact List

When the user is on a document, they can `@mention` other users. By default, the contact list for the `@mention` feature includes users from:

* Organization.
* Folder.
* Document.
* User Groups.
* `@here`: This is a special group that includes only the users explicitly added on the document. This doesn't include organization users or organization user groups.

### User Groups

User Groups let you organize users into teams (like "engineering" or "marketing") for easier management and access control.

* Mention an entire group (e.g., @engineering) instead of individual users, similar to Slack.
* Organization users can be in multiple groups.
* Only organization users can join user groups.

### Properties

* Uniqueness of the user is determined by its `userId`.
* A user can be part of multiple organizations.

### APIs

### Frontend APIs

#### Authenticate a User

There are two ways to authenticate a user in Velt.

1. Using an Auth Provider (recommended)
2. Using Identify method

<Info>
  **Error Handling**: By default, authentication methods return `null` on failure. You can configure them to throw errors instead by setting `throwError: true`. [Learn more about error handling](/get-started/advanced#error-handling-in-authentication).
</Info>

##### **1. Use Auth Provider**

* With this approach, you configure an authentication provider by specifying the user you want to authenticate and a function that returns a Velt JWT token.
* This function is automatically called by Velt whenever a token is required—such as during the initial sign-in or when the token expires.
* You should define this authentication provider within the Velt Provider during your app's initialization.
* Use this to [generate a Velt JWT token.](/api-reference/rest-apis/v2/auth/generate-token)
* **Params**:
  * `user`: [User](/api-reference/sdk/models/data-models#user)
  * `retryConfig`: [AuthRetryConfig](/api-reference/sdk/models/data-models#authretryconfig)
  * `generateToken`: `() => Promise<string>`
  * `options`: [Options](/api-reference/sdk/models/data-models#options)
    * `authToken`: `string`
    * `forceReset`: `boolean`: By default, once the user is authenticated, the authentication state is preserved in the browser and a new token is not generated until you explicitly sign them out. If you want to force re-login the user, set this to `true`.

<Tabs>
  <Tab title="React / Next.js">
    ```js theme={null}
    <VeltProvider authProvider={{
      user,
      retryConfig: { retryCount: 3, retryDelay: 1000 },
      generateToken: async () => {
        // See generateVeltAuthToken() tab for example implementation
        const token = await generateVeltAuthToken();
        return token;
      }
    }} />
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```js theme={null}
    Velt.setVeltAuthProvider({
      user,
      retryConfig: { retryCount: 3, retryDelay: 1000 },
      generateToken: async () => {
        // See generateVeltAuthToken() tab for example implementation
        const token = await generateVeltAuthToken();
        return token;
      }
    });

    ```
  </Tab>

  <Tab title="generateVeltAuthToken()">
    ```ts expandable theme={null}
    // Backend example: minimal token generator
    export async function generateVeltAuthToken({
      userId,
      organizationId,
      email,
    }: {
      userId: string;
      organizationId: string;
      email?: string;
    }) {
      const res = await fetch('https://api.velt.dev/v2/auth/generate_token', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'x-velt-api-key': YOUR_VELT_API_KEY_HERE,
          'x-velt-auth-token': YOUR_VELT_AUTH_TOKEN_HERE,
        },
        body: JSON.stringify({
          data: {
            userId,
            userProperties: {
              organizationId,
              ...(email ? { email } : {}),
            },
          },
        }),
      });

      const json = await res.json();
      return json?.result?.data?.token as string | undefined;
    }
    ```
  </Tab>
</Tabs>

##### **2. Use Identify with JWT Token**

* In this approach, you will call the `identify` method with the `user` object and a JWT token.
* Here you are responsible for re-generating a JWT token whenever it expires.
* This gives you more flexibility on when and where to initialize the user and generate the token.
* **Params**:
  * `user`: [User](/api-reference/sdk/models/data-models#user)
  * `options`: [Options](/api-reference/sdk/models/data-models#options)
    * `authToken`: `string`
    * `forceReset`: `boolean`: By default, once the user is authenticated, the authentication state is preserved in the browser and a new jwt token is not used until you explicitly sign them out. If you want to force re-login the user, set this to `true`.

<Tabs>
  <Tab title="React / Next.js">
    **Using Hook:**

    ```js theme={null}
      const user = {
        userId: uid,
        organizationId: organizationId, // this is the organization id the user belongs to. You should always use this.
        name: displayName,
        email: email,
        photoUrl: photoURL,
        color: colorCode, // Use valid Hex code value. Used in the background color of the user's avatar.
        textColor: textColor // Use valid Hex code value. Used in the text color of the user's intial when photoUrl is not present.
      };

      useIdentify(user, {
        authToken: authToken, // this is optional but highly recommended.
      });
    ```

    **Using API:**

    ```js theme={null}
    await client.identify(user, {
        authToken: authToken, // this is optional but highly recommended.
    });
    ```
  </Tab>

  <Tab title="Other Frameworks">
    **Using API:**

    ```js theme={null}
    await Velt.identify(user, {
        authToken: authToken, // this is optional but highly recommended.
    });
    ```
  </Tab>
</Tabs>

##### Sign in with force reset

* By default, when you identify a user, their authentication state is preserved in the browser until you explicitly sign them out.
* If you update a user's metadata or default access settings in the console and want those changes to take effect right away, you should call the `identify` method again with the `forceReset` option set to `true`.
* `Default: false`

```js theme={null}
await client.identify(user, {
  forceReset: true
});

```

#### Get Current User

You can retrieve the currently authenticated user object using [`getCurrentUser()`](/api-reference/sdk/api/api-methods#getcurrentuser) method or [`useCurrentUser()`](/api-reference/sdk/api/react-hooks#usecurrentuser) hook.

<Tabs>
  <Tab title="React / Next.js">
    **Using Hook:**

    ```jsx theme={null}
    const currentUser = useCurrentUser();
    console.log('Current user:', currentUser);
    ```

    **Using API:**

    ```jsx theme={null}
    client.getCurrentUser().subscribe((user) => {
      console.log('Current user:', user);
    });
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```js theme={null}
    Velt.getCurrentUser().subscribe((user) => {
      console.log('Current user:', user);
    });
    ```
  </Tab>
</Tabs>

#### Sign out a User

In a given session or browser tab, if you want to switch users,
you need to first signout the current user and then sign in using `identify` method again.
This will ensure we clean up the current user session and start a new session with the new user.

```jsx theme={null}
client.signOutUser();
```

#### Contact List

### Frontend APIs

You can update the contact list dynamically in your frontend. These updates are not saved in Velt. You can also fetch contacts from your backend and show them in Velt components.

* [Add/Update Users](/async-collaboration/comments/customize-behavior#updatecontactlist)
* [Search Users](/async-collaboration/comments/customize-behavior#customautocompletesearch)

### Backend APIs

You can add/delete users from your backend and save the list in Velt.

* [Add Users](/api-reference/rest-apis/v2/users/add-users)
* [Delete Users](/api-reference/rest-apis/v2/users/delete-users)

#### User Groups:

* [Add User Groups](/api-reference/rest-apis/v2/user-groups/add-groups)
* [Add Users to User Groups](/api-reference/rest-apis/v2/user-groups/add-users-to-group)
* [Delete Users from User Groups](/api-reference/rest-apis/v2/user-groups/delete-users-from-group)

## Access Control

### Overview

Velt's access control system is built around four main concepts:

1. [**Resources**](#1-resources) - The hierarchical structure of your app (Organizations → Folders → Documents)
2. [**Access Types**](#2-access-types) - This is applied to a resource to determine who can access it (public, organizationPrivate, or restricted)
3. [**Roles**](#3-roles) - This is applied to a user to determine what they can do on a resource (editor or viewer)
4. [**Permissions**](#4-permissions) – Define whether a user can access a resource, based on the resource's access type, the user's role, and explicit permission grants. Access can be temporary or permanent.

### Access Control Model

* **Inheritance (default)**:  Similar to Google Drive, Velt Resources (Organizations, Folders, and Documents) follow a hierarchical permission model. By default, child resources inherit access control settings from their parents.
* **Overrides**: If a resource defines its own access type or user permissions, those explicit settings **override** the inherited values. This precedence applies during both permission evaluation and access enforcement.

**Example: Think of it like folders in Google Drive**

* You create a **folder** and set it to "Anyone with the link can view"
* Any **document** you add to that folder automatically inherits those same sharing settings
* If you want, you can override a specific document's sharing settings to be more restrictive or more open

**In Velt, this works the same way:**

* All **Folders** in that org automatically inherit `organizationPrivate` access
* All **Documents** in those folders also inherit `organizationPrivate` access
* If you explicitly set a specific Document to `restricted` access, that override takes precedence

### 1. Resources

Velt permissions apply to these resources and at the feature level using **Access Context**:

**Resource-Level Permissions:**

* **Organization** – top-level container that groups users, folders, and documents.
* **Folder** – groups documents under an organization.
* **Document** – individual collaborative unit (e.g., a canvas, page, or file).

<Note>
  Most permission changes occur at the **Folder** and **Document** level, but Organizations can set defaults that flow down hierarchically.
</Note>

**Feature-Level Permissions (Access Context):**

Access Context enables granular, feature-level permissions using custom metadata. Unlike resource-level permissions that control access to entire organizations, folders, or documents, Access Context allows you to control access to specific features data (like individual comments or notifications) based on custom metadata fields you define.

**When to use Access Context:**

* **Fine-grained control**: When you need to restrict visibility of specific features data within a document rather than the entire document. For example, in a multi-tenant dashboard, users may access the same dashboard (document) but only see comments for widgets they’re authorized to view (scoped by widgetId).
* **Data-driven permissions**: When access needs to be determined by dynamic metadata such as entity IDs, project codes, section identifiers, or other custom fields specific to your application's data model.
* **Complex scenarios**: When resource-level permissions alone are too broad and you need feature-specific isolation within the same collaborative space.

### 2. Access Types

Access types define **who** can access a resource:

* **`public`** **(default)**: Any authenticated user in your app who initializes Velt can access the resource’s collaboration layer.
* **`organizationPrivate`**: Only users in the same organization as the resource can access it.
* **`restricted`**: Only explicitly permitted users can access the resource.

#### APIs (backend)

* **Folder:** Use [Update Folder Access Type](/api-reference/rest-apis/v2/folders/update-folder-access).
* **Document:** Use [Update Document Access Type](/api-reference/rest-apis/v2/documents/update-document-access).
* **Defaults:** Update default access across your app.

<Steps>
  <Step title="Open Velt Console">
    Go to the App Config in the Velt Console: [console.velt.dev](https://console.velt.dev/dashboard/config/appconfig)
  </Step>

  <Step title="Choose default access type">
    Select the desired default access type for new resources and save your changes.
  </Step>
</Steps>

<Tip>
  **Access Types = who can access. Roles = what they can do once they have access.** These controls are orthogonal and compose together.
</Tip>

### 3. Roles

Roles define **what** an allowed user can do on a resource:

* **Editor:** Read and write access to collaboration features data for the given resource. **This is the default role.**
* **Viewer:** Read-only access to collaboration features data for the given resource.

<Note>
  Assign or override roles per resource via your backend when granting permissions. Frontend SDK methods cannot set or change `accessRole`.
</Note>

#### APIs

* [**Add users**](/api-reference/rest-apis/v2/users/add-users)
* [**Remove users**](/api-reference/rest-apis/v2/users/delete-users)
* [**Generate token**](/api-reference/rest-apis/v2/auth/generate-token) (to be used during login)
* [**Add permissions**](/api-reference/rest-apis/v2/auth/add-permissions)
* [**Remove permissions**](/api-reference/rest-apis/v2/auth/remove-permissions)

### 4. Permissions

Permissions control which users can access and collaborate on specific resources in your app. They determine what actions users can perform on organizations, folders, and documents.
Permissions are determined by a combination of the resource's **access type** and the user's **role**.

There are 3 ways to configure permissions in Velt. Choose the approach that best fits your app's architecture:

a. [On-Demand Permissions](#a-on-demand-permissions): Grant or revoke permissions **at runtime** when a user logs in or navigates to a resource.

b. [Synced Permissions](#b-synced-permissions): Periodically or event‑driven sync between your app and Velt. Do an initial bulk load, then keep up with adds/removes/role changes.

c. [Real-time Permission Provider](#c-real-time-permission-provider): With this approach, Velt pings your defined endpoint to verify whether a user should be granted access to a resource (organization, folder, or document). This ensures that your backend is still the source of truth and you don't have to sync the permissions into Velt directly.

### a. On-Demand Permissions

Grant or revoke permissions **at runtime** when a user logs in or navigates to a resource.

* Best when your app has a very complex and granular permissioning system and you want to keep your system as the source of truth.
* Supports temporary (time-bound) access and permanent access, enabling ad‑hoc sharing and expiring invites.

#### Temporary vs. Permanent Access

* **Temporary access**: Grant permissions with an expiry or revoke after session/end of task (e.g., guest reviewers, contractors). Use this when access should automatically end or be short‑lived.
* **Permanent access**: Grant durable permissions for members or long‑term collaborators. Use this when roles rarely change and should persist across sessions.

#### APIs

* [**Add Permissions**](/api-reference/rest-apis/v2/auth/add-permissions)
  * **When user logs in**: Use an auth provider with JWT token to grant permissions to the organization present in the `User` object in the auth provider. ([Generate token](/api-reference/rest-apis/v2/auth/generate-token)).
  * **When user sets documents**: Call [Add Permissions API](/api-reference/rest-apis/v2/auth/add-permissions) to grant or adjust access for the set of documents or folders in the `setDocuments` method.
* [**Remove Permissions**](/api-reference/rest-apis/v2/auth/remove-permissions)
  * Revoke access when the user signs out, loses membership, or navigates away from folder/document using [Remove Permissions API](/api-reference/rest-apis/v2/auth/remove-permissions).

<Note>
  When you include `organizationId` in the identify/auth payload, Velt automatically creates and associates the user with that organization. This happens because the "Auto-create Organization Users" console setting is **enabled by default**. To change this default behavior, [go to Console under App Configuration -> Auto-create Organization User](https://console.velt.dev/dashboard/config/appconfig)
</Note>

### b. Synced Permissions

* Periodically or event‑driven sync between your app and Velt.
* Do an initial bulk load, then keep up with adds/removes/role changes.

#### APIs

* [**Add users**](/api-reference/rest-apis/v2/users/add-users)
  * **Initial sync:** Bulk add existing users so they appear in mentions and can be permissioned.
  * **Ongoing sync:** When a user is added or granted permissions to additional resources in your app, call this API to sync that change in Velt.
* [**Remove users**](/api-reference/rest-apis/v2/users/delete-users)
  * **Ongoing sync:** When a user is removed or their permissions are revoked to resources in your app, call this API to sync that change in Velt.

<Note>
  When you include `organizationId` in the identify/auth payload, Velt automatically creates and associates the user with that organization. The Auto-create Organization Users console setting is **enabled by default**, so you don't need to pre-create users for on-demand flows. [Go to Console under App Configuration -> Auto-create Organization User](https://console.velt.dev/dashboard/config/appconfig)
</Note>

### c. Real-time Permission Provider

With this approach, Velt pings your defined endpoint to verify whether a user should be granted access to a resource (organization, folder, or document). This ensures that your backend is still the source of truth and you don't have to sync the permissions into Velt directly.

#### How it works

1. **Configure endpoint**: Set up your backend endpoint URL and optional auth token in the [Velt Console](https://console.velt.dev/dashboard/config/permission-provider).
2. **Initialize frontend**: Configure Permission Provider in your app using VeltProvider or [`setPermissionProvider()`](/api-reference/sdk/api/api-methods#setpermissionprovider).
3. **Automatic validation**: When users access resources (organizations, folders, documents, or contexts), Velt automatically queries your endpoint.
4. **Backend response**: Your backend checks permissions and returns access decisions.
5. **Instant enforcement**: Velt enforces the permissions immediately based on your response.
6. **Auto-revocation** (optional): Configure automatic permission cleanup when users switch documents or log out.

#### When to use

* Your app has complex, dynamic permissions that change frequently
* You want to avoid syncing permission data to an external system
* You need real-time permission validation without backend synchronization overhead

**How to Setup:**

**Step 1: Configure Endpoint in Velt Console**

1. Enable [Permission Provider in Velt Console](https://console.velt.dev/dashboard/config/permission-provider)
2. Add your POST endpoint URL (e.g., [https://yourdomain.com/api/check-permissions](https://yourdomain.com/api/check-permissions))
3. (Optional) Add auth token for request authentication

**Step 2: Implement Your Backend Endpoint**

Your backend receives permission requests from Velt, checks your authorization system, and returns access decisions.

* **Request (Velt → your endpoint)**: [PermissionQuery](/api-reference/sdk/models/data-models#permissionquery)
* **Response (your endpoint → Velt)**: [PermissionResult](/api-reference/sdk/models/data-models#permissionresult)

**Example**

<Tabs>
  <Tab title="Sample Request from Velt">
    ```javascript expandable theme={null}
    // Velt sends a POST request to your configured endpoint
    fetch('https://yourdomain.com/api/check-permissions', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': 'Bearer ${permissionProviderToken}'
      },
      body: JSON.stringify({
        data: {
          requests: [
            {
              userId: 'user123',
              resource: {
                id: 'org456',
                type: 'organization',
                source: 'identify',
                organizationId: 'org456'
              }
            },
            {
              userId: 'user123',
              resource: {
                id: 'doc789',
                type: 'document',
                source: 'setDocuments',
                organizationId: 'org456'
              }
            },
            {
              userId: 'user123',
              resource: {
                id: 'folder101',
                type: 'folder',
                source: 'setDocuments',
                organizationId: 'org456'
              }
            },
            {
              userId: 'user123',
              resource: {
                id: 'doc789',
                type: 'context',
                source: 'setDocuments',
                organizationId: 'org456',
                context: {
                  access: {
                    entityId: 'numberOfVisitors'
                  }
                }
              }
            }
          ]
        }
      })
    });
    ```
  </Tab>

  <Tab title="Expected Response from Your Endpoint">
    ```json expandable theme={null}
    {
      "data": [
        {
          "userId": "user123",
          "resourceId": "org456",
          "type": "organization",
          "organizationId": "org456",
          "hasAccess": true
        },
        {
          "userId": "user123",
          "resourceId": "doc789",
          "type": "document",
          "organizationId": "org456",
          "hasAccess": true,
          "accessRole": "editor",
          "expiresAt": 1699876543210
        },
        {
          "userId": "user123",
          "resourceId": "folder101",
          "type": "folder",
          "organizationId": "org456",
          "hasAccess": true
        },
        {
          "userId": "user123",
          "resourceId": "doc789",
          "type": "context",
          "organizationId": "org456",
          "hasAccess": true
        }
      ],
      "success": true,
      "statusCode": 200,
      "message": "Permissions validated successfully"
    }
    ```
  </Tab>

  <Tab title="Your endpoint sample (Node.js / Express)">
    ```javascript expandable theme={null}
    app.post('/api/check-permissions', async (req, res) => {
      // Receive requests from Velt
      const { requests } = req.body.data;

      // Check your authorization system and build permissions array
      const permissions = [];

      for (const request of requests) {
        let permission;

        // Handle context-based permission requests
        if (request.resource.type === 'context') {
          const hasAccess = await yourAuthSystem.checkContextAccess(
            request.userId,
            request.resource.id,
            request.resource.context.access
          );

          permission = {
            userId: request.userId,
            resourceId: request.resource.id,
            type: 'context',
            organizationId: request.resource.organizationId,
            hasAccess: hasAccess,
          };
        }
        // Handle standard resource permission requests
        else {
          const hasAccess = await yourAuthSystem.checkUserAccess(
            request.userId,
            request.resource.id,
            request.resource.type
          );

          permission = {
            userId: request.userId,
            resourceId: request.resource.id,
            type: request.resource.type,
            organizationId: request.resource.organizationId,
            hasAccess: hasAccess,
          };

          // For documents, add access role
          if (request.resource.type === 'document' && hasAccess) {
            permission.accessRole = await yourAuthSystem.getUserRole(
              request.userId,
              request.resource.id
            ); // 'viewer' or 'editor'
            permission.expiresAt = Date.now() + 10 * 60 * 1000; // Optional: 10 min expiry
          }
        }

        permissions.push(permission);
      }

      // Return response in expected format
      res.json({
        data: permissions,
        success: true,
        statusCode: 200,
        message: 'Permissions validated successfully'
      });
    });
    ```
  </Tab>

  <Tab title="Your endpoint sample (Python / Flask)">
    ```python expandable theme={null}
    @app.route('/api/check-permissions', methods=['POST'])
    def check_permissions():
        # Receive requests from Velt
        request_data = request.json
        requests_list = request_data.get('data', {}).get('requests', [])

        # Check your authorization system and build permissions array
        permissions = []

        for req in requests_list:
            # Handle context-based permission requests
            if req['resource']['type'] == 'context':
                has_access = your_auth_system.check_context_access(
                    req['userId'],
                    req['resource']['id'],
                    req['resource']['context']['access']
                )

                permission = {
                    'userId': req['userId'],
                    'resourceId': req['resource']['id'],
                    'type': 'context',
                    'organizationId': req['resource']['organizationId'],
                    'hasAccess': has_access
                }
            # Handle standard resource permission requests
            else:
                has_access = your_auth_system.check_user_access(
                    req['userId'],
                    req['resource']['id'],
                    req['resource']['type']
                )

                permission = {
                    'userId': req['userId'],
                    'resourceId': req['resource']['id'],
                    'type': req['resource']['type'],
                    'organizationId': req['resource']['organizationId'],
                    'hasAccess': has_access
                }

                # For documents, add access role
                if req['resource']['type'] == 'document' and has_access:
                    permission['accessRole'] = your_auth_system.get_user_role(
                        req['userId'],
                        req['resource']['id']
                    )  # 'viewer' or 'editor'
                    permission['expiresAt'] = int(time.time() * 1000) + 10 * 60 * 1000  # Optional: 10 min expiry

            permissions.append(permission)

        # Return response in expected format
        return jsonify({
            'data': permissions,
            'success': True,
            'statusCode': 200,
            'message': 'Permissions validated successfully'
        })
    ```
  </Tab>
</Tabs>

**Step 3: Configure Permission Provider Behavior in your Frontend**

Configure Permission Provider behavior in your frontend using [`setPermissionProvider()`](/api-reference/sdk/api/api-methods#setpermissionprovider).

**Configuration Options:**

View the complete [`VeltPermissionProvider` schema](/api-reference/sdk/models/data-models#veltpermissionprovider) for all available options.

* `isContextEnabled`: Enable context-based permission requests for granular access control per context value. Default: `false`
* `retryConfig`: Configure retry attempts and delays for failed permission requests. Default: 3 retries with 2000ms delay. See [`AuthRetryConfig`](/api-reference/sdk/models/data-models#authretryconfig)
* `forceRefresh`: Force re-validation on each access check when permissions change frequently. Default: `false`
* `revokeAccessOn`: Configure automatic access revocation on specific events (e.g., document unset, user logout).

<Tabs>
  <Tab title="React / Next.js">
    You can configure the Permission Provider in two ways:

    Option 1: In VeltProvider (Recommended)

    ```jsx expandable theme={null}
    <VeltProvider
      apiKey="YOUR_API_KEY"
      permissionProvider={{
        isContextEnabled: true,
        retryConfig: { retryCount: 3, retryDelay: 2000 },
        forceRefresh: false,
      }}
    >
      {/* Your app */}
    </VeltProvider>
    ```

    Option 2: Using setPermissionProvider()

    ```jsx expandable theme={null}
    const { client } = useVeltClient();
    client.setPermissionProvider({
      isContextEnabled: true,
      retryConfig: { retryCount: 3, retryDelay: 2000 },
      forceRefresh: false,
    });
    ```

    <Note>
      When using `setPermissionProvider()` method, call it before `identify()`, `setAuthProvider()`, and `setDocument()` methods to ensure proper initialization.
    </Note>
  </Tab>

  <Tab title="Other Frameworks">
    <Note>
      When using `setPermissionProvider()` method, call it before `identify()`, `setAuthProvider()`, and `setDocument()` methods to ensure proper initialization.
    </Note>

    ```javascript theme={null}
    Velt.setPermissionProvider({
      isContextEnabled: true,
      retryConfig: { retryCount: 3, retryDelay: 2000 },
      forceRefresh: false,
    });
    ```
  </Tab>
</Tabs>

**Step 4: Configure Auto Revoke Access (optional)**

* Automatically revoke permissions when specific events occur, providing better control over user access and security.
* Access is automatically revoked from both cache and backend when triggered. This ensures immediate permission removal without requiring manual cleanup.
* Context access is only revoked when the user logs out and not at document unset.

**Configuration Options:**

* `type`: [`RevokeAccessOnType`](/api-reference/sdk/models/data-models#revokeaccessontype)
  * `document_unset`: Revokes access when user unsets or leaves a document
  * `user_logout`: Revokes access when user logs out

* `revokeOrganizationAccess`: Set to `true` to also revoke organization-level permissions (default: `false`)

<Tabs>
  <Tab title="React / Next.js">
    **Option 1: In VeltProvider (Recommended)**

    ```jsx expandable theme={null}
    <VeltProvider
      apiKey="YOUR_API_KEY"
      permissionProvider={{
        isContextEnabled: true,
        revokeAccessOn: {
          type: 'document_unset', // Revoke access when user leaves document
          revokeOrganizationAccess: false // Keep organization access
        }
      }}
    >
      {/* Your app */}
    </VeltProvider>
    ```

    **Option 2: Using setPermissionProvider()**

    ```jsx expandable theme={null}
    const { client } = useVeltClient();

    // Example 1: Revoke access on document unset only
    client.setPermissionProvider({
      revokeAccessOn: {
        type: 'document_unset',
        revokeOrganizationAccess: false
      }
    });

    // Example 2: Revoke all access including organization on user logout
    client.setPermissionProvider({
      revokeAccessOn: {
        type: 'user_logout',
        revokeOrganizationAccess: true // Also revoke organization permissions
      }
    });
    ```

    <Note>
      Context-level access is only revoked on user logout, not on document unset.
    </Note>
  </Tab>

  <Tab title="Other Frameworks">
    ```javascript expandable theme={null}
    // Example 1: Revoke access on document unset only
    Velt.setPermissionProvider({
      revokeAccessOn: {
        type: 'document_unset',
        revokeOrganizationAccess: false
      }
    });

    // Example 2: Revoke all access including organization on user logout
    Velt.setPermissionProvider({
      revokeAccessOn: {
        type: 'user_logout',
        revokeOrganizationAccess: true // Also revoke organization permissions
      }
    });
    ```
  </Tab>
</Tabs>

**Permission Provider Events**

[**On()**](/api-reference/sdk/api/api-methods#on-5)

Monitor permission checks by subscribing to Permission Provider events. These are the sub-event types you can receive:

| Sub-Event Type                         | Description                                                                                | Event Object                                                                             |
| -------------------------------------- | ------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------- |
| `resourceAccessRequestFormed`          | Triggered when a permission request is formed internally before being sent                 | [PermissionProviderEvent](/api-reference/sdk/models/data-models#permissionproviderevent) |
| `resourceAccessRequestTriggered`       | Triggered when a permission request is actually triggered and sent                         | [PermissionProviderEvent](/api-reference/sdk/models/data-models#permissionproviderevent) |
| `resourceAccessResult`                 | Triggered when a permission check result is received from your server                      | [PermissionProviderEvent](/api-reference/sdk/models/data-models#permissionproviderevent) |
| `resourceAccessError`                  | Triggered when an error occurs during permission checking                                  | [PermissionProviderEvent](/api-reference/sdk/models/data-models#permissionproviderevent) |
| `resourceAccessResultFromCache`        | Triggered when a permission result is retrieved from cache instead of making a new request | [PermissionProviderEvent](/api-reference/sdk/models/data-models#permissionproviderevent) |
| `revokeAccessOnDocumentUnsetTriggered` | Triggered when permissions are automatically revoked due to document unset trigger         | [RevokeAccessEvent](/api-reference/sdk/models/data-models#revokeaccessevent)             |
| `revokeAccessOnUserLogoutTriggered`    | Triggered when permissions are automatically revoked due to user logout trigger            | [RevokeAccessEvent](/api-reference/sdk/models/data-models#revokeaccessevent)             |

<Tabs>
  <Tab title="React / Next.js">
    **Using React Hook**

    ```jsx expandable theme={null}
    import { useVeltEventCallback } from '@veltdev/react';

    function PermissionMonitor() {
      // Subscribe to all permission provider events
      useVeltEventCallback('permissionProvider', (event) => {
        console.log('Permission provider event:', event);
      });
      // Event payload example for resourceAccessRequestTriggered:
      // {
      //   "event": "resourceAccessRequestTriggered",
      //   "timestamp": 1761580810137,
      //   "methodName": "onResourceAccessRequired",
      //   "source": "internal",
      //   "payload": {
      //     "requests": [
      //       {
      //         "userId": "1.1",
      //         "resource": {
      //           "id": "org1",
      //           "type": "organization",
      //           "source": "identify"
      //         }
      //       }
      //     ],
      //     "fromCache": false
      //   }
      // }

      // Event payload example for resourceAccessResult:
      // {
      //   "event": "resourceAccessResult",
      //   "timestamp": 1761580811228,
      //   "methodName": "onResourceAccessRequired",
      //   "source": "internal",
      //   "payload": {
      //     "result": {
      //       "data": [
      //         {
      //           "userId": "1.1",
      //           "resourceId": "org1",
      //           "type": "organization",
      //           "hasAccess": true
      //         }
      //       ],
      //       "success": true,
      //       "statusCode": 200,
      //       "signature": "811824052c1ea76f22fc67b36ca5dd867b89d4efeb85cf648bbbc0d2c0675545"
      //     }
      //   }
      // }

      // Event payload example for revokeAccessOnDocumentUnsetTriggered:
      // {
      //   "event": "revokeAccessOnDocumentUnsetTriggered",
      //   "timestamp": 1761580810137,
      //   "payload": {
      //     "userId": "user_123",
      //     "documentId": "doc_456",
      //     "organizationId": "org_789",
      //     "revokeOrganizationAccess": false
      //   }
      // }

      // Event payload example for revokeAccessOnUserLogoutTriggered:
      // {
      //   "event": "revokeAccessOnUserLogoutTriggered",
      //   "timestamp": 1761580810137,
      //   "payload": {
      //     "userId": "user_123",
      //     "organizationId": "org_789",
      //     "revokeOrganizationAccess": true
      //   }
      // }
      return <div>Monitoring permission events...</div>;
    }
    ```

    **Using Client Method**

    ```jsx expandable theme={null}
    const { client } = useVeltClient();

    // Subscribe to all permission provider events
    client.on('permissionProvider').subscribe(event => console.log(event));

    // Event payload example for resourceAccessRequestFormed:
    // {
    //   "event": "resourceAccessRequestFormed",
    //   "methodName": "identify",
    //   "timestamp": 1761580810137,
    //   "source": "internal",
    //   "payload": {
    //     "requests": [
    //       {
    //         "userId": "1.1",
    //         "resource": {
    //           "id": "org1",
    //           "type": "organization",
    //           "source": "identify"
    //         }
    //       }
    //     ]
    //   }
    // }

    // Event payload example for resourceAccessRequestTriggered:
    // {
    //   "event": "resourceAccessRequestTriggered",
    //   "timestamp": 1761580810137,
    //   "methodName": "onResourceAccessRequired",
    //   "source": "internal",
    //   "payload": {
    //     "requests": [
    //       {
    //         "userId": "1.1",
    //         "resource": {
    //           "id": "org1",
    //           "type": "organization",
    //           "source": "identify"
    //         }
    //       }
    //     ],
    //     "fromCache": false
    //   }
    // }

    // Event payload example for resourceAccessResult:
    // {
    //   "event": "resourceAccessResult",
    //   "timestamp": 1761580811228,
    //   "methodName": "onResourceAccessRequired",
    //   "source": "internal",
    //   "payload": {
    //     "result": {
    //       "data": [
    //         {
    //           "userId": "1.1",
    //           "resourceId": "org1",
    //           "type": "organization",
    //           "hasAccess": true
    //         }
    //       ],
    //       "success": true,
    //       "statusCode": 200,
    //       "signature": "811824052c1ea76f22fc67b36ca5dd867b89d4efeb85cf648bbbc0d2c0675545"
    //     }
    //   }
    // }

    // Event payload example for revokeAccessOnDocumentUnsetTriggered:
    // {
    //   "event": "revokeAccessOnDocumentUnsetTriggered",
    //   "timestamp": 1761580810137,
    //   "payload": {
    //     "userId": "user_123",
    //     "documentId": "doc_456",
    //     "organizationId": "org_789",
    //     "revokeOrganizationAccess": false
    //   }
    // }


    // Event payload example for revokeAccessOnUserLogoutTriggered:
    // {
    //   "event": "revokeAccessOnUserLogoutTriggered",
    //   "timestamp": 1761580810137,
    //   "payload": {
    //     "userId": "user_123",
    //     "organizationId": "org_789",
    //     "revokeOrganizationAccess": true
    //   }
    // }

    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```javascript theme={null}
    // Subscribe to all permission provider events
    Velt.on('permissionProvider').subscribe(event => console.log(event));

    // Event payload example for resourceAccessRequestFormed:
    // {
    //   "event": "resourceAccessRequestFormed",
    //   "methodName": "identify",
    //   "timestamp": 1761580810137,
    //   "source": "internal",
    //   "payload": {
    //     "requests": [
    //       {
    //         "userId": "1.1",
    //         "resource": {
    //           "id": "org1",
    //           "type": "organization",
    //           "source": "identify"
    //         }
    //       }
    //     ]
    //   }
    // }

    // Event payload example for resourceAccessRequestTriggered:
    // {
    //   "event": "resourceAccessRequestTriggered",
    //   "timestamp": 1761580810137,
    //   "methodName": "onResourceAccessRequired",
    //   "source": "internal",
    //   "payload": {
    //     "requests": [
    //       {
    //         "userId": "1.1",
    //         "resource": {
    //           "id": "org1",
    //           "type": "organization",
    //           "source": "identify"
    //         }
    //       }
    //     ],
    //     "fromCache": false
    //   }
    // }


    // Event payload example for resourceAccessResult:
    // {
    //   "event": "resourceAccessResult",
    //   "timestamp": 1761580811228,
    //   "methodName": "onResourceAccessRequired",
    //   "source": "internal",
    //   "payload": {
    //     "result": {
    //       "data": [
    //         {
    //           "userId": "1.1",
    //           "resourceId": "org1",
    //           "type": "organization",
    //           "hasAccess": true
    //         }
    //       ],
    //       "success": true,
    //       "statusCode": 200,
    //       "signature": "811824052c1ea76f22fc67b36ca5dd867b89d4efeb85cf648bbbc0d2c0675545"
    //     }
    //   }
    // }

    // Event payload example for revokeAccessOnDocumentUnsetTriggered:
    // {
    //   "event": "revokeAccessOnDocumentUnsetTriggered",
    //   "timestamp": 1761580810137,
    //   "payload": {
    //     "userId": "user_123",
    //     "documentId": "doc_456",
    //     "organizationId": "org_789",
    //     "revokeOrganizationAccess": false
    //   }
    // }

    // Event payload example for revokeAccessOnUserLogoutTriggered:
    // {
    //   "event": "revokeAccessOnUserLogoutTriggered",
    //   "timestamp": 1761580810137,
    //   "payload": {
    //     "userId": "user_123",
    //     "organizationId": "org_789",
    //     "revokeOrganizationAccess": true
    //   }
    // }
    ```
  </Tab>
</Tabs>

### d. Set Feature Level Permissions using Access Context

Access Context allows you to set granular, feature-level permissions using custom metadata. When configured, new feature data is added and existing feature data is fetched only for the access context values the current user has access to.

#### How it works

Access Context enables you to control access to specific features (like comments, notifications) based on custom metadata fields. For example, you could restrict comment visibility based on `widgetId`, `dashboardId`, or any custom field relevant to your application.

**Matching Logic:**

* When multiple fields are present in the context, Velt checks access for each field combination
* When multiple array values exist in each field, each value creates a separate permission request
* A user must have access to **all** fields in a context to view the associated feature data
* The access context supports up to **200 items** total

#### Configuration Steps

**Step 1: Add Access Context to Features**

You need to add access context metadata to your features on both frontend and backend.

**Frontend:**

<Note>
  If you add access context to comments, other features associated with it (like notifications) will automatically inherit the same access context.
</Note>

When a comment annotation is added, attach the access context using the `addContext()` method. Pass a **string or number** for each context field:

<Tabs>
  <Tab title="React / Next.js">
    ```jsx theme={null}
    const commentElement = client.getCommentElement();

    commentElement.on('addCommentAnnotation').subscribe((event) => {
      event.addContext({
        access: {
          widgetId: 2  // Pass string or number, not array
        }
      });
    });
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```js theme={null}
    const commentElement = Velt.getCommentElement();

    commentElement.on('addCommentAnnotation').subscribe((event) => {
      event.addContext({
        access: {
          widgetId: 2  // Pass string or number, not array
        }
      });
    });
    ```
  </Tab>
</Tabs>

**Backend:**
If you are adding comments or notifications using REST APIs, you can use the following:

<Tabs>
  <Tab title="Comments">
    Use the REST API to add access context when creating comments programmatically:

    ```json theme={null}
    POST /v2/comments
    {
      "data": {
        "organizationId": "org1",
        "documentId": "document1",
        "commentText": "This is a comment",
        "context": {
          "access": {
            "widgetId": 2
          }
        }
      }
    }
    ```
  </Tab>

  <Tab title="Notifications">
    Use the REST API to add access context when creating notifications:

    ```json theme={null}
    POST /v2/notifications
    {
      "data": {
        "organizationId": "org1",
        "documentId": "document1",
        "notificationText": "New update available",
        "context": {
          "access": {
            "dashboardId": "dashboard1"
          }
        }
      }
    }
    ```
  </Tab>
</Tabs>

**Step 2: Enable Context-Based Permissions**

Enable access context permission validation by setting `isContextEnabled: true` in your Permission Provider configuration. When enabled, the Permission Provider will receive individual requests for each context value, allowing you to control access at a granular level for features like comments and notifications.

<Tabs>
  <Tab title="React / Next.js">
    Option 1: In VeltProvider (Recommended)

    ```jsx expandable theme={null}
    <VeltProvider
      apiKey="YOUR_API_KEY"
      permissionProvider={{
        isContextEnabled: true, // Enable context-based permissions for notifications
        retryConfig: {
          retryCount: 3,
          retryDelay: 2000
        },
        forceRefresh: false,
        revokeAccessOn: [
          {
            type: "document_unset",
            revokeOrganizationAccess: false
          },
          {
            type: "user_logout",
            revokeOrganizationAccess: true
          }
        ]
      }}
    >
      {/* Your app */}
    </VeltProvider>
    ```

    Option 2: Using setPermissionProvider()

    ```jsx expandable theme={null}
    const { client } = useVeltClient();

    client.setPermissionProvider({
      isContextEnabled: true, // Enable context-based permissions for notifications
      retryConfig: {
        retryCount: 3,
        retryDelay: 2000
      },
      forceRefresh: false,
      revokeAccessOn: [
        {
          type: "document_unset",
          revokeOrganizationAccess: false
        },
        {
          type: "user_logout",
          revokeOrganizationAccess: true
        }
      ]
    });
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```js expandable theme={null}
    Velt.setPermissionProvider({
      isContextEnabled: true, // Enable context-based permissions for notifications
      retryConfig: {
        retryCount: 3,
        retryDelay: 2000
      },
      forceRefresh: false,
      revokeAccessOn: [
        {
          type: "document_unset",
          revokeOrganizationAccess: false
        },
        {
          type: "user_logout",
          revokeOrganizationAccess: true
        }
      ]
    });
    ```
  </Tab>
</Tabs>

**Step 3: Subscribe to documents with specific Access Context**

Add access context when subscribing to documents. Pass the access context values as arrays in `setDocuments()`. Each value will generate a separate permission request:

<Info>
  **Context to Permission Conversion:** When you pass arrays of context values in `setDocuments()`, Velt automatically converts them to individual permission requests. For example, `entityId: ['value1', 'value2']` becomes two separate requests with `entityId: 'value1'` and `entityId: 'value2'`.
</Info>

<Tabs>
  <Tab title="React / Next.js">
    ```jsx expandable theme={null}
    const { client } = useVeltClient();

    client.setDocuments(documents, {
      context: {
        access: {
          widgetId: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] // Up to 200 items total
        }
      }
    });
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```js expandable theme={null}
    Velt.setDocuments(documents, {
      context: {
        access: {
          widgetId: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] // Up to 200 items total
        }
      }
    });
    ```
  </Tab>

  <Tab title="Request Example">
    **Example Request to Your Permission Provider Endpoint:**

    ```json expandable theme={null}
    {
      "data": {
        "requests": [
          {
            "userId": "1.1",
            "resource": {
              "id": "document1",
              "type": "document",
              "source": "setDocuments",
              "organizationId": "org1"
            }
          },
          {
            "userId": "1.1",
            "resource": {
              "id": "{\"widgetId\":1}",
              "type": "context",
              "source": "setDocuments",
              "organizationId": "org1",
              "context": {
                "access": { "widgetId": 1 }
              }
            }
          },
          {
            "userId": "1.1",
            "resource": {
              "id": "{\"widgetId\":2}",
              "type": "context",
              "source": "setDocuments",
              "organizationId": "org1",
              "context": {
                "access": { "widgetId": 2 }
              }
            }
          }
          // ... more context items
        ]
      }
    }
    ```
  </Tab>

  <Tab title="Response Example">
    **Example Response from Your Endpoint:**

    ```json expandable theme={null}
    {
      "data": [
        {
          "userId": "1.1",
          "resourceId": "document1",
          "type": "document",
          "hasAccess": true,
          "organizationId": "org1"
        },
        {
          "userId": "1.1",
          "resourceId": "{\"widgetId\":1}",
          "type": "context",
          "hasAccess": true,
          "organizationId": "org1"
        },
        {
          "userId": "1.1",
          "resourceId": "{\"widgetId\":2}",
          "type": "context",
          "hasAccess": false,
          "organizationId": "org1"
        }
        // ... more context results
      ],
      "success": true,
      "statusCode": 200
    }
    ```
  </Tab>
</Tabs>

### Query Permissions

The following APIs can be used to query user permissions regardless of which permission approach you're using (On-Demand, Synced, or Real-time Permission Provider).

#### Backend API

[**Get Permissions**](/api-reference/rest-apis/v2/auth/get-permissions): Query a user's effective permissions/roles for the given resources. This returns what permissions your user has according to Velt.

#### Frontend APIs

##### getUserPermissions()

One-time fetch that returns a promise with the current user's permissions.

* **Params:** `request?`: [GetUserPermissionsRequest](/api-reference/sdk/models/data-models#getuserpermissionsrequest)
* **Returns:** `Promise<`[GetUserPermissionsResponse](/api-reference/sdk/models/data-models#getuserpermissionsresponse)`>`

<Tabs>
  <Tab title="React / Next.js">
    ```ts theme={null}
    const request = {
      organizationId: 'org_123',
      folderIds: ['folder_1', 'folder_2'],
      documentIds: ['doc_1', 'doc_2']
    };

    const permissions = await client.getUserPermissions(request);
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```js theme={null}
    const request = {
      organizationId: 'org_123',
      folderIds: ['folder_1', 'folder_2'],
      documentIds: ['doc_1', 'doc_2']
    };

    const permissions = await Velt.getUserPermissions(request);
    ```
  </Tab>
</Tabs>

##### getCurrentUserPermissions()

Subscribe to real-time permission updates for the current authenticated user. Returns an observable that emits whenever permissions change.

* **Params:** None
* **Returns:** `Observable<`[GetUserPermissionsResponse](/api-reference/sdk/models/data-models#getuserpermissionsresponse)`>`

<Tabs>
  <Tab title="React / Next.js">
    ```ts theme={null}
    const subscription = client.getCurrentUserPermissions().subscribe((permissions) => {
      console.log('Current user permissions:', permissions);
    });

    // Cleanup when done
    subscription.unsubscribe();
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```js theme={null}
    const subscription = Velt.getCurrentUserPermissions().subscribe((permissions) => {
      console.log('Current user permissions:', permissions);
    });

    // Cleanup when done
    subscription.unsubscribe();
    ```
  </Tab>
</Tabs>

**Response Structure:**

Both APIs return the same response format:

```json theme={null}
{
  "result": {
    "status": "success",
    "message": "User permissions retrieved successfully.",
    "data": {
      "user_123": {
        "folders": {
          "folder1": {
            "accessRole": "editor",
            "accessType": "restricted"
          }
        },
        "documents": {
          "document1": {
            "accessRole": "editor",
            "accessType": "restricted"
          }
        },
        "organization": {
          "org1": {
            "accessRole": "editor"
          }
        },
        "context": {
          "accessFields": ["widgetId:1", "widgetId:2", "widgetId:3"]
        }
      }
    }
  }
}
```

<Note>
  See the [API Reference](/api-reference/sdk/api/api-methods#getcurrentuserpermissions) for detailed method documentation.
</Note>
