Capabilities / Developers

HTTP API reference

Every HTTP operation an API key can call, with parameters, responses, access and errors.

X4 Tech SolutionsUpdated October 30, 2026268 HTTP operations

Every HTTP operation a Unity API key can call, with its parameters, body, response, access and errors. Connect your AI explains keys, scopes and the agent tools; the same operations are in the OpenAPI 3.1 document: download openapi.json, or read GET /api/openapi.json from your deployment.

Send Authorization: Bearer YOUR_UNITY_API_KEY with every request and Content-Type: application/json with a JSON body; the account comes from the key, so omit caller fields such as userId. workspace:read keys call the operations that only read; workspace:write keys also change reports and run the assistant. Every operation also applies your report access (its access label). Every error carries error, message (the same text) and a code. These routes are Unity's application API, not a versioned /api/v1 contract.

Complete endpoint directory

This snapshot contains 268 registered HTTP operations. 152 of them are the API: they document their parameters, request body, response, examples and errors under Request and response, and the same contracts are published as an OpenAPI 3.1 document: openapi.json, or GET /api/openapi.json from your deployment, for client generators and AI agents. Unity's browser also calls 9 others that accept a key; they aren't part of the API. Browser-only and public routes are listed for completeness; a listing does not make a browser-only route available to an API key.

Route parameters use {name}. Every page parameter accepts the page UUID or its numeric ID. Authentication labels describe the token scope. Access labels describe the report role or account the operation needs: Unity refuses an operation labelled Edit access, Admin or Owner, or Owner with 403 and a code such as edit_access_required when the report it names, directly or through a page, chat, or visual, gives the caller less access. Connection ownership, administrator rules, and operation-specific validation still apply.

Reports14 operations

Create, list, rename and delete reports; read a report's workspace, catalog and instructions.

POST/api/instructions

Save report instructions

workspace:writeEdit access · reaches report
Request and response

Replaces the report's instructions. An empty string clears them. Edit access.

Body

reportIdstringRequired

Report ID.

instructionsstringRequired

At most 1,500 characters.

maxLength: 1500

Example request body

JSON
{
  "reportId": "9af3fb53-34e2-4e88-a953-ffdecdeece82",
  "instructions": "Amounts are USD. Fiscal year starts in May."
}

Response 200

messagestringOptional

Errors

400 Invalid input · 403 Scope, access or subscription. Every error has error, message and code.

GET/api/instructions/{report_id}

Read report instructions

workspace:readView access · reaches report
Request and response

The report's lasting guidance to the assistant (terminology, units, conventions).

Parameters

report_idpath · stringRequired

Response 200

instructionsstringOptional

Example response

JSON
{
  "instructions": "Amounts are USD. Fiscal year starts in May."
}

Errors

403 Scope, access or subscription. Every error has error, message and code.

GET/api/reports

List reports

workspace:readAny signed-in account · reaches report
Request and response

Reports the caller can open, newest first, including ones being deleted (with deletion).

Response 200

Example response

JSON
[
  {
    "id": "9af3fb53-34e2-4e88-a953-ffdecdeece82",
    "reportName": "Sales overview",
    "accessLevel": "Owner",
    "ownerFullName": "Alex Morgan",
    "createdAt": "2026-10-13T10:52:04.120Z",
    "sourceCount": 1
  }
]
GET/api/reports/{report_id}/catalog

Search a report

workspace:readView access · reaches model, pages
Request and response

Pages, visuals and connections across the whole report without loading every visual. Each page carries its id, name, kind, viewport and hidden (limited to editors and people added to it). Each visual carries its key, type, title, page, query, contract, appearance, revision and layout; detail=true adds bindings and lineage. Page with offset and nextOffset while complete is false.

Parameters

report_idpath · stringRequired
kindquery · stringOptional
queryquery · stringOptional

Search text over titles and queries.

pageIdquery · stringOptional

Restrict to one page: its UUID or numeric ID.

currentPageIdquery · stringOptional

The page the caller is looking at (marks it in the result).

visualKeyquery · array<string>Optional
detailquery · stringOptional

true adds bindings, lineage and filters per visual.

offsetquery · integerOptional
limitquery · integerOptional

Response 200

statusstringOptional
enum: ["success"]
itemsarray<object>Optional
totalintegerOptional
offsetintegerOptional
completebooleanOptional
nextOffsetinteger | nullOptional
missingVisualKeysarray<string>Optional

Errors

400 Invalid input · 403 Scope, access or subscription. Every error has error, message and code.

DELETE/api/reports/{report_id}

Delete a report

workspace:writeOwner · reaches report
Request and response

Owner only. Deletion runs in the background: the report disappears from content APIs at once and GET /api/reports/{report_id}/deletion follows it. An active assistant run must stop first.

Parameters

report_idpath · stringRequired

Response 200

deletionobjectOptional

Errors

400 Invalid input · 403 Scope, access or subscription · 409 Conflict: re-read and reconcile. Every error has error, message and code.

GET/api/reports/{report_id}/deletion

Follow a report deletion

workspace:readOwner · reaches report
Request and response

Parameters

report_idpath · stringRequired

Response 200

deletionobjectOptional

Errors

404 Not found. Every error has error, message and code.

GET/api/reports/{report_id}/live

Poll a report for changes

workspace:readAny access to the page · reaches chat, pages, report
Request and response

Cheap revision counters: compare them with the last values you saw to know what to re-read (pagesVersion, modelRevision, pagesFingerprint, and with visualsPage that page's visualsRevision), plus each of your conversations' run state. pagesFingerprint changes when any page (HTML or canvas) is saved, created or deleted. With visualsPage it also answers `page` ({pageUid, kind, version}), `hold`, `leases` and `presence` for that page; each HTML page's own version comes from GET /api/html/pages/{pageUid}; history is the report's (GET /api/reports/{reportId}/versions).

Parameters

report_idpath · stringRequired
visualsPagequery · integerOptional

Numeric page ID whose visualsRevision to include.

Response 200

reportIdstringOptional

Report ID.

accessLevelstringOptional
pagesVersionstringOptional
modelRevisionintegerOptional
pagesFingerprintstringOptional
pageobject | nullOptional
visualsPageIdinteger | nullOptional
visualsRevisionstring | nullOptional
chatobjectOptional

Errors

403 Scope, access or subscription. Every error has error, message and code.

PUT/api/reports/{report_id}/name

Rename a report

workspace:writeEdit access · reaches report
Request and response

Parameters

report_idpath · stringRequired

Body

reportNamestringRequired

1 to 50 characters.

minLength: 1 maxLength: 50

Example request body

JSON
{
  "reportName": "Sales overview FY27"
}

Response 200

reportNamestringOptional
messagestringOptional

Errors

400 Invalid input · 403 Scope, access or subscription · 404 Not found. Every error has error, message and code.

GET/api/reports/{report_id}/versions

List report versions

workspace:readAny access to the page · reaches history, model, pages, report
Request and response

The report's saved versions, newest first. Every saved change makes one; version n is the report after that change. Each entry is one assistant run or one person's burst of edits (each within 5 minutes of the one before); expand lists one entry's versions one by one, so one change inside an entry can be undone by restoring the version before it. The first list of the whole report also has deletedPages. Needs Edit access to the report, or to the page with pageId.

Parameters

report_idpath · stringRequired
pageIdquery · stringOptional

A page's pageId: only that page's versions and its filters (page Edit is enough).

beforeVersionquery · integerOptional

nextBeforeVersion from the previous list, for older entries.

expandquery · integerOptional

An entry's version: its versions one by one, each as an entry of its own.

Response 200

headinteger | nullOptional

The latest version.

versionsarray<object>Optional
nextBeforeVersioninteger | nullOptional
deletedPagesarray<object>Optional

Pages deleted since history started that are still gone, newest first (the first list of the whole report).

Example response

JSON
{
  "head": 42,
  "nextBeforeVersion": null,
  "versions": [
    {
      "version": 42,
      "firstVersion": 39,
      "count": 4,
      "at": "2026-11-01T09:12:44.120Z",
      "actor": {
        "name": "Alex Morgan",
        "kind": "assistant"
      },
      "label": "Moved visual",
      "changed": [
        "Model",
        "Page 'Sales'"
      ]
    }
  ]
}

Errors

400 Invalid input · 403 Scope, access or subscription. Every error has error, message and code.

GET/api/reports/{report_id}/versions/{version}

Read a report version

workspace:readAny access to the page · reaches history, model, pages, report
Request and response

The report's definition document (GetReportDefinition) as it was at that version; with pageId, only that page and its filters.

Parameters

report_idpath · stringRequired
versionpath · integerRequired
pageIdquery · stringOptional

A page's pageId: only that page's versions and its filters (page Edit is enough).

Response 200

The report's definition document at that version (UnityReportDefinition), or with pageId {unityReportDefinition, pages: [that page], filters: [its filters]}.

Errors

400 Invalid input · 403 Scope, access or subscription. Every error has error, message and code.

POST/api/reports/{report_id}/versions/{version}/restore

Restore a report version

workspace:writeAny access to the page · reaches history, model, pages, report
Request and response

Make the report, or one page with pageId (a deleted page too), equal to a saved version, with the checks a save makes. Version n is the report after change n: to undo a change, restore the version listed before it (GET /api/reports/{report_id}/versions); for one change inside a grouped entry, list the entry with expand and restore the version before that change. A dry run (dryRun true, the default) changes nothing and returns the changes, the warnings (what can't come back), expectedVersion and expectedWarnings; the restore (dryRun false) needs both and answers 409 version_conflict when the report or the warnings moved since, and 409 restore_failed when a section wouldn't come back as saved. Restoring the whole report deletes pages added after that version. A restore is a new version. Needs Edit access to the report, or to the page with pageId; a deleted page needs Edit access to the report.

Parameters

report_idpath · stringRequired
versionpath · integerRequired

Body

pageIdstring | nullOptional

A page's pageId: only that page and its filters.

dryRunbooleanOptional
expectedVersioninteger | nullOptional

expectedVersion from the dry run.

expectedWarningsstring | nullOptional

expectedWarnings from the dry run.

Example request body

JSON
{
  "pageId": null,
  "dryRun": false,
  "expectedVersion": 42,
  "expectedWarnings": "3f9a1c0b7d2e4a65"
}

Response 200

dryRunbooleanOptional
appliedbooleanOptional

Whether the restore changed anything (it made a version).

reportVersionintegerOptional

The new version the restore made; absent when it changed nothing.

restoredFromintegerOptional
pageIdstring | nullOptional
expectedVersionintegerOptional
expectedWarningsstringOptional
changesarray<object>Optional
warningsarray<object>Optional
moreintegerOptional

How many changes beyond the first 300 are left out.

Example response

JSON
{
  "dryRun": true,
  "restoredFrom": 38,
  "pageId": null,
  "expectedVersion": 42,
  "expectedWarnings": "3f9a1c0b7d2e4a65",
  "changes": [
    {
      "section": "pages",
      "kind": "page",
      "id": "34432e64-7f1e-43b7-8a6c-bdb0926d0577",
      "name": "Draft",
      "pageId": "34432e64-7f1e-43b7-8a6c-bdb0926d0577",
      "change": "removed",
      "keys": []
    }
  ],
  "warnings": [
    {
      "code": "page_removed",
      "section": "pages",
      "id": "34432e64-7f1e-43b7-8a6c-bdb0926d0577",
      "name": "Draft",
      "text": "Page 'Draft' isn't in version 38, so the restore deletes it; it can be brought back from the deleted pages."
    }
  ]
}

Errors

400 Invalid input · 403 Scope, access or subscription · 409 Conflict: re-read and reconcile. Every error has error, message and code.

GET/api/reports/{report_id}/versions/diff

Compare report versions

workspace:readAny access to the page · reaches history, model, pages, report
Request and response

What changed from one saved version to another (to omitted: the report now): each object added, removed or changed, by section, kind, id and name, with the keys that changed.

Parameters

report_idpath · stringRequired
fromquery · integerRequired

The earlier version.

toquery · integerOptional

The later version.

pageIdquery · stringOptional

A page's pageId: only that page's versions and its filters (page Edit is enough).

Response 200

fromVersionintegerOptional
toVersioninteger | nullOptional
changesarray<object>Optional
moreintegerOptional

How many changes beyond the first 300 are left out.

Example response

JSON
{
  "fromVersion": 38,
  "toVersion": null,
  "changes": [
    {
      "section": "pages",
      "kind": "visual",
      "id": "8c1f0b7e-2d1a-4c55-9a0e-5b7f0e1d2c3a",
      "name": "Revenue by month",
      "pageId": "34432e64-7f1e-43b7-8a6c-bdb0926d0577",
      "change": "changed",
      "keys": [
        "position"
      ]
    }
  ]
}

Errors

400 Invalid input · 403 Scope, access or subscription. Every error has error, message and code.

GET/api/reports/{report_id}/workspace

Read a report workspace

workspace:readAny access to the page · reaches chat, model, pages, report
Request and response

The report's name, the caller's access, its pages (both page IDs, kind, visibility and canvas) and its attached connections. Start here after choosing a report. contentEdit is true when the caller's View share is Edit content (they can also save text through the report's HTML pages); accessLevel stays View.

Parameters

report_idpath · stringRequired

Response 200

reportIdstringOptional

Report ID.

reportNamestringOptional
hasPermissionbooleanOptional
accessLevelstringOptional
contentEditbooleanOptional
pagesarray<value>Optional
connectionsarray<object>Optional

Example response

JSON
{
  "reportId": "9af3fb53-34e2-4e88-a953-ffdecdeece82",
  "reportName": "Sales overview",
  "hasPermission": true,
  "accessLevel": "Owner",
  "connections": [],
  "pages": [
    {
      "PageID": 888,
      "PageUID": "34432E64-7F1E-43B7-8A6C-BDB0926D0577",
      "PageName": "Page 1",
      "PageKind": "report",
      "Hidden": false,
      "lockedViewport": null
    }
  ]
}

Errors

403 Scope, access or subscription · 404 Not found. Every error has error, message and code.

POST/api/reports/create

Create a report

workspace:writeAny signed-in account · reaches report
Request and response

A new report owned by the caller, with one empty canvas page and one conversation.

Body

reportNamestringRequired

1 to 50 characters.

minLength: 1 maxLength: 50
clientRequestIdstringOptional

Optional retry key, a UUID or any string up to 64 characters. Retrying with the same key returns the first result instead of a second report.

maxLength: 64

Example request body

JSON
{
  "reportName": "Sales overview",
  "clientRequestId": "sales-overview-1"
}

Response 201

reportIdstringOptional

Report ID.

defaultPageIdintegerOptional

Numeric ID of the first page.

defaultPageUidstringOptional

UUID of the first page.

messagestringOptional

Example response

JSON
{
  "reportId": "9af3fb53-34e2-4e88-a953-ffdecdeece82",
  "defaultPageId": 888,
  "defaultPageUid": "34432e64-7f1e-43b7-8a6c-bdb0926d0577",
  "message": "Report created successfully"
}

Errors

400 Invalid input · 409 Conflict: re-read and reconcile. Every error has error, message and code.

Pages8 operations

Create, rename, duplicate, delete and restore report pages and their canvas settings.

GET/api/pages

List a report's pages

workspace:readAny access to the page · reaches pages
Request and response

Pages visible to the caller, in creation order, with both IDs and the kind of page: report (a canvas of native visuals) or html.

Parameters

reportIdquery · stringRequired

Report ID. Also accepted as report_id.

Response 200

PageIDintegerOptional
PageUIDstringOptional
PageNamestringOptional
PageKindstringOptional
enum: ["report","html"]
ReportIDstringOptional
HiddenbooleanOptional

Errors

400 Invalid input · 403 Scope, access or subscription. Every error has error, message and code.

POST/api/pages/add

Create a page

workspace:writeEdit access · reaches pages
Request and response

A canvas page (pageKind report) for native visuals, or an HTML page (pageKind html) that starts from a blank template. Returns [page] by default, or the full receipt with includeReceipt.

Body

reportIdstringRequired

Report ID.

pageNamestringRequired

Alias: newPageName.

pageKindstringOptional
enum: ["report","html"] default: "report"
clientRequestIdstringOptional

Retry key: a UUID or any string up to 64 characters.

maxLength: 64
includeReceiptbooleanOptional

Return the receipt instead of [page].

default: false

Example request body

JSON
{
  "reportId": "9af3fb53-34e2-4e88-a953-ffdecdeece82",
  "pageName": "Spending",
  "clientRequestId": "page-spending-1"
}

Response 200

Example response

JSON
[
  {
    "PageID": 890,
    "PageUID": "678AE2F0-1469-489E-AE28-B729A0000E51",
    "PageName": "Spending",
    "PageKind": "report",
    "PageLayout": {
      "kind": "report"
    },
    "Hidden": false,
    "ReportID": "9af3fb53-34e2-4e88-a953-ffdecdeece82"
  }
]

Errors

403 Scope, access or subscription · 409 Conflict: re-read and reconcile · 422 Cannot be applied. Every error has error, message and code.

DELETE/api/pages/delete

Delete a page

workspace:writeEdit access · reaches pages
Request and response

Deletes the page with its visuals and filters. Conversations remain. The report's versions list it as a deleted page (GET /api/reports/{reportId}/versions), and restoring it brings it back with its original IDs.

Body

reportIdstringRequired

Report ID.

pageIdstringRequired

The page: its UUID or its numeric ID (every page parameter accepts either).

Response 200

A page receipt (see Receipt). The change is one report version; restoring the version listed before it (POST /api/reports/{reportId}/versions/{version}/restore) reverses it.

pagevalueOptional
reportIdstringOptional

Report ID.

resourceTypestringOptional
mutationobjectOptional
changeobjectOptional
canvasBoundsobjectOptional

Errors

403 Scope, access or subscription · 422 Cannot be applied. Every error has error, message and code.

POST/api/pages/duplicate

Duplicate a page

workspace:writeEdit access · reaches pages
Request and response

Copies a page's visual definitions, layout and saved filters into a new page.

Body

reportIdstringRequired

Report ID.

sourcePageIdstringRequired

The page: its UUID or its numeric ID (every page parameter accepts either).

newPageNamestringRequired
clientRequestIdstringOptional

Example request body

JSON
{
  "reportId": "9af3fb53-34e2-4e88-a953-ffdecdeece82",
  "sourcePageId": 890,
  "newPageName": "Spending copy"
}

Response 200

pagevalueOptional
reportIdstringOptional

Report ID.

resourceTypestringOptional
mutationobjectOptional
changeobjectOptional
canvasBoundsobjectOptional
sourcePageobjectOptional
duplicatedVisualsarray<object>Optional
lockedViewportobjectOptional

Errors

403 Scope, access or subscription · 409 Conflict: re-read and reconcile · 422 Cannot be applied. Every error has error, message and code.

PUT/api/pages/update

Rename a page

workspace:writeEdit access · reaches pages
Request and response

Body

reportIdstringRequired

Report ID.

pageIdstringRequired

The page: its UUID or its numeric ID (every page parameter accepts either).

pageNamestringRequired

Alias: newPageName.

Response 200

A page receipt (see Receipt). The change is one report version; restoring the version listed before it (POST /api/reports/{reportId}/versions/{version}/restore) reverses it.

pagevalueOptional
reportIdstringOptional

Report ID.

resourceTypestringOptional
mutationobjectOptional
changeobjectOptional
canvasBoundsobjectOptional

Errors

403 Scope, access or subscription · 422 Cannot be applied. Every error has error, message and code.

GET/api/pages/viewport-settings

Read a page's canvas settings

workspace:readAny access to the page · reaches pages
Request and response

Parameters

reportIdquery · stringRequired

Report ID. Also accepted as report_id.

pageIdquery · stringRequired

The page: its UUID or its numeric ID (every page parameter accepts either). Also accepted as page_id.

Response 200

reportIdstringOptional

Report ID.

pageIdintegerOptional
lockedViewportvalueOptional

Errors

400 Invalid input · 403 Scope, access or subscription · 404 Not found · 422 Cannot be applied. Every error has error, message and code.

PUT/api/pages/viewport-settings

Change a page's canvas size and colors

workspace:writeEdit access · reaches pages
Request and response

Canvas pages have a fixed logical size (default 1280x720); visuals do not grow it. Send lockedViewport or its fields at the top level. An HTML page fills the window and has no canvas size: viewport fields on one are refused (422).

Body

reportIdstringRequired

Report ID.

pageIdstringRequired

The page: its UUID or its numeric ID (every page parameter accepts either).

lockedViewportvalueOptional

Example request body

JSON
{
  "reportId": "9af3fb53-34e2-4e88-a953-ffdecdeece82",
  "pageId": 890,
  "lockedViewport": {
    "width": 1600,
    "height": 900,
    "backgroundColor": "#ffffff"
  }
}

Response 200

pagevalueOptional
reportIdstringOptional

Report ID.

resourceTypestringOptional
mutationobjectOptional
changeobjectOptional
canvasBoundsobjectOptional
statusstringOptional
pageIdintegerOptional
pageLayoutobjectOptional
lockedViewportvalueOptional

Errors

403 Scope, access or subscription · 422 Cannot be applied. Every error has error, message and code.

GET/api/pages/visual-shell-manifest

Read a page's visual layout

workspace:readAny access to the page · reaches model, pages
Request and response

Every visual on a page with its kind, title, position and connection, without data. The browser draws placeholders from it; read data with POST /api/reports/{report_id}/visual-data.

Parameters

reportIdquery · stringRequired

Report ID. Also accepted as report_id.

pageIdquery · stringOptional

The page: its UUID or its numeric ID (every page parameter accepts either). Also accepted as page_id.

initialPagequery · stringOptional

Read the first visible page when pageId is omitted.

Response 200

visualsarray<object>Optional
connectionsarray<object>Optional
shellCountsobjectOptional
pageobjectOptional

Errors

400 Invalid input · 403 Scope, access or subscription · 422 Cannot be applied. Every error has error, message and code.

Native visuals24 operations

Inspect visual capabilities and state; preview, create, update, copy, move and delete visuals.

PUT/api/barGraphs/update

Update a bar chart Compatibility · use POST /api/visuals/update

workspace:writeEdit access to the page · reaches pages
Request and response

Response 200

PUT/api/dataCards/update

Update a data card Compatibility · use POST /api/visuals/update

workspace:writeEdit access to the page · reaches pages
Request and response

Response 200

PUT/api/dataTables/update

Update a table Compatibility · use POST /api/visuals/update

workspace:writeEdit access to the page · reaches pages
Request and response

Response 200

GET/api/datachats

List your conversations on a page

workspace:readAny access to the page · reaches chat
Request and response

Your own report chats on a page (conversations are private to their creator).

Parameters

reportIdquery · stringRequired

Report ID.

pageIdquery · stringRequired

The page: its UUID or numeric ID.

Response 200

DataChatIDintegerOptional
NamestringOptional
PageIDintegerOptional

Errors

400 Invalid input · 403 Scope, access or subscription · 404 Not found. Every error has error, message and code.

POST/api/datachats/add

Create a conversation

workspace:writeAny access to the page · reaches chat
Request and response

A new report chat for assistant runs (POST /api/agent/runs takes its DataChatID).

Body

reportIdstringRequired

Report ID.

activePagestringRequired

The page: its UUID or numeric ID.

namestringOptional
clientRequestIdstringOptional

Example request body

JSON
{
  "reportId": "9af3fb53-34e2-4e88-a953-ffdecdeece82",
  "activePage": 890,
  "name": "API exploration"
}

Response 201

DataChatIDintegerOptional
NamestringOptional
PageIDintegerOptional
createdNowbooleanOptional

False when clientRequestId replayed an earlier creation.

Errors

400 Invalid input · 403 Scope, access or subscription · 404 Not found · 409 Conflict: re-read and reconcile. Every error has error, message and code.

GET/api/declarativeCharts/data

Read a chart's data Compatibility · use POST /api/reports/{report_id}/visual-data

workspace:readAny access to the page · reaches model, pages
Request and response

Response 200

PUT/api/declarativeCharts/update

Update a chart Compatibility · use POST /api/visuals/update

workspace:writeEdit access to the page · reaches pages
Request and response

Response 200

DELETE/api/declarativecharts/delete

Delete a chart Compatibility · use POST /api/visuals/delete

workspace:writeEdit access to the page · reaches pages
Request and response

Response 200

PUT/api/lineGraphs/update

Update a line chart Compatibility · use POST /api/visuals/update

workspace:writeEdit access to the page · reaches pages
Request and response

Response 200

GET/api/matrices/data

Read a matrix's data Compatibility · use POST /api/reports/{report_id}/visual-data

workspace:readAny access to the page · reaches model, pages
Request and response

Response 200

DELETE/api/matrices/delete

Delete a matrix Compatibility · use POST /api/visuals/delete

workspace:writeEdit access to the page · reaches pages
Request and response

Response 200

PUT/api/matrices/update

Update a matrix Compatibility · use POST /api/visuals/update

workspace:writeEdit access to the page · reaches pages
Request and response

Response 200

PUT/api/pieCharts/update

Update a pie chart Compatibility · use POST /api/visuals/update

workspace:writeEdit access to the page · reaches pages
Request and response

Response 200

PUT/api/scatterPlots/update

Update a scatter plot Compatibility · use POST /api/visuals/update

workspace:writeEdit access to the page · reaches pages
Request and response

Response 200

GET/api/visuals/capabilities

Read visual capabilities

workspace:readAny signed-in account · reaches docs
Request and response

Without kind: the native kinds and their purpose. With kind (repeat for up to three): the exact JSON Schemas for a definition, its changes and its appearance, plus rendering semantics and the renderer guide. Build create and update bodies from these.

Parameters

kindquery · array<string>Optional

Response 200

schemaVersionintegerOptional
kindsobjectOptional

Errors

400 Invalid input. Every error has error, message and code.

POST/api/visuals/copy

Copy a visual

workspace:writeEdit access to the page · reaches pages
Request and response

Copies a visual (definition, appearance and filters) to a page of the same report.

Body

reportIdstringRequired

Report ID.

typestringRequired

Native visual kind. Chart presets (bar, line, scatter, pie) are declarativeChart specifications; an older name (barGraph, pieChart, ...) is refused with the current kind.

enum: ["declarativeChart","dataTable","matrix","dataCard","textBox","shape"]
idstring | integerRequired

The visual's UUID (visualUid), or its legacy numeric ID.

pageIdstringRequired

The page: its UUID or numeric ID.

positionobjectOptional

Logical canvas pixels on the page (default page 1280x720). Omitted: Unity finds free space.

Response 200

idvalueOptional
reportIdstringOptional

Report ID.

pageIdintegerOptional
visualvalueOptional
mutationobjectOptional
changeobjectOptional

Errors

403 Scope, access or subscription · 409 Conflict: re-read and reconcile · 422 Cannot be applied. Every error has error, message and code.

POST/api/visuals/create

Create a visual

workspace:writeEdit access to the page · reaches pages
Request and response

Validates the definition and its query against the report model and the kind's rules, saves it on the page and returns the receipt. Text boxes and shapes need no query.

A query or presentation that breaks a rule answers 422 with one sentence and its code (invalid_query, unknown_field, or legacy_sql for a visual saved as SQL).

Body

reportIdstringRequired

Report ID.

typestringRequired

Native visual kind. Chart presets (bar, line, scatter, pie) are declarativeChart specifications; an older name (barGraph, pieChart, ...) is refused with the current kind.

enum: ["declarativeChart","dataTable","matrix","dataCard","textBox","shape"]
pageIdstringRequired

The page: its UUID or numeric ID.

definitionobjectRequired

Per kind: GET /api/visuals/capabilities?kind={kind} returns the exact definition, changes and appearance schemas, required fields and rendering semantics.

positionobjectOptional

Logical canvas pixels on the page (default page 1280x720). Omitted: Unity finds free space.

Example request body

JSON
{
  "reportId": "9af3fb53-34e2-4e88-a953-ffdecdeece82",
  "type": "declarativeChart",
  "pageId": "678AE2F0-1469-489E-AE28-B729A0000E51",
  "definition": {
    "title": "Spend by category",
    "query": {
      "groups": [
        {
          "name": "Category",
          "field": "col_6f1c0d2a9b8e4f3a8c7d6e5f4a3b2c1d"
        }
      ],
      "values": [
        {
          "name": "Spend",
          "field": "fld_0a1b2c3d4e5f60718293a4b5c6d7e8f9"
        }
      ],
      "sort": [
        {
          "name": "Spend",
          "direction": "desc"
        }
      ]
    },
    "rendererSpec": {
      "mark": {
        "type": "bar",
        "cornerRadiusEnd": 3
      },
      "encoding": {
        "x": {
          "field": "Spend",
          "type": "quantitative"
        },
        "y": {
          "field": "Category",
          "type": "nominal",
          "sort": "-x",
          "title": null
        }
      }
    }
  },
  "position": {
    "x": 24,
    "y": 24,
    "width": 600,
    "height": 320
  }
}

Response 200

A visual change receipt. The change is one report version: GET /api/reports/{reportId}/versions lists it, and restoring the version listed before it brings the visual back as it was.

persistedbooleanOptional
visualUidstringOptional
visual_idstringOptional
visual_typestringOptional
visualvalueOptional
mutationobjectOptional
changeobjectOptional

The visual before and after the change (null: created, deleted), for the tabs that show it.

layoutobjectOptional

Geometry feedback: canvasBounds, fitsWithinPage, overflowPixels, overlaps.

warningsarray<object>Optional
reportIdstringOptional

Report ID.

visual_dataobjectOptional

The saved definition and, for charts and cards, the first read (sql_data, outputs, generatedSql).

Errors

403 Scope, access or subscription · 409 Conflict: re-read and reconcile · 422 Cannot be applied. Every error has error, message and code.

POST/api/visuals/delete

Delete a visual

workspace:writeEdit access to the page · reaches pages
Request and response

Deletes one visual. Restoring the report version listed before the delete brings it back.

Body

reportIdstringRequired

Report ID.

typestringRequired

Native visual kind. Chart presets (bar, line, scatter, pie) are declarativeChart specifications; an older name (barGraph, pieChart, ...) is refused with the current kind.

enum: ["declarativeChart","dataTable","matrix","dataCard","textBox","shape"]
idstring | integerRequired

The visual's UUID (visualUid), or its legacy numeric ID.

expectedRevisionstringOptional
clientRequestIdstringOptional

Retry key, a UUID or any string up to 64 characters. A retry of a committed request writes nothing and answers the first attempt's outcome with replayed true; the same key with a different body answers 409.

maxLength: 64

Response 200

A visual change receipt. The change is one report version: GET /api/reports/{reportId}/versions lists it, and restoring the version listed before it brings the visual back as it was.

persistedbooleanOptional
visualUidstringOptional
visual_idstringOptional
visual_typestringOptional
visualvalueOptional
mutationobjectOptional
changeobjectOptional

The visual before and after the change (null: created, deleted), for the tabs that show it.

layoutobjectOptional

Geometry feedback: canvasBounds, fitsWithinPage, overflowPixels, overlaps.

warningsarray<object>Optional
reportIdstringOptional

Report ID.

visual_dataobjectOptional

The saved definition and, for charts and cards, the first read (sql_data, outputs, generatedSql).

Errors

400 Invalid input · 403 Scope, access or subscription · 409 Conflict: re-read and reconcile. Every error has error, message and code.

POST/api/visuals/delete-batch

Delete several visuals

workspace:writeEdit access to the page · reaches pages
Request and response

Deletes 1 to 100 visuals in one transaction.

Body

reportIdstringRequired

Report ID.

targetsarray<object>Required
clientRequestIdstringOptional

Retry key, a UUID or any string up to 64 characters. A retry of a committed request writes nothing and answers the first attempt's outcome with replayed true; the same key with a different body answers 409.

maxLength: 64

Response 200

receiptsarray<object>Optional

One receipt per visual.

Errors

403 Scope, access or subscription · 409 Conflict: re-read and reconcile · 422 Cannot be applied. Every error has error, message and code.

GET/api/visuals/page-state

Read every visual on a page

workspace:readAny access to the page · reaches pages
Request and response

All saved visuals of one page and the page's visualsRevision (compare it with GET /api/reports/{report_id}/live to know when to re-read).

Parameters

reportIdquery · stringRequired

Report ID. Also accepted as report_id.

pageIdquery · stringRequired

The page: its UUID or numeric ID. Also accepted as page_id, pageUid.

Response 200

reportIdstringOptional

Report ID.

pageIdintegerOptional
pageUidstringOptional
visualsRevisionstringOptional
visualsarray<value>Optional

Errors

403 Scope, access or subscription · 422 Cannot be applied. Every error has error, message and code.

POST/api/visuals/positions

Move and resize visuals

workspace:writeEdit access to the page · reaches pages
Request and response

Saves 1 to 100 visuals' positions and z-order in one transaction.

Body

reportIdstringRequired

Report ID.

targetsarray<object>Required
clientRequestIdstringOptional

Retry key, a UUID or any string up to 64 characters. A retry of a committed request writes nothing and answers the first attempt's outcome with replayed true; the same key with a different body answers 409.

maxLength: 64

Example request body

JSON
{
  "reportId": "9af3fb53-34e2-4e88-a953-ffdecdeece82",
  "targets": [
    {
      "type": "declarativeChart",
      "id": "3976903A-10E2-4861-B202-A29CF2BD7531",
      "position": {
        "x": 24,
        "y": 24,
        "width": 620,
        "height": 320
      }
    }
  ]
}

Response 200

receiptsarray<object>Optional

One receipt per visual, in request order.

Errors

403 Scope, access or subscription · 409 Conflict: re-read and reconcile · 422 Cannot be applied. Every error has error, message and code.

POST/api/visuals/preview

Preview a visual

workspace:writeEdit access to at least one page (or report View access) · reaches model, pages
Request and response

Validates a definition and runs its query without saving anything: the result a create would produce. Use it to check a query, its outputs and a renderer specification.

Body

reportIdstringRequired

Report ID.

typestringRequired

Native visual kind. Chart presets (bar, line, scatter, pie) are declarativeChart specifications; an older name (barGraph, pieChart, ...) is refused with the current kind.

enum: ["declarativeChart","dataTable","matrix","dataCard","textBox","shape"]
definitionobjectRequired

Per kind: GET /api/visuals/capabilities?kind={kind} returns the exact definition, changes and appearance schemas, required fields and rendering semantics.

Response 200

persistedbooleanOptional
enum: [false]
sql_dataobjectOptional
outputsarray<object>Optional

The query's outputs: groups, then values, with the result's types.

generatedSqlstringOptional

The SQL the visual query compiles to (read-only).

rendererSpecobjectOptional

Errors

403 Scope, access or subscription · 409 Conflict: re-read and reconcile · 422 Cannot be applied. Every error has error, message and code.

GET/api/visuals/state

Read a visual

workspace:readAny access to the page · reaches pages
Request and response

A saved visual's authored state (its visual query), its outputs and generatedSql, position and revision, with both page IDs.

Parameters

reportIdquery · stringRequired

Report ID. Also accepted as report_id.

typequery · stringRequired

Native visual kind. Chart presets (bar, line, scatter, pie) are declarativeChart specifications; an older name (barGraph, pieChart, ...) is refused with the current kind.

idquery · string | integerRequired

The visual's UUID (visualUid), or its legacy numeric ID.

Response 200

Errors

403 Scope, access or subscription · 422 Cannot be applied. Every error has error, message and code.

POST/api/visuals/update

Update a visual

workspace:writeEdit access to the page · reaches pages
Request and response

Applies only the given changes (title, query, rendererSpec, customization, position, pageId to move it, ...). Send expectedRevision from the last read; a stale one answers 409 visual_conflict with currentRevision.

Body

reportIdstringRequired

Report ID.

typestringRequired

Native visual kind. Chart presets (bar, line, scatter, pie) are declarativeChart specifications; an older name (barGraph, pieChart, ...) is refused with the current kind.

enum: ["declarativeChart","dataTable","matrix","dataCard","textBox","shape"]
idstring | integerRequired

The visual's UUID (visualUid), or its legacy numeric ID.

changesobjectRequired

Fields to change; GET /api/visuals/capabilities lists them per kind.

expectedRevisionstringOptional

The revision you read, for example 0x000000000000c356.

refreshDatabooleanOptional

Return a fresh read.

default: true
clientRequestIdstringOptional

Retry key, a UUID or any string up to 64 characters. A retry of a committed request writes nothing and answers the first attempt's outcome with replayed true; the same key with a different body answers 409.

maxLength: 64

Example request body

JSON
{
  "reportId": "9af3fb53-34e2-4e88-a953-ffdecdeece82",
  "type": "declarativeChart",
  "id": "3976903A-10E2-4861-B202-A29CF2BD7531",
  "expectedRevision": "0x000000000000c356",
  "changes": {
    "title": "Debit spend by category"
  },
  "refreshData": false
}

Response 200

A visual change receipt. The change is one report version: GET /api/reports/{reportId}/versions lists it, and restoring the version listed before it brings the visual back as it was.

persistedbooleanOptional
visualUidstringOptional
visual_idstringOptional
visual_typestringOptional
visualvalueOptional
mutationobjectOptional
changeobjectOptional

The visual before and after the change (null: created, deleted), for the tabs that show it.

layoutobjectOptional

Geometry feedback: canvasBounds, fitsWithinPage, overflowPixels, overlaps.

warningsarray<object>Optional
reportIdstringOptional

Report ID.

visual_dataobjectOptional

The saved definition and, for charts and cards, the first read (sql_data, outputs, generatedSql).

Errors

400 Invalid input · 403 Scope, access or subscription · 409 Conflict: re-read and reconcile · 422 Cannot be applied. Every error has error, message and code.

Visual data1 operations

Read saved visuals' data, several visuals per request.

POST/api/reports/{report_id}/visual-data

Read visuals' data

workspace:readAny access to the page · reaches model, pages
Request and response

Reads 1 to 40 saved visuals of one page, with saved report, page and visual filters applied. The response is NDJSON: one line per read as it completes, {"key": index in reads, "status": HTTP status, "data": payload}, then {"done": true}. A read still running after the synchronous wait has status 202 and data {readJob}; collect it with GET /api/read-jobs/{job_id}.

Parameters

report_idpath · stringRequired

Body

pageIdstringRequired

The page: its UUID or numeric ID.

readsarray<object>Required

Example request body

JSON
{
  "pageId": "678AE2F0-1469-489E-AE28-B729A0000E51",
  "reads": [
    {
      "type": "declarativeChart",
      "id": "3976903A-10E2-4861-B202-A29CF2BD7531"
    },
    {
      "type": "dataTable",
      "id": "755B3D02-0153-4031-BE24-73E1DB250E5B",
      "options": {
        "pageIndex": 0,
        "pageSize": 50
      }
    }
  ]
}

Response 200 (application/x-ndjson)

One NDJSON line.

keyintegerOptional
statusintegerOptional
dataobjectOptional
donebooleanOptional

Example response

JSON
{
  "key": 0,
  "status": 200,
  "data": {
    "visualUid": "3976903A-10E2-4861-B202-A29CF2BD7531",
    "sql_data": {
      "columns": [
        "Category",
        "Spend"
      ],
      "rows": [
        [
          "Groceries",
          "27711.43"
        ]
      ],
      "column_metadata": [
        {
          "name": "Spend",
          "type_code": "DECIMAL(38,2)",
          "valueEncoding": "decimal-string"
        }
      ]
    }
  }
}

Errors

400 Invalid input · 403 Scope, access or subscription · 409 Conflict: re-read and reconcile. Every error has error, message and code.

Filters4 operations

Report, page and visual filters, your own values for them, and the values a filter can choose from.

GET/api/filters

Read the filters on a page

workspace:readAny access to the page · reaches pages
Request and response

InspectFilters: the report's filters, and with pageId the page's and each of its native visuals', with the value that applies to you. sorts lists your own table sorts (the page's; every page's without pageId). differs is true when any of your values in this report differs from its default, or you sort a table yourself. Viewers don't see hidden filters. filterRevision is what PUT /api/filters sends back.

Parameters

reportIdquery · stringRequired
pageIdquery · stringOptional

The page's UUID; omit for the report's filters only.

Response 200

filtersarray<object>Optional
sortsarray<object>Optional
differsbooleanOptional
filterRevisionintegerOptional

Errors

400 Invalid input · 403 Scope, access or subscription. Every error has error, message and code.

PUT/api/filters

Change filters for everyone

workspace:writeAny access to the page · reaches pages
Request and response

UpdateFilters: add (filterUid null), change or remove filters (report design; Edit access, and report Edit for report scope). A filter's field and scope are fixed. A new default keeps the values people set themselves; changing kind, locked or hidden, or removing a filter, deletes everyone's values for it. filterRevision is the one GET /api/filters returned; if the filters changed since, nothing is saved (409 filter_conflict).

Body

reportIdstringRequired
filtersarray<object>Required
removearray<string>Required
filterRevisionintegerRequired

Example request body

JSON
{
  "reportId": "9af3fb53-34e2-4e88-a953-ffdecdeece82",
  "filterRevision": 12,
  "remove": [],
  "filters": [
    {
      "filterUid": null,
      "scope": "page",
      "target": "678ae2f0-1469-489e-ae28-b729a0000e51",
      "fieldUid": "6f1d2c9a8b7e4f30a1c5d9e2b4f7a8c1",
      "kind": "basic",
      "default": {
        "values": [
          "Dining",
          "Groceries"
        ],
        "exclude": false
      },
      "locked": false,
      "hidden": false,
      "label": null
    }
  ]
}

Response 200

filtersarray<object>Optional
removedarray<string>Optional
filterRevisionintegerOptional

Errors

400 Invalid input · 403 Scope, access or subscription · 409 Conflict: re-read and reconcile. Every error has error, message and code.

GET/api/filters/values

List the values a filter can choose

workspace:readAny access to the page · reaches pages
Request and response

A field's members on a page (and visual), under your filters there without the filter being edited (filterUid). (Blank) is null. A measure answers manualEntryOnly: true with no values. Report access; with access to the page only, the members of a filter you see on it (filterUid), as your page reads them.

Parameters

reportIdquery · stringRequired
pageIdquery · stringRequired

The page's UUID.

fieldUidquery · stringRequired
visualUidquery · stringOptional
filterUidquery · stringOptional

The filter being edited.

qquery · stringOptional

Search text (contains, ignoring case).

offsetquery · integerOptional
limitquery · integerOptional

Response 200

fieldUidstringOptional
fieldstringOptional
valuesarray<value>Optional
manualEntryOnlybooleanOptional
offsetintegerOptional
limitintegerOptional
hasMorebooleanOptional
nextOffsetinteger | nullOptional

Errors

400 Invalid input · 403 Scope, access or subscription. Every error has error, message and code.

PUT/api/my-view

Set your own view

workspace:writeAny access to the page · reaches pages
Request and response

UpdateMyView: your own filter values and table sorts in this report; only you see them, and they're kept between visits. Each value replaces yours for that filter (null shows all); each sort replaces yours for that table (direction null returns it to the table's own order, its query's sort); reset true first returns all of yours to the defaults. Locked and hidden filters need Edit access.

Body

reportIdstringRequired
valuesarray<object>Required
sortsarray<object>Optional
resetbooleanRequired

Response 200

filtersarray<object>Optional
sortsarray<object>Optional
differsbooleanOptional

Errors

400 Invalid input · 403 Scope, access or subscription. Every error has error, message and code.

Data model13 operations

The report-owned model: sources, entities, fields, measures, relationships and model queries.

GET/api/reports/{report_id}/data-model

Read a report's data model

workspace:readEdit access to at least one page (or report View access) · reaches model, pages
Request and response

Every entity, field, measure, relationship and source of the report, with the model revision that writes must send. Report SQL (POST /api/sql/execute) reads exactly this namespace.

Parameters

report_idpath · stringRequired

Response 200

statusstringOptional
modelobjectOptional

The report's semantic model: the namespace report SQL reads.

PUT/api/reports/{report_id}/data-model/calculated-tables

Create or edit a calculated table

workspace:writeEdit access · reaches model
Request and response

Report SQL (DuckDB) over the report's tables whose output columns become fields. It is static: computed from all rows of its tables; filters reach it only through its relationships. Saving runs the SQL once to set its fields and types; a column keeps its fieldUid while its name stays. The entity key cannot change. Removing a field also removes the calculated fields, measures and relationships that use it. When anything reads what a write removes, or SQL names what it renames, the write is refused with code in_use (HTTP 409) and the readers (kind, title, id, pageId, page, effect); confirm=true makes it anyway, and the result lists what went with it (removedWith) and what now shows an error (breaks). Documentation topic connections has the full rules.

Parameters

report_idpath · stringRequired

Body

entityKeystringRequired

Its report name: lowercase letters, digits and underscores.

sqlstringRequired

One SELECT or WITH statement over the report's tables.

entityNamestringOptional

Display name.

descriptionstringOptional
expectedModelRevisionintegerRequired

The model revision you inspected. A stale revision answers 409 model_conflict.

minimum: 0
confirmbooleanOptional

true makes the change after 409 in_use.

Example request body

JSON
{
  "entityKey": "customer_orders",
  "entityName": "Customer orders",
  "expectedModelRevision": 4,
  "sql": "SELECT o.customer_id, COUNT(*) AS orders FROM dbo_transactions o GROUP BY o.customer_id"
}

Response 200

statusstringOptional
modelobjectOptional

The report's semantic model: the namespace report SQL reads.

Errors

400 Invalid input · 403 Scope, access or subscription · 409 Conflict: re-read and reconcile. Every error has error, message and code.

DELETE/api/reports/{report_id}/data-model/calculated-tables/{entity_key}

Delete a calculated table

workspace:writeEdit access · reaches model
Request and response

Removes it and its relationships, listed in removedRelationships. Removing a field also removes the calculated fields, measures and relationships that use it. When anything reads what a write removes, or SQL names what it renames, the write is refused with code in_use (HTTP 409) and the readers (kind, title, id, pageId, page, effect); confirm=true makes it anyway, and the result lists what went with it (removedWith) and what now shows an error (breaks). Documentation topic connections has the full rules.

Parameters

report_idpath · stringRequired
entity_keypath · stringRequired

Body

expectedModelRevisionintegerRequired

The model revision you inspected. A stale revision answers 409 model_conflict.

minimum: 0
confirmbooleanOptional

true makes the change after 409 in_use.

Response 200

statusstringOptional
modelobjectOptional

The report's semantic model: the namespace report SQL reads.

removedRelationshipsarray<object>Optional

Errors

400 Invalid input · 403 Scope, access or subscription · 409 Conflict: re-read and reconcile. Every error has error, message and code.

DELETE/api/reports/{report_id}/data-model/fields/{field_uid}

Remove a field from the model

workspace:writeEdit access · reaches model
Request and response

Removes a field (by fieldUid): a definition, or a column of a tables-mode table, whose generated query then selects the others. A custom-SQL table's columns come from its SQL: remove one from its query. A table keeps at least one column. Removing a field also removes the calculated fields, measures and relationships that use it. When anything reads what a write removes, or SQL names what it renames, the write is refused with code in_use (HTTP 409) and the readers (kind, title, id, pageId, page, effect); confirm=true makes it anyway, and the result lists what went with it (removedWith) and what now shows an error (breaks). Documentation topic connections has the full rules.

Parameters

report_idpath · stringRequired
field_uidpath · stringRequired

Body

expectedModelRevisionintegerOptional

The model revision you inspected. A stale revision answers 409 model_conflict.

minimum: 0
confirmbooleanOptional

true makes the change after 409 in_use.

checkbooleanOptional

true removes nothing (a column only): the answer is 409 in_use with what the removal would remove or break, an empty readers list when nothing.

Response 200

Errors

400 Invalid input · 403 Scope, access or subscription · 409 Conflict: re-read and reconcile. Every error has error, message and code.

POST/api/reports/{report_id}/data-model/query

Query the model (preview)

workspace:readView access · reaches model
Request and response

Runs report SQL over the model and returns up to 200 rows with column details, for checking a model while editing it. For analysis use POST /api/sql/execute.

Parameters

report_idpath · stringRequired

Body

sqlstringRequired

Report SQL (DuckDB).

rowLimitintegerOptional

Example request body

JSON
{
  "sql": "SELECT region, COUNT(*) AS n FROM dbo_customers GROUP BY region",
  "rowLimit": 10
}

Response 200

columnsarray<string>Optional
rowsarray<array<value>>Optional
column_metadataarray<value>Optional
columnDetailsarray<object>Optional

Errors

400 Invalid input · 409 Conflict: re-read and reconcile. Every error has error, message and code.

PUT/api/reports/{report_id}/data-model/relationships

Replace the report's relationships

workspace:writeEdit access · reaches model
Request and response

The report's complete relationship collection, including edges between sources. Entity keys and output columns identify each end. A relationship change (added, removed, activated, deactivated or a new crossFilter) that would break a saved visual or page dataset, change what it shows (another join path), or stop or change a filter's reach to one is refused with code in_use and the readers (effect breaks, changes or stopsFiltering); confirm=true makes it anyway, and the result lists them (breaks). A key (to) end with duplicate or blank values is refused (code duplicate_key or blank_key), as is a both that gives a filter a second path (code ambiguous_both).

Parameters

report_idpath · stringRequired

Body

relationshipsarray<object>Required
expectedModelRevisionintegerRequired

The model revision you inspected. A stale revision answers 409 model_conflict.

minimum: 0
confirmbooleanOptional

true makes the change after 409 in_use.

entityLayoutsobjectOptional

Optional diagram positions by entity key.

Example request body

JSON
{
  "expectedModelRevision": 3,
  "relationships": [
    {
      "fromEntityKey": "dbo_transactions",
      "fromColumn": "customer_id",
      "toEntityKey": "dbo_customers",
      "toColumn": "customer_id",
      "isActive": true
    }
  ]
}

Response 200

statusstringOptional
modelobjectOptional

The report's semantic model: the namespace report SQL reads.

Errors

400 Invalid input · 403 Scope, access or subscription · 409 Conflict: re-read and reconcile. Every error has error, message and code.

DELETE/api/reports/{report_id}/data-model/sources/{connection_id}

Remove a source from the model

workspace:writeEdit access · reaches model
Request and response

Removes the source's outputs from this report's model; the source stays attached, with no tables. Removing a field also removes the calculated fields, measures and relationships that use it. When anything reads what a write removes, or SQL names what it renames, the write is refused with code in_use (HTTP 409) and the readers (kind, title, id, pageId, page, effect); confirm=true makes it anyway, and the result lists what went with it (removedWith) and what now shows an error (breaks). Documentation topic connections has the full rules.

Parameters

report_idpath · stringRequired
connection_idpath · integerRequired

Body

expectedModelRevisionintegerOptional

The model revision you inspected. A stale revision answers 409 model_conflict.

minimum: 0
confirmbooleanOptional

true makes the change after 409 in_use.

Response 200

statusstringOptional

Errors

400 Invalid input · 404 Not found · 409 Conflict: re-read and reconcile. Every error has error, message and code.

GET/api/reports/{report_id}/data-model/sources/{connection_id}/catalog

Search a source's model

workspace:readView access · reaches model
Request and response

Entities, fields and relationships of one source, searchable and paged; lighter than the whole model.

Parameters

report_idpath · stringRequired
connection_idpath · integerRequired
kindquery · stringOptional
queryquery · stringOptional

Search by model terminology.

fieldUidquery · array<string>Optional
offsetquery · integerOptional
limitquery · integerOptional
reportIdquery · stringOptional

Compatibility path only: the report.

Response 200

statusstringOptional
itemsarray<object>Optional
totalintegerOptional
offsetintegerOptional
completebooleanOptional
nextOffsetinteger | nullOptional
modelRevisionintegerOptional
snapshotVersionstringOptional
missingFieldUidsarray<string>Optional

Errors

400 Invalid input · 403 Scope, access or subscription · 409 Conflict: re-read and reconcile. Every error has error, message and code.

PUT/api/reports/{report_id}/data-model/sources/{connection_id}/definitions

Save a source's fields and measures

workspace:writeEdit access · reaches model
Request and response

Replaces this source's definitions: send every definition to keep (with its definitionId) plus new ones. Each is validated against the source before saving; a definition sent with its definitionId and a new aliasName is renamed and keeps its fieldUid. Removing a field also removes the calculated fields, measures and relationships that use it. When anything reads what a write removes, or SQL names what it renames, the write is refused with code in_use (HTTP 409) and the readers (kind, title, id, pageId, page, effect); confirm=true makes it anyway, and the result lists what went with it (removedWith) and what now shows an error (breaks). Documentation topic connections has the full rules. Edit access.

Use a measure in report SQL through its entity: SELECT t."Total Spend" FROM dbo_transactions t.

Parameters

report_idpath · stringRequired
connection_idpath · integerRequired

Body

definitionsarray<value | value>Required
expectedModelRevisionintegerOptional

The model revision you inspected. A stale revision answers 409 model_conflict.

minimum: 0
confirmbooleanOptional

true makes the change after 409 in_use.

Example request body

JSON
{
  "expectedModelRevision": 2,
  "definitions": [
    {
      "aliasName": "Total Spend",
      "description": "Sum of absolute debit amounts, excluding internal transfers.",
      "sqlExpression": "SUM(CASE WHEN direction = 'debit' AND type <> 'INTERNAL_TRANSFER' THEN ABS(signed_amount) ELSE 0 END)",
      "definitionType": "measure",
      "sourceEntityKey": "dbo_transactions",
      "sourceColumns": [
        "direction",
        "type",
        "signed_amount"
      ]
    }
  ]
}

Response 200

statusstringOptional
definitionsarray<value | value>Optional
modelobjectOptional

Errors

400 Invalid input · 404 Not found · 409 Conflict: re-read and reconcile. Every error has error, message and code.

GET/api/reports/{report_id}/data-model/sources/{connection_id}/editor-context

Read a source's editing context

workspace:readView access · reaches model
Request and response

What a source editor needs: discovered schema, current selection and mode, saved entities and relationships, and entities suggested for the selected tables.

Parameters

report_idpath · stringRequired
connection_idpath · integerRequired

Response 200

statusstringOptional
connectionobjectOptional
schemaobjectOptional
selectedSchemaobjectOptional
selectedTablesarray<string>Optional
sourceModestringOptional
modelobjectOptional
suggestedEntitiesarray<object>Optional
entitiesarray<object>Optional
relationshipsarray<object>Optional

Errors

400 Invalid input · 404 Not found. Every error has error, message and code.

PUT/api/reports/{report_id}/data-model/sources/{connection_id}/entities

Save a source's entities

workspace:writeEdit access · reaches model
Request and response

Saves this source's part of the model: its mode, selection, entities and optionally its relationships and definitions. Sent without entities, each selected table with no query yet gets a full-table query; saved queries stay. Other reports using the same connection are unaffected. An entity key cannot change after saving. Sent entities can't be empty: removing a source's last table is removing its outputs (the source DELETE). Removing a field also removes the calculated fields, measures and relationships that use it. When anything reads what a write removes, or SQL names what it renames, the write is refused with code in_use (HTTP 409) and the readers (kind, title, id, pageId, page, effect); confirm=true makes it anyway, and the result lists what went with it (removedWith) and what now shows an error (breaks). Documentation topic connections has the full rules. A relationship change (added, removed, activated, deactivated or a new crossFilter) that would break a saved visual or page dataset, change what it shows (another join path), or stop or change a filter's reach to one is refused with code in_use and the readers (effect breaks, changes or stopsFiltering); confirm=true makes it anyway, and the result lists them (breaks). A key (to) end with duplicate or blank values is refused (code duplicate_key or blank_key), as is a both that gives a filter a second path (code ambiguous_both). Edit access.

Parameters

report_idpath · stringRequired
connection_idpath · integerRequired

Body

sourceModestringOptional

tables: entities read whole tables; custom_sql: authored queries.

enum: ["tables","custom_sql"]
selectedTablesarray<string>Optional

Tables to model, as discovered (dbo.transactions). Sent without entities, each one with no query yet gets one, and the saved queries stay.

selectedSchemaobjectOptional

tables mode: the selection; columns come from discovery.

entitiesarray<object>Optional

Replaces this source's entities.

relationshipsarray<object>Optional

Relationships within this source.

definitionsarray<value | value>Optional

This source's reusable fields and measures.

descriptionstring | nullOptional
expectedModelRevisionintegerOptional

The model revision you inspected. A stale revision answers 409 model_conflict.

minimum: 0
confirmbooleanOptional

true makes the change after 409 in_use.

finalizeConnectionbooleanOptional

Mark the source configured (the editor's Save).

Example request body

JSON
{
  "sourceMode": "tables",
  "selectedTables": [
    "dbo.customers",
    "dbo.transactions"
  ],
  "selectedSchema": {
    "tables": {
      "dbo.customers": {},
      "dbo.transactions": {}
    }
  },
  "finalizeConnection": true,
  "expectedModelRevision": 1
}

Response 200

statusstringOptional
modelobjectOptional

Errors

400 Invalid input · 403 Scope, access or subscription · 404 Not found · 409 Conflict: re-read and reconcile. Every error has error, message and code.

POST/api/reports/{report_id}/data-model/sources/{connection_id}/entities/preview

Preview an entity query

workspace:readEdit access · reaches model, source
Request and response

Runs a native-dialect entity query (or a saved entity, by entityKey) on the source and returns the first rows and typed columns, without saving.

Parameters

report_idpath · stringRequired
connection_idpath · integerRequired

Body

entitySqlQuerystringOptional

Native-dialect SELECT.

entityKeystringOptional

Or a saved entity.

rowLimitintegerOptional

Example request body

JSON
{
  "entitySqlQuery": "SELECT TOP 10 * FROM dbo.transactions",
  "rowLimit": 10
}

Response 200

statusstringOptional
previewobjectOptional

Errors

400 Invalid input · 404 Not found · 409 Conflict: re-read and reconcile. Every error has error, message and code.

POST/api/reports/{report_id}/data-model/sources/{connection_id}/refresh-model

Refresh an Analysis Services model

workspace:writeEdit access · reaches model, source
Request and response

Rediscovers the cube's columns and measures as the caller: existing fields keep their names, new ones are added, removed ones disappear. Removing a field also removes the calculated fields, measures and relationships that use it. When anything reads what a write removes, or SQL names what it renames, the write is refused with code in_use (HTTP 409) and the readers (kind, title, id, pageId, page, effect); confirm=true makes it anyway, and the result lists what went with it (removedWith) and what now shows an error (breaks). Documentation topic connections has the full rules.

Parameters

report_idpath · stringRequired
connection_idpath · integerRequired

Body

expectedModelRevisionintegerOptional

The model revision you inspected. A stale revision answers 409 model_conflict.

minimum: 0
confirmbooleanOptional

true makes the change after 409 in_use.

Response 200

Errors

400 Invalid input · 403 Scope, access or subscription · 409 Conflict: re-read and reconcile. Every error has error, message and code.

Connections10 operations

Data source connections and their attachment to reports.

GET/api/connections

List your connections

workspace:readAny signed-in account · reaches source
Request and response

Connections the caller owns, whether or not a report uses them. Credentials are never returned.

Response 200

idintegerOptional

Connection ID.

ownerUserIdstringOptional
namestringOptional
serverTypestringOptional
authTypestring | nullOptional
serverNamestringOptional

Empty for uploaded-file connections.

databaseNamestring | nullOptional
connectionTypestring | nullOptional
enum: ["database","api","file"]
fileTypestring | nullOptional
createdAtstring | nullOptional
GET/api/connections/{connection_id}/credentials

Read what a connection's credentials page asks for

workspace:readAny signed-in account · reaches source
Request and response

For the connection's owner (anyone else: 404): where its credentials go (recipients: host, port, account, token endpoint, provider) and which its sign-in takes (fields: who signs in, the user name or client ID, then the secrets), never their values. credentials is set or missing, null when the sign-in takes none.

Parameters

connection_idpath · integerRequired

Response 200

connectionIdintegerOptional
namestringOptional
typestring | nullOptional
authTypestring | nullOptional
databaseNamestring | nullOptional
credentialsstring | nullOptional
enum: ["set","missing"]
recipientsarray<object>Optional
fieldsarray<object>Optional
readerSignInbooleanOptional

Each reader signs in with their own account.

Errors

404 Not found. Every error has error, message and code.

POST/api/connections/{connection_id}/test

Test a connection

workspace:writeAny signed-in account · reaches source
Request and response

For the connection's owner (anyone else: 404): connects with its saved settings and credentials and rediscovers its tables, as the TestConnection tool does. An API provider is checked as configured (recognized, its key present), without calling it.

Parameters

connection_idpath · integerRequired

Response 200

connectionIdintegerOptional
okbooleanOptional
checkedstringOptional
enum: ["source","configuration"]
tablesintegerOptional

Tables discovered.

modelobjectOptional

Analysis Services: the model's cube and counts.

needsCredentialsbooleanOptional
credentialsUrlstringOptional
errorstringOptional

The source's error, without credentials.

sourceAuthobjectOptional

A reader must sign in.

Errors

404 Not found. Every error has error, message and code.

POST/api/connections/add

Create a connection

workspace:writeAny signed-in account · reaches source
Request and response

The one create: saves a source connection owned by the caller, and attaches it to reportId when given. It does not connect (except an Analysis Services model, discovered as it is attached): test it (POST /api/connections/{connection_id}/test) or list its tables (POST /get-schema). Add the source to the report's data model to query it. In production, a server whose address is private (a private network, loopback, link-local or cloud metadata address) is refused when Unity connects.

Body

reportIdstringOptional

Attach to this report (Edit access).

serverTypestringRequired

Source kind; fixed once created.

enum: ["SQLServer","Snowflake","Databricks","AnalysisServices","API"]
serverNamestringRequired

Server or host (SQL Server: host[,port]; Snowflake: account; API: the provider, FRED, WORLDBANK or USCENSUS).

databaseNamestringOptional

Database, catalog, or Analysis Services model.

authTypestringOptional

How Unity signs in. SQL Server: UserPassAuth (SQL login), EntraPassword, EntraServicePrincipal (username = client ID, password = secret), EntraBrowser. Snowflake: UserPassAuth, KeyPairAuth (privateKey), OAuthClientCredentials, SnowflakeOAuth. Databricks: DatabricksEntraServicePrincipalSecret (default), DatabricksEntraServicePrincipalCert, DatabricksEntraUserSSO (databricksAccessToken), DatabricksEntraBrowser, DatabricksOAuth. Analysis Services: AASInteractive, EntraServicePrincipal, AASServicePrincipalCertificate, EntraPassword. API providers: ApiKey. Browser methods (EntraBrowser, SnowflakeOAuth, DatabricksEntraBrowser, DatabricksOAuth, AASInteractive) sign each reader in through the browser application and cannot complete headlessly. Server-identity methods (WindowsAuth, EntraIntegrated, EntraManagedIdentity) need a platform administrator.

enum: ["UserPassAuth","EntraPassword","EntraServicePrincipal","EntraBrowser","EntraIntegrated","EntraManagedIdentity","WindowsAuth","KeyPairAuth","OAuthClientCredentials","SnowflakeOAuth","DatabricksEntraServicePrincipalSecret","DatabricksEntraServicePrincipalCert","DatabricksEntraUserSSO","DatabricksEntraBrowser","DatabricksOAuth","AASInteractive","AASServicePrincipalCertificate","ApiKey"]
usernamestringOptional

Login.

clientIdstringOptional

Client (application) ID of a service principal.

passwordstringOptional

Password, API key, client secret or access token. Stored encrypted; never returned.

portintegerOptional
connectionNamestringOptional

Display name; generated from server and database when omitted, numbered when taken.

apiKeystringOptional

API providers: the provider's key.

accountstringOptional

Snowflake account.

warehousestringOptional

Snowflake warehouse.

schemaNamestringOptional

Snowflake schema.

rolestringOptional

Snowflake role.

privateKeystringOptional

Snowflake key-pair private key (PEM).

privateKeyPassphrasestringOptional
oauthClientIdstringOptional
oauthClientSecretstringOptional
oauthTokenUrlstringOptional
oauthScopestringOptional
httpPathstringOptional

Databricks SQL warehouse HTTP path.

databricksSchemastringOptional

Databricks schema.

tenantIdstringOptional

Microsoft Entra tenant.

databricksClientIdstringOptional
databricksClientSecretstringOptional
databricksAccessTokenstringOptional

Databricks personal access token.

analysisServicesOptionsobjectOptional

Analysis Services sign-in options (tenant, client, endpoint).

Example request body

JSON
{
  "serverType": "SQLServer",
  "serverName": "sql.example.com",
  "databaseName": "Sales",
  "authType": "UserPassAuth",
  "username": "unity_reader",
  "password": "********",
  "reportId": "9af3fb53-34e2-4e88-a953-ffdecdeece82"
}

Response 201

statusstringOptional
messagestringOptional
connectionobjectOptional

Example response

JSON
{
  "status": "success",
  "message": "Connection created successfully",
  "connection": {
    "id": 31,
    "name": "SQLServer - sql.example.com - Sales",
    "serverType": "SQLServer",
    "serverName": "sql.example.com",
    "databaseName": "Sales"
  }
}

Errors

400 Invalid input · 403 Scope, access or subscription. Every error has error, message and code.

GET/api/connections/check-report-usage/{connection_id}

List reports using a connection

workspace:readAny signed-in account · reaches source
Request and response

Reports the caller can open that use the connection; others are only counted. A report being deleted no longer uses it: deletingReports names those the caller can open.

Parameters

connection_idpath · stringRequired

Response 200

statusstringOptional
affectedReportsarray<object>Optional
otherReportCountintegerOptional
deletingReportsarray<object>Optional

Errors

400 Invalid input · 404 Not found. Every error has error, message and code.

DELETE/api/connections/delete/{connection_id}

Delete a connection

workspace:writeAny signed-in account · reaches source
Request and response

Deletes a connection the caller owns. While reports use it the answer is 409 connection_in_use naming them; confirm=true deletes it anyway and those reports show an error until an editor replaces the source. A connection an organization's report uses is never deleted this way (409 company_source_in_use, even with confirm): detach it from that report first.

Parameters

connection_idpath · stringRequired
confirmquery · stringOptional

Response 200

statusstringOptional
messagestringOptional

Errors

400 Invalid input · 404 Not found · 409 Conflict: re-read and reconcile. Every error has error, message and code.

GET/api/connections/report/{report_id}

List a report's connections

workspace:readView access · reaches source
Request and response

Connections attached to the report, with each one's model state.

Parameters

report_idpath · stringRequired

Response 200

connectionIdintegerOptional
namestringOptional
serverTypestringOptional

Errors

403 Scope, access or subscription. Every error has error, message and code.

POST/api/connections/report/add

Attach a connection to a report

workspace:writeEdit access · reaches model, source
Request and response

Edit access to the report and access to the connection. Then add its outputs to the report's data model (PUT /api/reports/{report_id}/data-model/sources/{connection_id}).

Body

reportIdstringRequired
connectionIdintegerRequired

Response 200

statusstringOptional
messagestringOptional

Errors

400 Invalid input · 403 Scope, access or subscription. Every error has error, message and code.

DELETE/api/connections/report/remove

Detach a connection from a report

workspace:writeEdit access · reaches model, source
Request and response

Removes the source and its model outputs from the report. Removing a field also removes the calculated fields, measures and relationships that use it. When anything reads what a write removes, or SQL names what it renames, the write is refused with code in_use (HTTP 409) and the readers (kind, title, id, pageId, page, effect); confirm=true makes it anyway, and the result lists what went with it (removedWith) and what now shows an error (breaks). Documentation topic connections has the full rules.

Body

reportIdstringRequired
connectionIdintegerRequired
confirmbooleanOptional

true makes the change after 409 in_use.

Response 200

statusstringOptional
messagestringOptional

Errors

400 Invalid input · 403 Scope, access or subscription · 409 Conflict: re-read and reconcile. Every error has error, message and code.

PUT/api/connections/update/{connection_id}

Update a connection

workspace:writeAny signed-in account · reaches source
Request and response

Changes the given settings of a connection the caller owns; omitted settings keep their values. serverType and connectionType cannot change. An uploaded file's connection only renames. An API key may change only connectionName: other settings and secrets change in Unity, signed in (403 otherwise); create a new connection instead.

Parameters

connection_idpath · stringRequired

Body

serverNamestringOptional

Server or host (SQL Server: host[,port]; Snowflake: account; API: the provider, FRED, WORLDBANK or USCENSUS).

databaseNamestringOptional

Database, catalog, or Analysis Services model.

authTypestringOptional

How Unity signs in. SQL Server: UserPassAuth (SQL login), EntraPassword, EntraServicePrincipal (username = client ID, password = secret), EntraBrowser. Snowflake: UserPassAuth, KeyPairAuth (privateKey), OAuthClientCredentials, SnowflakeOAuth. Databricks: DatabricksEntraServicePrincipalSecret (default), DatabricksEntraServicePrincipalCert, DatabricksEntraUserSSO (databricksAccessToken), DatabricksEntraBrowser, DatabricksOAuth. Analysis Services: AASInteractive, EntraServicePrincipal, AASServicePrincipalCertificate, EntraPassword. API providers: ApiKey. Browser methods (EntraBrowser, SnowflakeOAuth, DatabricksEntraBrowser, DatabricksOAuth, AASInteractive) sign each reader in through the browser application and cannot complete headlessly. Server-identity methods (WindowsAuth, EntraIntegrated, EntraManagedIdentity) need a platform administrator.

enum: ["UserPassAuth","EntraPassword","EntraServicePrincipal","EntraBrowser","EntraIntegrated","EntraManagedIdentity","WindowsAuth","KeyPairAuth","OAuthClientCredentials","SnowflakeOAuth","DatabricksEntraServicePrincipalSecret","DatabricksEntraServicePrincipalCert","DatabricksEntraUserSSO","DatabricksEntraBrowser","DatabricksOAuth","AASInteractive","AASServicePrincipalCertificate","ApiKey"]
usernamestringOptional

Login.

clientIdstringOptional

Client (application) ID of a service principal.

passwordstringOptional

Password, API key, client secret or access token. Stored encrypted; never returned.

portintegerOptional
connectionNamestringOptional

Display name; generated from server and database when omitted, numbered when taken.

apiKeystringOptional

API providers: the provider's key.

accountstringOptional

Snowflake account.

warehousestringOptional

Snowflake warehouse.

schemaNamestringOptional

Snowflake schema.

rolestringOptional

Snowflake role.

privateKeystringOptional

Snowflake key-pair private key (PEM).

privateKeyPassphrasestringOptional
oauthClientIdstringOptional
oauthClientSecretstringOptional
oauthTokenUrlstringOptional
oauthScopestringOptional
httpPathstringOptional

Databricks SQL warehouse HTTP path.

databricksSchemastringOptional

Databricks schema.

tenantIdstringOptional

Microsoft Entra tenant.

databricksClientIdstringOptional
databricksClientSecretstringOptional
databricksAccessTokenstringOptional

Databricks personal access token.

analysisServicesOptionsobjectOptional

Analysis Services sign-in options (tenant, client, endpoint).

Example request body

JSON
{
  "connectionName": "Sales warehouse"
}

Response 200

statusstringOptional
messagestringOptional

Errors

400 Invalid input · 403 Scope, access or subscription · 404 Not found. Every error has error, message and code.

Schema discovery2 operations

Source schema discovery (compatibility).

POST/get-schema

List a connection's tables again

workspace:writeEdit access · reaches source
Request and response

Connects with the saved connection's settings and credentials and lists its tables and columns, through its connector, saving them as its discovery. The connection's owner, or an editor of reportId when the connection belongs to it. Create connections with POST /api/connections/add. No /api prefix.

A source that needs the reader's own sign-in answers 409 with code source_auth_sign_in_required and a sourceAuth payload; sign in through the browser application.

Body

connectionIdintegerRequired

The connection whose tables to list.

reportIdstringOptional

Example request body

JSON
{
  "connectionId": 42,
  "reportId": "9af3fb53-34e2-4e88-a953-ffdecdeece82"
}

Response 200

schemaobjectOptional

Tables, each with its columns and types.

selectedSchemaobjectOptional
connectionIdintegerOptional

Errors

400 Invalid input · 403 Scope, access or subscription · 409 Conflict: re-read and reconcile · 500 · 503 Unavailable or read stopped. Every error has error, message and code.

GET/get-selected-schema/{report_id}

Read the selected schema of a report source

workspace:readView access · reaches model
Request and response

The tables and columns selected for a source in this report. No /api prefix.

Parameters

report_idpath · stringRequired
connectionIdquery · integerRequired

Response 200

statusstringOptional
selectedSchemaobjectOptional

Errors

400 Invalid input · 403 Scope, access or subscription. Every error has error, message and code.

SQL4 operations

Run read-only report SQL and keep saved queries.

DELETE/api/sql/delete-query/{query_id}

Delete a saved query

workspace:writeAny signed-in account · reaches source
Request and response

Parameters

query_idpath · integerRequired

Response 200

messagestringOptional

Errors

404 Not found. Every error has error, message and code.

POST/api/sql/execute

Run report SQL

workspace:readAny signed-in account · reaches source
Request and response

Runs one read-only DuckDB query over the report's whole model: every entity of every source, joins across sources, model fields and measures (t."Total Spend"). Name each entity by its entity key alone, as the model lists it, with no schema (FROM dbo_transactions); case is ignored. Writes, commands and multiple statements are refused. Unity adds LIMIT rowLimit when the outermost query has none. Saved report filters do not apply here.

A read still running after the synchronous wait answers 202 with {readJob}: poll GET /api/read-jobs/{job_id}.

A name that is not in the model answers 400 naming it and the closest entity keys. A table name, display name or schema-qualified name is not a name.

Body

reportIdstringRequired
sqlQuerystringRequired

Report SQL (DuckDB).

rowLimitintegerOptional

Rows to return when the query has no LIMIT of its own.

default: 1000 minimum: 1
skipLimitbooleanOptional

Return every row (within Unity's result bound) instead of rowLimit.

default: false
connectionIdintegerOptional

Compatibility hint; the report model decides the sources.

Example request body

JSON
{
  "reportId": "9af3fb53-34e2-4e88-a953-ffdecdeece82",
  "sqlQuery": "SELECT c.region, COUNT(*) AS n, t.\"Total Spend\" AS spend FROM dbo_transactions t JOIN dbo_customers c ON c.customer_id = t.customer_id GROUP BY 1 ORDER BY 1",
  "rowLimit": 100
}

Response 200

Example response

JSON
{
  "columns": [
    "region",
    "n",
    "spend"
  ],
  "rows": [
    [
      "East",
      71,
      "14520.11"
    ]
  ],
  "column_metadata": [
    {
      "name": "region",
      "type_code": "VARCHAR",
      "valueEncoding": "string"
    },
    {
      "name": "n",
      "type_code": "BIGINT",
      "valueEncoding": "big-integer"
    },
    {
      "name": "spend",
      "type_code": "DECIMAL(38,2)",
      "valueEncoding": "decimal-string"
    }
  ],
  "limitApplied": true,
  "rowLimit": 100
}

Errors

400 Invalid input · 403 Scope, access or subscription · 409 Conflict: re-read and reconcile · 503 Unavailable or read stopped. Every error has error, message and code.

POST/api/sql/save-query

Save a query

workspace:writeAny signed-in account · reaches source
Request and response

Keeps a named query with a report, in your saved queries (SQL Playground).

Body

reportIdstringRequired
namestringRequired
sqlQuerystringRequired

Response 201

idintegerOptional
namestringOptional
messagestringOptional

Errors

400 Invalid input · 403 Scope, access or subscription. Every error has error, message and code.

GET/api/sql/saved-queries

List saved queries

workspace:readAny signed-in account · reaches source
Request and response

Your saved queries across reports, newest first.

Response 200

idintegerOptional
namestringOptional
sqlQuerystringOptional
reportIdstringOptional
reportNamestringOptional
createdAtstringOptional
Long-running reads2 operations

Follow, collect and cancel data reads that outlive one request.

GET/api/read-jobs/{job_id}

Follow a long-running read

workspace:readAny access to the page · reaches model, pages
Request and response

202 with {readJob} (state and progress) while the read runs; afterwards the original operation's own response and status, once (collecting it removes the job). Poll at least every 45 seconds or the read is abandoned. 404 read_job_gone: the job ended, was collected, or its server restarted; start the read again. A stopped read answers 503 read_stopped with its reason.

Read jobs belong to the account that started them.

Parameters

job_idpath · stringRequired

Response 200

The original operation's response.

Errors

404 Not found · 503 Unavailable or read stopped. Every error has error, message and code.

POST/api/read-jobs/{job_id}/cancel

Cancel a long-running read

workspace:readAny access to the page · reaches model, pages
Request and response

Stops your read; it never undoes saved changes.

Parameters

job_idpath · stringRequired

Response 200

cancelledbooleanOptional

Whether a running job was found.

Assistant runs13 operations

Ask Unity's assistant to do work, follow its runs and events, and read runtime documentation.

POST/api/agent/chats/{datachat_id}/read

Mark a conversation read

workspace:writeAny access to the page · reaches chat
Request and response

Parameters

datachat_idpath · integerRequired

Body

reportIdstringRequired

Response 200

last_seen_message_idinteger | nullOptional

Errors

400 Invalid input · 403 Scope, access or subscription · 404 Not found. Every error has error, message and code.

POST/api/agent/client-timing

Report client timings

workspace:writeAny signed-in account · reaches chat
Request and response

Browser latency telemetry.

Response 200

GET/api/agent/context-runs

List recent runs' context (administrators)

workspace:readPlatform administrator · reaches chat
Request and response

Platform administrators: recent assistant runs with what entered their context.

Parameters

reportIdquery · stringOptional
offsetquery · integerOptional
entryquery · stringOptional

Response 200

Errors

400 Invalid input · 403 Scope, access or subscription. Every error has error, message and code.

GET/api/agent/documentation

Read Unity's runtime documentation

workspace:readAny signed-in account · reaches docs
Request and response

The guides Unity's assistant reads, from the running deployment: how report SQL, the model, visuals, HTML pages, files and testing work. Give these to your own AI.

Parameters

topicquery · stringOptional

Response 200

versionstringOptional

Content version.

topicstringOptional
titlestringOptional
markdownstringOptional

The guide (topics).

sourcestringOptional
topicsarray<object>Optional

With topic index.

Errors

400 Invalid input. Every error has error, message and code.

POST/api/agent/runs

Ask Unity's assistant

workspace:writeAny access to the page · reaches chat
Request and response

Queues a run of Unity's own assistant in one of your conversations (POST /api/datachats/add creates one) and answers 202 at once. The assistant inspects, queries and, with Edit access, changes the report through its tools; with View access it only reads. One run per conversation at a time (409 returns the active run). Requires an active subscription.

To control Unity with your own AI instead, call the same tools directly: GET /api/reports/{report_id}/tools, or connect an MCP client to /mcp.

Body

reportIdstringRequired
dataChatIdintegerRequired

The conversation's DataChatID.

user_inputstringRequired

The request, up to 50,000 characters.

maxLength: 50000
clientRequestIdstringOptional

Deduplicates a retried submission.

maxLength: 64
modestringOptional
enum: ["data_chat"] default: "data_chat"
layoutContextobjectOptional

Optional: pageId the user is on, selected visuals, referenceFiles [{id}] to attach report files (report Edit, Admin or Owner only; anyone else is refused 403).

attachmentsarray<object>Optional

Optional images.

Example request body

JSON
{
  "reportId": "9af3fb53-34e2-4e88-a953-ffdecdeece82",
  "dataChatId": 37,
  "user_input": "Summarize spending by category and add a bar chart to the Spending page.",
  "clientRequestId": "run-spending-summary-1"
}

Response 202

runvalueOptional
createdbooleanOptional

False when clientRequestId matched an earlier run.

timingsobjectOptional

Errors

400 Invalid input · 403 Scope, access or subscription · 404 Not found · 409 Conflict: re-read and reconcile. Every error has error, message and code.

GET/api/agent/runs/{run_id}

Read a run

workspace:readAny access to the page · reaches chat
Request and response

Parameters

run_idpath · stringRequired

Response 200

runvalueOptional

Errors

404 Not found. Every error has error, message and code.

GET/api/agent/runs/{run_id}/context

Read a run's context (administrators)

workspace:readPlatform administrator · reaches chat
Request and response

Platform administrators: one run's context receipts (export=json for a download).

Parameters

run_idpath · stringRequired
exportquery · stringOptional

Response 200

Errors

400 Invalid input · 403 Scope, access or subscription · 404 Not found. Every error has error, message and code.

GET/api/agent/runs/{run_id}/context/content/{digest}

Read one context entry (administrators)

workspace:readPlatform administrator · reaches chat
Request and response

Parameters

run_idpath · stringRequired
digestpath · stringRequired

Response 200

Errors

400 Invalid input · 403 Scope, access or subscription · 404 Not found. Every error has error, message and code.

GET/api/agent/runs/{run_id}/events

Read a run's events

workspace:readAny access to the page · reaches chat
Request and response

view=conversation: the run and its conversation events after afterSequence (messages, tool activity, answers), plus a cursor for the next poll; works while queued. Without view: stored events and tool_calls (each tool's arguments and result) of an initialized run.

Parameters

run_idpath · stringRequired
viewquery · stringOptional
afterSequencequery · integerOptional

Return events after this sequence (the last cursor).

Response 200

runvalueOptional
eventsarray<object>Optional
cursorintegerOptional

With view=conversation.

tool_callsarray<object>Optional

Errors

400 Invalid input · 404 Not found. Every error has error, message and code.

POST/api/agent/runs/{run_id}/stop

Stop a run

workspace:writeAny access to the page · reaches chat
Request and response

A queued run is cancelled at once; a running run stops its future work and a running read promptly. A write in progress finishes and keeps its receipt. Nothing is rolled back.

Parameters

run_idpath · stringRequired

Response 200

runvalueOptional

Errors

403 Scope, access or subscription · 404 Not found. Every error has error, message and code.

GET/api/agent/runs/{run_id}/stream

Stream a run's events

workspace:readAny access to the page · reaches chat
Request and response

Server-sent events for a run executing on the serving worker; resume with afterSequence or Last-Event-ID. data: {"fallback":true} means poll the events endpoint instead (another worker, a finished run, or stream capacity). A browser EventSource cannot send a bearer header.

Parameters

run_idpath · stringRequired
afterSequencequery · integerOptional

Response 200 (text/event-stream)

Server-sent events.

Errors

400 Invalid input · 404 Not found. Every error has error, message and code.

POST/api/agent/transcribe

Transcribe a voice message

workspace:writeAny signed-in account · reaches chat
Request and response

Multipart form: reportId and an audio file. Returns the text for a message.

Body (multipart/form-data)

reportIdstringOptional
audiostringOptional

Response 200

textstringOptional

Errors

400 Invalid input · 413 Too large · 415 Unsupported media type. Every error has error, message and code.

GET/api/agent/workspace

Read your conversations' state

workspace:readAny access to the page · reaches chat
Request and response

Your conversations in a report with their latest run state and unread counts.

Parameters

reportIdquery · stringRequired

Response 200

sessionsarray<object>Optional
summaryobjectOptional

Errors

400 Invalid input · 403 Scope, access or subscription. Every error has error, message and code.

Agent tools3 operations

Call the assistant's tools directly, with your own AI: the same contracts, permissions and receipts.

GET/api/reports/{report_id}/tools

List the agent tools

workspace:readAny access to the page · reaches docs
Request and response

The tools Unity's own assistant uses, offered to your AI for this report: each with its description, access (view or edit), readOnly, and exact JSON input schema. available says whether you can call it here (Edit access and a workspace:write key for tools that change the report); tools your access could never call are left out. A report Viewer (or Edit content person) who also holds Edit on some pages can call the tools that change those pages (editablePages), and only for those pages. Give these to your model as function definitions; call them with POST /api/reports/{report_id}/tools/{name}.

Parameters

report_idpath · stringRequired

Response 200

reportIdstringOptional
accessLevelstringOptional
contentEditbooleanOptional

True for an Edit content share (View access: the tools are a Viewer's).

toolsarray<object>Optional
editablePagesarray<object>Optional

Present for a Viewer who holds Edit on pages: the pages the change tools work on (every other page, and every report-level action, stays a Viewer's).

Errors

403 Scope, access or subscription. Every error has error, message and code.

POST/api/reports/{report_id}/tools/{name}

Call an agent tool

workspace:writeAny access to the page · reaches docs, files, history, model, pages, report, source
Request and response

Runs one tool as you, exactly as Unity's assistant would: the arguments are validated against its schema, your report access and key scope apply, and the result is what the assistant would receive. A change returns its receipt and reportVersion, the report version it made: ListReportVersions lists it and RestoreReportVersion brings back the version before it. View tools accept a workspace:read key; tools that change the report need workspace:write and Edit access. Parameters named *Json (also inside a list's items, and HTML operation) take the JSON as text or as the value.

The HTTP status says whether the call ran: 200 for an executed call (status success or error), 4xx when it did not (unknown tool 404 tool_not_found, invalid arguments 422 invalid_tool_arguments with the failing field, access or scope 403).

Parameters

report_idpath · stringRequired
namepath · stringRequired

Body

argumentsobjectRequired

The tool's arguments, per its inputSchema.

sessionIdstringOptional

Optional, up to 64 characters: groups your calls into one recorded session (an external assistant run without a conversation).

maxLength: 64

Example request body

JSON
{
  "arguments": {
    "visuals": [
      {
        "pageId": "678AE2F0-1469-489E-AE28-B729A0000E51",
        "visualType": "dataCard",
        "definitionJson": {
          "title": "Total spend",
          "query": {
            "values": [
              {
                "name": "Spend",
                "field": "fld_0a1b2c3d4e5f60718293a4b5c6d7e8f9"
              }
            ]
          }
        }
      }
    ]
  },
  "sessionId": "my-agent-session-1"
}

Response 200

toolstringOptional
statusstringOptional

error: the tool ran and refused or failed; read result.error.

enum: ["success","error"]
resultobjectOptional

The tool's result as the assistant receives it.

imagesarray<object>Optional

Screenshots from preview tools (PreviewPage, PreviewFile, ...).

runIdstringOptional
callIdstringOptional

Errors

400 Invalid input · 403 Scope, access or subscription · 404 Not found · 422 Cannot be applied. Every error has error, message and code.

GET/api/reports/{report_id}/tools/{name}

Read one agent tool

workspace:readAny access to the page · reaches docs
Request and response

Parameters

report_idpath · stringRequired
namepath · stringRequired

Response 200

namestringOptional
descriptionstringOptional
accessstringOptional
enum: ["view","edit"]
readOnlybooleanOptional

The tool only reads: a workspace:read key may call it.

reacharray<string>Optional
availablebooleanOptional
unavailableReasonstringOptional
inputSchemaobjectOptional

The exact JSON Schema of the tool's arguments.

Errors

403 Scope, access or subscription · 404 Not found. Every error has error, message and code.

Model Context Protocol2 operations

Unity's tools and guides for MCP clients.

POST/mcp

Model Context Protocol endpoint

workspace:writeAny access to the page · reaches docs, files, history, model, pages, report, source
Request and response

Connect any MCP client (Claude, ChatGPT, Cursor, Grok, your own agent) to Unity: Streamable HTTP transport, one JSON-RPC message per POST, answered with JSON; no session. Authenticate with a Unity API key (Authorization: Bearer). tools/list returns the agent tools you may call; tools/call runs one with the same validation, access, receipts and versions as POST /api/reports/{report_id}/tools/{name} (images come back as image content). resources/list offers Unity's guides (unity://docs/{topic}) and this API's OpenAPI document. With ?reportId= the server is bound to that report; without it every tool takes reportId, and ListReports and CreateReport are added.

A workspace:read key can list tools, read resources and call view tools; changing tools need workspace:write and Edit access on the report.

Claude Code: claude mcp add --transport http unity https://api.x4tech.org/mcp --header "Authorization: Bearer $UNITY_API_KEY".

Parameters

reportIdquery · stringOptional

Bind the server to one report.

Body

jsonrpcstringRequired
enum: ["2.0"]
idvalueOptional

Request ID; omitted for notifications.

methodstringRequired
enum: ["initialize","ping","tools/list","tools/call","resources/list","resources/read","resources/templates/list","prompts/list","notifications/initialized"]
paramsobjectOptional

Example request body

JSON
{
  "jsonrpc": "2.0",
  "id": 3,
  "method": "tools/call",
  "params": {
    "name": "InspectReport",
    "arguments": {
      "reportId": "9af3fb53-34e2-4e88-a953-ffdecdeece82",
      "query": "",
      "kind": "page",
      "pageId": null,
      "visualKeys": [],
      "detail": false,
      "offset": 0,
      "limit": 20
    }
  }
}

Response 200

The JSON-RPC response; 202 with no body for a notification.

jsonrpcstringOptional
idvalueOptional
resultobjectOptional
errorobjectOptional

Errors

400 Invalid input · 403 Scope, access or subscription. Every error has error, message and code.

GET/mcp

MCP server stream (not offered)

workspace:readAny signed-in account · reaches docs
Request and response

Answers 405: this server sends no server-initiated messages; every response comes on its POST.

Response 405

MCP OAuth7 operations

Discovery, authorization, token, registration and revocation for MCP clients that connect by signing in.

GET/.well-known/oauth-authorization-server

Authorization server metadata

No Unity token required; endpoint checks may applyNo sign-in · reaches account
GET/.well-known/oauth-protected-resource

Protected resource metadata

No Unity token required; endpoint checks may applyNo sign-in · reaches account
GET/.well-known/oauth-protected-resource/mcp

Protected resource metadata

No Unity token required; endpoint checks may applyNo sign-in · reaches account
GET/oauth/authorize

Authorize

No Unity token required; endpoint checks may applyNo sign-in · reaches account
POST/oauth/register

Register

No Unity token required; endpoint checks may applyNo sign-in · reaches account
POST/oauth/revoke

Revoke

No Unity token required; endpoint checks may applyNo sign-in · reaches account
POST/oauth/token

Token

No Unity token required; endpoint checks may applyNo sign-in · reaches account
Connected apps4 operations

The consent page's request and decision, and the account's connected apps (browser only).

GET/api/oauth/connections

Connections

Browser session requiredAny signed-in account · reaches account
DELETE/api/oauth/connections/{grant_id}

Disconnect

Browser session requiredAny signed-in account · reaches account

Path: grant_id (string)

GET/api/oauth/requests/{request_id}

Consent request

Browser session requiredAny signed-in account · reaches account

Path: request_id (string)

POST/api/oauth/requests/{request_id}/decision

Consent decision

Browser session requiredAny signed-in account · reaches account

Path: request_id (string)

Conversations3 operations

Report chats: transcripts and messages.

PUT/api/datachat/message

Update a chat message's visual

workspace:writeView access · reaches chat
Request and response

The browser's inline chat-visual edits.

Response 200

GET/api/datachat/transcript

Read a conversation

workspace:readAny access to the page · reaches chat
Request and response

Your conversation's messages, the actions its runs took (with change receipts) and its timeline, in one read. Conversations are private to their creator (404 otherwise).

Parameters

reportIdquery · stringRequired
dataChatIdquery · integerRequired

Response 200

messagesarray<object>Optional
actionsarray<object>Optional
projectionobjectOptional

Errors

400 Invalid input · 403 Scope, access or subscription · 404 Not found. Every error has error, message and code.

PUT/api/datachats/update

Rename a conversation

workspace:writeAny access to the page · reaches chat
Request and response

Body

reportIdstringRequired
dataChatIdintegerRequired
newNamestringRequired

Response 200

Errors

400 Invalid input · 403 Scope, access or subscription · 404 Not found. Every error has error, message and code.

Conversation streaming (compatibility)2 operations

The browser's streaming chat transport.

DELETE/api/datachat/delete

Delete a conversation

workspace:writeAny access to the page · reaches chat
Request and response

Deletes your conversation and its history (202: cleanup continues). Refused while a run is active.

Body

reportIdstringRequired
idintegerRequired

DataChatID.

Response 202

messagestringOptional
detailsobjectOptional

Errors

400 Invalid input · 403 Scope, access or subscription · 404 Not found · 409 Conflict: re-read and reconcile. Every error has error, message and code.

POST/api/datachat/pull_visual

Add a chat visual to a page

workspace:writeEdit access · reaches chat, pages
Request and response

The browser's Add to page of an inline chat preview.

Response 200

HTML pages9 operations

HTML report pages: source, registrations, data and queries.

GET/api/html/pages/{page_uid}

Read an HTML page

workspace:readAny access to the page · reaches pages
Request and response

One page's source, registered datasets and visuals, filters and its version (`version`), which changes to it must send as baseVersion.

Parameters

page_uidpath · stringRequired

The HTML page UUID.

Response 200

An HTML page (or, for a report-wide read, every page the caller can see) with its version.

idstringOptional

Report ID.

reportIdstringOptional

Report ID.

pageIdstringOptional

The page (single-page projection).

namestringOptional

Report name.

versionintegerOptional

This page's version: send it as baseVersion (for a report-wide read, the highest page version).

pageVersionsobjectOptional

{pageUid: version} for every page in the document.

revisionScopestringOptional
enum: ["page"]
accessLevelstringOptional
documentobjectOptional
nativePagesarray<object>Optional
feedbackobjectOptional
updatedAtstring | nullOptional
scopestringOptional

Present for a page-only reader (page grants, no report access): the page is returned without queries, filters or renderer feedback.

enum: ["pages"]
dataContextstringOptional

An opaque fingerprint of the page's data definitions and the filters as they apply to you. Data responses and renderer feedback repeat it.

Errors

403 Scope, access or subscription · 404 Not found. Every error has error, message and code.

GET/api/html/pages/{page_uid}/assets/{asset_id}/content

Read an image the page uses

workspace:readAny access to the page · reaches files, pages
Request and response

The bytes of an asset the page's current content references as `unity-asset:<assetId>` (any part: HTML, visual HTML/CSS/script, registrations), for anyone who can open the page, including a page-only reader. An asset the page does not reference is refused, and nothing is listed: the report file library routes are for report Edit, Admin and Owner only.

Parameters

page_uidpath · stringRequired

The HTML page UUID.

asset_idpath · stringRequired

The 64-character asset ID in a `unity-asset:` reference.

Response 200 (image/png)

Errors

400 Invalid input · 403 Scope, access or subscription · 404 Not found. Every error has error, message and code.

POST/api/html/pages/{page_uid}/operations

Change an HTML page

workspace:writeEdit access to the page · reaches pages
Request and response

Applies one document operation as one saved version of this page (a report version: GET /api/reports/{reportId}/versions lists it). A baseVersion older than the page's version still applies when what the operation reads or writes is the same in that version and now (element identities aside); otherwise it answers 409 revision_conflict with the page's currentVersion and the changes since, and nothing is saved. A repeated clientRequestId returns the first outcome.

Parameters

page_uidpath · stringRequired

The HTML page UUID.

Body

baseVersionintegerRequired
operationobjectRequired

One atomic change to one HTML page. The html-authoring guide (GET /api/agent/documentation?topic=html-authoring) describes each kind, the renderer API (unity.bind, unity.query) and examples.

labelstringOptional

History label.

clientRequestIdstringOptional

A UUID or short string naming this command: a retry with the same ID and body answers with the original outcome instead of saving twice.

Example request body

JSON
{
  "baseVersion": 1,
  "label": "Headline",
  "operation": {
    "kind": "patch_source",
    "part": "html",
    "edits": [
      {
        "find": "Your data.<br>A different perspective.",
        "replace": "Spending at a glance",
        "expectedMatches": 1
      }
    ]
  }
}

Response 200

The page as saved and the change receipt.

idstringOptional

Report ID.

reportIdstringOptional

Report ID.

pageIdstringOptional

The page (single-page projection).

namestringOptional

Report name.

versionintegerOptional

This page's version: send it as baseVersion (for a report-wide read, the highest page version).

pageVersionsobjectOptional

{pageUid: version} for every page in the document.

revisionScopestringOptional
enum: ["page"]
accessLevelstringOptional
documentobjectOptional
nativePagesarray<object>Optional
feedbackobjectOptional
updatedAtstring | nullOptional
scopestringOptional

Present for a page-only reader (page grants, no report access): the page is returned without queries, filters or renderer feedback.

enum: ["pages"]
dataContextstringOptional

An opaque fingerprint of the page's data definitions and the filters as they apply to you. Data responses and renderer feedback repeat it.

receiptobjectOptional

Receipt: {resourceType: 'html', label, mutation, change: {before: {pageUid}, after: {pageUid, version}}, pageVersion, changedPageIds, verificationKeys}.

changedElementsarray<string>Optional

element_ops: the uids written.

Errors

400 Invalid input · 403 Scope, access or subscription · 409 Conflict: re-read and reconcile · 413 Too large · 422 Cannot be applied. Every error has error, message and code.

POST/api/html/pages/{page_uid}/script-save

Save text from a page's own script

workspace:writeEdit content access to the page · reaches pages
Request and response

What `unity.save(element, text)` in an HTML page sends. Writes `text` as plain text into the element whose `data-unity-id` is `uid`, which the page's editors marked `data-unity-writable` (a text-only element), as one new attributed version of the page (ActorKind `page_script`, the label 'Saved text from the page'); every viewer sees it through the live feed. Needs Edit content or above on the page: report Admin/Owner/Edit, a page Edit or Edit content grant, or a report share at Edit content (HTML pages open to everyone). A person who can only view is refused `view_only`; public links have no save route. At most 20,000 characters, 30 saves a minute per person per page. Refusals: 403 `view_only` / `no_access` / `page_unavailable`, 422 `not_writable` (no marker, not a text-only element, unknown uid, or the page has no element identities) / `too_long` / `invalid_text` (a report image reference), 409 `page_held` (another person is editing: {holder}) / `changed` (the element no longer holds previousText: someone changed it; {currentVersion}), 429 `rate_limited` ({retryAfter}, Retry-After). Changes to other elements never refuse it. A repeated clientRequestId answers the first outcome.

Parameters

page_uidpath · stringRequired

The HTML page UUID.

Body

uidstringRequired

The element's data-unity-id.

textstringRequired

Plain text, up to 20,000 characters.

previousTextstringRequired

The element's text as the saver's page last applied it (after its own earlier saves; not a change held back while they type).

clientRequestIdstringRequired

A UUID or short string naming this command: a retry with the same ID and body answers with the original outcome instead of saving twice.

Example request body

JSON
{
  "uid": "k3m9xq",
  "text": "Approved",
  "previousText": "Pending",
  "clientRequestId": "a-new-id-per-save"
}

Response 200

savedbooleanOptional
pageIdstringOptional
uidstringOptional
versionintegerOptional

The page version holding the text.

appliedbooleanOptional

False when the element already held exactly this text (no new version).

Errors

400 Invalid input · 403 Scope, access or subscription · 409 Conflict: re-read and reconcile · 422 Cannot be applied · 429 Rate limited. Every error has error, message and code.

GET/api/html/reports/{report_id}

Read the HTML pages of a report

workspace:readView access · reaches pages
Request and response

Every HTML page the caller can see, with `pageVersions` ({pageUid: version}).

Parameters

report_idpath · stringRequired

Response 200

An HTML page (or, for a report-wide read, every page the caller can see) with its version.

idstringOptional

Report ID.

reportIdstringOptional

Report ID.

pageIdstringOptional

The page (single-page projection).

namestringOptional

Report name.

versionintegerOptional

This page's version: send it as baseVersion (for a report-wide read, the highest page version).

pageVersionsobjectOptional

{pageUid: version} for every page in the document.

revisionScopestringOptional
enum: ["page"]
accessLevelstringOptional
documentobjectOptional
nativePagesarray<object>Optional
feedbackobjectOptional
updatedAtstring | nullOptional
scopestringOptional

Present for a page-only reader (page grants, no report access): the page is returned without queries, filters or renderer feedback.

enum: ["pages"]
dataContextstringOptional

An opaque fingerprint of the page's data definitions and the filters as they apply to you. Data responses and renderer feedback repeat it.

Errors

403 Scope, access or subscription · 404 Not found. Every error has error, message and code.

POST/api/html/reports/{report_id}/feedback

Record renderer feedback

workspace:writeAny access to the page · reaches pages
Request and response

The browser renderer's diagnostics; `revision` is the page's version.

Parameters

report_idpath · stringRequired

Response 200

GET/api/html/reports/{report_id}/pages/{page_id}/data

Read an HTML page's data

workspace:readAny access to the page · reaches model, pages
Request and response

Reads the page's registered visual queries with saved and interactive filters and returns their results: columns, rows, records, outputs and generatedSql. A dataset saved as SQL answers code legacy_sql. The browser renderer calls it; an agent previews pages with the PreviewPage tool.

Parameters

report_idpath · stringRequired
page_idpath · stringRequired

The HTML page UUID.

statequery · stringOptional

JSON runtime state, at most 16,000 characters: a click (interaction: {visualId, dataId, fields: [{column, value}]}, each column a group output of that dataset's query; Unity builds its filters from the stored query), a table window, targets.

targetquery · stringOptional

One dataset or visual ID.

Response 200

versionintegerOptional
contextobjectOptional
resultsobjectOptional

Errors

400 Invalid input · 403 Scope, access or subscription · 409 Conflict: re-read and reconcile · 503 Unavailable or read stopped. Every error has error, message and code.

GET/api/html/reports/{report_id}/pages/{page_id}/data-stream

Stream an HTML page's data

workspace:readAny access to the page · reaches model, pages
Request and response

NDJSON: {context, keys}, then {results} as datasets finish, {jobs} for reads continuing as read jobs, then {done: true}.

Parameters

report_idpath · stringRequired
page_idpath · stringRequired
statequery · stringOptional

Response 200 (application/x-ndjson)

Errors

400 Invalid input · 403 Scope, access or subscription. Every error has error, message and code.

POST/api/html/reports/{report_id}/query

Query data for HTML authoring

workspace:writeEdit access · reaches model
Request and response

Reads a visual query under the report's filters (and the page's, with a pageId) as they apply to you and returns a sample with its outputs and generatedSql, to design datasets. Edit access.

Parameters

report_idpath · stringRequired

Body

queryobjectRequired

A visual query, as a dataset takes it.

pageIdstringOptional
filtersarray<value>Optional

Dataset filters for this query.

Response 200

Errors

400 Invalid input · 403 Scope, access or subscription. Every error has error, message and code.

Live viewing and editing presence9 operations

An HTML page's live feed, and the leases and presence of every page.

POST/api/pages/{page_uid}/hold

Start editing a page or a chart

Browser session requiredEdit access to the page · reaches pages
Request and response

An HTML page: starts or joins the caller's editing session (409 page_held when another person holds it). A native page: leases the chart named by `target` (`visual:<id>`; 409 element_held when another person holds it). A browser session only: an API key, MCP or OAuth token answers 403 browser_session_required. A browser sends the tab's edit session as the X-Unity-Edit-Session header on every write and on the hold and presence routes, so they start or join the caller's session or lease (an API caller's credential is a one-shot participant that never extends it).

Parameters

page_uidpath · stringRequired

The HTML page UUID.

Body

targetstringOptional

Native pages: `visual:<visual uid>`. HTML pages: omit or `page`.

Response 200

One person's lease on a target of a page: an HTML page's editing session, or a chart of a native page. A participant (a browser tab, an assistant run, an API caller) is live for the mode's window after its last renewal (see `mode`); the lease ends when none is live.

pageUidstringOptional
targetstringOptional

`page` for an HTML page's session; `visual:<uid>` for a native page's element lease.

modestringOptional

`session`: an HTML page's editing session (45 s from the last renewal, 10 minutes from the last write); `lease`: a chart on a native page (10 s from the last activity); `oneshot`: held for one write.

enum: ["session","lease","oneshot"]
holdIdstringOptional

Only the holder sees it: send it with every renew, leave and answer (a stale one answers 409 hold_lost).

holderobjectOptional
sincestringOptional
kindsarray<string>Optional

Who is acting under the hold.

minebooleanOptional

The caller is the holder.

expiresAtstringOptional

The hold lapses then unless a participant renews.

participantsarray<object>Optional

The holder's live participants (holder only).

takeoverRequestedbooleanOptional
takeoverRequestedByobject | nullOptional
takeoverDeadlinestring | nullOptional

Server time at which an unanswered request is granted.

Errors

400 Invalid input · 403 Scope, access or subscription · 409 Conflict: re-read and reconcile. Every error has error, message and code.

DELETE/api/pages/{page_uid}/hold

Stop editing a page or a chart

Browser session requiredEdit access to the page · reaches pages
Request and response

Ends only this session's participation; the lease ends when no participant remains. 409 hold_lost for a stale `holdId`. A browser session only: an API key, MCP or OAuth token answers 403 browser_session_required.

Parameters

page_uidpath · stringRequired

The HTML page UUID.

Body

holdIdstringRequired

Response 200

releasedbooleanOptional

Errors

400 Invalid input · 403 Scope, access or subscription · 409 Conflict: re-read and reconcile. Every error has error, message and code.

PUT/api/pages/{page_uid}/hold

Keep editing a page or a chart

Browser session requiredEdit access to the page · reaches pages
Request and response

Renews this session's participation (every 30 s while the tab is focused, every 4 s while a chart's drawer holds unsaved edits). 409 hold_lost when `holdId` is no longer current (lapsed, ended at its limit, taken over or released); the response then carries the page's session. Renewing is not a write: it does not move the 10 minute (page) or 5 minute (chart) limit. A browser session only: an API key, MCP or OAuth token answers 403 browser_session_required.

Parameters

page_uidpath · stringRequired

The HTML page UUID.

Body

holdIdstringRequired

Response 200

One person's lease on a target of a page: an HTML page's editing session, or a chart of a native page. A participant (a browser tab, an assistant run, an API caller) is live for the mode's window after its last renewal (see `mode`); the lease ends when none is live.

pageUidstringOptional
targetstringOptional

`page` for an HTML page's session; `visual:<uid>` for a native page's element lease.

modestringOptional

`session`: an HTML page's editing session (45 s from the last renewal, 10 minutes from the last write); `lease`: a chart on a native page (10 s from the last activity); `oneshot`: held for one write.

enum: ["session","lease","oneshot"]
holdIdstringOptional

Only the holder sees it: send it with every renew, leave and answer (a stale one answers 409 hold_lost).

holderobjectOptional
sincestringOptional
kindsarray<string>Optional

Who is acting under the hold.

minebooleanOptional

The caller is the holder.

expiresAtstringOptional

The hold lapses then unless a participant renews.

participantsarray<object>Optional

The holder's live participants (holder only).

takeoverRequestedbooleanOptional
takeoverRequestedByobject | nullOptional
takeoverDeadlinestring | nullOptional

Server time at which an unanswered request is granted.

Errors

400 Invalid input · 403 Scope, access or subscription · 409 Conflict: re-read and reconcile. Every error has error, message and code.

GET/api/pages/{page_uid}/hold

Read the leases on a page and who is on it

workspace:readAny access to the page · reaches pages
Request and response

`hold` is an HTML page's editing session (null when free or native). `leases` are the live element leases of a native page (a chart is leased while someone drags or resizes it, has unsaved edits in its edit drawer, or their assistant is changing it, and never more than 5 minutes after it was taken or last written; the caller's own are flagged `mine`). `presence` lists the people on the page and what each has selected. `granularity` is `page` (HTML: one editor at a time) or `element` (native: everyone edits at once; a chart is protected for about 10 s after the activity stops). The same for HTML and native pages.

Parameters

page_uidpath · stringRequired

The HTML page UUID.

Response 200

granularitystringOptional
enum: ["page","element"]
holdobject | nullOptional

One person's lease on a target of a page: an HTML page's editing session, or a chart of a native page. A participant (a browser tab, an assistant run, an API caller) is live for the mode's window after its last renewal (see `mode`); the lease ends when none is live.

leasesarray<object>Optional
presencearray<object>Optional

Errors

403 Scope, access or subscription. Every error has error, message and code.

POST/api/pages/{page_uid}/hold/takeover

Ask to edit an HTML page someone else holds, or end chart leases

Browser session requiredEdit access to the page · reaches pages
Request and response

An HTML page: asks the holder to hand the page over: granted when the holder releases, when 30 s pass unanswered, or when the session ends. `force` (report Owner or Admin) takes it immediately. A takeover issues a new holdId, so the previous holder's requests answer 409 hold_lost. A native page has no takeover (409 page_kind_unsupported) unless `force` is set: a report Owner or Admin then ends the other people's chart leases (`target`: `visual:<id>` for one chart, else every lease on the page) and the answer is `{ended}`; anyone else gets 403. A browser session only: an API key, MCP or OAuth token answers 403 browser_session_required.

Parameters

page_uidpath · stringRequired

The HTML page UUID.

Body

forcebooleanOptional
targetstringOptional

Native pages with `force`: the chart whose lease to end.

Response 200

One person's lease on a target of a page: an HTML page's editing session, or a chart of a native page. A participant (a browser tab, an assistant run, an API caller) is live for the mode's window after its last renewal (see `mode`); the lease ends when none is live.

pageUidstringOptional
targetstringOptional

`page` for an HTML page's session; `visual:<uid>` for a native page's element lease.

modestringOptional

`session`: an HTML page's editing session (45 s from the last renewal, 10 minutes from the last write); `lease`: a chart on a native page (10 s from the last activity); `oneshot`: held for one write.

enum: ["session","lease","oneshot"]
holdIdstringOptional

Only the holder sees it: send it with every renew, leave and answer (a stale one answers 409 hold_lost).

holderobjectOptional
sincestringOptional
kindsarray<string>Optional

Who is acting under the hold.

minebooleanOptional

The caller is the holder.

expiresAtstringOptional

The hold lapses then unless a participant renews.

participantsarray<object>Optional

The holder's live participants (holder only).

takeoverRequestedbooleanOptional
takeoverRequestedByobject | nullOptional
takeoverDeadlinestring | nullOptional

Server time at which an unanswered request is granted.

Errors

400 Invalid input · 403 Scope, access or subscription · 409 Conflict: re-read and reconcile. Every error has error, message and code.

POST/api/pages/{page_uid}/hold/takeover/answer

Answer a request to take over an HTML page

Browser session requiredEdit access to the page · reaches pages
Request and response

The holder's answer: `release: true` hands the page to the requester (new holdId), `release: false` keeps editing and rejects the request. A browser session only: an API key, MCP or OAuth token answers 403 browser_session_required.

Parameters

page_uidpath · stringRequired

The HTML page UUID.

Body

holdIdstringRequired
releasebooleanRequired

Response 200

One person's lease on a target of a page: an HTML page's editing session, or a chart of a native page. A participant (a browser tab, an assistant run, an API caller) is live for the mode's window after its last renewal (see `mode`); the lease ends when none is live.

pageUidstringOptional
targetstringOptional

`page` for an HTML page's session; `visual:<uid>` for a native page's element lease.

modestringOptional

`session`: an HTML page's editing session (45 s from the last renewal, 10 minutes from the last write); `lease`: a chart on a native page (10 s from the last activity); `oneshot`: held for one write.

enum: ["session","lease","oneshot"]
holdIdstringOptional

Only the holder sees it: send it with every renew, leave and answer (a stale one answers 409 hold_lost).

holderobjectOptional
sincestringOptional
kindsarray<string>Optional

Who is acting under the hold.

minebooleanOptional

The caller is the holder.

expiresAtstringOptional

The hold lapses then unless a participant renews.

participantsarray<object>Optional

The holder's live participants (holder only).

takeoverRequestedbooleanOptional
takeoverRequestedByobject | nullOptional
takeoverDeadlinestring | nullOptional

Server time at which an unanswered request is granted.

Errors

400 Invalid input · 403 Scope, access or subscription · 409 Conflict: re-read and reconcile. Every error has error, message and code.

GET/api/pages/{page_uid}/live

Read what changed on a page since a version (live viewing)

workspace:readAny access to the page · reaches pages
Request and response

The net change from `after` (the version the viewer shows) to the page's head, for anyone who can view the page: in-place patches addressed by `data-unity-id`, or `rebuild: true` asking the viewer to rebuild. It never reveals what happened in between: every patch is taken from the head markup. HTML pages only (a native page answers 400: its viewers follow the report liveness poll). `rebuild: false` carries patches addressed by `data-unity-id`: `attrs` (the element's full final attributes and start tag), `text` (text-only elements) and `children` (new inner HTML), at most 40 patches and 200 KB; `rebuild: true` asks the viewer to rebuild the page (reason: styles, script, visuals, data, filters, settings, unidentified, structure, too_large, unverified or history_unavailable: the version shown isn't in the report's versions). `after` must be between 1 and the head version. Answers are cached for 30 s.

Parameters

page_uidpath · stringRequired

The HTML page UUID.

afterquery · integerRequired

The page version the viewer shows.

Response 200

pageUidstringOptional
fromVersionintegerOptional
versionintegerOptional
rebuildbooleanOptional
reasonstringOptional

Why the viewer must rebuild; present when rebuild is true.

patchesarray<object>Optional

Errors

400 Invalid input · 403 Scope, access or subscription · 409 Conflict: re-read and reconcile. Every error has error, message and code.

PUT/api/pages/{page_uid}/presence

Say you are on a page and what you selected

Browser session requiredAny access to the page · reaches pages
Request and response

Presence for the people who can open the page: one heartbeat per tab, valid for about 15 s (send one every 5 s). `target` is what the tab has selected (`visual:<id>`, `page`) or null. The answer is who is on the page. Presence is never shown on a public link and never given to the assistant. A browser session only: an API key, MCP or OAuth token answers 403 browser_session_required.

Parameters

page_uidpath · stringRequired

The HTML page UUID.

Body

targetstring | nullOptional

Response 200

presencearray<object>Optional

Errors

400 Invalid input · 403 Scope, access or subscription. Every error has error, message and code.

DELETE/api/pages/{page_uid}/presence

Leave a page

Browser session requiredAny access to the page · reaches pages
Request and response

Ends this tab's presence at once. A browser session only: an API key, MCP or OAuth token answers 403 browser_session_required.

Parameters

page_uidpath · stringRequired

The HTML page UUID.

Response 200

leftbooleanOptional

Errors

400 Invalid input · 403 Scope, access or subscription. Every error has error, message and code.

Reference files and assets13 operations

Files attached to a report and the images they contain.

GET/api/reports/{report_id}/assets

List report images

workspace:readEdit access · reaches files
Request and response

Images imported into the report's asset library. Report Edit, Admin or Owner only (a page displays its own images through the page's asset route).

Parameters

report_idpath · stringRequired

Response 200

Errors

403 Scope, access or subscription. Every error has error, message and code.

GET/api/reports/{report_id}/assets/{asset_id}/content

Read a report image

workspace:readEdit access · reaches files
Request and response

Report Edit, Admin or Owner only. The page that displays an image reads it through GET /api/html/pages/{pageUid}/assets/{assetId}/content, which any viewer of the page may use.

Parameters

report_idpath · stringRequired
asset_idpath · stringRequired

Response 200 (image/png)

Errors

403 Scope, access or subscription · 404 Not found. Every error has error, message and code.

GET/api/reports/{report_id}/files

List a report's files

workspace:readEdit access · reaches files
Request and response

Reference files attached to the report (documents, slides, spreadsheets, HTML, images) that the assistant can read, with the upload limits. Report Edit, Admin or Owner only.

Parameters

report_idpath · stringRequired

Response 200

filesarray<object>Optional
maxBytesintegerOptional
maxAttachmentsintegerOptional
extensionsarray<string>Optional

Errors

403 Scope, access or subscription. Every error has error, message and code.

POST/api/reports/{report_id}/files

Upload a reference file

workspace:writeEdit access · reaches files
Request and response

Multipart form with file (up to 25 MB): PDF, PPTX, DOCX, XLSX, CSV, HTML, text and images. Unity extracts its text, layout and embedded images. Report Edit, Admin or Owner only.

Parameters

report_idpath · stringRequired

Body (multipart/form-data)

filestringRequired
fileIdstringOptional

Optional: replace this file.

Response 200

idstringOptional
namestringOptional
typestringOptional
sizeBytesintegerOptional
createdAtstringOptional

Errors

400 Invalid input · 403 Scope, access or subscription · 413 Too large. Every error has error, message and code.

DELETE/api/reports/{report_id}/files/{file_id}

Delete a file

workspace:writeEdit access · reaches files
Request and response

Parameters

report_idpath · stringRequired
file_idpath · stringRequired

Response 200

deletedbooleanOptional

Errors

403 Scope, access or subscription · 404 Not found. Every error has error, message and code.

GET/api/reports/{report_id}/files/{file_id}

Inspect a file

workspace:readEdit access · reaches files
Request and response

Sections (pages, slides, sheets), an HTML/CSS outline and the embedded image inventory. Report Edit, Admin or Owner only.

Parameters

report_idpath · stringRequired
file_idpath · stringRequired

Response 200

Errors

403 Scope, access or subscription · 404 Not found. Every error has error, message and code.

GET/api/reports/{report_id}/files/{file_id}/assets/{asset_id}/preview

Read an embedded image

workspace:readEdit access · reaches files
Request and response

Report Edit, Admin or Owner only.

Parameters

report_idpath · stringRequired
file_idpath · stringRequired
asset_idpath · stringRequired

Response 200 (image/png)

Errors

403 Scope, access or subscription · 404 Not found. Every error has error, message and code.

POST/api/reports/{report_id}/files/{file_id}/assets/{asset_id}/reuse

Import an image from a file

workspace:writeEdit access · reaches files
Request and response

Copies an exact embedded image into the report's asset library; HTML references it as unity-asset:<assetId>. Report Edit, Admin or Owner only.

Parameters

report_idpath · stringRequired
file_idpath · stringRequired
asset_idpath · stringRequired

Response 200

Errors

403 Scope, access or subscription · 404 Not found. Every error has error, message and code.

GET/api/reports/{report_id}/files/{file_id}/content

Read a file's text

workspace:readEdit access · reaches files
Request and response

Readable text of one section (or the file), paged by characters or spreadsheet rows; embedded media appear as short asset references. Report Edit, Admin or Owner only.

Parameters

report_idpath · stringRequired
file_idpath · stringRequired
sectionIdquery · stringOptional
offsetquery · integerOptional
limitquery · integerOptional
columnOffsetquery · integerOptional

Response 200

Errors

400 Invalid input · 403 Scope, access or subscription · 404 Not found. Every error has error, message and code.

GET/api/reports/{report_id}/files/{file_id}/download

Download a file

workspace:readEdit access · reaches files
Request and response

Report Edit, Admin or Owner only.

Parameters

report_idpath · stringRequired
file_idpath · stringRequired

Response 200 (application/octet-stream)

Errors

403 Scope, access or subscription · 404 Not found. Every error has error, message and code.

POST/api/reports/{report_id}/files/{file_id}/preview

Render a file page or image

workspace:writeEdit access · reaches files
Request and response

Renders one page or slide (page, 1-based) or one embedded image (assetId) to an image, for an AI that reads images. Report Edit, Admin or Owner only.

Parameters

report_idpath · stringRequired
file_idpath · stringRequired

Body

pageintegerOptional
assetIdstringOptional

Response 200

Errors

400 Invalid input · 403 Scope, access or subscription · 404 Not found. Every error has error, message and code.

GET/api/reports/{report_id}/files/{file_id}/previews/{page}

Read a rendered page image

workspace:readEdit access · reaches files
Request and response

Report Edit, Admin or Owner only.

Parameters

report_idpath · stringRequired
file_idpath · stringRequired
pagepath · integerRequired

Response 200 (image/png)

Errors

403 Scope, access or subscription · 404 Not found. Every error has error, message and code.

GET/api/reports/{report_id}/files/{file_id}/search

Search a file

workspace:readEdit access · reaches files
Request and response

Report Edit, Admin or Owner only.

Parameters

report_idpath · stringRequired
file_idpath · stringRequired
queryquery · stringRequired
sectionIdquery · stringOptional
offsetquery · integerOptional
limitquery · integerOptional
caseSensitivequery · stringOptional

Response 200

Errors

400 Invalid input · 403 Scope, access or subscription · 404 Not found. Every error has error, message and code.

File imports7 operations

Upload a CSV file as a queryable dataset.

POST/api/file/datasets

Start a CSV import

workspace:writeEdit access · reaches model
Request and response

Step 1 of 4. Returns a short-lived uploadUrl (Azure Blob, about 60 minutes): PUT the file's bytes there with the header x-ms-blob-type: BlockBlob. Then POST .../uploaded, choose column types with .../import, and poll the upload until status is ready. Edit access; active subscription. Three uploads in progress refuse another: the 400 names them (pendingUploads, each uploadId, fileName, reportId and reportName); the uploader may cancel any of them (DELETE .../datasets/{uploadId}).

Body

reportIdstringRequired
fileNamestringRequired

A .csv name.

sizeBytesintegerRequired
tableNamestringOptional

Entity name; defaults to the file name.

Response 201

uploadIdstringOptional
statusstringOptional

Follow it until ready (or failed).

fileNamestringOptional
tableNamestringOptional
rowCountinteger | nullOptional
rowsProcessedinteger | nullOptional
progressinteger | nullOptional
errorstring | nullOptional
connectionIdinteger | nullOptional

Set when ready: the queryable file connection.

previewobject | nullOptional
firstSpellingsobject | nullOptional

Set when ready: per column, the later spellings stored as an earlier one (Unity's text rule treats them as equal) and the rows they were in.

messagestring | nullOptional
uploadUrlstringOptional
maxBytesintegerOptional

Errors

400 Invalid input · 403 Scope, access or subscription. Every error has error, message and code.

GET/api/file/datasets

List a report's unfinished CSV imports

workspace:readEdit access · reaches model
Request and response

Every upload of the report not yet ready, failed or cancelled, whoever started it, oldest first. mine: you started it, so you can follow and cancel it. Edit access.

Parameters

reportIdquery · stringRequired

Response 200

uploadsarray<object>Optional

Errors

400 Invalid input · 403 Scope, access or subscription. Every error has error, message and code.

DELETE/api/file/datasets/{dataset_id}

Cancel a CSV import

workspace:writeEdit access · reaches model
Request and response

Before it is ready; afterwards delete its connection.

Parameters

dataset_idpath · stringRequired

Response 200

Errors

400 Invalid input · 404 Not found. Every error has error, message and code.

GET/api/file/datasets/{dataset_id}

Follow a CSV import

workspace:readEdit access · reaches model
Request and response

Parameters

dataset_idpath · stringRequired

Response 200

uploadIdstringOptional
statusstringOptional

Follow it until ready (or failed).

fileNamestringOptional
tableNamestringOptional
rowCountinteger | nullOptional
rowsProcessedinteger | nullOptional
progressinteger | nullOptional
errorstring | nullOptional
connectionIdinteger | nullOptional

Set when ready: the queryable file connection.

previewobject | nullOptional
firstSpellingsobject | nullOptional

Set when ready: per column, the later spellings stored as an earlier one (Unity's text rule treats them as equal) and the rows they were in.

messagestring | nullOptional

Errors

404 Not found. Every error has error, message and code.

POST/api/file/datasets/{dataset_id}/import

Import a CSV with column types

workspace:writeEdit access · reaches model
Request and response

Step 3. One type per preview column; the import continues in the background (poll to ready).

Parameters

dataset_idpath · stringRequired

Body

columnMappingsobjectRequired

Preview column name to type.

Example request body

JSON
{
  "columnMappings": {
    "date": "date",
    "amount": "decimal",
    "category": "string"
  }
}

Response 202

uploadIdstringOptional
statusstringOptional

Follow it until ready (or failed).

fileNamestringOptional
tableNamestringOptional
rowCountinteger | nullOptional
rowsProcessedinteger | nullOptional
progressinteger | nullOptional
errorstring | nullOptional
connectionIdinteger | nullOptional

Set when ready: the queryable file connection.

previewobject | nullOptional
firstSpellingsobject | nullOptional

Set when ready: per column, the later spellings stored as an earlier one (Unity's text rule treats them as equal) and the rows they were in.

messagestring | nullOptional

Errors

400 Invalid input · 404 Not found. Every error has error, message and code.

POST/api/file/datasets/{dataset_id}/uploaded

Confirm an uploaded CSV

workspace:writeEdit access · reaches model
Request and response

Step 2. Checks the stored size and starts profiling; poll until preview appears.

Parameters

dataset_idpath · stringRequired

Response 202

uploadIdstringOptional
statusstringOptional

Follow it until ready (or failed).

fileNamestringOptional
tableNamestringOptional
rowCountinteger | nullOptional
rowsProcessedinteger | nullOptional
progressinteger | nullOptional
errorstring | nullOptional
connectionIdinteger | nullOptional

Set when ready: the queryable file connection.

previewobject | nullOptional
firstSpellingsobject | nullOptional

Set when ready: per column, the later spellings stored as an earlier one (Unity's text rule treats them as equal) and the rows they were in.

messagestring | nullOptional

Errors

400 Invalid input · 404 Not found. Every error has error, message and code.

GET/api/file/datasets/limits

Read CSV import limits

workspace:readAny signed-in account · reaches model
Request and response

Response 200

maxBytesintegerOptional
maxColumnsintegerOptional
Text boxes and shapes (compatibility)6 operations

Older text box and shape endpoints.

POST/api/shapes/add

Add a shape Compatibility · use POST /api/visuals/create with type shape

workspace:writeEdit access to the page · reaches pages
Request and response

Response 200

DELETE/api/shapes/delete

Delete a shape Compatibility · use POST /api/visuals/delete

workspace:writeEdit access to the page · reaches pages
Request and response

Response 200

PUT/api/shapes/update

Update a shape Compatibility · use POST /api/visuals/update

workspace:writeEdit access to the page · reaches pages
Request and response

Response 200

POST/api/textboxes/add

Add a text box Compatibility · use POST /api/visuals/create with type textBox

workspace:writeEdit access to the page · reaches pages
Request and response

Response 200

DELETE/api/textboxes/delete

Delete a text box Compatibility · use POST /api/visuals/delete

workspace:writeEdit access to the page · reaches pages
Request and response

Response 200

PUT/api/textboxes/update

Update a text box Compatibility · use POST /api/visuals/update

workspace:writeEdit access to the page · reaches pages
Request and response

Response 200

Chart preset routes (compatibility)10 operations

Older per-chart data and delete endpoints.

GET/api/bargraphs/data

Read a chart preset's data Compatibility · use POST /api/reports/{report_id}/visual-data

workspace:readAny access to the page · reaches model, pages
Request and response

Response 200

DELETE/api/bargraphs/delete

Delete a chart preset Compatibility · use POST /api/visuals/delete

workspace:writeEdit access to the page · reaches pages
Request and response

Response 200

GET/api/datacards/data

Read a chart preset's data Compatibility · use POST /api/reports/{report_id}/visual-data

workspace:readAny access to the page · reaches model, pages
Request and response

Response 200

DELETE/api/datacards/delete

Delete a chart preset Compatibility · use POST /api/visuals/delete

workspace:writeEdit access to the page · reaches pages
Request and response

Response 200

GET/api/linegraphs/data

Read a chart preset's data Compatibility · use POST /api/reports/{report_id}/visual-data

workspace:readAny access to the page · reaches model, pages
Request and response

Response 200

DELETE/api/linegraphs/delete

Delete a chart preset Compatibility · use POST /api/visuals/delete

workspace:writeEdit access to the page · reaches pages
Request and response

Response 200

GET/api/piecharts/data

Read a chart preset's data Compatibility · use POST /api/reports/{report_id}/visual-data

workspace:readAny access to the page · reaches model, pages
Request and response

Response 200

DELETE/api/piecharts/delete

Delete a chart preset Compatibility · use POST /api/visuals/delete

workspace:writeEdit access to the page · reaches pages
Request and response

Response 200

GET/api/scatterplots/data

Read a chart preset's data Compatibility · use POST /api/reports/{report_id}/visual-data

workspace:readAny access to the page · reaches model, pages
Request and response

Response 200

DELETE/api/scatterplots/delete

Delete a chart preset Compatibility · use POST /api/visuals/delete

workspace:writeEdit access to the page · reaches pages
Request and response

Response 200

Data tables (compatibility)4 operations

Older data table endpoints.

POST/api/datatables/create-from-entity

Create a table from an entity

workspace:writeEdit access · reaches model, pages
Request and response

Creates a table visual grouping by the chosen columns of one model entity, its distinct rows (the Data panel's drag-a-table action). POST /api/visuals/create with a dataTable definition gives full control.

Body

reportIdstringRequired
pageIdstringRequired

UUID or numeric page ID.

entityKeystringRequired
columnNamesarray<string>Required
titlestringOptional
positionobjectOptional
dimensionsobjectOptional

Response 200

The created table's receipt.

Errors

400 Invalid input · 403 Scope, access or subscription · 404 Not found. Every error has error, message and code.

GET/api/datatables/data

Read a table page Compatibility · use POST /api/reports/{report_id}/visual-data

workspace:readAny access to the page · reaches model, pages
Request and response

Response 200

DELETE/api/datatables/delete

Delete a table Compatibility · use POST /api/visuals/delete

workspace:writeEdit access to the page · reaches pages
Request and response

Response 200

GET/api/datatables/export

Export a table's rows

workspace:readAny access to the page · reaches model, pages
Request and response

Every row of a saved table, under the filters as they apply to you and in your own sort (PUT /api/my-view), else its query's, for an export; the browser writes it as CSV. Large exports may continue as a read job (202).

Parameters

reportIdquery · stringRequired

Report ID.

pageIdquery · stringOptional

The table's page: UUID or numeric ID.

dataTableIdquery · stringRequired

The table's UUID or legacy numeric ID.

Response 200

sql_dataobjectOptional

Errors

400 Invalid input · 403 Scope, access or subscription · 409 Conflict: re-read and reconcile. Every error has error, message and code.

Preferences2 operations

The account's workspace preferences.

GET/api/ui/preferences

Read workspace preferences

workspace:readAny signed-in account · reaches account
Request and response

The account's browser workspace preferences.

Response 200

preferencesobjectOptional
updatedAtstringOptional
PUT/api/ui/preferences

Save workspace preferences

workspace:writeAny signed-in account · reaches account
Request and response

Body

preferencesobjectRequired

Response 200

preferencesobjectOptional
updatedAtstringOptional
Workspaces1 operations

The account's workspaces.

GET/api/workspaces

List workspaces

workspace:readAny signed-in account · reaches report
Request and response

The account's personal workspaces.

Response 200

Service2 operations

Health and the API description.

GET/api/openapi.json

Read the OpenAPI document

workspace:readAny signed-in account · reaches docs
Request and response

The OpenAPI 3.1 description of this deployment's token-callable operations, with request and response schemas, examples, token scopes (x-unity-scope) and report access labels (x-unity-access). Generate a client from it, or give it to an AI agent.

Response 200

An OpenAPI 3.1 document.

GET/health

Check service health

No Unity token required; endpoint checks may applyNo sign-in · reaches platform
Request and response

Answers while the web process is serving. It does not check the database or sources.

Response 200

statusstringOptional
enum: ["healthy"]

Example response

JSON
{
  "status": "healthy"
}
Sign-in and API keys19 operations

Browser sign-in, sessions and API key management.

POST/api/auth/email-login

Email login

No Unity token required; endpoint checks may applyNo sign-in · reaches account
POST/api/auth/email-login/verify

Verify email login

No Unity token required; endpoint checks may applyNo sign-in · reaches account
POST/api/auth/google

Google login

No Unity token required; endpoint checks may applyNo sign-in · reaches account
POST/api/auth/logout

Logout

Browser session requiredAny signed-in account · reaches account
POST/api/auth/logout-all

Logout all

Browser session requiredAny signed-in account · reaches account
POST/api/auth/register-and-checkout

Register and checkout

No Unity token required; endpoint checks may applyNo sign-in · reaches account
POST/api/auth/registration/start

Start registration

No Unity token required; endpoint checks may applyNo sign-in · reaches account
POST/api/auth/registration/verify

Verify registration

No Unity token required; endpoint checks may applyNo sign-in · reaches account
POST/api/auth/request-password-reset

Request password reset

No Unity token required; endpoint checks may applyNo sign-in · reaches account
POST/api/auth/reset-password

Reset password

No Unity token required; endpoint checks may applyNo sign-in · reaches account
GET/api/auth/session

Session details

Browser session requiredAny signed-in account · reaches account
GET/api/auth/sessions

Browser sessions

Browser session requiredAny signed-in account · reaches account
DELETE/api/auth/sessions/{credential_id}

End browser session

Browser session requiredAny signed-in account · reaches account

Path: credential_id (string)

GET/api/auth/tokens

API tokens

Browser session requiredAny signed-in account · reaches account
POST/api/auth/tokens

API tokens

Browser session requiredAny signed-in account · reaches account
DELETE/api/auth/tokens/{credential_id}

Revoke token

Browser session requiredAny signed-in account · reaches account

Path: credential_id (string)

GET/api/auth/validate

Validate session

Browser session requiredAny signed-in account · reaches account
POST/login

Login

No Unity token required; endpoint checks may applyNo sign-in · reaches account
POST/register

Register

No Unity token required; endpoint checks may applyNo sign-in · reaches account
Organizations and teams29 operations

Organizations, teams, members and invitations.

GET/api/collaboration

Overview

Browser session requiredAny signed-in account · reaches organization
DELETE/api/collaboration/invitations/{invitation_id}

Revoke invitation

Browser session requiredAdmin or Owner · reaches organization

Path: invitation_id (string)

POST/api/collaboration/invitations/accept

Accept invitation

Browser session requiredAny signed-in account · reaches organization
POST/api/collaboration/organizations

Create organization

Browser session requiredAny signed-in account · reaches organization
GET/api/collaboration/organizations/{org_id}

Organization details

Browser session requiredAny signed-in account · reaches organization

Path: org_id (string)

PATCH/api/collaboration/organizations/{org_id}

Update organization

Browser session requiredAdmin or Owner · reaches organization

Path: org_id (string)

GET/api/collaboration/organizations/{org_id}/audit

Audit events

Browser session requiredAdmin or Owner · reaches organization

Path: org_id (string)

POST/api/collaboration/organizations/{org_id}/invitations

Invite org

Browser session requiredAdmin or Owner · reaches organization

Path: org_id (string)

PUT/api/collaboration/organizations/{org_id}/members/{member_id}

Update org member

Browser session requiredAdmin or Owner · reaches organization

Path: org_id (string), member_id (string)

POST/api/collaboration/organizations/{org_id}/recover-report

Recover report

Browser session requiredOwner · reaches organization, sharing

Path: org_id (string)

POST/api/collaboration/organizations/{org_id}/teams

Create team

Browser session requiredAdmin or Owner · reaches organization

Path: org_id (string)

POST/api/collaboration/organizations/{org_id}/teams/{team_id}/invitations

Invite team

Browser session requiredAdmin or Owner · reaches organization

Path: org_id (string), team_id (string)

POST/api/collaboration/reports/{report_id}/owner

Transfer owner

Browser session requiredOwner · reaches sharing

Path: report_id (string)

GET/api/collaboration/reports/{report_id}/page-shares

Report page shares

Browser session requiredAdmin or Owner · reaches pages, sharing

Path: report_id (string)

GET/api/collaboration/reports/{report_id}/pages/{page_id}/sharing

Page sharing summary

Browser session requiredAny access to the page · reaches pages, sharing

Path: report_id (string), page_id (string)

PUT/api/collaboration/reports/{report_id}/pages/{page_id}/sharing/mode

Set page mode

Browser session requiredAdmin or Owner · reaches pages, sharing

Path: report_id (string), page_id (string)

DELETE/api/collaboration/reports/{report_id}/pages/{page_id}/sharing/teams/{team_id}

Share page team

Browser session requiredAdmin or Owner · reaches organization, pages, sharing

Path: report_id (string), page_id (string), team_id (string)

PUT/api/collaboration/reports/{report_id}/pages/{page_id}/sharing/teams/{team_id}

Share page team

Browser session requiredAdmin or Owner · reaches organization, pages, sharing

Path: report_id (string), page_id (string), team_id (string)

DELETE/api/collaboration/reports/{report_id}/pages/{page_id}/sharing/users/{grantee_id}

Share page user

Browser session requiredAdmin or Owner · reaches pages, sharing

Path: report_id (string), page_id (string), grantee_id (string)

PUT/api/collaboration/reports/{report_id}/pages/{page_id}/sharing/users/{grantee_id}

Share page user

Browser session requiredAdmin or Owner · reaches pages, sharing

Path: report_id (string), page_id (string), grantee_id (string)

GET/api/collaboration/reports/{report_id}/sharing

Report sharing

Browser session requiredView access · reaches sharing

Path: report_id (string)

DELETE/api/collaboration/reports/{report_id}/teams/{team_id}

Share team

Browser session requiredAdmin or Owner · reaches organization, sharing

Path: report_id (string), team_id (string)

PUT/api/collaboration/reports/{report_id}/teams/{team_id}

Share team

Browser session requiredAdmin or Owner · reaches organization, sharing

Path: report_id (string), team_id (string)

DELETE/api/collaboration/reports/{report_id}/users/{grantee_id}

Share user

Browser session requiredAdmin or Owner · reaches sharing

Path: report_id (string), grantee_id (string)

PUT/api/collaboration/reports/{report_id}/users/{grantee_id}

Share user

Browser session requiredAdmin or Owner · reaches sharing

Path: report_id (string), grantee_id (string)

GET/api/collaboration/teams/{team_id}

Team details

Browser session requiredAny signed-in account · reaches organization

Path: team_id (string)

PATCH/api/collaboration/teams/{team_id}

Update team

Browser session requiredAdmin or Owner · reaches organization

Path: team_id (string)

PUT/api/collaboration/teams/{team_id}/members/{member_id}

Update team member

Browser session requiredAdmin or Owner · reaches organization

Path: team_id (string), member_id (string)

GET/api/collaboration/users/by-email

User by email

Browser session requiredAdmin or Owner · reaches sharing
Public page links6 operations

Anonymous, read-only viewing of one HTML page by its link token (no sign-in).

GET/api/public/pages/{token}/assets/{asset_id}

Asset

No Unity token required; endpoint checks may applyNo sign-in · reaches files, pages

Path: token (string), asset_id (string)

POST/api/public/pages/{token}/data

Data

No Unity token required; endpoint checks may applyNo sign-in · reaches model, pages, source

Path: token (string)

POST/api/public/pages/{token}/filter-values

Filter values

No Unity token required; endpoint checks may applyNo sign-in · reaches model, pages, source

Path: token (string)

GET/api/public/pages/{token}/live

Live

No Unity token required; endpoint checks may applyNo sign-in · reaches pages

Path: token (string)

GET/api/public/pages/{token}/page

Page

No Unity token required; endpoint checks may applyNo sign-in · reaches pages

Path: token (string)

GET/api/public/pages/{token}/version

Version

No Unity token required; endpoint checks may applyNo sign-in · reaches pages

Path: token (string)

Public page link management4 operations

Create and remove a page's public link (browser only).

POST/api/collaboration/public-link/open

Open link

Browser session requiredAny signed-in account · reaches pages
POST/api/collaboration/reports/{report_id}/pages/{page_id}/public-link

Create link

Browser session requiredAdmin or Owner · reaches pages, sharing

Path: report_id (string), page_id (string)

GET/api/collaboration/reports/{report_id}/pages/{page_id}/public-link

Read link

Browser session requiredAdmin or Owner · reaches pages, sharing

Path: report_id (string), page_id (string)

DELETE/api/collaboration/reports/{report_id}/pages/{page_id}/public-link

Revoke link

Browser session requiredAdmin or Owner · reaches pages, sharing

Path: report_id (string), page_id (string)

Account administration12 operations

Platform administration.

GET/api/admin/assistant-model

Assistant model

Browser session requiredPlatform administrator · reaches platform
PUT/api/admin/assistant-model

Assistant model

Browser session requiredPlatform administrator · reaches platform
GET/api/admin/context-registry

Get context registry

Browser session requiredPlatform administrator · reaches chat, platform
POST/api/demo-info-nuke

Demo info nuke

Browser session requiredPlatform administrator · reaches account, platform
GET/api/subscription-plan

Get active plan

No Unity token required; endpoint checks may applyNo sign-in · reaches account
POST/api/subscription-plan

Set active plan

Browser session requiredPlatform administrator · reaches platform
GET/api/users

Get all users

Browser session requiredPlatform administrator · reaches account, platform
POST/api/users/admin/promote

Promote user to admin

Browser session requiredPlatform administrator · reaches account, platform
POST/api/users/delete

Delete user

Browser session requiredPlatform administrator · reaches account, platform
POST/api/users/subscription/activate

Activate subscription

Browser session requiredPlatform administrator · reaches account, platform
POST/api/users/subscription/cancel

Cancel subscription

Browser session requiredPlatform administrator · reaches account, platform
POST/api/users/testers

Create tester

Browser session requiredPlatform administrator · reaches account, organization, platform
Billing6 operations

Subscriptions and checkout.

POST/api/stripe/cancel-subscription

Cancel subscription

Browser session requiredAny signed-in account · reaches account
POST/api/stripe/create-checkout-session

Create checkout session

Browser session requiredAny signed-in account · reaches account
POST/api/stripe/create-portal-session

Create portal session

Browser session requiredAny signed-in account · reaches account
POST/api/stripe/renew-subscription

Renew subscription

Browser session requiredAny signed-in account · reaches account
GET/api/stripe/subscription-details

Get subscription details

Browser session requiredAny signed-in account · reaches account
POST/api/stripe/webhook

Stripe webhook

No Unity token required; endpoint checks may applyNo sign-in · reaches account
Analysis Services sign-in5 operations

Browser sign-in to Analysis Services.

GET/api/connections/analysis-services/auth/callback

Callback

Browser session requiredAny signed-in account · reaches account
POST/api/connections/analysis-services/auth/cancel

Cancel

Browser session requiredAny signed-in account · reaches account
POST/api/connections/analysis-services/auth/disconnect

Disconnect

Browser session requiredAny signed-in account · reaches account
POST/api/connections/analysis-services/auth/start

Start

Browser session requiredAny signed-in account · reaches account
GET/api/connections/analysis-services/auth/status

Status

Browser session requiredAny signed-in account · reaches account
Source sign-in6 operations

Browser sign-in to data sources.

GET/api/connections/browser-auth/callback

Callback

Browser session requiredAny signed-in account · reaches account
POST/api/connections/browser-auth/cancel

Cancel

Browser session requiredAny signed-in account · reaches account
POST/api/connections/browser-auth/disconnect

Disconnect

Browser session requiredAny signed-in account · reaches account
POST/api/connections/browser-auth/settings

Settings

Browser session requiredAny signed-in account · reaches source
POST/api/connections/browser-auth/start

Start

Browser session requiredAny signed-in account · reaches account
POST/api/connections/browser-auth/status

Status

Browser session requiredAny signed-in account · reaches account
Contact1 operations

The public contact form.

POST/api/contact

Contact form

No Unity token required; endpoint checks may applyNo sign-in · reaches platform
Site telemetry1 operations

Anonymous page hits.

POST/api/page-hit

Record page hit

No Unity token required; endpoint checks may applyNo sign-in · reaches platform

Questions about your environment? Contact us.