Skip to main content

API overview

Programmatically list and run Hex projects with the API.

info

Available on the Team and Enterprise plans; certain endpoints are exclusive to the Enterprise plan.

The Hex public API allows teams to programmatically interact with their Hex workspace — including listing projects, triggering runs of published projects, managing access controls, and configuring data connections.

  • Core Admin APIs, such as user, group, collection, and project run management, are available to both Team and Enterprise plans.
  • Advanced capabilities, such as retrieving queried tables for a given project, are available on the Enterprise plan only.

If you are looking to integrate Hex project runs into orchestration tools, check our native integrations with Airflow, Dagster, and Shipyard.

For full path parameters and request/response schemas, view the API reference.

Authentication

API requests are authenticated using OAuth 2.0 Bearer Tokens in the header of the HTTP request. The token is always bound to a single Hex user's account and requests are executed as that Hex user, meaning the user can only execute requests against projects that are in line with the current permissions for that project.

Token creation

There are two types of tokens users can create: Personal access tokens and Workspace tokens.

UI showing API keys page

Personal access tokens

Personal access tokens mirror the same permissions that a user has within the Hex product. They can be created by anyone with an Editor or higher workspace role. Unlike workspace tokens (which can have no expiration), they must be configured to expire after a fixed duration.

info

Enforcing token expiration for personal access tokens ensures that tokens are rotated frequently.

To create a Personal access token, head to the user settings, and then the API keys page under the Account section. Then, select the New Token button and provide a description and an expiration time frame. An existing token can be regenerated at any time by selecting the three-dot menu to the right of the token, and selecting Regenerate.

warning

Regenerating a personal access token will generate a new value for the token and immediately revoke the existing token.

If a user is deactivated in a workspace, their personal access tokens will no longer work.

Workspace tokens

Workspace tokens are created, managed, and shared by Admins of a workspace. Unlike personal access tokens, workspace tokens can be configured to never expire. This more permissive setting is available for workspace tokens, since any Admin can revoke this token at any time.

To create a Workspace token, head to the user settings, and then the API keys page under the Account section. Then, select the New Token button and provide a description and an expiration time frame. Workspace tokens can be configured to have the following scopes:

  • Read projects: The token will work with any API endpoint that only gets information (e.g. ListProjects and GetProjectRuns).
  • Run projects: The token will also work with the RunProjects endpoint.
  • For Users, Groups, Collections, and Data connections: The token can be specified to have read-only or write access (which includes read).
Example dialog of adding scopes to an API token
tip

If you are creating a token that is used to orchestrate projects across a workspace, consider using a Workspace token so that the token is not scoped to an individual user.

Comparison

FeaturePersonal access tokenWorkspace token
Required workspace roleEditor or higherAdmin only
Maximum expirationFollows expiration rules configured by AdminsCan be configured to never expire
PermissionsMirrors an individual user's permissionsMirrors the admin permissions for the workspace, with additional configuration for scopes

Token expiration

When creating a token, users can specify an expiration period:

  • Personal access tokens: When creating a personal access token, users can specify a time to live that is equal to, or less than, the maximum expiration time configured by an Admin (see below). Durations may include 7, 30, 60, 90, or 120 days.
  • Workspace tokens: When creating a workspace token, admins can specify an expiration that is a fixed duration (one of 7, 30, 60, 90, or 120 days), or no expiry.

To configure the maximum expiration for a personal access token, Admins can head to the Integrations page, under the Workspace section of Settings.

Users will receive an email notification 72 hours before and 24 hours before any token expires, warning them that the token will be expiring soon. Tokens can be manually revoked by clicking the three-dot menu to the right of the token, and selecting Revoke. Once a token is revoked or expired, the token can never again be used to authenticate requests.

Using the API

The Hex API provides programmatic access to a broad set of capabilities within the Hex platform, supporting both project execution and administrative workflows.

Initially designed to run published Hex projects with specific inputs—enabling automation of workflows, refreshing cached query results, and updating app state—the API has since expanded to include endpoints for managing:

  • Users and their roles
  • Groups and access controls
  • Collections of projects
  • Data connections and credentials (for Tier 1 connectors)

This expanded API surface allows teams to automate administration, enforce governance, and integrate Hex more deeply into existing systems. You can find the full reference documentation for the Hex API here.

info

If your workspace is using Directory Sync, users and groups will continue to be managed there and not via API.

The examples below use the requests package to run the API, though it can also be accessed using tools like running a cURL command, Postman, or any HTTP client of your choice.

Setup needed for the API

To use the API correctly, first run some setup code. Ensure that you replace values for your specific use-case.

  • Base URL: For most Hex users, this will be https://app.hex.tech/api/v1. Single-tenant app users should replace the app.hex.tech part of this URL with the URL they use to access Hex (e.g. atreides.hex.tech).
  • Project ID: The project ID can be found by visiting the project you wish to run, and copying it from the URL — the ID is the part of the URL after the /hex/. Additionally, the project ID can be found in the Variables view of the sidebar.
  • Token: See the above section on token creation. Consider using a secret to store this more securely.
import requests

# Single tenant users will need to replace this with their Hex URL
BASE_URL = 'https://app.hex.tech/api/v1'

# Replace this with the project ID
PROJECT_ID = '5a8591dd-4039-49df-9202-96385ba3eff8'

# Replace this with your token
TOKEN = '5bbf1c8b1989d6657d5c'

Run a published project with default inputs

This API call uses the RunProject endpoint to run a published project with its default inputs. It does not update the cache for this project.

response = requests.post(
url=f"{BASE_URL}/projects/{PROJECT_ID}/runs",
headers={"Authorization" : f"Bearer {TOKEN}"}
)

The response from this request will contain a runUrl which will display the results of the project run as a Snapshot, viewable by any user who has at least view access to the project.

Run a published project with custom inputs

The RunProject endpoint contains an optional inputParams body parameter that allows users to specify the values for Input parameters to be used in the project run.

inputs = {
"inputParams": {
"user_name": "j_doe",
"team": "finance",
"id": 1234567890
}
}

response = requests.post(
url=f"{BASE_URL}/projects/{PROJECT_ID}/runs",
json=inputs,
headers={"Authorization" : f"Bearer {TOKEN}"}
)

Update the cached state and query cache of a published project

The RunProject API allows control over two key caching options: updatePublishedResults for updating the published app's state, and useCachedSqlResults for controlling whether cached SQL results are used.

updatePublishedResults: When updatePublishedResults is set to false in a RunProject request (the default), the project run will not update the published app state. When updatePublishedResults is set to true, the project run will update the cached state of the published app with the latest run results⁠. This ensures that viewers see the results generated by the run when they open the app.⁠

In order to set updatePublishedResults to true, "Show results from a publish, or scheduled run" must be enabled. If inputParams are included in the request with updatePublishedResults set to true, the provided parameter values will be ignored, as updating the published app’s cache state requires the default Input parameter values to be used.

useCachedSqlResults: When useCachedSqlResults is set to true in a RunProject request (the default), the project will use cached SQL results if available. When useCachedSqlResults is set to false, SQL cells will run without hitting the cache, essentially refreshing the cached SQL query results for future runs.

In order for a query to execute and update cached results using useCachedSqlResults, "Use SQL caching in published app" must be enabled on the project’s Published app run settings.

# Forces a fresh run of SQL queries and updates the published app with new results
inputs = {
"useCachedSqlResults": "false",
"updatePublishedResults": "true"
}

response = requests.post(
url=f"{BASE_URL}/projects/{PROJECT_ID}/runs",
json=inputs,
headers={"Authorization" : f"Bearer {TOKEN}"}
)

Create a new group given a list of user emails

warning

Group names are not unique - if you create a group with the same name as one that already exists, a new group with the same name will be created.

Step 1: Get User IDs from Emails

import requests

# Example: Fetch user list to get IDs
resp = requests.get(
"https://api.hex.tech/api/v1/users",
headers={"Authorization": f"Bearer {YOUR_API_TOKEN}"}
)
users = resp.json()["users"]
email_to_id = {u["email"]: u["id"] for u in users}
tip

You’ll need to fetch all users across paginated API responses

Step 2: Create the Group

group_payload = {
"name": "Data Engineering Team",
"members": {
"users": [{"id": email_to_id["[email protected]"]}, {"id": email_to_id["[email protected]"]}]
}
}

resp = requests.post(
"https://api.hex.tech/api/v1/groups",
json=group_payload,
headers={"Authorization": f"Bearer {YOUR_API_TOKEN}"}
)

Create a new Collection with specific sharing permissions

The CreateCollection endpoint lets you define sharing settings for users, groups, or the workspace at creation.

info

You must have admin privileges to set group and workspace-level access.

collection_payload = {
"id": "collection-projects-q3",
"name": "Q3 Projects",
"description": "All Q3 cross-functional initiatives",
"members": {
"groups": [
{"id": "group-analytics", "access": "MEMBER"},
{"id": "group-admins", "access": "MANAGER"}
],
"workspace": {"members": "MEMBER"}
}
}

resp = requests.post(
"https://api.hex.tech/api/v1/collections",
json=collection_payload,
headers={"Authorization": f"Bearer {YOUR_API_TOKEN}"}
)

Change Collection permissions

To update permissions on an existing Collection, use the EditCollection endpoint. You can upsert user/group/workspace access using the sharing.upsert field.

edit_payload = {
"id": "collection-projects-q3",
"sharing": {
"upsert": {
"groups": [
{"id": "group-analytics", "access": "NONE"}, # Remove access
{"id": "group-ops", "access": "MEMBER"} # Add new group
],
"workspace": {"members": "MANAGER"}
}
}
}

resp = requests.patch(
"https://api.hex.tech/api/v1/collection/collection-projects-q3",
json=edit_payload,
headers={"Authorization": f"Bearer {YOUR_API_TOKEN}"}
)
print(resp.json())

Rotate data connection credentials

To rotate secrets (e.g., passwords, service accounts), use the EditDataConnection endpoint and supply a new connectionDetails block.

info

This is only applicable for Tier 1 data connectors.

Step 1: Get data connection ID

import requests

resp = requests.get(
"https://api.hex.tech/api/v1/data-connections",
headers={"Authorization": f"Bearer {YOUR_API_TOKEN}"}
)

# Print available connections
for conn in resp.json()["dataConnections"]:
print(f"{conn['name']} → ID: {conn['id']}")

Step 2: Update the connectionDetails block

edit_conn_payload = {
"id": "data-conn-1234",
"connectionDetails": {
"postgres": {
"hostname": "db.mycompany.com",
"port": 5432,
"database": "prod_data",
"username": "hex_user",
"password": "NEW_SECURE_PASSWORD"
}
}
}

resp = requests.patch(
"https://api.hex.tech/api/v1/data-connections/data-conn-1234",
json=edit_conn_payload,
headers={"Authorization": f"Bearer {YOUR_API_TOKEN}"}
)

You can also rotate BigQuery service accounts by updating the serviceAccountJsonConfig in the bigquery object.

Cancel active runs for a project

Project runs can be cancelled using the CancelRun endpoint. This can be especially useful if project runs triggered by the API are contributing to database performance degradation, or your user is running into the kernel limit. The GetProjectRuns endpoint can be used in conjunction with this in order to easily cancel all API-triggered project runs.

# Get all runs for project
response = requests.get(
url=f"{BASE_URL}/projects/{PROJECT_ID}/runs",
params={"limit": 25, "statusFilter": "RUNNING"},
headers={"Authorization" : f"Bearer {TOKEN}"}
)
response = response.json()

# Iterate through runs and cancel them
for run in response["runs"]:
run_id = run["runId"]
requests.delete(
url=f"{BASE_URL}/projects/{PROJECT_ID}/runs/{run_id}",
headers={"Authorization" : f"Bearer {TOKEN}"}
)
tip

The GetProjectRuns endpoint will only return information on API-triggered project runs. To cancel ongoing Scheduled Runs, you'll need the relevant runId, which can be found as the final argument in the URL when you view a given run from the Run Log.

Kernel and rate limits

Users are limited to 60 API requests per minute. If a user exceeds 60 requests in a minute, subsequent requests will be denied and return a 429 status until the rate limit is reset, 60 seconds after the first request. Request response headers contain metadata about the remaining number of requests allowed, and when the rate limit will be reset. Some Hex API endpoints may have additional rate limits which can be found in the API reference docs.

Users are also limited to 25 concurrently running kernels between projects opened in the Hex UI and project runs triggered via the API. Each RunProject request will use a single kernel until the project run completes. Once 25 kernels are running, subsequent RunProject requests will result in a 503 status code, with no project run created. In addition to this, projects opened in the UI that do not already have a running kernel will show an error that you have reached the maximum number of running kernels. Cancelling a project run using the CancelRun endpoint will stop a running kernel and free it for use via the UI or API.

The API and hextoolkit

The hextoolkit contains a wrapper for all of the Hex API's functionality. This section is a brief overview of the functionality and syntax. You can view all of the ApiClient methods, their arguments, and their return objects in the API reference docs.

Create the client

To make requests using the hextoolkit, you will need to generate an ApiClient with your token. We recommend storing this token as a secret.

import hextoolkit as htk
import hex_api
api_client = htk.get_api_client(TOKEN)

Get project metadata

Metadata can be fetched for an individual project via the get_project endpoint or for up to 100 projects via the list_projects endpoint.

single_project = api_client.get_project(project_id=PROJECT_ID)
many_projects = api_client.list_projects(limit=100)

A ProjectApiResource is returned from the get_project endpoint, which contains various pieces of metadata about the project (see the API Reference docs for the complete object structure). The list_projects endpoint will return a list of these, as well as a pagination object containing cursor information for fetching the next page of projects. You can pass in the pagination.after cursor string into a subsequent list_projects() request in order to continue fetching new projects. When the end of pagination has been reached, the after value will be None. See below for an example of a loop to fetch metadata for all projects in a workspace:

first_page = client.list_projects(limit=100)
after = first_page.pagination.after
projects = first_page.values

while after:
response = client.list_projects(limit = 100, after=after)
after = response.pagination.after
new_projects = response.values
projects = [*projects, *new_projects]

Run projects

Running a project with no inputs is as simple as specifying the project_id:

project_run = api_client.run_project(project_id=PROJECT_ID)

The run_project method returns a ProjectRunResponsePayload object containing metadata, as well as a run_url where you can view the results.

It is also possible to run a project with inputs or to update the cache of a project using the run_project_request_body argument:

# Run a project with inputs
input_request_body = hex_api.RunProjectRequestBody(
input_params={
"input_parameter_name": "input_parameter_value",
...
}
)

# Set a new cache
update_cache_request_body = hex_api.RunProjectRequestBody(
update_cache=True
)

# Update the value used for run_project_request_body depending on desired behavior
project_run = api_client.run_project(project_id=PROJECT_ID, run_project_request_body=input_request_body)

Get a run status

The status of a run can be viewed using the run_status_url as part of the returned object from the run_project method. The get_run_status method can also be used to programmatically check the status of a run:

project_run = api_client.run_project(project_id=PROJECT_ID)
status = api_client.get_run_status(project_id=PROJECT_ID, run_id=project_run.run_id)

Cancel a project run

Project runs can be cancelled using the cancel_run method:

project_run = api_client.run_project(project_id=PROJECT_ID)
api_client.cancel_run(project_id=PROJECT_ID, run_id=project_run.run_id)

Get all project runs

All runs of a given project can be retrieved using the get_project_runs method. The project runs can be filtered using the status_filter argument to easily identify project runs that have completed, errored, etc.

active_runs = api_client.get_project_runs(project_id=PROJECT_ID, status_filter='RUNNING')

Troubleshooting

401 Unauthorized

A 401 status code indicates that Hex was unable to authenticate the request. Make sure that a token is being included in the header of your request, and that you have specified a valid base URL. If you are including a token in the header of the request, double-check that the token has not expired and consider regenerating the token or creating a new token.

404 Not found

A 404 status code indicates that Hex was unable to find the resource referenced. This could mean that the project ID or run ID included in the request are not accurate, or that your user does not have permission for the requested resource. Double-check that the user an access the Hex project in the UI.

422 Unprocessable Entity

A 422 status code can indicate that you are attempting to interact with a project that hasn't been published, or that you have provided invalid input parameters as a part of your request. Double-check that your app has been published, and that any input parameters provided are correctly specified.

429 Too many requests

A 429 status code indicates that you have hit the request rate limit. See the section on rate limiting above for more information.

500 Internal server error

A 500 status code indicates an error with the Hex application. Please contact Hex support for help troubleshooting.

503 Service Unavailable

A 503 status code indicates that the user has reached the maximum number of concurrently running kernels. See the section on kernel limits above for more information.