Autodesk Construction Cloud
Autodesk Construction Cloud (ACC) integrates with VIKTOR using OAuth 2.0 through Autodesk Platform Services (APS) integration. Within VIKTOR, you can access the full set of ACC APIs. The following sections describe the main guidelines, requirements, and limitations.
Preliminary steps
The first step is to set up an OAuth 2.0 integration, which provides token-based authentication and authorization. A VIKTOR administrator must configure this integration in both APS and VIKTOR, following these steps.
After this, your VIKTOR–APS integration can connect to Autodesk Construction Cloud using Custom integrations. A custom integration links your ACC account to your APS application, and you can query your hubs and projects as shown here.
Requirements and guidelines for using ACC APIs
After setting up the APS and ACC integration, you can take advantage of VIKTOR building blocks and focus on what you want to create instead of worrying about OAuth workflows, tokens, and authentication. In the following sections we cover the most used APIs and the considerations you should keep in mind when integrating them in VIKTOR.
The most common way to integrate your models in your own applications is by using the Data Management API, AEC Data Model API, and Data Exchange API. These APIs allow you to navigate your project structure, manage files and their versions, and query elements from your Revit models to access their properties. With this information, you can build quantity takeoff workflows, quality assurance and compliance checks, or generate dashboards to get the most out of your BIM models.
Family | Purpose |
---|---|
Data Management API | Manage hubs, projects, folders, and files. Retrieve folder contents, get file versions, and access metadata. |
AEC Data Model API | Query design data across hubs, projects, element groups, and elements with region-aware GraphQL requests. |
Data Exchange API | Query and manage data stored in a Data Exchange, such as elements, properties, and relationships. |
Data Management API
The Data Management API lets you navigate through the content of your ACC hub. You can get the list of hubs linked to your account, the projects inside each hub, and the files in every project. You can also select a file and read its information.
With this API you can:
- Access your ACC structure: Navigate through hubs, projects, folders, and items to understand your project organization.
- Manage file versions: Retrieve version history, download specific versions, and track changes over time.
- Upload and update files: Programmatically upload new files or create new versions of existing files.
- Search and filter: Find files and folders using search queries and filters to quickly locate the data you need.
- Work with metadata: Read and update custom attributes and metadata associated with your files.
- Manage permissions: Check user access and collaborate with team members by understanding who has access to which resources.
Typically, you would build a user interface to let users pick a file and then open it with the APS Viewer to explore the BIM model. However, these functions work out of the box with the VIKTOR SDK, and we will see how in the later sections.
AEC Data Model API
The AEC Data Model API exposes a GraphQL interface that gives direct cloud access to granular design data. You do not need to write application plugins or perform extra processing to retrieve the data.
Here are the main things you can do:
- Navigate projects and designs: Access hubs, projects, and design models to retrieve detailed data such as elements and their parameters.
- Work with versions: Retrieve design versions and query elements at a specific version.
- Search elements: Find elements in one design or across multiple designs using filters.
- List properties: Get all property definitions available in a design or project.
- Query by property: Filter elements by categories (doors, windows, pipes) or by parameter name and value (area, volume).
Activating the AEC Data Model
Before using the AEC Data Model API, it must be activated in your ACC account by your ACC Account Administrator. Contact your admin and request that they activate the AEC Data Model for your account. The admin can do this by going to Settings in the Account Admin page and toggling the "Enable AEC Data Model capabilities" option. It is not active by default. You can follow the complete onboarding guide for detailed steps.
AEC Data Model limitations
The following are known limitations that should be considered when working with the AEC Data Model API and VIKTOR:
- Supported regions: US, EMEA, and AUS. See the regions guide.
- Linked Revit models are not supported.
- Full geometry queries are not yet available. See the list of limitations.
- Only works with Revit 2024 and later. Check your version and review the FAQ.
Data Exchange API
The Data Exchange API lets you share only the parts of a model that you need for your work. A Data Exchange is created from a 3D view in your software (such as Revit) and published to ACC.
This allows you to share a Revit view that shows only the structural elements of a building instead of sharing the entire model. This makes it easier to focus on what matters, improves performance, and enables you to share data with the right team.
With the Data Exchange API you can:
- Navigate to your ACC hub(s), project(s), and folder(s to retrieve a Data Exchange and its detailed data such as elements, properties, and their values
- Retrieve only the data you need through GraphQL queries
- Retrieve a list of property definitions within a Data Exchange
- Retrieve a specific version of a Data Exchange
Creating a Data Exchange
You can create a Data Exchange directly in ACC and then use the API. Follow the official guide to set this up.
A Data Exchange can also be created through connectors. You can see the list of available connectors on this page. For example, with Revit you can create a Data Exchange by following this guide.
Limitations
The following are known limitations of the Data Exchange API:
- Supported in the same regions as the AEC Data Model API
- Full geometry information about the model is not yet fully supported
- See the complete list of limitations
Working with ACC in VIKTOR apps
VIKTOR supports OAuth2 workflows out of the box with the OAuth2Integration. This means you can request a token inside your VIKTOR app with a single method call.
In addition, you have the vkt.AutodeskFileField
, which lets you navigate through your hubs. Under the hood this component uses the Data Management API and gives you key information such as the file URN, version, and file downloads.
You also have the vkt.AutodeskView
, which makes it simple to work with the APS Viewer so you can explore BIM models directly in your app.
To set up the integration in your VIKTOR app, the developer must add the integration name to the app configuration. The platform then shows a login button when the user opens the app. Make sure your viktor.config.toml
contains the name exactly as configured in the Administrator panel, and include an oauth2_integrations
entry with the integration name, for example:
viktor.config.toml
:
app_type = "editor"
python_version = "3.13"
registered_name = "your-app-name"
oauth2_integrations = [
"aps-integration-1"
]
With just a few lines of code you can create an app that lets you select a file from your ACC hub and view the Revit model:
import viktor as vkt
class Parametrization(vkt.Parametrization):
revit_file = vkt.AutodeskFileField(
"Select Revit File from ACC",
oauth2_integration="aps-integration-1"
)
class Controller(vkt.Controller):
parametrization = Parametrization
@vkt.AutodeskView("File Visualization")
def visualize_file(self, params, **kwargs):
if not params.revit_file:
raise vkt.UserError("Please select a Revit file from ACC")
integration = vkt.external.OAuth2Integration("aps-integration-1")
access_token = integration.get_access_token()
return vkt.AutodeskResult(params.revit_file, access_token=access_token)
The integration name in OAuth2Integration
must match the value in viktor.config.toml
. The ACC custom integration must be added in Account Admin, and the user must have access to projects in that account.
Example - Data Management API
While VIKTOR's building blocks like AutodeskFileField
and AutodeskView
provide the easiest way to work with ACC, you can also create custom implementations using the Data Management API directly. This example shows how to retrieve a list of all hubs linked to your ACC account and display them in a table. You can use this approach when you need more control or want to build custom workflows beyond what the built-in components offer.
import viktor as vkt
import requests
class Parametrization(vkt.Parametrization):
pass
class Controller(vkt.Controller):
parametrization = Parametrization
@vkt.TableView("Hubs Overview")
def view_hubs_table(self, params, **kwargs):
# Get access token from OAuth2 integration
integration = vkt.external.OAuth2Integration("aps-integration-1")
access_token = integration.get_access_token()
# Fetch hubs data from APS Data Management API
base_url = "https://developer.api.autodesk.com"
endpoint = f"{base_url}/project/v1/hubs"
headers = {
"Authorization": f"Bearer {access_token}",
"Content-Type": "application/json"
}
response = requests.get(endpoint, headers=headers)
if response.status_code != 200:
raise Exception(f"Failed to fetch hubs: {response.status_code} - {response.text}")
data = response.json()
hubs_data = data.get('data', [])
# Prepare table data
table_data = []
column_headers = [
vkt.TableHeader("Hub Name"),
vkt.TableHeader("Hub ID"),
vkt.TableHeader("Region")
]
for hub in hubs_data:
# Extract hub information
hub_name = hub.get('attributes', {}).get('name', 'Unknown')
hub_id = hub.get('id', 'Unknown')
region = hub.get('attributes', {}).get('region', 'Unknown')
# Add row to table
table_data.append([hub_name, hub_id, region])
return vkt.TableResult(data=table_data, column_headers=column_headers)
Example - AEC Data Model API
After setting up the APS integration, you can also use the AEC Data Model API inside VIKTOR. This API gives you direct access to granular design data such as hubs, projects, elements, and their properties.
import viktor as vkt
import requests
AEC_GRAPHQL_URL = "https://developer.api.autodesk.com/aec/graphql"
AEC_REGION = "US" # Use "EMEA" if your tenant is in Europe
class Parametrization(vkt.Parametrization):
pass
class Controller(vkt.Controller):
parametrization = Parametrization
def get_hubs(self, token):
query = """
query GetHubs {
hubs {
results { id name }
}
}
"""
headers = {
"Authorization": f"Bearer {token}",
"Content-Type": "application/json",
"Region": AEC_REGION,
}
response = requests.post(AEC_GRAPHQL_URL, headers=headers, json={"query": query})
data = response.json().get("data", {})
return data.get("hubs", {}).get("results", [])
def get_projects(self, token, hub_id):
query = """
query GetProjects($hubId: ID!) {
projects(hubId: $hubId) {
pagination {
cursor
}
results {
id
name
alternativeIdentifiers {
dataManagementAPIProjectId
}
}
}
}
"""
headers = {
"Authorization": f"Bearer {token}",
"Content-Type": "application/json",
"Region": AEC_REGION,
}
payload = {
"query": query,
"variables": {"hubId": hub_id}
}
response = requests.post(AEC_GRAPHQL_URL, headers=headers, json=payload)
data = response.json().get("data", {})
return data.get("projects", {}).get("results", [])
def get_element_groups(self, token, project_id):
query = """
query GetElementGroupsByProject($projectId: ID!) {
elementGroupsByProject(projectId: $projectId) {
pagination {
cursor
}
results {
name
id
alternativeIdentifiers {
fileUrn
fileVersionUrn
}
}
}
}
"""
headers = {
"Authorization": f"Bearer {token}",
"Content-Type": "application/json",
"Region": AEC_REGION,
}
payload = {
"query": query,
"variables": {"projectId": project_id}
}
response = requests.post(AEC_GRAPHQL_URL, headers=headers, json=payload)
data = response.json().get("data", {})
return data.get("elementGroupsByProject", {}).get("results", [])
@vkt.TableView("AEC Element Groups")
def get_aec_element_groups(self, params, **kwargs):
integration = vkt.external.OAuth2Integration("aps-integration-1")
token = integration.get_access_token()
# Get hubs
hubs = self.get_hubs(token)
if not hubs:
return vkt.TableResult([["No hubs found", "", "", ""]], column_headers=["Element Group Name", "Element Group ID", "File URN", "File Version URN"])
# Get projects from the first hub
first_hub_id = hubs[0].get("id", "")
projects = self.get_projects(token, first_hub_id)
if not projects:
return vkt.TableResult([["No projects found", "", "", ""]], column_headers=["Element Group Name", "Element Group ID", "File URN", "File Version URN"])
# Prepare table data
rows = []
# Iterate through all projects
for project in projects:
project_id = project.get("id", "")
element_groups = self.get_element_groups(token, project_id)
# Add element groups from this project to rows
for group in element_groups:
group_name = group.get("name", "")
group_id = group.get("id", "")
alt_ids = group.get("alternativeIdentifiers") or {}
file_urn = alt_ids.get("fileUrn", "")
file_version_urn = alt_ids.get("fileVersionUrn", "")
rows.append([group_name, group_id, file_urn, file_version_urn])
# Check if no element groups found across all projects
if not rows:
return vkt.TableResult([["No element groups found", "", "", ""]], column_headers=["Element Group Name", "Element Group ID", "File URN", "File Version URN"])
return vkt.TableResult(rows, column_headers=["Element Group Name", "Element Group ID", "File URN", "File Version URN"])
Example – Data Exchange API
To use the Data Exchange API in VIKTOR, the endpoints are accessed through GraphQL queries. GraphQL is a query language where you retrieve data with queries. Below is a simple example to query the Data Exchange API and list hubs, projects, folders, and data exchanges. You can extend it to retrieve detailed model information. See more advanced queries.
import viktor as vkt
import requests
DX_GRAPHQL_URL = "https://developer.api.autodesk.com/dataexchange/2023-05/graphql"
APS_REGION = "US" # Use "EMEA" if your tenant is in Europe
class Parametrization(vkt.Parametrization):
pass
class Controller(vkt.Controller):
parametrization = Parametrization
def get_hubs(self, token):
query = """
query GetHubs {
hubs {
results {
name
id
}
}
}
"""
headers = {
"Authorization": f"Bearer {token}",
"x-ads-region": APS_REGION,
"Content-Type": "application/json",
}
response = requests.post(DX_GRAPHQL_URL, headers=headers, json={"query": query})
data = response.json().get("data", {})
return data.get("hubs", {}).get("results", [])
def get_projects(self, token, hub_id):
query = """
query GetProjects($hubId: ID!) {
projects(hubId: $hubId) {
results {
id
name
}
}
}
"""
headers = {
"Authorization": f"Bearer {token}",
"x-ads-region": APS_REGION,
"Content-Type": "application/json",
}
payload = {
"query": query,
"variables": {"hubId": hub_id}
}
response = requests.post(DX_GRAPHQL_URL, headers=headers, json=payload)
data = response.json().get("data", {})
return data.get("projects", {}).get("results", [])
def get_project_folders(self, token, project_id):
query = """
query GetProjectFolders($projectId: ID!) {
project(projectId: $projectId) {
id
name
folders {
results {
id
name
}
}
}
}
"""
headers = {
"Authorization": f"Bearer {token}",
"x-ads-region": APS_REGION,
"Content-Type": "application/json",
}
payload = {
"query": query,
"variables": {"projectId": project_id}
}
response = requests.post(DX_GRAPHQL_URL, headers=headers, json=payload)
data = response.json().get("data", {})
project = data.get("project", {})
return project.get("folders", {}).get("results", [])
def get_folder_content(self, token, folder_id):
query = """
query GetFolderContent($folderId: ID!) {
folder(folderId: $folderId) {
exchanges {
results {
id
name
alternativeIdentifiers {
fileUrn
fileVersionUrn
}
}
}
}
}
"""
headers = {
"Authorization": f"Bearer {token}",
"x-ads-region": APS_REGION,
"Content-Type": "application/json",
}
payload = {
"query": query,
"variables": {"folderId": folder_id}
}
response = requests.post(DX_GRAPHQL_URL, headers=headers, json=payload)
data = response.json().get("data", {})
return data.get("folder", {})
@vkt.TableView("Data Exchanges")
def get_data_exchanges(self, params, **kwargs):
integration = vkt.external.OAuth2Integration("aps-integration-1")
token = integration.get_access_token()
# Step 1: Get first hub
hubs = self.get_hubs(token)
if not hubs:
return vkt.TableResult([["No hubs found", "", ""]], column_headers=["Exchange Name", "Exchange ID", "File URN"])
first_hub_id = hubs[0].get("id", "")
# Step 2: Get first project from hub
projects = self.get_projects(token, first_hub_id)
if not projects:
return vkt.TableResult([["No projects found", "", ""]], column_headers=["Exchange Name", "Exchange ID", "File URN"])
first_project_id = projects[0].get("id", "")
# Step 3: Get folders from project
folders = self.get_project_folders(token, first_project_id)
if not folders:
return vkt.TableResult([["No folders found", "", ""]], column_headers=["Exchange Name", "Exchange ID", "File URN"])
first_folder_id = folders[0].get("id", "")
# Step 4: Get folder content (including data exchanges)
folder_content = self.get_folder_content(token, first_folder_id)
exchanges = folder_content.get("exchanges", {}).get("results", [])
# Check if no exchanges found
if not exchanges:
return vkt.TableResult([["No exchanges found in this folder", "", ""]], column_headers=["Exchange Name", "Exchange ID", "File URN"])
# Prepare table data
rows = []
for exchange in exchanges:
exchange_name = exchange.get("name", "")
exchange_id = exchange.get("id", "")
alt_ids = exchange.get("alternativeIdentifiers") or {}
file_urn = alt_ids.get("fileUrn", "")
rows.append([exchange_name, exchange_id, file_urn])
return vkt.TableResult(rows, column_headers=["Exchange Name", "Exchange ID", "File URN"])