Skip to content

Comotion Dash API Reference

Version 2 · October 2026

This document describes the HTTP APIs behind the Comotion Python SDK. It is for engineers who want to call the APIs directly, with curl, Python requests or any other HTTP client.

You should know HTTP and JSON. You do not need to know anything about how Comotion runs the service.

In examples, replace <org> with your org name and <zone> with your zone name. $TOKEN stands for a valid access token (see Authentication).


1. Overview

There are three APIs:

API What it is for Base URL
Org API Query and load data in your org's main data lake. https://<org>.api.comodash.io/v2
Zone API Query and load data in one zone of your org. https://<zone>.<org>.api.comodash.io/v2
DailyRun API Turn the nightly daily run on or off, start a run, check run status. https://api.<org>.comodash.io/superset/dailyRun/...

All three APIs:

  • use HTTPS (TLS 1.2 or later) and JSON,
  • need an Authorization: Bearer <access token> header on every request,
  • get their tokens from your org's ComoAuth realm.

Org vs zone

An org is your Comotion Dash tenant. It has a main data lake.

A zone is a separate data area inside your org, with its own lake, its own permissions and its own API host. Use the Zone API for data in a zone. Use the Org API for the org's main lake. The two APIs have the same query and load endpoints. Only the Org API has the identity endpoints.

The data lake (data model v2)

  • Lake tables hold your data. You add data to a lake table with a load.
  • Every row has a service client (service_client_id). Your access is limited to the service clients your user has been given. See Roles and permissions.
  • You read data with a query (SQL, Amazon Athena / Trino dialect).

Where the SDK fits

The Comotion Python SDK wraps these APIs. It handles login, token refresh, polling, file conversion and chunked uploads for you. Each endpoint below names the matching SDK call. If you work in Python, the SDK is usually the easiest option. Use the HTTP API directly from other languages, or when you need more control.


2. Hosts and regions

Region API domain
Europe (eu-west-1) comodash.io
United States (us-east-1) comodash.com
API Host pattern
Org API <orgname>.api.<domain> with base path /v2
Zone API <zonename>.<orgname>.api.<domain> with base path /v2
DailyRun API api.<orgname>.<domain> with base path /superset

All paths in this document are relative to the base URL. For example, POST /query on the Org API is POST https://<org>.api.comodash.io/v2/query.


3. Authentication

3.1 Your ComoAuth realm

Each org has its own login realm on ComoAuth (an OpenID Connect provider):

Item Value for your org
Issuer https://auth.comotion.us/auth/realms/<org>
Discovery document https://auth.comotion.us/auth/realms/<org>/.well-known/openid-configuration
Authorization endpoint https://auth.comotion.us/auth/realms/<org>/protocol/openid-connect/auth
Token endpoint https://auth.comotion.us/auth/realms/<org>/protocol/openid-connect/token

The APIs only accept tokens whose issuer is your org's realm. A token from another org's realm is rejected.

3.2 Getting a token as a user (interactive)

The SDK's comotion authenticate command uses the OAuth 2.0 authorization code flow with PKCE:

  1. It opens your browser at the authorization endpoint with client_id=comotion_cli, response_type=code, scope=openid, a PKCE code_challenge (S256) and a redirect to http://localhost:<random port>.
  2. You log in. ComoAuth redirects back to the local port with a code.
  3. The SDK swaps the code for tokens at the token endpoint (grant_type=authorization_code, the code_verifier and the same redirect_uri).
  4. The SDK saves the refresh token in your operating system's credential manager (keyring). It does not save access tokens.
  5. Each time it needs an access token, the SDK posts grant_type=refresh_token, client_id=comotion_cli and the saved refresh token to the token endpoint. It gets a new access token about 30 seconds before the current one expires.

If you already use the SDK, the simplest way to get a token for curl is:

from comotion.auth import Auth
print(Auth("<org>").get_access_token())

To do it yourself, refresh a token like this:

curl -s https://auth.comotion.us/auth/realms/<org>/protocol/openid-connect/token \
  -d grant_type=refresh_token \
  -d client_id=comotion_cli \
  -d refresh_token="$REFRESH_TOKEN" | jq -r .access_token

3.3 Getting a token as an application (machine to machine)

For scheduled jobs and services, Comotion can set up an application client for you with a client ID and client secret. It uses the OAuth 2.0 client credentials grant:

TOKEN=$(curl -s https://auth.comotion.us/auth/realms/<org>/protocol/openid-connect/token \
  -d grant_type=client_credentials \
  -d client_id="$CLIENT_ID" \
  -d client_secret="$CLIENT_SECRET" | jq -r .access_token)
import requests

resp = requests.post(
    "https://auth.comotion.us/auth/realms/<org>/protocol/openid-connect/token",
    data={
        "grant_type": "client_credentials",
        "client_id": CLIENT_ID,
        "client_secret": CLIENT_SECRET,
    },
)
resp.raise_for_status()
TOKEN = resp.json()["access_token"]

SDK equivalent: Auth("<org>", entity_type=Auth.APPLICATION, application_client_id=..., application_client_secret=...).

Ask Comotion support to create an application client. Its roles, scopes and service clients are set when it is created.

3.4 Token lifetime

Access tokens are short-lived. Read expires_in in the token response, or the exp claim in the token, and get a new token before it expires.

3.5 What the APIs check in the token

Check Org API Zone API (<zone>) DailyRun API
Issuer your realm your realm your realm
Audience (aud) dash_api dash_api_<zone> dash_api
Scope per endpoint, e.g. query:write per endpoint, e.g. <zone>:query:write per endpoint, e.g. dailyrun:execution:read
Claims the handler reads sub, jti, service_client_id, resource_access same none

The service_client_id claim is a string in the form [12 13]: square brackets around service client IDs separated by spaces.

resource_access must contain an entry for the API's client (dash_api or dash_api_<zone>) listing your roles. See Roles and permissions.

Your Comotion administrator sets your audiences, scopes, roles and service clients. If a call fails with 401 or 403, decode your token (for example at a JWT debugger you trust, or with jq -R 'split(".")[1] | @base64d | fromjson') and compare it with the table above.

3.6 Common 401 and 403 causes

Response Likely cause Fix
401 {"message":"Unauthorized"} No Authorization header, a token that has expired, a token from the wrong realm, or the wrong audience (for example a dash_api token sent to the Zone API). Get a fresh token from your org's realm with the right audience.
403 {"message":"Forbidden"} The token is valid but lacks the scope this endpoint needs. Ask your administrator for the scope.
403 with a "permissions problem" message Your query touches data your role or service clients cannot read. See Roles and permissions.
500 on query endpoints right after login The token lacks the service_client_id, sub, jti or resource_access claim, or service_client_id is badly formed. Ask your administrator to assign you a service client and a role.

4. Roles and permissions

4.1 Service clients

Comotion uses service clients for row-level security. A service client usually represents one of your own clients or business units, and your access is limited to the service clients assigned to you.

Two IDs are special:

ID Meaning
901 Public. Everyone with a role can read public rows. It is added to every user's list automatically.
0 All service clients. A user whose service_client_id claim includes 0, and who has any role other than PublicConsumer, can read every service client.

4.2 Roles

Roles are assigned per API: on dash_api for the Org API, and on dash_api_<zone> for each zone. A user can have different roles in different zones.

Role In short
PublicConsumer Reads public (901) insights only.
OwnServiceClientConsumer Reads insights for their own service clients.
OwnServiceClientAnalyst Reads lake and insights data for their own service clients. Can create tables in the sandbox.
AllServiceClientAnalyst Reads all service clients. Can write to lake and insights tables.
ZoneAdmin Everything an AllServiceClientAnalyst can do, plus delete and modify tables.

4.3 Capability matrix

Capability Public­Consumer OwnSC­Consumer OwnSC­Analyst AllSC­Analyst Zone­Admin
Read public (901) insights ✓ ✓ ✓ ✓ ✓
Read insights for own service clients ✓ ✓ ✓ ✓
Read insights for all service clients ¹ ¹ ✓ ✓
Read lake and data-input tables (own service clients) ✓ ✓ ✓
Read lake and data-input tables (all service clients) ¹ ✓ ✓
Create, change and drop tables in the sandbox ✓ ✓ ✓
Create and update lake and insights tables, add and remove partitions, write data with SQL ✓ ✓
Drop and modify lake and insights tables ✓
Load rows for a service client through the load API ² ✓ ✓ ✓ (any) ✓ (any)

¹ Only if the user's service_client_id claim includes 0. ² Public (901) rows only.

Notes:

  • If a user has several roles, the capabilities add up.
  • The load API also needs the load:write scope (or <zone>:load:write). Loads write through Comotion's load pipeline, not with your own permissions. The pipeline checks that every row belongs to a service client you can access.
  • A user with no recognised role can only read their own query results. Every query that touches data fails.

4.4 How data scoping works in queries

Access is enforced on the stored data, which is split by service client. In practice:

  • A query that reads data outside your service clients fails with a permissions error. It does not silently drop those rows.
  • To read only what you may see, add your service client filter to the query. GET /identity/security_metadata returns a ready-made condition, for example service_client_id IN ('12', '901') or 1=1 (all rows).
  • Your query results are stored in a location tied to your user, roles and service clients. Only you can read them. If your roles or service clients change, you can no longer read results of queries you ran before the change.

4.5 Scopes per endpoint

Endpoint Org API scope Zone API scope
GET /identity/security_metadata none (any valid token) not available
POST /query query:write <zone>:query:write
GET /query/{query_id} query:read <zone>:query:read
DELETE /query/{query_id} query:write <zone>:query:write
GET /query/{query_id}/result query:read <zone>:query:read
GET /query/{query_id}/csv query:read <zone>:query:read
POST /load load:write <zone>:load:write
POST /load/{load_id}/file load:write <zone>:load:write
POST /load/{load_id}/commit load:write <zone>:load:write
GET /load/{load_id} load:read <zone>:load:read
GET /dailyRun/dailyRun_enabled dailyrun:enabled:read (DailyRun API) not available
POST /dailyRun/dailyRun_enabled dailyrun:enabled:write (DailyRun API) not available
GET /dailyRun/execution_status dailyrun:execution:read (DailyRun API) not available
POST /dailyRun/start_execution dailyrun:execution:write (DailyRun API) not available

5. Conventions

  • Requests: send JSON bodies with Content-Type: application/json.
  • Responses: JSON unless stated otherwise.
  • Errors: most errors have the body {"message": "..."}. The identity endpoint also adds an error field. Where a message includes a request code (...please quote this code: <id>), send that code to support.
  • Gateway errors: some errors come from the API gateway before your request reaches Comotion's code: 401 Unauthorized, 403 Forbidden (missing scope), 404 Not Found (unknown path), 413 (request too large) and a timeout error for requests that take longer than 30 seconds.
  • Timeouts: every endpoint is designed to answer within seconds. Long-running work (queries, load commits, daily runs) runs in the background, and you poll for status.

Shell examples use these variables:

export ORG=<org>
export API=https://$ORG.api.comodash.io/v2
export TOKEN=...   # access token, see section 3

Python examples use:

import requests

ORG = "<org>"
API = f"https://{ORG}.api.comodash.io/v2"
TOKEN = "..."  # access token, see section 3
HEADERS = {"Authorization": f"Bearer {TOKEN}"}