REST API
API: Catalog
Business glossary, asset certification, ownership, and lineage. All endpoints require authentication unless noted. 38 endpoints, 4 of them app only: an API key gets 403 there.
GET /api/audit-logs
Section titled “GET /api/audit-logs”List audit logs
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
userId |
string | no | |
action |
string | no | |
resourceType |
string | no | |
from |
string | no | |
to |
string | no | |
limit |
integer | no | |
offset |
integer | no |
Responses: 200 · 400 · 401
GET /api/audit-logs/export
Section titled “GET /api/audit-logs/export”Export audit logs (CSV download, or seq-cursored NDJSON for SIEM collectors)
Part of the Enterprise plan (compliance auditing): below it 403 PLAN_TIER_REQUIRED, unless the workspace keeps the export until the renewal of the period running when it moved. The NDJSON feed also carries the workspace’s rows kept in the 7-year archive (each line’s kept: archive or live). Reading the log stays on every plan.
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
userId |
string | no | |
action |
string | no | |
resourceType |
string | no | |
from |
string | no | |
to |
string | no | |
limit |
integer | no | |
format |
"csv" | "ndjson" |
no | |
afterSeq |
integer | no |
Responses: 200
GET /api/audit-logs/queries
Section titled “GET /api/audit-logs/queries”List query executions: who ran which query on which source, how long, how many rows, and any error
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
userId |
string | no | |
sourceId |
string | no | |
origin |
string | no | |
errorsOnly |
boolean | no | |
from |
string | no | |
to |
string | no | |
limit |
integer | no | |
offset |
integer | no |
Responses: 200 · 400 · 401
GET /api/audit-logs/queries/export
Section titled “GET /api/audit-logs/queries/export”Export query executions as NDJSON for SIEM collectors, oldest first, resumed with the x-next-cursor header
Part of the Enterprise plan (compliance auditing): below it 403 PLAN_TIER_REQUIRED, unless the workspace keeps the export until the renewal of the period running when it moved. Listing query executions stays on every plan.
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
limit |
integer | no | |
after |
string | no |
Responses: 200
GET /api/audit-logs/verify
Section titled “GET /api/audit-logs/verify”Verify the audit log hash chain
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
fromSeq |
integer | no | |
limit |
integer | no |
Responses: 200
GET /api/catalog/assets
Section titled “GET /api/catalog/assets”List governed assets with owner/domain facets
The dashboards, models, data sources and metrics the reader may open, each with its owner, domain, certification and where it opens. A request with none of q, sort, order or offset answers as it always has: { items, facets }, up to 500 by type then name, facets over the type asked. A request with any of them answers a page: { items, total, facets }, 50 by default, sorted by sort (name) in order (asc), names whatever their case, no owner or never changed last either way, ties by name, then type, then id; total counts the matches on every page, the facets describe the whole workspace whatever the filters, and facets.hidden counts the assets of types the reader may not open, never naming them.
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
type |
"dashboard" | "model" | "source" | "metric" |
no | |
domain |
string | no | |
ownerId |
string | no | |
unowned |
boolean | no | |
undocumented |
boolean | no | Only what Describe with AI can document: dashboards and metrics with no description, and models with a visible table or field that has none. |
q |
string | no | Text the asset’s name holds, whatever its case (a % or _ is that character); close spellings too where the database can. |
sort |
"name" | "type" | "updated" | "owner" |
no | A page’s order: name unless given. |
order |
"asc" | "desc" |
no | asc unless given. No owner, or never changed, comes last either way. |
offset |
integer | no | |
limit |
integer | no | 500 on today’s call, 50 on a page. |
Schema: CatalogAssetsPage (the response to a page request, one with q, sort, order or offset)
Responses: 200 · 400 · 401 · 403
PATCH /api/catalog/assets/{type}/{id}
Section titled “PATCH /api/catalog/assets/{type}/{id}”Assign owner/domain to a governed asset
Sets or clears the asset’s owner, its business domain, or both (null clears one; a body with neither is refused). The owner must be an active member of the workspace (400, details.reason owner_not_a_member). A domain is trimmed, each run of spaces one space, and written in the spelling the workspace already uses whatever its case. A model’s owner also reviews the AI’s notes about the model, so only someone who can edit models sets or clears it (403, details.reason caller_cannot_edit_models), and only to someone who can edit models (400, details.reason owner_cannot_edit_models). Setting an owner or a domain does not change the asset’s updated_at.
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
type |
"dashboard" | "model" | "source" | "metric" |
yes | |
id |
string | yes |
Request body (JSON)
| Field | Type | Required | Description |
|---|---|---|---|
ownerId |
string | null | no | The new owner, a member of the workspace. Null clears it; absent leaves it. |
domain |
string | null | no | The new domain, in the spelling the workspace already uses. Null or blank clears it; absent leaves it. |
Schema: CatalogAssetPatch (the request body) · CatalogAssetPatchAnswer (the response)
Responses: 200 · 400 · 401 · 403 · 404
GET /api/catalog/assets/{type}/{id}/notices
Section titled “GET /api/catalog/assets/{type}/{id}/notices”Data notices: an asset’s own and those it inherits
For a dashboard, model, data source or metric the caller may open: its own notices, then those on what it is built on, every step of the way, as the lineage graph reads it. What the caller may not open is never named: such a notice’s asset has no id, name or link, and no setter. can_manage says whether the caller may set, edit and clear its own; setting_needs_upgrade, that setting and editing need Business. Every plan. The first 50, with total. 404 when the caller can’t open the asset. An API key needs dashboard:read, and source:read for a data source, as the Catalog opens one.
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
type |
"dashboard" | "model" | "source" | "metric" |
yes | |
id |
string | yes |
Responses: 200 · 400 · 401 · 403 · 404
POST /api/catalog/assets/{type}/{id}/notices
Section titled “POST /api/catalog/assets/{type}/{id}/notices”Set a data notice on an asset
Sets a notice on a dashboard, model, data source or metric. Its owner, someone who may edit it (the type’s own update; for a dashboard an editor grant on it too) or an admin (403, details.reason cannot_manage otherwise), on an asset they may open (404 otherwise). Business (403 PLAN_TIER_REQUIRED on Team). One notice of each kind per asset: 409 while one of that kind is in force (edit it instead); one that has ended gives its place to this one. 400 for words past the limit or holding hidden text, a custom note without words, or an end that has passed. Its words show to everyone who reads what is built on it; its asset’s name only to those who may open it. An API key needs dashboard:write, and its owner’s role decides.
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
type |
"dashboard" | "model" | "source" | "metric" |
yes | |
id |
string | yes |
Request body (JSON)
| Field | Type | Required | Description |
|---|---|---|---|
kind |
"deprecated" | "maintenance" | "stale" | "sensitive" | "custom" |
yes | deprecated (being retired: use something else), maintenance (being worked on: its numbers may change), stale (its data is out of date), sensitive (it holds sensitive data: take care sharing it), or custom (a note in the setter’s own words). |
message |
string | null | no | Its words, plain text: white space is folded to single spaces and the result kept to 500 characters. Required for a custom note; null or blank says no more than its kind. |
expiresAt |
string | null | no | When it stops showing on its own, an instant still to come. Null or absent: until someone clears it. |
Responses: 201 · 400 · 401 · 403 · 404 · 409
PATCH /api/catalog/assets/{type}/{id}/notices/{noticeId}
Section titled “PATCH /api/catalog/assets/{type}/{id}/notices/{noticeId}”Edit a data notice
Changes a notice’s words, its end, or both: null clears one, absent leaves it. Its kind stays. Its owner, someone who may edit it (the type’s own update; for a dashboard an editor grant on it too) or an admin (403, details.reason cannot_manage otherwise), on an asset they may open (404 otherwise). Business (403 PLAN_TIER_REQUIRED on Team). 404 for a notice that has ended, which shows nowhere. 400 for an empty change, words past the limit or holding hidden text, a custom note without words, or an end that has passed. An API key needs dashboard:write, and its owner’s role decides.
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
type |
"dashboard" | "model" | "source" | "metric" |
yes | |
id |
string | yes | |
noticeId |
string | yes |
Request body (JSON)
| Field | Type | Required | Description |
|---|---|---|---|
message |
string | null | no | Its words, plain text: white space is folded to single spaces and the result kept to 500 characters. Required for a custom note; null or blank says no more than its kind. |
expiresAt |
string | null | no | When it stops showing on its own, an instant still to come. Null or absent: until someone clears it. |
Responses: 200 · 400 · 401 · 403 · 404
DELETE /api/catalog/assets/{type}/{id}/notices/{noticeId}
Section titled “DELETE /api/catalog/assets/{type}/{id}/notices/{noticeId}”Clear a data notice
Clears a notice: it shows nowhere from now on, and the audit log keeps what it said. Its owner, someone who may edit it (the type’s own update; for a dashboard an editor grant on it too) or an admin (403, details.reason cannot_manage otherwise), on an asset they may open (404 otherwise). Every plan, so a notice left after a downgrade can always come down. An API key needs dashboard:write, and its owner’s role decides.
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
type |
"dashboard" | "model" | "source" | "metric" |
yes | |
id |
string | yes | |
noticeId |
string | yes |
Responses: 204 — Cleared · 400 · 401 · 403 · 404
GET /api/catalog/assets/{type}/{id}/summary
Section titled “GET /api/catalog/assets/{type}/{id}/summary”About this data: one asset’s trust card
For a dashboard, model, data source or metric the caller may open: its owner, domain, certification (who, when, and a metric’s note and version), description, when it last changed, how fresh the data it reads is, the latest outcome of the quality checks on what it reads, a dashboard’s views in the last 30 days, the glossary terms linked to it, and how many assets feed it and read it, every step of the way: what the caller may open counted by type, the rest counted and never named. explain says whether Explain this asset would run for the caller; asking runs no AI and spends nothing. Every plan; lineage and Explain this asset need Business (withheld.lineage is plan), and lineage the Catalog’s view (permission). 404 when the caller can’t open the asset or the workspace has no such asset. An API key needs dashboard:read.
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
type |
"dashboard" | "model" | "source" | "metric" |
yes | |
id |
string | yes |
Responses: 200 · 400 · 401 · 403 · 404
GET /api/catalog/descriptions/drafts
Section titled “GET /api/catalog/descriptions/drafts”Describe with AI: the drafts waiting for your review, and whether it would run for you now
App only. An API key gets 403: AI features are available in the DataSquares app; API keys can’t use them.
The AI-drafted descriptions of the dashboards and metrics the caller may edit: state=pending (the default) lists the ones waiting for review, by type then name; state=all adds the decided ones (published: what an approval wrote), newest first. type and id narrow it to one asset. A pending draft whose asset got a description another way meanwhile is superseded. describeWithAi says whether drafting would run for the caller now. No AI is called.
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
state |
"pending" | "all" |
no | |
type |
"dashboard" | "metric" |
no | |
id |
string | no |
Responses: 200 · 400 · 401 · 403 · 404
POST /api/catalog/descriptions/drafts
Section titled “POST /api/catalog/descriptions/drafts”Describe with AI: draft the missing descriptions of dashboards and metrics (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 dashboard and metric named (at most 10) that has none, one quick AI call each, charged in AI credits (Description drafts). The AI is sent what the asset is, from its lineage chain: its name, a dashboard’s card titles, a metric’s formula (quoted text left out), grain and time field, and the models, fields, measures, metrics and filters it reads, with the descriptions they have; never a value, and a labelled field by its name alone. Nothing is published: each draft waits for a person’s review. Each asset’s outcome: drafted (the draft waits for review), pending (a draft already waited: no AI call), described (it has a description: no AI call), empty (a dashboard with no cards: no AI call), dropped (the checks left the draft out, its text not kept; reason: too_long, screened (personal, secret or instruction-like text), invented_number (a number the asset does not carry), no_answer), failed (the AI call failed: nothing stored) or not_started (the request’s time ran out first: ask again). Drafting and reviewing take the asset’s own edit right (403 details.reason cannot_edit, naming them); several assets in one request take the Catalog’s update right too (403 details.reason several_need_catalog); an asset the caller may not open is not found (404). One request at a time per workspace: another meanwhile is refused with 409 DRAFTS_RUNNING before any AI call, details.running saying whether you started the run, when, and for how many assets; 429 DRAFTS_BUSY (Retry-After 60 seconds) when the server drafts as many runs as it holds at once. 503 AI_NOT_CONFIGURED on a server without AI.
Request body (JSON)
| Field | Type | Required | Description |
|---|---|---|---|
assets |
array of object | yes |
Responses: 200 · 400 · 401 · 403 · 404 · 409 · 429 · 503
PUT /api/catalog/descriptions/drafts
Section titled “PUT /api/catalog/descriptions/drafts”Describe with AI: approve or reject drafted descriptions
App only. An API key gets 403: AI features are available in the DataSquares app; API keys can’t use them.
approve writes the draft, or text in its place, as the dashboard’s or metric’s description, only where it still has none (otherwise the draft is superseded); reject keeps it out. Every draft must be one of the workspace’s drafts waiting for review (400 otherwise, naming them), of an asset the caller may edit (403 otherwise, details.reason cannot_edit), and nothing is changed then.
Request body (JSON)
| Field | Type | Required | Description |
|---|---|---|---|
decisions |
array of object | yes |
Responses: 200 · 400 · 401 · 403 · 404
GET /api/catalog/notices/for/{type}/{id}
Section titled “GET /api/catalog/notices/for/{type}/{id}”Data notices for a viewed dashboard, report, presentation or story
The notices in force on what a dashboard, report, presentation or story the caller may open is built on, every step of the way through the lineage graph (a notice on a data source reaches the dashboards whose models read it, and so on), and a dashboard’s own; for the short line its page shows. Read as the caller reads the item: a presentation’s speaker notes and working copy for its makers, its published version for everyone else; a story’s sections they may see. What the caller may not open is never named: such a notice’s asset has no id, name or link, no setter or editor, and an id of its own in each answer. Every plan. 404 when the caller can’t open the item. An API key needs the item’s own read scope (dashboard:read, reports:read, presentations:read, stories:read), and names an asset only with dashboard:read.
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
type |
"dashboard" | "report" | "presentation" | "story" |
yes | |
id |
string | yes |
Responses: 200 · 400 · 401 · 403 · 404
PUT /api/certification/{assetType}/{id}
Section titled “PUT /api/certification/{assetType}/{id}”Certify or un-certify a governed asset (workspace admins)
Workspace admins. A metric may also be certified by someone whose role holds the Certify metrics permission; its certification records the version it is of (certified_version) and an optional note, both cleared by its next version.
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
assetType |
"dashboard" | "model" | "source" | "metric" |
yes | |
id |
string | yes |
Request body (JSON)
| Field | Type | Required | Description |
|---|---|---|---|
certified |
boolean | yes | |
note |
string | null | no | A metric’s certification only: why it is certified, such as “for board reporting”. Kept with it until a new version clears it. |
Responses: 200 · 400 · 401 · 404
GET /api/classification/proposals
Section titled “GET /api/classification/proposals”A model’s open sensitive-column proposals
Every open proposal of a field still unlabelled and still proposable (visible, not calculated, of a visible table and a classified source), by table and field order: the detector its sampled values matched, the label proposed, how many values were sampled and how many matched, and whether the column’s name agreed. No value is kept or returned. With where the model’s checks stand: when a table was last read, how many tables the last check could not read, how many columns are not checked because their names cannot be written safely in a query, and how many unlabelled columns without a proposal are not checked because a column of the same name carries a label elsewhere on the source (that label does not mask them), with the first 200 of them by table and field.
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
modelId |
string | yes | The model whose proposals to list. |
Responses: 200 · 400 · 401 · 403 · 404
POST /api/classification/proposals/approve
Section titled “POST /api/classification/proposals/approve”Approve sensitive-column proposals: add their labels (model editors, up to 200 at once)
Checked whole first: 404 when a proposal is not this model’s, 409 when one was decided already or is no longer proposed (its column or table was hidden, deleted or changed since, or its live database is no longer checked), and nothing is changed. Each approval then adds the proposed label to its field in one transaction with the decision; a field that carries a label by then keeps it (a model editor may add a label, never change one) and its proposal is closed as superseded. One that can no longer be applied by then (decided, withdrawn, or no longer proposed meanwhile) is left as it is and counted in notApplied. Should a write fail, the approvals before it stay and the rest stay open.
Request body (JSON)
| Field | Type | Required | Description |
|---|---|---|---|
modelId |
string | yes | The model the proposals are of. |
ids |
array of string | yes | The proposals to decide: 1 to 200, each once. |
Responses: 200 · 400 · 401 · 403 · 404 · 409
POST /api/classification/proposals/reject
Section titled “POST /api/classification/proposals/reject”Reject sensitive-column proposals (model editors, up to 200 at once)
All or nothing, as approving. A rejected field is not proposed again for 90 days; its label is not changed.
Request body (JSON)
| Field | Type | Required | Description |
|---|---|---|---|
modelId |
string | yes | The model the proposals are of. |
ids |
array of string | yes | The proposals to decide: 1 to 200, each once. |
Responses: 200 · 400 · 401 · 403 · 404 · 409
GET /api/classification/settings
Section titled “GET /api/classification/settings”Whether this workspace’s live databases are classified for sensitive columns
Sensitive columns are found by rules over sampled values (never an AI). Staged sources and the Warehouse are always classified; live databases only once a company admin turns it on.
Responses: 200 · 400 · 401 · 403 · 404
PUT /api/classification/settings
Section titled “PUT /api/classification/settings”Turn classification of live databases on or off (company admins)
On, the sampler also reads this workspace’s live databases: one bounded query a table, run by the system on the database’s own server, at most 200 values a column, matched and dropped; only counts are kept.
Request body (JSON)
| Field | Type | Required | Description |
|---|---|---|---|
liveSources |
boolean | yes |
Responses: 200 · 400 · 401 · 403 · 404
GET /api/company-audit
Section titled “GET /api/company-audit”The company audit view: every workspace’s actions and the company-level ones (Enterprise)
Every audit row of your company, newest first: each workspace’s, and the actions that belong to no workspace (people, the company profile, its security policy, single sign-on, menus, billing, sign-ins). Two years, as every audit log keeps; the export reads the 7-year archive too. Company admins only, on the Enterprise plan.
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
scope |
"all" | "company" |
no | company: only actions with no workspace (people, settings, sign-ins). |
workspaceId |
string | no | Only this workspace’s rows (one of your company’s). |
userId |
string | no | |
action |
string | no | |
resourceType |
string | no | |
from |
string | no | |
to |
string | no | |
limit |
integer | no | |
offset |
integer | no |
Responses: 200 · 400 · 401
GET /api/company-audit/export
Section titled “GET /api/company-audit/export”Export the company’s audit trail, the 7-year archive included: CSV, or NDJSON for SIEM collectors (Enterprise)
For a signed-in company admin, or a collector polling with an API key (X-API-Key) whose owner is a company admin and whose scopes let it read the audit log (admin_audit:view, or read).
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
scope |
"all" | "company" |
no | company: only actions with no workspace (people, settings, sign-ins). |
workspaceId |
string | no | Only this workspace’s rows (one of your company’s). |
userId |
string | no | |
action |
string | no | |
resourceType |
string | no | |
from |
string | no | |
to |
string | no | |
format |
"csv" | "ndjson" |
no | |
afterSeq |
integer | no | NDJSON: the x-last-seq of the page before; absent = from the oldest kept row. |
limit |
integer | no | CSV: at most this many rows (more is refused). NDJSON: one page (at most 10,000). |
Responses: 200
GET /api/glossary
Section titled “GET /api/glossary”List glossary terms
Every live term with its links, in name order (the default, as before). view=lookup: each term’s name, synonyms and a definition cut to 280 characters, no links (for field tooltips). view=page: \{ items, total, offset, limit }, found by q in a name, a synonym or a definition. A link to a metric, a model or a field is listed only to a reader who may open metrics, or models. Every view sends an ETag; send it back in If-None-Match to get 304 when nothing changed.
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
view |
"full" | "lookup" | "page" |
no | |
q |
string | no | view=page: words in the name, a synonym or the definition. |
offset |
integer | no | |
limit |
integer | no |
Schema: GlossaryTerm (the response without view: a list of them) · GlossaryPage (the response to view=page) · GlossaryLookupItem (the response to view=lookup: a list of them)
Responses: 200 · 304 — Not modified · 400 · 401 · 403
POST /api/glossary
Section titled “POST /api/glossary”Create a glossary term
Published at once. 409 CONFLICT (details.reason term_taken, with the term) for a name the workspace has; 400 VALIDATION_ERROR for a blank name or definition (blank), characters that can’t be seen (hidden_text), a word another term already has (synonym_taken, with the word and the term) or a steward who is not a member (not_a_member).
Request body (JSON)
| Field | Type | Required | Description |
|---|---|---|---|
term |
string | yes | |
definition |
string | yes | |
synonyms |
array of string | no | |
stewardId |
string | null | no | The person to ask about the term (a member of the workspace); null clears it. |
Schema: GlossaryTermCreate (the request body) · GlossaryTerm (the response)
Responses: 201 · 400 · 401 · 403 · 409
PUT /api/glossary/{id}
Section titled “PUT /api/glossary/{id}”Update a glossary term
Changes the fields sent and answers the term with the links the reader may open; an edit that changes nothing writes nothing. Send expectedUpdatedAt (the term’s updated_at as read) to be refused (409 CONFLICT, details.reason changed) when someone changed it since. 409 term_taken for a name the workspace has; 400 as for create, for the names the edit adds only; 404 when there is no such term.
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
id |
string | yes |
Request body (JSON)
| Field | Type | Required | Description |
|---|---|---|---|
term |
string | no | |
definition |
string | no | |
synonyms |
array of string | no | |
stewardId |
string | null | no | The person to ask about the term (a member of the workspace); null clears it. |
expectedUpdatedAt |
string | no | The term’s updated_at when the editor opened it: a 409 (details.reason changed) when it changed since. |
Schema: GlossaryTermUpdate (the request body) · GlossaryTerm (the response)
Responses: 200 · 400 · 401 · 403 · 404 · 409
DELETE /api/glossary/{id}
Section titled “DELETE /api/glossary/{id}”Delete a glossary term
On every plan, for a role that may delete glossary terms. 404 when there is no such live term.
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
id |
string | yes |
Responses: 204 — Deleted · 400 · 401 · 403 · 404
GET /api/glossary/{id}/history
Section titled “GET /api/glossary/{id}/history”A glossary term’s history
Its changes, newest first, from the audit log (kept two years): created, updated, deleted, link added, link removed, with who and what each changed; a link’s change only to a reader who may open its kind of asset. A deleted term’s history is readable too. On every plan.
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
id |
string | yes |
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
limit |
integer | no |
Schema: GlossaryHistory (the response)
Responses: 200 · 400 · 401 · 403 · 404
POST /api/glossary/{id}/links
Section titled “POST /api/glossary/{id}/links”Link a glossary term to an asset
The asset must be a live metric, model or field of the workspace, of a kind the caller may open (400 VALIDATION_ERROR otherwise, details.reason asset_not_found with its asset_type, malformed, blank or not_a_field_link). Answers the link with its term and its asset’s name; linking what is already linked answers that link.
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
id |
string | yes |
Request body (JSON)
| Field | Type | Required | Description |
|---|---|---|---|
assetType |
"metric" | "model_field" | "model" |
yes | |
assetRef |
string | no | A metric’s or a model’s id, or a field’s ‘<model id>:<field name>’. |
fieldId |
string | no | model_field only: the field itself (instead of assetRef). |
Schema: GlossaryLinkCreate (the request body) · GlossaryLinkCreated (the response)
Responses: 201 · 400 · 401 · 403 · 404 · 409
DELETE /api/glossary/{id}/links/{linkId}
Section titled “DELETE /api/glossary/{id}/links/{linkId}”Unlink a glossary term from an asset
404 when the term has no such link, or none of a kind of asset the caller may open.
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
id |
string | yes | |
linkId |
string | yes |
Responses: 204 — Unlinked · 400 · 401 · 403 · 404
GET /api/glossary/suggestions
Section titled “GET /api/glossary/suggestions”Suggest terms to define: the words your names use that the glossary does not define yet
The words and two-word phrases the names of the dashboards, metrics and models (their tables, visible fields and measures) the caller may open use most, that no term names by its name or a synonym (case, plurals and separators aside), most used first. uses: how many names use it; examples: a few of them. A plain count (method count): no AI is called and no AI credits are used. Words that mean nothing alone (of, id, date, total, …) are left out; a phrase used once is left out. Only a person writes a definition.
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
limit |
integer | no |
Responses: 200 · 400 · 401 · 403
GET /api/lineage/graph
Section titled “GET /api/lineage/graph”Asset-level lineage graph (source → pipeline → model or blend → query or metric → dashboard or report → share, and the decks and stories that bind a metric, a model or a saved query)
Names only what the caller may open, by the same permissions as the pages that open each asset (sources, pipelines, models and blends, saved queries, metrics, dashboards and reports by role or grant, decks and stories by their own readers); the rest is counted, one node per neighbour, with hidden holding how many (“2 sources you can’t open”), and it opens nothing. With asset, the view is that asset’s lineage: what feeds it (direction=up), what reads it (down) or both (the default), depth hops from it (1 to 10, 2 by default) or all; without asset both are ignored and the graph is the whole workspace. At most 5000 assets are drawn (a scoped view keeps the nearest first); truncated is true when the depth or that limit left some out. An asset the caller may not open, or one that does not exist, is an empty graph. Requires the Catalog view permission; an API key also needs dashboard:read.
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
asset |
string | no | |
direction |
"up" | "down" | "both" |
no | |
depth |
string | no |
Schema: LineageGraph (the response)
Responses: 200 · 400 · 401 · 403 · 429
GET /api/lineage/graph/chain
Section titled “GET /api/lineage/graph/chain”The lineage chain of a dashboard, a card, a metric or a model
Built by rules from the workspace’s references, in a fixed order: source, pipeline, Warehouse dataset, model, the fields, measures and metric formulas read, the cards, the dashboard, then its filters. A model’s chain is what feeds it, up to the model itself. Only what the caller may open is named; the rest is counted in hidden. A model a row-level security policy applies on is marked policy (never its rule); a labelled field is marked labelled; no value is included. Column lineage through pipelines is not tracked, and a chain with a pipeline says so in notes. explainWithAi says whether Explain with AI would run for the caller now, and if not why. 404 when the caller can’t open the dashboard (or the card’s), or the model (the Data models view).
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
kind |
"dashboard" | "card" | "metric" | "model" |
yes | |
id |
string | yes |
Schema: LineageChainAnswer (the response)
Responses: 200 · 404
GET /api/lineage/graph/count
Section titled “GET /api/lineage/graph/count”How many assets the lineage graph names, of each type, without the graph
The view GET /api/lineage/graph would draw for the caller, counted: total the assets it names (only what the caller may open, by the same permissions), byType how many of each type, a type with none left out. asset, direction and depth scope it as they scope the graph. Never cut short: the graph draws at most 5000 assets, the count counts them all. Requires the Catalog view permission; an API key also needs dashboard:read.
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
asset |
string | no | |
direction |
"up" | "down" | "both" |
no | |
depth |
string | no |
Responses: 200 · 400 · 401 · 403 · 429
POST /api/lineage/graph/explain
Section titled “POST /api/lineage/graph/explain”Explain the lineage of a dashboard, a card, a metric or a model in one paragraph (AI)
App only. An API key gets 403: AI features are available in the DataSquares app; API keys can’t use them.
Uses AI credits. One AI call writes a paragraph from the lineage chain alone (the chain GET /chain returns), charged to the caller for the AI work it used. The paragraph is checked: every name in it must come from the chain and every number must be one of its counts. outcome is written when it passes, dropped when it does not (paragraph is null and the chain is the answer), and unavailable when the AI returned nothing usable. Nothing is stored. 400 when there is no lineage to explain; 503 AI_NOT_CONFIGURED when AI isn’t set up on this server.
Request body (JSON)
| Field | Type | Required | Description |
|---|---|---|---|
kind |
"dashboard" | "card" | "metric" | "model" |
yes | |
id |
string | yes |
Schema: LineageExplanation (the response)
Responses: 200 · 400 · 403 · 404 · 429 · 503
PUT /api/ownership/{assetType}/{id}
Section titled “PUT /api/ownership/{assetType}/{id}”Set/clear an asset’s owner and business domain
The same assignment, body and answer as PATCH /api/catalog/assets/:type/:id: null clears the owner or the domain. The owner must be an active member of the workspace (400, details.reason owner_not_a_member); a model’s owner is set only by someone who can edit models (403, details.reason caller_cannot_edit_models), to someone who can edit models (400, details.reason owner_cannot_edit_models).
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
assetType |
"dashboard" | "model" | "source" | "metric" |
yes | |
id |
string | yes |
Request body (JSON)
| Field | Type | Required | Description |
|---|---|---|---|
ownerId |
string | null | no | The new owner, a member of the workspace. Null clears it; absent leaves it. |
domain |
string | null | no | The new domain, in the spelling the workspace already uses. Null or blank clears it; absent leaves it. |
Schema: CatalogAssetPatch (the request body) · CatalogAssetPatchAnswer (the response)
Responses: 200 · 400 · 401 · 403 · 404
GET /api/ownership/domains
Section titled “GET /api/ownership/domains”Business domains in use (filter facets)
Responses: 200 · 400 · 401 · 403 · 404