Skip to content
datasquares.aiSign inStart free

REST API

API: Semantic Model

Models, tables, fields, relationships, hierarchies, RLS policies, and SquareX measures. All endpoints require authentication unless noted. 67 endpoints, 7 of them app only: an API key gets 403 there.

List semantic models

Query parameters

Name Type Required Description
limit integer no
offset integer no
search string no
sort "recent" | "name" | "tables" no

Responses: 200 · 400 · 401

Create a new semantic model

Request body (JSON)

Field Type Required Description
name string yes
description string no
sourceId string yes

Responses: 201 · 400 · 401 · 409

Get semantic model by ID

Path parameters

Name Type Required Description
id string yes

Responses: 200 · 400 · 401 · 404

Update a semantic model

Path parameters

Name Type Required Description
id string yes

Request body (JSON)

Field Type Required Description
name string no
description string no
isCertified boolean no
certifiedBy string no

Responses: 200 · 400 · 401 · 404

Delete a semantic model

Path parameters

Name Type Required Description
id string yes

Responses: 204 — No content · 401 · 404

Publish a model version (snapshot current state)

Path parameters

Name Type Required Description
id string yes

Request body (JSON)

Field Type Required Description
override boolean no
overrideReason string no

Responses: 200 · 400 · 401 · 404

GET /api/models/{id}/relationship-suggestions

Section titled “GET /api/models/{id}/relationship-suggestions”

List the relationship suggestions of a model that are waiting for a decision

What suggest-relationships found and nobody has accepted or dismissed, best evidence first. Each one names the one side (the referenced key, which a stored relationship starts from) and the many side (the table holding the key). A pair the model has joined since, or whose tables or fields are gone, is not listed. secondRoute says an active relationship already connects the two tables.

Path parameters

Name Type Required Description
id string yes

Responses: 200 · 400 · 401

POST /api/models/{id}/relationship-suggestions/{suggestionId}/accept

Section titled “POST /api/models/{id}/relationship-suggestions/{suggestionId}/accept”

Accept a relationship suggestion: create the relationship

Creates the relationship the suggestion describes with the referenced table as from (cardinality 1:N, or 1:1 when the key holder’s key is its own table’s primary key) and closes the suggestion. When an active relationship already connects the two tables, the new one is created inactive (secondRoute: true): two active routes make the planner refuse a measure across them, so switching the route is the person’s decision. 409 when the model already joins those fields.

Path parameters

Name Type Required Description
id string yes
suggestionId string yes

Responses: 201 · 400 · 401 · 409

POST /api/models/{id}/relationship-suggestions/{suggestionId}/dismiss

Section titled “POST /api/models/{id}/relationship-suggestions/{suggestionId}/dismiss”

Dismiss a relationship suggestion

Closes the suggestion without creating anything. A later suggest-relationships run does not bring the same field pair back.

Path parameters

Name Type Required Description
id string yes
suggestionId string yes

Responses: 204 — No content · 401 · 404

POST /api/models/{id}/suggest-relationships

Section titled “POST /api/models/{id}/suggest-relationships”

Suggest relationships for a model from its tables’ keys (rule-based)

The joins the model’s tables imply, best evidence first: a foreign key the source declares (0.98), a column named like another table’s sole primary key (0.95), the \{prefix}_id → id convention (0.9 / 0.7), and last a same-named *_id column in a table whose name holds the prefix (0.6 / 0.5). Pairs the model already joins are left out. Each suggestion’s action names the table that holds the key as source* (the many side) and the table it references as target* (the one side); a stored relationship is the other way round (the referenced table is from, cardinality 1:N). New suggestions are also kept as pending suggestions, once per field pair. The rules read the tables’ keys and names; no model is asked and no credits are used.

Path parameters

Name Type Required Description
id string yes

Responses: 200

List model versions

Path parameters

Name Type Required Description
id string yes

Responses: 200

POST /api/models/{id}/versions/{version}/restore

Section titled “POST /api/models/{id}/versions/{version}/restore”

Restore the model definition from a version snapshot

400, naming it, when the version holds a calculated field or an add-column step that reads past its own table’s row (a subquery, a query written without SELECT, a function that runs one): a version published before such expressions were refused is not written back.

Path parameters

Name Type Required Description
id string yes
version integer yes

Responses: 200 · 400 · 401 · 404

GET /api/models/{modelId}/ai-descriptions/drafts

Section titled “GET /api/models/{modelId}/ai-descriptions/drafts”

The model’s AI-drafted descriptions waiting for review, or all of them (model editors)

state=pending (the default) lists the drafts waiting for review, table by table; state=all adds the ones approved (published: what was written into the model), rejected or superseded (the table or field got a description another way first).

Path parameters

Name Type Required Description
modelId string yes

Query parameters

Name Type Required Description
state "pending" | "all" no

Responses: 200 · 400 · 401 · 403 · 404

POST /api/models/{modelId}/ai-descriptions/drafts

Section titled “POST /api/models/{modelId}/ai-descriptions/drafts”

Draft the missing descriptions of a model’s tables and fields with AI (models:create; AI credits)

App only. An API key gets 403: AI features are available in the DataSquares app; API keys can’t use them.

Drafts a description for each table and field in the AI scope that has none, for up to 10 tables a request: the ones named, or the next ones with something to draft. One quick AI call a table, charged in AI credits (Description drafts). Nothing is published: each draft waits for a model editor’s review. dropped: the drafts the checks left out, their text not kept, and droppedFor why (quotedValue: it quoted a code stored in the table’s data; tooLong; screened: it looked like personal details, a secret or an instruction; noAnswer: the AI gave none). A draft that was rejected or dropped is drafted again only for a table named here. One request at a time per model: another one meanwhile is refused with 409 DRAFTS_RUNNING before any AI call, details.running saying whether you started the run, when, and for how many tables. 429 DRAFTS_BUSY, also before any AI call, when the server is drafting for as many models as it runs at once: try again after Retry-After (60 seconds); nothing was drafted or charged. A table is started only while its call can end within 4 minutes of the request’s start: notStarted lists the tables chosen and not started (the next request drafts them; name them again if you named them). remaining: the tables still with something to draft. A caller a row-level security policy restricts on the model’s source gets drafts written without the tables’ counts. 400 when more tables are named than a request drafts, or one is not the model’s or outside its AI scope; 503 AI_NOT_CONFIGURED on a server without AI.

Path parameters

Name Type Required Description
modelId string yes

Request body (JSON)

Field Type Required Description
tableIds array of string no

Responses: 200 · 400 · 401 · 403 · 404 · 409 · 429 · 503

PUT /api/models/{modelId}/ai-descriptions/drafts

Section titled “PUT /api/models/{modelId}/ai-descriptions/drafts”

Approve or reject AI-drafted descriptions (models:update)

approve writes the draft, or text in its place, into the model as the table’s or field’s description, only where it still has none (otherwise the draft is superseded); reject keeps it out. Every draft must be one of this model’s drafts waiting for review (400 otherwise, naming them), and nothing is changed then.

Path parameters

Name Type Required Description
modelId string yes

Request body (JSON)

Field Type Required Description
decisions array of object yes

Responses: 200 · 400 · 401 · 403 · 404

Detect relationships between a model’s tables from their keys (rule-based)

The same detection as suggest-relationships, answered directly instead of being stored: from is the table that holds the key, to the table it references. Pairs the model already joins are left out. The rules read the tables’ keys and names; no model is asked and no credits are used, whatever the path says.

Path parameters

Name Type Required Description
modelId string yes

Responses: 200 · 400 · 401 · 404

The AI’s notes about a model’s tables: those waiting for the owner’s review, or the shared ones (model editors)

App only. An API key gets 403: AI features are available in the DataSquares app; API keys can’t use them.

Notes the DataSquares AI assistant keeps about this model’s tables (phase 3 of the AI plan): what a table’s rows mean, its key and date column, usual filters, what a column’s codes mean, which joins hold, questions and the tables that answered them. state=pending (the default) lists the notes waiting for the model owner’s review: meanings the AI inferred from people’s answers or found by Explore this model, and people’s own words; they apply only to the person whose notes they are until approved. Only the model’s owner and workspace admins, with permission to update data models, see them (canReview); another editor gets their count and no items. state=shared lists the notes the workspace shares: facts a check of the data proved (shared at once) and notes approved. A note naming a field labelled sensitive is listed only to people who may read labelled values in clear. Oldest first.

Path parameters

Name Type Required Description
modelId string yes

Query parameters

Name Type Required Description
state "pending" | "shared" no
limit integer no
offset integer no

Responses: 200 · 400 · 401 · 403 · 404

GET /api/models/{modelId}/ai-notes/explore

Section titled “GET /api/models/{modelId}/ai-notes/explore”

Explore this model: whether it can run, its estimate in AI credits, and its progress (model editors)

App only. An API key gets 403: AI features are available in the DataSquares app; API keys can’t use them.

Explore this model runs the DataSquares AI assistant’s schema finder over every table of the model in your AI scope, in the background, to learn them before the first questions: what each table’s rows mean, its key, its date column, its codes, how the tables join. What it infers waits for the model owner’s review; facts its checks of the data prove are shared at once. estimate: about how many AI credits it uses, whole credits rounded up (it is charged what it used, as one line). job: the running exploration, else the latest, with its progress and what it was charged so far. Nothing here calls the AI.

Path parameters

Name Type Required Description
modelId string yes

Responses: 200 · 400 · 401 · 403 · 404

POST /api/models/{modelId}/ai-notes/explore

Section titled “POST /api/models/{modelId}/ai-notes/explore”

Start Explore this model in the background, its estimate confirmed (models:create; AI credits)

App only. An API key gets 403: AI features are available in the DataSquares app; API keys can’t use them.

Starts the exploration (202) and returns it running; follow it with GET …/ai-notes/explore. confirmCredits: the estimate you were shown, whole credits; when the estimate is now higher (the model grew), 409 ESTIMATE_CHANGED with details.estimateCredits, and nothing starts. Refused before anything runs: the AI policy (403 AI_TURNED_OFF, 403 AI_NOT_ALLOWED, 429 AI_BUDGET_REACHED, also when this month’s budget has less left than the estimate), the workspace’s AI credits (429 CREDITS_EXHAUSTED, past what may go below zero), 409 MEMORY_PAUSED while your memory is paused (what it infers is kept as your own notes about the tables, and a paused memory keeps nothing new), 409 EXPLORE_NOT_AVAILABLE (details.reason, as the GET’s), 409 EXPLORE_RUNNING (details.job) while one runs for the model, 429 EXPLORE_BUSY while the server explores as many models as it runs at once (try again after Retry-After, 60 seconds), 503 AI_NOT_CONFIGURED on a server without AI. It runs as you: your AI scope, your access to labelled fields, your row-level security. It is charged to the workspace’s AI credits as one line, what it used, a stop included.

Path parameters

Name Type Required Description
modelId string yes

Request body (JSON)

Field Type Required Description
confirmCredits integer yes The estimate you were shown, whole credits

Responses: 202 · 400 · 401 · 403 · 404 · 409 · 429 · 503

POST /api/models/{modelId}/ai-notes/explore/stop

Section titled “POST /api/models/{modelId}/ai-notes/explore/stop”

Stop the model’s running exploration at its next step (models:create)

App only. An API key gets 403: AI features are available in the DataSquares app; API keys can’t use them.

Asks the running Explore this model to stop, wherever it runs; it stops at its next step and keeps what it learned so far. It is charged for what it used. 409 EXPLORE_NOT_RUNNING when none runs.

Path parameters

Name Type Required Description
modelId string yes

Responses: 200 · 400 · 401 · 403 · 404 · 409

Approve, reject or remove the AI’s notes about a model’s tables (the model’s owner or a workspace admin)

App only. An API key gets 403: AI features are available in the DataSquares app; API keys can’t use them.

approve shares a note waiting for review with the workspace: everyone it may reach uses it from then on (a note shared on the same thing before is superseded). title and body approve it in your own words instead: checked as every note is (personal or secret details, data values and instructions to the AI are refused, whole, never cut). A note whose table changed since it was written is not approved: it goes back to review (changed). One note is shared about the same thing (the same place): approving two notes of one place in a request is refused (400, naming them in details.notes; details.reason same_place). reject keeps it from everyone, the person whose note it was included; they see it was not approved. remove takes a shared note (a checked fact, an approved note) out of use. Every decision must name one of this model’s notes in the state its action needs, at most 200 a request: all or none (400, naming them in details.notes; details.reason not_waiting, as when another reviewer decided them meanwhile). The person whose note was decided is told, once a review. Needs permission to update data models.

Path parameters

Name Type Required Description
modelId string yes

Request body (JSON)

Field Type Required Description
decisions array of object yes

Responses: 200 · 400 · 401 · 403 · 404

The model’s AI scope: which tables and fields the AI may use (model editors)

Every table and field of the model, each with inScope. Everything is in scope until it is excluded, so a table a re-discovery adds is in scope. AI search, its table pick and the AI’s schema tools use only what is in scope; a table or field every model over a source keeps outside it is not read by the AI’s SQL and data tools either.

Path parameters

Name Type Required Description
modelId string yes

Responses: 200 · 400 · 401 · 403 · 404

Set the model’s AI scope: the tables and fields the AI may not use (models:update)

Replaces the model’s exclusions. Every id must be a table or field of this model (400 otherwise, naming them); a field of an excluded table needs no exclusion of its own and is refused as one (400). The AI catalog follows within minutes: what is excluded is deleted from the AI’s search documents.

Path parameters

Name Type Required Description
modelId string yes

Request body (JSON)

Field Type Required Description
excludedTables array of string yes
excludedFields array of string yes

Responses: 200 · 400 · 401 · 403 · 404

List all fields of a model (all tables, hidden excluded)

Path parameters

Name Type Required Description
modelId string yes

Responses: 200

GET /api/models/{modelId}/fields/{fieldId}/usage

Section titled “GET /api/models/{modelId}/fields/{fieldId}/usage”

What reads a model field — cards, metrics, measures (field-level lineage)

Path parameters

Name Type Required Description
modelId string yes
fieldId string yes

Responses: 200 · 400 · 401 · 404

List hierarchies in a model

Path parameters

Name Type Required Description
modelId string yes

Responses: 200 · 400 · 401

Create a drill-down hierarchy

Path parameters

Name Type Required Description
modelId string yes

Request body (JSON)

Field Type Required Description
name string yes
tableId string no
levels array of object yes

Responses: 201 · 400 · 401 · 409

PUT /api/models/{modelId}/hierarchies/{hierId}

Section titled “PUT /api/models/{modelId}/hierarchies/{hierId}”

Update a hierarchy

Path parameters

Name Type Required Description
modelId string yes
hierId string yes

Request body (JSON)

Field Type Required Description
name string no
tableId string no
levels array of object no

Responses: 200 · 400 · 401 · 404

DELETE /api/models/{modelId}/hierarchies/{hierId}

Section titled “DELETE /api/models/{modelId}/hierarchies/{hierId}”

Delete a hierarchy

Path parameters

Name Type Required Description
modelId string yes
hierId string yes

Responses: 204 — No content · 401 · 404

Import tables from the data source into the model

Path parameters

Name Type Required Description
modelId string yes

Request body (JSON)

Field Type Required Description
schema string no Filter by schema name
tables array of string no Specific table names to import (imports all if omitted)
createRelationships boolean no After the import, create the relationships the source declares (a foreign key) or that a column named like another table’s sole primary key implies. Created parent first (the referenced table is from, cardinality 1:N), flagged ai_detected, and only between tables no active relationship connects yet, so no second route is ever added; weaker matches and the ones left out stay in suggest-relationships. Default false.

Responses: 200

List SquareX measures on a model

Path parameters

Name Type Required Description
modelId string yes

Responses: 200 · 400 · 401

Create a SquareX measure (validated at save)

Path parameters

Name Type Required Description
modelId string yes

Request body (JSON)

Field Type Required Description
name string yes
expression string yes
dataType "number" | "integer" | "decimal" | "string" | "date" | "boolean" no
format object | null no
folder string | null no
description string | null no
isHidden boolean no

Responses: 201 · 400 · 401 · 409

Fetch a SquareX measure

Path parameters

Name Type Required Description
modelId string yes
mid string yes

Responses: 200 · 400 · 401 · 404

Update a SquareX measure (revalidates; marks dependents stale)

Path parameters

Name Type Required Description
modelId string yes
mid string yes

Request body (JSON)

Field Type Required Description
name string no
expression string no
dataType "number" | "integer" | "decimal" | "string" | "date" | "boolean" no
format object | null no
folder string | null no
description string | null no
isHidden boolean no

Responses: 200 · 400 · 401 · 404

DELETE /api/models/{modelId}/measures/{mid}

Section titled “DELETE /api/models/{modelId}/measures/{mid}”

Soft-delete a SquareX measure (409 while referenced)

Path parameters

Name Type Required Description
modelId string yes
mid string yes

Responses: 204 — No content · 401 · 404

POST /api/models/{modelId}/measures/{mid}/preview

Section titled “POST /api/models/{modelId}/measures/{mid}/preview”

Compiled SQL preview of a SquareX measure for a dialect

Path parameters

Name Type Required Description
modelId string yes
mid string yes

Request body (JSON)

Field Type Required Description
dialect string no

Responses: 200 · 400 · 401 · 404

POST /api/models/{modelId}/measures/copilot

Section titled “POST /api/models/{modelId}/measures/copilot”

SquareX copilot: draft a measure from natural language, validated + self-repaired (AIX-18)

App only. An API key gets 403: AI features are available in the DataSquares app; API keys can’t use them.

One AI call drafts an expression from the model’s real schema + glossary + canonical exemplars; the draft runs through the REAL analyzer and SQX0xx diagnostics are fed back for up to 2 repair rounds. ok:true is only returned for a GREEN expression — clients insert nothing else; ok:false is a draft that failed the checks or held no formula. A draft the AI never answered is an error that says why: 429 when the workspace’s AI credits are used up (CREDITS_EXHAUSTED, with details.recharge_path) or its usage limit is reached, 403 for an effort level the workspace lacks, 503 when AI is unavailable or took too long. 503 AI_NOT_CONFIGURED on a server without AI.

Path parameters

Name Type Required Description
modelId string yes

Request body (JSON)

Field Type Required Description
prompt string yes
currentExpression string | null no
name string | null no
measureId string | null no

Responses: 200 · 403 · 429 · 503

POST /api/models/{modelId}/measures/validate

Section titled “POST /api/models/{modelId}/measures/validate”

Validate a SquareX expression (diagnostics, never a 4xx)

Path parameters

Name Type Required Description
modelId string yes

Request body (JSON)

Field Type Required Description
expression string yes
name string no
measureId string no

Responses: 200 · 400 · 401 · 404

Prep for AI: how ready the model is for the AI, what to do next, and its joins with their provenance (model editors)

score (0–100) weighs the tables and fields in the AI scope that have a description, the tables a declared or saved-SQL join reaches, and, while the server runs AI search (band is null otherwise and the size is left out), the model’s size (read whole, with a one-line overview of its tables, or too large for either). recommendations: what to do next, with counts: draft_descriptions (tables and fields with no description and no draft yet), review_drafts, describe_left_out (no description, and their draft was rejected or left out by the checks, so it is not drafted again), define_scope, meaning_search, joins (tables no declared or saved-SQL join reaches). joins lists every join of the model’s tables and how it is known: declared (detected: found from the source’s keys and not yet confirmed), saved_sql (used by the workspace’s saved SQL; usage: how many queries), value_match (matched from the values of both sides: confidence and the counts it rests on, never a value; a possible join the AI confirms before using it), ai_suggested (a possible join too). No AI is called.

Path parameters

Name Type Required Description
modelId string yes

Responses: 200 · 400 · 401 · 403 · 404

List relationships in a model

Path parameters

Name Type Required Description
modelId string yes

Responses: 200 · 400 · 401

Create a relationship between model tables

Path parameters

Name Type Required Description
modelId string yes

Request body (JSON)

Field Type Required Description
fromTableId string yes
fromFieldId string yes
toTableId string yes
toFieldId string yes
joinType "inner" | "left" | "right" | "full" no
cardinality "1:1" | "1:N" | "N:M" no
isActive boolean no

Responses: 201 · 400 · 401 · 409

PUT /api/models/{modelId}/relationships/{relId}

Section titled “PUT /api/models/{modelId}/relationships/{relId}”

Update a model relationship

Path parameters

Name Type Required Description
modelId string yes
relId string yes

Request body (JSON)

Field Type Required Description
fromTableId string no
fromFieldId string no
toTableId string no
toFieldId string no
joinType "inner" | "left" | "right" | "full" no
cardinality "1:1" | "1:N" | "N:M" no
isActive boolean no
aiDetected boolean no

Responses: 200 · 400 · 401 · 404

DELETE /api/models/{modelId}/relationships/{relId}

Section titled “DELETE /api/models/{modelId}/relationships/{relId}”

Delete a model relationship

Path parameters

Name Type Required Description
modelId string yes
relId string yes

Responses: 204 — No content · 401 · 404

List RLS policies for a model

Path parameters

Name Type Required Description
modelId string yes

Responses: 200 · 400 · 401

Create a row-level security policy

Path parameters

Name Type Required Description
modelId string yes

Request body (JSON)

Field Type Required Description
name string yes
tableId string yes A table of this model; the policy filters its rows.
filterExpression string no A SQL condition over the table’s own columns, e.g. region = ‘EU’. Rows it does not keep are hidden. Required unless the policy has attribute rules, beside which it is an extra condition.
appliesTo array of object yes Who the policy applies to. An empty list applies it to everyone who can query the model, company admins included. Otherwise it applies to anyone matching any target. Several policies on one table combine with OR; a table with no policy that applies to a caller is not filtered for them. A policy binds its data source: it filters its table’s rows through every model over the source that reads the same source table, and the policies written on different model tables combine with AND. Anyone a policy on the source restricts can’t add, change or remove the source’s policies (403); company admins can. A target that can never match is refused (400, details.targets).
attributeRules array of object no Rules on the person’s attributes. Each keeps a row only when column holds one of the person’s values for attribute; a person this policy applies to who has no value for a named attribute sees no rows of the table. They AND with filterExpression, which is then optional. An empty list removes the rules.

Responses: 201 · 400 · 401 · 409

Update an RLS policy

Path parameters

Name Type Required Description
modelId string yes
policyId string yes

Request body (JSON)

Field Type Required Description
name string no
tableId string no A table of this model; the policy filters its rows.
filterExpression string no A SQL condition over the table’s own columns, e.g. region = ‘EU’. Rows it does not keep are hidden. Required unless the policy has attribute rules, beside which it is an extra condition.
appliesTo array of object no Who the policy applies to. An empty list applies it to everyone who can query the model, company admins included. Otherwise it applies to anyone matching any target. Several policies on one table combine with OR; a table with no policy that applies to a caller is not filtered for them. A policy binds its data source: it filters its table’s rows through every model over the source that reads the same source table, and the policies written on different model tables combine with AND. Anyone a policy on the source restricts can’t add, change or remove the source’s policies (403); company admins can. A target that can never match is refused (400, details.targets).
attributeRules array of object no Rules on the person’s attributes. Each keeps a row only when column holds one of the person’s values for attribute; a person this policy applies to who has no value for a named attribute sees no rows of the table. They AND with filterExpression, which is then optional. An empty list removes the rules.

Responses: 200 · 400 · 401 · 404

DELETE /api/models/{modelId}/rls/{policyId}

Section titled “DELETE /api/models/{modelId}/rls/{policyId}”

Delete an RLS policy

Path parameters

Name Type Required Description
modelId string yes
policyId string yes

Responses: 204 — No content · 401 · 404

List the people’s attributes a row-level security policy can name

The attribute names held by the people who can query this model’s workspace (set by a company admin or SCIM), with how many hold each. Never the values. For people who may create or edit models.

Path parameters

Name Type Required Description
modelId string yes

Responses: 200 · 400 · 401 · 404

Preview who a row-level security policy applies to

What a draft policy would do once saved, evaluated by the same rules queries use: how many of the people who can query the workspace it applies to, and how many would then see every row of the table, only filtered rows, or none, together with the policies already on the table. Each person’s outcome is listed. Nothing is saved.

Path parameters

Name Type Required Description
modelId string yes

Request body (JSON)

Field Type Required Description
tableId string yes The table the draft policy filters.
appliesTo array of object yes The draft’s targets, as for a policy: an empty list is everyone. Unlike a save, a target that can never match is not refused here: it comes back in targets with its status and is counted as queries would read it.
attributeRules array of object no The draft’s rules on people’s attributes, checked as a save checks them: who holds a value for every named attribute sees the rows they keep, who does not sees none.
policyId string no When editing: the policy the draft replaces, so it is not counted twice.
list "covered" | "not_covered" no Which people to list: those the draft applies to, or the rest. Everyone when absent.
search string no Part of a name or email, any case.
limit integer no
offset integer no

Responses: 200 · 400 · 401 · 404

List the row-level security policies a model inherits from other models over its source

A policy binds its data source: it filters its table’s rows through every model over the source that reads the same source table. These are the active policies of other models over this model’s source that bind its tables, read-only (one is changed on the model it is written on), by model and name: each with the model and the table it is written on, the source table that joins them, and binds, the tables of this model it filters. unmatched: its table can’t be matched to a table, so every query on the source it would narrow is refused.

Path parameters

Name Type Required Description
modelId string yes

Responses: 200 · 400 · 401 · 404

List the people a row-level security policy can apply to

Everyone who can query this model’s workspace: its members and the company’s admins, by name. roles counts the people holding each company role a role target can match. For people who may create or edit models.

Path parameters

Name Type Required Description
modelId string yes

Query parameters

Name Type Required Description
search string no Part of a name or email, any case.
limit integer no
offset integer no

Responses: 200 · 400 · 401 · 404

List tables in a model

Path parameters

Name Type Required Description
modelId string yes

Query parameters

Name Type Required Description
includeFields boolean no Include fields for each table

Responses: 200 · 400 · 401

Add a table to the model

Path parameters

Name Type Required Description
modelId string yes

Request body (JSON)

Field Type Required Description
sourceSchema string yes
sourceTable string yes
alias string yes
description string no

Responses: 201 · 400 · 401 · 409

GET /api/models/{modelId}/tables/{tableId}

Section titled “GET /api/models/{modelId}/tables/{tableId}”

Get a model table by ID

Path parameters

Name Type Required Description
modelId string yes
tableId string yes

Responses: 200 · 400 · 401 · 404

PUT /api/models/{modelId}/tables/{tableId}

Section titled “PUT /api/models/{modelId}/tables/{tableId}”

Update a model table

Path parameters

Name Type Required Description
modelId string yes
tableId string yes

Request body (JSON)

Field Type Required Description
sourceSchema string no
sourceTable string no
alias string no
description string no

Responses: 200 · 400 · 401 · 404

DELETE /api/models/{modelId}/tables/{tableId}

Section titled “DELETE /api/models/{modelId}/tables/{tableId}”

Delete a model table

Path parameters

Name Type Required Description
modelId string yes
tableId string yes

Responses: 204 — No content · 401 · 404

GET /api/models/{modelId}/tables/{tableId}/fields

Section titled “GET /api/models/{modelId}/tables/{tableId}/fields”

List fields for a model table

Path parameters

Name Type Required Description
modelId string yes
tableId string yes

Responses: 200 · 400 · 401

POST /api/models/{modelId}/tables/{tableId}/fields

Section titled “POST /api/models/{modelId}/tables/{tableId}/fields”

Add a field to a model table

409 when the table already has a field by that name, or one that reads a column of that name, ignoring case: a field by that name would take over the charts and filters that read the other. 400 when a calculated field (fieldType calculated, or one with an expression) is given a sourceColumn: it reads no column of its own, and a filter on a column never reads it. 400, naming it, when the expression reads past its own table’s row: a subquery, a query written without SELECT (TABLE, FROM first, a table after IN) or a function that runs one (query_to_xml and the like), which would read the source past row-level security; the same expression is refused when a query reads it. A field added by anyone but a schedule’s creator or a workspace admin pauses the publisher-mode schedules that read the model, for their creators.

Path parameters

Name Type Required Description
modelId string yes
tableId string yes

Request body (JSON)

Field Type Required Description
name string yes
sourceColumn string no
fieldType "dimension" | "measure" | "calculated" yes
dataType "string" | "number" | "integer" | "decimal" | "boolean" | "date" | "datetime" | "time" | "geo" yes
aggregation "sum" | "count" | "count_distinct" | "avg" | "min" | "max" | "none" no
expression string no
format string no
description string no
isHidden boolean no
sortByField string no
semanticType string no
isMetric boolean no

Responses: 201 · 400 · 401 · 409

PUT /api/models/{modelId}/tables/{tableId}/fields/{fieldId}

Section titled “PUT /api/models/{modelId}/tables/{tableId}/fields/{fieldId}”

Update a model field

409 when the new name is, ignoring case, another field’s name or the column another field reads in its table; the field’s own name, in any case, is no new name. 400 when sourceColumn is given to a field that is, or with this change becomes, calculated (fieldType calculated, or an expression): it reads no column of its own. 400, naming it, when the expression reads past its own table’s row (a subquery, a query written without SELECT, a function that runs one), as on create. A change by anyone but a schedule’s creator or a workspace admin to what a send of the model shows pauses the publisher-mode schedules that read the model, for their creators.

Path parameters

Name Type Required Description
modelId string yes
tableId string yes
fieldId string yes

Request body (JSON)

Field Type Required Description
name string no
sourceColumn string no
fieldType "dimension" | "measure" | "calculated" no
dataType "string" | "number" | "integer" | "decimal" | "boolean" | "date" | "datetime" | "time" | "geo" no
aggregation "sum" | "count" | "count_distinct" | "avg" | "min" | "max" | "none" no
expression string no
format string no
description string no
isHidden boolean no
sortByField string no
semanticType string no
isMetric boolean no
ordinal integer no
sensitivityLabel string | null no

Responses: 200 · 400 · 401 · 404 · 409

DELETE /api/models/{modelId}/tables/{tableId}/fields/{fieldId}

Section titled “DELETE /api/models/{modelId}/tables/{tableId}/fields/{fieldId}”

Delete a model field

409 while a dashboard card, a report, a dashboard’s filter pane, the filters a schedule sends or a metric names the field by its id (in any spelling of it), or a relationship joins on it.

Path parameters

Name Type Required Description
modelId string yes
tableId string yes
fieldId string yes

Responses: 204 — No content · 401 · 404 · 409

GET /api/models/{modelId}/tables/{tableId}/transforms

Section titled “GET /api/models/{modelId}/tables/{tableId}/transforms”

List transform steps for a table

Path parameters

Name Type Required Description
modelId string yes
tableId string yes

Responses: 200

POST /api/models/{modelId}/tables/{tableId}/transforms

Section titled “POST /api/models/{modelId}/tables/{tableId}/transforms”

Add a transform step to a table

400 when the step cannot compile. An add_column expression reads its own row only: one with a subquery, a query written without SELECT (TABLE, FROM first, a table after IN) or a function that runs one (query_to_xml and the like) is refused, naming it, because it would read the source past row-level security; a step stored before is refused when a query reads it.

Path parameters

Name Type Required Description
modelId string yes
tableId string yes

Request body (JSON)

Field Type Required Description
type "filter_rows" | "remove_columns" | "rename_column" | "change_type" | "add_column" | "replace_values" | "sort_rows" | "top_n" | "deduplicate" | "group_aggregate" yes
config object yes
label string no

Responses: 200

PUT /api/models/{modelId}/tables/{tableId}/transforms/{transformId}

Section titled “PUT /api/models/{modelId}/tables/{tableId}/transforms/{transformId}”

Update a transform step

400 when the new config cannot compile, an add_column expression that reads past its own row included, as on create.

Path parameters

Name Type Required Description
modelId string yes
tableId string yes
transformId string yes

Request body (JSON)

Field Type Required Description
config object no
label string no
isEnabled boolean no

Responses: 200

DELETE /api/models/{modelId}/tables/{tableId}/transforms/{transformId}

Section titled “DELETE /api/models/{modelId}/tables/{tableId}/transforms/{transformId}”

Delete a transform step

Path parameters

Name Type Required Description
modelId string yes
tableId string yes
transformId string yes

Responses: 200

POST /api/models/{modelId}/tables/{tableId}/transforms/reorder

Section titled “POST /api/models/{modelId}/tables/{tableId}/transforms/reorder”

Reorder transform steps

Path parameters

Name Type Required Description
modelId string yes
tableId string yes

Request body (JSON)

Field Type Required Description
orderedIds array of string yes

Responses: 200

Re-sync imported tables with the source’s latest discovered schema

Path parameters

Name Type Required Description
modelId string yes

Responses: 200

POST /api/models/{modelId}/validate-expression

Section titled “POST /api/models/{modelId}/validate-expression”

Validate a calculated-field expression

Path parameters

Name Type Required Description
modelId string yes

Request body (JSON)

Field Type Required Description
expression string yes
tableId string no When set, referenced columns are checked against this table’s schema

Responses: 200 · 400 · 401 · 404