HTTP API reference
Every HTTP operation an API key can call, with parameters, responses, access and errors.
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.
268 operations
Reports14 operations
Create, list, rename and delete reports; read a report's workspace, catalog and instructions.
/api/instructionsSave report instructions
workspace:writeEdit access · reaches reportRequest and response
Replaces the report's instructions. An empty string clears them. Edit access.
Body
reportIdstringRequiredReport ID.
instructionsstringRequiredAt most 1,500 characters.
maxLength:1500
Example request body
{
"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.
/api/instructions/{report_id}Read report instructions
workspace:readView access · reaches reportRequest and response
The report's lasting guidance to the assistant (terminology, units, conventions).
Parameters
report_idpath · stringRequired
Response 200
instructionsstringOptional
Example response
{
"instructions": "Amounts are USD. Fiscal year starts in May."
}
Errors
403 Scope, access or subscription. Every error has error, message and code.
/api/reportsList reports
workspace:readAny signed-in account · reaches reportRequest and response
Reports the caller can open, newest first, including ones being deleted (with deletion).
Response 200
Example response
[
{
"id": "9af3fb53-34e2-4e88-a953-ffdecdeece82",
"reportName": "Sales overview",
"accessLevel": "Owner",
"ownerFullName": "Alex Morgan",
"createdAt": "2026-10-13T10:52:04.120Z",
"sourceCount": 1
}
]
/api/reports/{report_id}/catalogSearch a report
workspace:readView access · reaches model, pagesRequest 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 · stringRequiredkindquery · stringOptionalqueryquery · stringOptionalSearch text over titles and queries.
pageIdquery · stringOptionalRestrict to one page: its UUID or numeric ID.
currentPageIdquery · stringOptionalThe page the caller is looking at (marks it in the result).
visualKeyquery · array<string>Optionaldetailquery · stringOptionaltrue adds bindings, lineage and filters per visual.
offsetquery · integerOptionallimitquery · integerOptional
Response 200
statusstringOptional- enum:
["success"] itemsarray<object>OptionaltotalintegerOptionaloffsetintegerOptionalcompletebooleanOptionalnextOffsetinteger | nullOptionalmissingVisualKeysarray<string>Optional
Errors
400 Invalid input · 403 Scope, access or subscription. Every error has error, message and code.
/api/reports/{report_id}Delete a report
workspace:writeOwner · reaches reportRequest 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.
/api/reports/{report_id}/deletionFollow a report deletion
workspace:readOwner · reaches reportRequest and response
Parameters
report_idpath · stringRequired
Response 200
deletionobjectOptional
Errors
404 Not found. Every error has error, message and code.
/api/reports/{report_id}/livePoll a report for changes
workspace:readAny access to the page · reaches chat, pages, reportRequest 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 · stringRequiredvisualsPagequery · integerOptionalNumeric page ID whose visualsRevision to include.
Response 200
reportIdstringOptionalReport ID.
accessLevelstringOptionalpagesVersionstringOptionalmodelRevisionintegerOptionalpagesFingerprintstringOptionalpageobject | nullOptionalvisualsPageIdinteger | nullOptionalvisualsRevisionstring | nullOptionalchatobjectOptional
Errors
403 Scope, access or subscription. Every error has error, message and code.
/api/reports/{report_id}/nameRename a report
workspace:writeEdit access · reaches reportRequest and response
Parameters
report_idpath · stringRequired
Body
reportNamestringRequired1 to 50 characters.
minLength:1maxLength:50
Example request body
{
"reportName": "Sales overview FY27"
}
Response 200
reportNamestringOptionalmessagestringOptional
Errors
400 Invalid input · 403 Scope, access or subscription · 404 Not found. Every error has error, message and code.
/api/reports/{report_id}/versionsList report versions
workspace:readAny access to the page · reaches history, model, pages, reportRequest 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 · stringRequiredpageIdquery · stringOptionalA page's pageId: only that page's versions and its filters (page Edit is enough).
beforeVersionquery · integerOptionalnextBeforeVersion from the previous list, for older entries.
expandquery · integerOptionalAn entry's version: its versions one by one, each as an entry of its own.
Response 200
headinteger | nullOptionalThe latest version.
versionsarray<object>OptionalnextBeforeVersioninteger | nullOptionaldeletedPagesarray<object>OptionalPages deleted since history started that are still gone, newest first (the first list of the whole report).
Example response
{
"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.
/api/reports/{report_id}/versions/{version}Read a report version
workspace:readAny access to the page · reaches history, model, pages, reportRequest 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 · stringRequiredversionpath · integerRequiredpageIdquery · stringOptionalA 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.
/api/reports/{report_id}/versions/{version}/restoreRestore a report version
workspace:writeAny access to the page · reaches history, model, pages, reportRequest 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 · stringRequiredversionpath · integerRequired
Body
pageIdstring | nullOptionalA page's pageId: only that page and its filters.
dryRunbooleanOptionalexpectedVersioninteger | nullOptionalexpectedVersion from the dry run.
expectedWarningsstring | nullOptionalexpectedWarnings from the dry run.
Example request body
{
"pageId": null,
"dryRun": false,
"expectedVersion": 42,
"expectedWarnings": "3f9a1c0b7d2e4a65"
}
Response 200
dryRunbooleanOptionalappliedbooleanOptionalWhether the restore changed anything (it made a version).
reportVersionintegerOptionalThe new version the restore made; absent when it changed nothing.
restoredFromintegerOptionalpageIdstring | nullOptionalexpectedVersionintegerOptionalexpectedWarningsstringOptionalchangesarray<object>Optionalwarningsarray<object>OptionalmoreintegerOptionalHow many changes beyond the first 300 are left out.
Example response
{
"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.
/api/reports/{report_id}/versions/diffCompare report versions
workspace:readAny access to the page · reaches history, model, pages, reportRequest 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 · stringRequiredfromquery · integerRequiredThe earlier version.
toquery · integerOptionalThe later version.
pageIdquery · stringOptionalA page's pageId: only that page's versions and its filters (page Edit is enough).
Response 200
fromVersionintegerOptionaltoVersioninteger | nullOptionalchangesarray<object>OptionalmoreintegerOptionalHow many changes beyond the first 300 are left out.
Example response
{
"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.
/api/reports/{report_id}/workspaceRead a report workspace
workspace:readAny access to the page · reaches chat, model, pages, reportRequest 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
reportIdstringOptionalReport ID.
reportNamestringOptionalhasPermissionbooleanOptionalaccessLevelstringOptionalcontentEditbooleanOptionalpagesarray<value>Optionalconnectionsarray<object>Optional
Example response
{
"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.
/api/reports/createCreate a report
workspace:writeAny signed-in account · reaches reportRequest and response
A new report owned by the caller, with one empty canvas page and one conversation.
Body
reportNamestringRequired1 to 50 characters.
minLength:1maxLength:50clientRequestIdstringOptionalOptional 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
{
"reportName": "Sales overview",
"clientRequestId": "sales-overview-1"
}
Response 201
reportIdstringOptionalReport ID.
defaultPageIdintegerOptionalNumeric ID of the first page.
defaultPageUidstringOptionalUUID of the first page.
messagestringOptional
Example response
{
"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.
/api/pagesList a report's pages
workspace:readAny access to the page · reaches pagesRequest 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 · stringRequiredReport ID. Also accepted as
report_id.
Response 200
PageIDintegerOptionalPageUIDstringOptionalPageNamestringOptionalPageKindstringOptional- enum:
["report","html"] ReportIDstringOptionalHiddenbooleanOptional
Errors
400 Invalid input · 403 Scope, access or subscription. Every error has error, message and code.
/api/pages/addCreate a page
workspace:writeEdit access · reaches pagesRequest 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
reportIdstringRequiredReport ID.
pageNamestringRequiredAlias: newPageName.
pageKindstringOptional- enum:
["report","html"]default:"report" clientRequestIdstringOptionalRetry key: a UUID or any string up to 64 characters.
maxLength:64includeReceiptbooleanOptionalReturn the receipt instead of [page].
default:false
Example request body
{
"reportId": "9af3fb53-34e2-4e88-a953-ffdecdeece82",
"pageName": "Spending",
"clientRequestId": "page-spending-1"
}
Response 200
Example response
[
{
"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.
/api/pages/deleteDelete a page
workspace:writeEdit access · reaches pagesRequest 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
reportIdstringRequiredReport ID.
pageIdstringRequiredThe 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.
pagevalueOptionalreportIdstringOptionalReport ID.
resourceTypestringOptionalmutationobjectOptionalchangeobjectOptionalcanvasBoundsobjectOptional
Errors
403 Scope, access or subscription · 422 Cannot be applied. Every error has error, message and code.
/api/pages/duplicateDuplicate a page
workspace:writeEdit access · reaches pagesRequest and response
Copies a page's visual definitions, layout and saved filters into a new page.
Body
reportIdstringRequiredReport ID.
sourcePageIdstringRequiredThe page: its UUID or its numeric ID (every page parameter accepts either).
newPageNamestringRequiredclientRequestIdstringOptional
Example request body
{
"reportId": "9af3fb53-34e2-4e88-a953-ffdecdeece82",
"sourcePageId": 890,
"newPageName": "Spending copy"
}
Response 200
pagevalueOptionalreportIdstringOptionalReport ID.
resourceTypestringOptionalmutationobjectOptionalchangeobjectOptionalcanvasBoundsobjectOptionalsourcePageobjectOptionalduplicatedVisualsarray<object>OptionallockedViewportobjectOptional
Errors
403 Scope, access or subscription · 409 Conflict: re-read and reconcile · 422 Cannot be applied. Every error has error, message and code.
/api/pages/updateRename a page
workspace:writeEdit access · reaches pagesRequest and response
Body
reportIdstringRequiredReport ID.
pageIdstringRequiredThe page: its UUID or its numeric ID (every page parameter accepts either).
pageNamestringRequiredAlias: 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.
pagevalueOptionalreportIdstringOptionalReport ID.
resourceTypestringOptionalmutationobjectOptionalchangeobjectOptionalcanvasBoundsobjectOptional
Errors
403 Scope, access or subscription · 422 Cannot be applied. Every error has error, message and code.
/api/pages/viewport-settingsRead a page's canvas settings
workspace:readAny access to the page · reaches pagesRequest and response
Parameters
reportIdquery · stringRequiredReport ID. Also accepted as
report_id.pageIdquery · stringRequiredThe page: its UUID or its numeric ID (every page parameter accepts either). Also accepted as
page_id.
Response 200
reportIdstringOptionalReport ID.
pageIdintegerOptionallockedViewportvalueOptional
Errors
400 Invalid input · 403 Scope, access or subscription · 404 Not found · 422 Cannot be applied. Every error has error, message and code.
/api/pages/viewport-settingsChange a page's canvas size and colors
workspace:writeEdit access · reaches pagesRequest 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
reportIdstringRequiredReport ID.
pageIdstringRequiredThe page: its UUID or its numeric ID (every page parameter accepts either).
lockedViewportvalueOptional
Example request body
{
"reportId": "9af3fb53-34e2-4e88-a953-ffdecdeece82",
"pageId": 890,
"lockedViewport": {
"width": 1600,
"height": 900,
"backgroundColor": "#ffffff"
}
}
Response 200
pagevalueOptionalreportIdstringOptionalReport ID.
resourceTypestringOptionalmutationobjectOptionalchangeobjectOptionalcanvasBoundsobjectOptionalstatusstringOptionalpageIdintegerOptionalpageLayoutobjectOptionallockedViewportvalueOptional
Errors
403 Scope, access or subscription · 422 Cannot be applied. Every error has error, message and code.
/api/pages/visual-shell-manifestRead a page's visual layout
workspace:readAny access to the page · reaches model, pagesRequest 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 · stringRequiredReport ID. Also accepted as
report_id.pageIdquery · stringOptionalThe page: its UUID or its numeric ID (every page parameter accepts either). Also accepted as
page_id.initialPagequery · stringOptionalRead the first visible page when pageId is omitted.
Response 200
visualsarray<object>Optionalconnectionsarray<object>OptionalshellCountsobjectOptionalpageobjectOptional
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.
/api/barGraphs/updateUpdate a bar chart Compatibility · use POST /api/visuals/update
workspace:writeEdit access to the page · reaches pagesRequest and response
Response 200
/api/dataCards/updateUpdate a data card Compatibility · use POST /api/visuals/update
workspace:writeEdit access to the page · reaches pagesRequest and response
Response 200
/api/dataTables/updateUpdate a table Compatibility · use POST /api/visuals/update
workspace:writeEdit access to the page · reaches pagesRequest and response
Response 200
/api/datachatsList your conversations on a page
workspace:readAny access to the page · reaches chatRequest and response
Your own report chats on a page (conversations are private to their creator).
Parameters
reportIdquery · stringRequiredReport ID.
pageIdquery · stringRequiredThe page: its UUID or numeric ID.
Response 200
DataChatIDintegerOptionalNamestringOptionalPageIDintegerOptional
Errors
400 Invalid input · 403 Scope, access or subscription · 404 Not found. Every error has error, message and code.
/api/datachats/addCreate a conversation
workspace:writeAny access to the page · reaches chatRequest and response
A new report chat for assistant runs (POST /api/agent/runs takes its DataChatID).
Body
reportIdstringRequiredReport ID.
activePagestringRequiredThe page: its UUID or numeric ID.
namestringOptionalclientRequestIdstringOptional
Example request body
{
"reportId": "9af3fb53-34e2-4e88-a953-ffdecdeece82",
"activePage": 890,
"name": "API exploration"
}
Response 201
DataChatIDintegerOptionalNamestringOptionalPageIDintegerOptionalcreatedNowbooleanOptionalFalse 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.
/api/declarativeCharts/dataRead a chart's data Compatibility · use POST /api/reports/{report_id}/visual-data
workspace:readAny access to the page · reaches model, pagesRequest and response
Response 200
/api/declarativeCharts/updateUpdate a chart Compatibility · use POST /api/visuals/update
workspace:writeEdit access to the page · reaches pagesRequest and response
Response 200
/api/declarativecharts/deleteDelete a chart Compatibility · use POST /api/visuals/delete
workspace:writeEdit access to the page · reaches pagesRequest and response
Response 200
/api/lineGraphs/updateUpdate a line chart Compatibility · use POST /api/visuals/update
workspace:writeEdit access to the page · reaches pagesRequest and response
Response 200
/api/matrices/dataRead a matrix's data Compatibility · use POST /api/reports/{report_id}/visual-data
workspace:readAny access to the page · reaches model, pagesRequest and response
Response 200
/api/matrices/deleteDelete a matrix Compatibility · use POST /api/visuals/delete
workspace:writeEdit access to the page · reaches pagesRequest and response
Response 200
/api/matrices/updateUpdate a matrix Compatibility · use POST /api/visuals/update
workspace:writeEdit access to the page · reaches pagesRequest and response
Response 200
/api/pieCharts/updateUpdate a pie chart Compatibility · use POST /api/visuals/update
workspace:writeEdit access to the page · reaches pagesRequest and response
Response 200
/api/scatterPlots/updateUpdate a scatter plot Compatibility · use POST /api/visuals/update
workspace:writeEdit access to the page · reaches pagesRequest and response
Response 200
/api/visuals/capabilitiesRead visual capabilities
workspace:readAny signed-in account · reaches docsRequest 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
schemaVersionintegerOptionalkindsobjectOptional
Errors
400 Invalid input. Every error has error, message and code.
/api/visuals/copyCopy a visual
workspace:writeEdit access to the page · reaches pagesRequest and response
Copies a visual (definition, appearance and filters) to a page of the same report.
Body
reportIdstringRequiredReport ID.
typestringRequiredNative 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 | integerRequiredThe visual's UUID (visualUid), or its legacy numeric ID.
pageIdstringRequiredThe page: its UUID or numeric ID.
positionobjectOptionalLogical canvas pixels on the page (default page 1280x720). Omitted: Unity finds free space.
Response 200
idvalueOptionalreportIdstringOptionalReport ID.
pageIdintegerOptionalvisualvalueOptionalmutationobjectOptionalchangeobjectOptional
Errors
403 Scope, access or subscription · 409 Conflict: re-read and reconcile · 422 Cannot be applied. Every error has error, message and code.
/api/visuals/createCreate a visual
workspace:writeEdit access to the page · reaches pagesRequest 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
reportIdstringRequiredReport ID.
typestringRequiredNative 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"]pageIdstringRequiredThe page: its UUID or numeric ID.
definitionobjectRequiredPer kind: GET /api/visuals/capabilities?kind={kind} returns the exact definition, changes and appearance schemas, required fields and rendering semantics.
positionobjectOptionalLogical canvas pixels on the page (default page 1280x720). Omitted: Unity finds free space.
Example request body
{
"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.
persistedbooleanOptionalvisualUidstringOptionalvisual_idstringOptionalvisual_typestringOptionalvisualvalueOptionalmutationobjectOptionalchangeobjectOptionalThe visual before and after the change (null: created, deleted), for the tabs that show it.
layoutobjectOptionalGeometry feedback: canvasBounds, fitsWithinPage, overflowPixels, overlaps.
warningsarray<object>OptionalreportIdstringOptionalReport ID.
visual_dataobjectOptionalThe 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.
/api/visuals/deleteDelete a visual
workspace:writeEdit access to the page · reaches pagesRequest and response
Deletes one visual. Restoring the report version listed before the delete brings it back.
Body
reportIdstringRequiredReport ID.
typestringRequiredNative 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 | integerRequiredThe visual's UUID (visualUid), or its legacy numeric ID.
expectedRevisionstringOptionalclientRequestIdstringOptionalRetry 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.
persistedbooleanOptionalvisualUidstringOptionalvisual_idstringOptionalvisual_typestringOptionalvisualvalueOptionalmutationobjectOptionalchangeobjectOptionalThe visual before and after the change (null: created, deleted), for the tabs that show it.
layoutobjectOptionalGeometry feedback: canvasBounds, fitsWithinPage, overflowPixels, overlaps.
warningsarray<object>OptionalreportIdstringOptionalReport ID.
visual_dataobjectOptionalThe 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.
/api/visuals/delete-batchDelete several visuals
workspace:writeEdit access to the page · reaches pagesRequest and response
Deletes 1 to 100 visuals in one transaction.
Body
reportIdstringRequiredReport ID.
targetsarray<object>RequiredclientRequestIdstringOptionalRetry 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>OptionalOne 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.
/api/visuals/page-stateRead every visual on a page
workspace:readAny access to the page · reaches pagesRequest 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 · stringRequiredReport ID. Also accepted as
report_id.pageIdquery · stringRequiredThe page: its UUID or numeric ID. Also accepted as
page_id,pageUid.
Response 200
reportIdstringOptionalReport ID.
pageIdintegerOptionalpageUidstringOptionalvisualsRevisionstringOptionalvisualsarray<value>Optional
Errors
403 Scope, access or subscription · 422 Cannot be applied. Every error has error, message and code.
/api/visuals/positionsMove and resize visuals
workspace:writeEdit access to the page · reaches pagesRequest and response
Saves 1 to 100 visuals' positions and z-order in one transaction.
Body
reportIdstringRequiredReport ID.
targetsarray<object>RequiredclientRequestIdstringOptionalRetry 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
{
"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>OptionalOne 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.
/api/visuals/previewPreview a visual
workspace:writeEdit access to at least one page (or report View access) · reaches model, pagesRequest 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
reportIdstringRequiredReport ID.
typestringRequiredNative 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"]definitionobjectRequiredPer 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_dataobjectOptionaloutputsarray<object>OptionalThe query's outputs: groups, then values, with the result's types.
generatedSqlstringOptionalThe 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.
/api/visuals/stateRead a visual
workspace:readAny access to the page · reaches pagesRequest and response
A saved visual's authored state (its visual query), its outputs and generatedSql, position and revision, with both page IDs.
Parameters
reportIdquery · stringRequiredReport ID. Also accepted as
report_id.typequery · stringRequiredNative visual kind. Chart presets (bar, line, scatter, pie) are declarativeChart specifications; an older name (barGraph, pieChart, ...) is refused with the current kind.
idquery · string | integerRequiredThe 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.
/api/visuals/updateUpdate a visual
workspace:writeEdit access to the page · reaches pagesRequest 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
reportIdstringRequiredReport ID.
typestringRequiredNative 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 | integerRequiredThe visual's UUID (visualUid), or its legacy numeric ID.
changesobjectRequiredFields to change; GET /api/visuals/capabilities lists them per kind.
expectedRevisionstringOptionalThe revision you read, for example 0x000000000000c356.
refreshDatabooleanOptionalReturn a fresh read.
default:trueclientRequestIdstringOptionalRetry 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
{
"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.
persistedbooleanOptionalvisualUidstringOptionalvisual_idstringOptionalvisual_typestringOptionalvisualvalueOptionalmutationobjectOptionalchangeobjectOptionalThe visual before and after the change (null: created, deleted), for the tabs that show it.
layoutobjectOptionalGeometry feedback: canvasBounds, fitsWithinPage, overflowPixels, overlaps.
warningsarray<object>OptionalreportIdstringOptionalReport ID.
visual_dataobjectOptionalThe 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.
/api/reports/{report_id}/visual-dataRead visuals' data
workspace:readAny access to the page · reaches model, pagesRequest 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
pageIdstringRequiredThe page: its UUID or numeric ID.
readsarray<object>Required
Example request body
{
"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.
keyintegerOptionalstatusintegerOptionaldataobjectOptionaldonebooleanOptional
Example response
{
"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.
/api/filtersRead the filters on a page
workspace:readAny access to the page · reaches pagesRequest 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 · stringRequiredpageIdquery · stringOptionalThe page's UUID; omit for the report's filters only.
Response 200
filtersarray<object>Optionalsortsarray<object>OptionaldiffersbooleanOptionalfilterRevisionintegerOptional
Errors
400 Invalid input · 403 Scope, access or subscription. Every error has error, message and code.
/api/filtersChange filters for everyone
workspace:writeAny access to the page · reaches pagesRequest 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
reportIdstringRequiredfiltersarray<object>Requiredremovearray<string>RequiredfilterRevisionintegerRequired
Example request body
{
"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>Optionalremovedarray<string>OptionalfilterRevisionintegerOptional
Errors
400 Invalid input · 403 Scope, access or subscription · 409 Conflict: re-read and reconcile. Every error has error, message and code.
/api/filters/valuesList the values a filter can choose
workspace:readAny access to the page · reaches pagesRequest 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 · stringRequiredpageIdquery · stringRequiredThe page's UUID.
fieldUidquery · stringRequiredvisualUidquery · stringOptionalfilterUidquery · stringOptionalThe filter being edited.
qquery · stringOptionalSearch text (contains, ignoring case).
offsetquery · integerOptionallimitquery · integerOptional
Response 200
fieldUidstringOptionalfieldstringOptionalvaluesarray<value>OptionalmanualEntryOnlybooleanOptionaloffsetintegerOptionallimitintegerOptionalhasMorebooleanOptionalnextOffsetinteger | nullOptional
Errors
400 Invalid input · 403 Scope, access or subscription. Every error has error, message and code.
/api/my-viewSet your own view
workspace:writeAny access to the page · reaches pagesRequest 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
reportIdstringRequiredvaluesarray<object>Requiredsortsarray<object>OptionalresetbooleanRequired
Response 200
filtersarray<object>Optionalsortsarray<object>OptionaldiffersbooleanOptional
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.
/api/reports/{report_id}/data-modelRead a report's data model
workspace:readEdit access to at least one page (or report View access) · reaches model, pagesRequest 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
statusstringOptionalmodelobjectOptionalThe report's semantic model: the namespace report SQL reads.
/api/reports/{report_id}/data-model/calculated-tablesCreate or edit a calculated table
workspace:writeEdit access · reaches modelRequest 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
entityKeystringRequiredIts report name: lowercase letters, digits and underscores.
sqlstringRequiredOne SELECT or WITH statement over the report's tables.
entityNamestringOptionalDisplay name.
descriptionstringOptionalexpectedModelRevisionintegerRequiredThe model revision you inspected. A stale revision answers 409 model_conflict.
minimum:0confirmbooleanOptionaltrue makes the change after 409 in_use.
Example request body
{
"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
statusstringOptionalmodelobjectOptionalThe 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.
/api/reports/{report_id}/data-model/calculated-tables/{entity_key}Delete a calculated table
workspace:writeEdit access · reaches modelRequest 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 · stringRequiredentity_keypath · stringRequired
Body
expectedModelRevisionintegerRequiredThe model revision you inspected. A stale revision answers 409 model_conflict.
minimum:0confirmbooleanOptionaltrue makes the change after 409 in_use.
Response 200
statusstringOptionalmodelobjectOptionalThe 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.
/api/reports/{report_id}/data-model/fields/{field_uid}Remove a field from the model
workspace:writeEdit access · reaches modelRequest 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 · stringRequiredfield_uidpath · stringRequired
Body
expectedModelRevisionintegerOptionalThe model revision you inspected. A stale revision answers 409 model_conflict.
minimum:0confirmbooleanOptionaltrue makes the change after 409 in_use.
checkbooleanOptionaltrue 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.
/api/reports/{report_id}/data-model/queryQuery the model (preview)
workspace:readView access · reaches modelRequest 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
sqlstringRequiredReport SQL (DuckDB).
rowLimitintegerOptional
Example request body
{
"sql": "SELECT region, COUNT(*) AS n FROM dbo_customers GROUP BY region",
"rowLimit": 10
}
Response 200
columnsarray<string>Optionalrowsarray<array<value>>Optionalcolumn_metadataarray<value>OptionalcolumnDetailsarray<object>Optional
Errors
400 Invalid input · 409 Conflict: re-read and reconcile. Every error has error, message and code.
/api/reports/{report_id}/data-model/relationshipsReplace the report's relationships
workspace:writeEdit access · reaches modelRequest 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>RequiredexpectedModelRevisionintegerRequiredThe model revision you inspected. A stale revision answers 409 model_conflict.
minimum:0confirmbooleanOptionaltrue makes the change after 409 in_use.
entityLayoutsobjectOptionalOptional diagram positions by entity key.
Example request body
{
"expectedModelRevision": 3,
"relationships": [
{
"fromEntityKey": "dbo_transactions",
"fromColumn": "customer_id",
"toEntityKey": "dbo_customers",
"toColumn": "customer_id",
"isActive": true
}
]
}
Response 200
statusstringOptionalmodelobjectOptionalThe 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.
/api/reports/{report_id}/data-model/sources/{connection_id}Remove a source from the model
workspace:writeEdit access · reaches modelRequest 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 · stringRequiredconnection_idpath · integerRequired
Body
expectedModelRevisionintegerOptionalThe model revision you inspected. A stale revision answers 409 model_conflict.
minimum:0confirmbooleanOptionaltrue 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.
/api/reports/{report_id}/data-model/sources/{connection_id}/catalogSearch a source's model
workspace:readView access · reaches modelRequest and response
Entities, fields and relationships of one source, searchable and paged; lighter than the whole model.
Parameters
report_idpath · stringRequiredconnection_idpath · integerRequiredkindquery · stringOptionalqueryquery · stringOptionalSearch by model terminology.
fieldUidquery · array<string>Optionaloffsetquery · integerOptionallimitquery · integerOptionalreportIdquery · stringOptionalCompatibility path only: the report.
Response 200
statusstringOptionalitemsarray<object>OptionaltotalintegerOptionaloffsetintegerOptionalcompletebooleanOptionalnextOffsetinteger | nullOptionalmodelRevisionintegerOptionalsnapshotVersionstringOptionalmissingFieldUidsarray<string>Optional
Errors
400 Invalid input · 403 Scope, access or subscription · 409 Conflict: re-read and reconcile. Every error has error, message and code.
/api/reports/{report_id}/data-model/sources/{connection_id}/definitionsSave a source's fields and measures
workspace:writeEdit access · reaches modelRequest 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 · stringRequiredconnection_idpath · integerRequired
Body
definitionsarray<value | value>RequiredexpectedModelRevisionintegerOptionalThe model revision you inspected. A stale revision answers 409 model_conflict.
minimum:0confirmbooleanOptionaltrue makes the change after 409 in_use.
Example request body
{
"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
statusstringOptionaldefinitionsarray<value | value>OptionalmodelobjectOptional
Errors
400 Invalid input · 404 Not found · 409 Conflict: re-read and reconcile. Every error has error, message and code.
/api/reports/{report_id}/data-model/sources/{connection_id}/editor-contextRead a source's editing context
workspace:readView access · reaches modelRequest 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 · stringRequiredconnection_idpath · integerRequired
Response 200
statusstringOptionalconnectionobjectOptionalschemaobjectOptionalselectedSchemaobjectOptionalselectedTablesarray<string>OptionalsourceModestringOptionalmodelobjectOptionalsuggestedEntitiesarray<object>Optionalentitiesarray<object>Optionalrelationshipsarray<object>Optional
Errors
400 Invalid input · 404 Not found. Every error has error, message and code.
/api/reports/{report_id}/data-model/sources/{connection_id}/entitiesSave a source's entities
workspace:writeEdit access · reaches modelRequest 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 · stringRequiredconnection_idpath · integerRequired
Body
sourceModestringOptionaltables: entities read whole tables; custom_sql: authored queries.
enum:["tables","custom_sql"]selectedTablesarray<string>OptionalTables to model, as discovered (dbo.transactions). Sent without entities, each one with no query yet gets one, and the saved queries stay.
selectedSchemaobjectOptionaltables mode: the selection; columns come from discovery.
entitiesarray<object>OptionalReplaces this source's entities.
relationshipsarray<object>OptionalRelationships within this source.
definitionsarray<value | value>OptionalThis source's reusable fields and measures.
descriptionstring | nullOptionalexpectedModelRevisionintegerOptionalThe model revision you inspected. A stale revision answers 409 model_conflict.
minimum:0confirmbooleanOptionaltrue makes the change after 409 in_use.
finalizeConnectionbooleanOptionalMark the source configured (the editor's Save).
Example request body
{
"sourceMode": "tables",
"selectedTables": [
"dbo.customers",
"dbo.transactions"
],
"selectedSchema": {
"tables": {
"dbo.customers": {},
"dbo.transactions": {}
}
},
"finalizeConnection": true,
"expectedModelRevision": 1
}
Response 200
statusstringOptionalmodelobjectOptional
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.
/api/reports/{report_id}/data-model/sources/{connection_id}/entities/previewPreview an entity query
workspace:readEdit access · reaches model, sourceRequest 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 · stringRequiredconnection_idpath · integerRequired
Body
entitySqlQuerystringOptionalNative-dialect SELECT.
entityKeystringOptionalOr a saved entity.
rowLimitintegerOptional
Example request body
{
"entitySqlQuery": "SELECT TOP 10 * FROM dbo.transactions",
"rowLimit": 10
}
Response 200
statusstringOptionalpreviewobjectOptional
Errors
400 Invalid input · 404 Not found · 409 Conflict: re-read and reconcile. Every error has error, message and code.
/api/reports/{report_id}/data-model/sources/{connection_id}/refresh-modelRefresh an Analysis Services model
workspace:writeEdit access · reaches model, sourceRequest 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 · stringRequiredconnection_idpath · integerRequired
Body
expectedModelRevisionintegerOptionalThe model revision you inspected. A stale revision answers 409 model_conflict.
minimum:0confirmbooleanOptionaltrue 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.
/api/connectionsList your connections
workspace:readAny signed-in account · reaches sourceRequest and response
Connections the caller owns, whether or not a report uses them. Credentials are never returned.
Response 200
idintegerOptionalConnection ID.
ownerUserIdstringOptionalnamestringOptionalserverTypestringOptionalauthTypestring | nullOptionalserverNamestringOptionalEmpty for uploaded-file connections.
databaseNamestring | nullOptionalconnectionTypestring | nullOptional- enum:
["database","api","file"] fileTypestring | nullOptionalcreatedAtstring | nullOptional
/api/connections/{connection_id}/credentialsRead what a connection's credentials page asks for
workspace:readAny signed-in account · reaches sourceRequest 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
connectionIdintegerOptionalnamestringOptionaltypestring | nullOptionalauthTypestring | nullOptionaldatabaseNamestring | nullOptionalcredentialsstring | nullOptional- enum:
["set","missing"] recipientsarray<object>Optionalfieldsarray<object>OptionalreaderSignInbooleanOptionalEach reader signs in with their own account.
Errors
404 Not found. Every error has error, message and code.
/api/connections/{connection_id}/testTest a connection
workspace:writeAny signed-in account · reaches sourceRequest 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
connectionIdintegerOptionalokbooleanOptionalcheckedstringOptional- enum:
["source","configuration"] tablesintegerOptionalTables discovered.
modelobjectOptionalAnalysis Services: the model's cube and counts.
needsCredentialsbooleanOptionalcredentialsUrlstringOptionalerrorstringOptionalThe source's error, without credentials.
sourceAuthobjectOptionalA reader must sign in.
Errors
404 Not found. Every error has error, message and code.
/api/connections/addCreate a connection
workspace:writeAny signed-in account · reaches sourceRequest 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
reportIdstringOptionalAttach to this report (Edit access).
serverTypestringRequiredSource kind; fixed once created.
enum:["SQLServer","Snowflake","Databricks","AnalysisServices","API"]serverNamestringRequiredServer or host (SQL Server: host[,port]; Snowflake: account; API: the provider, FRED, WORLDBANK or USCENSUS).
databaseNamestringOptionalDatabase, catalog, or Analysis Services model.
authTypestringOptionalHow 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"]usernamestringOptionalLogin.
clientIdstringOptionalClient (application) ID of a service principal.
passwordstringOptionalPassword, API key, client secret or access token. Stored encrypted; never returned.
portintegerOptionalconnectionNamestringOptionalDisplay name; generated from server and database when omitted, numbered when taken.
apiKeystringOptionalAPI providers: the provider's key.
accountstringOptionalSnowflake account.
warehousestringOptionalSnowflake warehouse.
schemaNamestringOptionalSnowflake schema.
rolestringOptionalSnowflake role.
privateKeystringOptionalSnowflake key-pair private key (PEM).
privateKeyPassphrasestringOptionaloauthClientIdstringOptionaloauthClientSecretstringOptionaloauthTokenUrlstringOptionaloauthScopestringOptionalhttpPathstringOptionalDatabricks SQL warehouse HTTP path.
databricksSchemastringOptionalDatabricks schema.
tenantIdstringOptionalMicrosoft Entra tenant.
databricksClientIdstringOptionaldatabricksClientSecretstringOptionaldatabricksAccessTokenstringOptionalDatabricks personal access token.
analysisServicesOptionsobjectOptionalAnalysis Services sign-in options (tenant, client, endpoint).
Example request body
{
"serverType": "SQLServer",
"serverName": "sql.example.com",
"databaseName": "Sales",
"authType": "UserPassAuth",
"username": "unity_reader",
"password": "********",
"reportId": "9af3fb53-34e2-4e88-a953-ffdecdeece82"
}
Response 201
statusstringOptionalmessagestringOptionalconnectionobjectOptional
Example response
{
"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.
/api/connections/check-report-usage/{connection_id}List reports using a connection
workspace:readAny signed-in account · reaches sourceRequest 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
statusstringOptionalaffectedReportsarray<object>OptionalotherReportCountintegerOptionaldeletingReportsarray<object>Optional
Errors
400 Invalid input · 404 Not found. Every error has error, message and code.
/api/connections/delete/{connection_id}Delete a connection
workspace:writeAny signed-in account · reaches sourceRequest 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 · stringRequiredconfirmquery · stringOptional
Response 200
statusstringOptionalmessagestringOptional
Errors
400 Invalid input · 404 Not found · 409 Conflict: re-read and reconcile. Every error has error, message and code.
/api/connections/report/{report_id}List a report's connections
workspace:readView access · reaches sourceRequest and response
Connections attached to the report, with each one's model state.
Parameters
report_idpath · stringRequired
Response 200
connectionIdintegerOptionalnamestringOptionalserverTypestringOptional
Errors
403 Scope, access or subscription. Every error has error, message and code.
/api/connections/report/addAttach a connection to a report
workspace:writeEdit access · reaches model, sourceRequest 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
reportIdstringRequiredconnectionIdintegerRequired
Response 200
statusstringOptionalmessagestringOptional
Errors
400 Invalid input · 403 Scope, access or subscription. Every error has error, message and code.
/api/connections/report/removeDetach a connection from a report
workspace:writeEdit access · reaches model, sourceRequest 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
reportIdstringRequiredconnectionIdintegerRequiredconfirmbooleanOptionaltrue makes the change after 409 in_use.
Response 200
statusstringOptionalmessagestringOptional
Errors
400 Invalid input · 403 Scope, access or subscription · 409 Conflict: re-read and reconcile. Every error has error, message and code.
/api/connections/update/{connection_id}Update a connection
workspace:writeAny signed-in account · reaches sourceRequest 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
serverNamestringOptionalServer or host (SQL Server: host[,port]; Snowflake: account; API: the provider, FRED, WORLDBANK or USCENSUS).
databaseNamestringOptionalDatabase, catalog, or Analysis Services model.
authTypestringOptionalHow 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"]usernamestringOptionalLogin.
clientIdstringOptionalClient (application) ID of a service principal.
passwordstringOptionalPassword, API key, client secret or access token. Stored encrypted; never returned.
portintegerOptionalconnectionNamestringOptionalDisplay name; generated from server and database when omitted, numbered when taken.
apiKeystringOptionalAPI providers: the provider's key.
accountstringOptionalSnowflake account.
warehousestringOptionalSnowflake warehouse.
schemaNamestringOptionalSnowflake schema.
rolestringOptionalSnowflake role.
privateKeystringOptionalSnowflake key-pair private key (PEM).
privateKeyPassphrasestringOptionaloauthClientIdstringOptionaloauthClientSecretstringOptionaloauthTokenUrlstringOptionaloauthScopestringOptionalhttpPathstringOptionalDatabricks SQL warehouse HTTP path.
databricksSchemastringOptionalDatabricks schema.
tenantIdstringOptionalMicrosoft Entra tenant.
databricksClientIdstringOptionaldatabricksClientSecretstringOptionaldatabricksAccessTokenstringOptionalDatabricks personal access token.
analysisServicesOptionsobjectOptionalAnalysis Services sign-in options (tenant, client, endpoint).
Example request body
{
"connectionName": "Sales warehouse"
}
Response 200
statusstringOptionalmessagestringOptional
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).
/get-schemaList a connection's tables again
workspace:writeEdit access · reaches sourceRequest 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
connectionIdintegerRequiredThe connection whose tables to list.
reportIdstringOptional
Example request body
{
"connectionId": 42,
"reportId": "9af3fb53-34e2-4e88-a953-ffdecdeece82"
}
Response 200
schemaobjectOptionalTables, each with its columns and types.
selectedSchemaobjectOptionalconnectionIdintegerOptional
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-selected-schema/{report_id}Read the selected schema of a report source
workspace:readView access · reaches modelRequest and response
The tables and columns selected for a source in this report. No /api prefix.
Parameters
report_idpath · stringRequiredconnectionIdquery · integerRequired
Response 200
statusstringOptionalselectedSchemaobjectOptional
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.
/api/sql/delete-query/{query_id}Delete a saved query
workspace:writeAny signed-in account · reaches sourceRequest and response
Parameters
query_idpath · integerRequired
Response 200
messagestringOptional
Errors
404 Not found. Every error has error, message and code.
/api/sql/executeRun report SQL
workspace:readAny signed-in account · reaches sourceRequest 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
reportIdstringRequiredsqlQuerystringRequiredReport SQL (DuckDB).
rowLimitintegerOptionalRows to return when the query has no LIMIT of its own.
default:1000minimum:1skipLimitbooleanOptionalReturn every row (within Unity's result bound) instead of rowLimit.
default:falseconnectionIdintegerOptionalCompatibility hint; the report model decides the sources.
Example request body
{
"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
{
"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.
/api/sql/save-querySave a query
workspace:writeAny signed-in account · reaches sourceRequest and response
Keeps a named query with a report, in your saved queries (SQL Playground).
Body
reportIdstringRequirednamestringRequiredsqlQuerystringRequired
Response 201
idintegerOptionalnamestringOptionalmessagestringOptional
Errors
400 Invalid input · 403 Scope, access or subscription. Every error has error, message and code.
/api/sql/saved-queriesList saved queries
workspace:readAny signed-in account · reaches sourceRequest and response
Your saved queries across reports, newest first.
Response 200
idintegerOptionalnamestringOptionalsqlQuerystringOptionalreportIdstringOptionalreportNamestringOptionalcreatedAtstringOptional
Long-running reads2 operations
Follow, collect and cancel data reads that outlive one request.
/api/read-jobs/{job_id}Follow a long-running read
workspace:readAny access to the page · reaches model, pagesRequest 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.
/api/read-jobs/{job_id}/cancelCancel a long-running read
workspace:readAny access to the page · reaches model, pagesRequest and response
Stops your read; it never undoes saved changes.
Parameters
job_idpath · stringRequired
Response 200
cancelledbooleanOptionalWhether a running job was found.
Assistant runs13 operations
Ask Unity's assistant to do work, follow its runs and events, and read runtime documentation.
/api/agent/chats/{datachat_id}/readMark a conversation read
workspace:writeAny access to the page · reaches chatRequest 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.
/api/agent/client-timingReport client timings
workspace:writeAny signed-in account · reaches chatRequest and response
Browser latency telemetry.
Response 200
/api/agent/context-runsList recent runs' context (administrators)
workspace:readPlatform administrator · reaches chatRequest and response
Platform administrators: recent assistant runs with what entered their context.
Parameters
reportIdquery · stringOptionaloffsetquery · integerOptionalentryquery · stringOptional
Response 200
Errors
400 Invalid input · 403 Scope, access or subscription. Every error has error, message and code.
/api/agent/documentationRead Unity's runtime documentation
workspace:readAny signed-in account · reaches docsRequest 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
versionstringOptionalContent version.
topicstringOptionaltitlestringOptionalmarkdownstringOptionalThe guide (topics).
sourcestringOptionaltopicsarray<object>OptionalWith topic index.
Errors
400 Invalid input. Every error has error, message and code.
/api/agent/runsAsk Unity's assistant
workspace:writeAny access to the page · reaches chatRequest 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
reportIdstringRequireddataChatIdintegerRequiredThe conversation's DataChatID.
user_inputstringRequiredThe request, up to 50,000 characters.
maxLength:50000clientRequestIdstringOptionalDeduplicates a retried submission.
maxLength:64modestringOptional- enum:
["data_chat"]default:"data_chat" layoutContextobjectOptionalOptional: 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>OptionalOptional images.
Example request body
{
"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
runvalueOptionalcreatedbooleanOptionalFalse 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.
/api/agent/runs/{run_id}Read a run
workspace:readAny access to the page · reaches chatRequest and response
Parameters
run_idpath · stringRequired
Response 200
runvalueOptional
Errors
404 Not found. Every error has error, message and code.
/api/agent/runs/{run_id}/contextRead a run's context (administrators)
workspace:readPlatform administrator · reaches chatRequest and response
Platform administrators: one run's context receipts (export=json for a download).
Parameters
run_idpath · stringRequiredexportquery · stringOptional
Response 200
Errors
400 Invalid input · 403 Scope, access or subscription · 404 Not found. Every error has error, message and code.
/api/agent/runs/{run_id}/context/content/{digest}Read one context entry (administrators)
workspace:readPlatform administrator · reaches chatRequest and response
Parameters
run_idpath · stringRequireddigestpath · stringRequired
Response 200
Errors
400 Invalid input · 403 Scope, access or subscription · 404 Not found. Every error has error, message and code.
/api/agent/runs/{run_id}/eventsRead a run's events
workspace:readAny access to the page · reaches chatRequest 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 · stringRequiredviewquery · stringOptionalafterSequencequery · integerOptionalReturn events after this sequence (the last cursor).
Response 200
runvalueOptionaleventsarray<object>OptionalcursorintegerOptionalWith view=conversation.
tool_callsarray<object>Optional
Errors
400 Invalid input · 404 Not found. Every error has error, message and code.
/api/agent/runs/{run_id}/stopStop a run
workspace:writeAny access to the page · reaches chatRequest 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.
/api/agent/runs/{run_id}/streamStream a run's events
workspace:readAny access to the page · reaches chatRequest 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 · stringRequiredafterSequencequery · integerOptional
Response 200 (text/event-stream)
Server-sent events.
Errors
400 Invalid input · 404 Not found. Every error has error, message and code.
/api/agent/transcribeTranscribe a voice message
workspace:writeAny signed-in account · reaches chatRequest and response
Multipart form: reportId and an audio file. Returns the text for a message.
Body (multipart/form-data)
reportIdstringOptionalaudiostringOptional
Response 200
textstringOptional
Errors
400 Invalid input · 413 Too large · 415 Unsupported media type. Every error has error, message and code.
/api/agent/workspaceRead your conversations' state
workspace:readAny access to the page · reaches chatRequest and response
Your conversations in a report with their latest run state and unread counts.
Parameters
reportIdquery · stringRequired
Response 200
sessionsarray<object>OptionalsummaryobjectOptional
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.
/api/reports/{report_id}/toolsList the agent tools
workspace:readAny access to the page · reaches docsRequest 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
reportIdstringOptionalaccessLevelstringOptionalcontentEditbooleanOptionalTrue for an Edit content share (View access: the tools are a Viewer's).
toolsarray<object>OptionaleditablePagesarray<object>OptionalPresent 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.
/api/reports/{report_id}/tools/{name}Call an agent tool
workspace:writeAny access to the page · reaches docs, files, history, model, pages, report, sourceRequest 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 · stringRequirednamepath · stringRequired
Body
argumentsobjectRequiredThe tool's arguments, per its inputSchema.
sessionIdstringOptionalOptional, up to 64 characters: groups your calls into one recorded session (an external assistant run without a conversation).
maxLength:64
Example request body
{
"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
toolstringOptionalstatusstringOptionalerror: the tool ran and refused or failed; read result.error.
enum:["success","error"]resultobjectOptionalThe tool's result as the assistant receives it.
imagesarray<object>OptionalScreenshots from preview tools (PreviewPage, PreviewFile, ...).
runIdstringOptionalcallIdstringOptional
Errors
400 Invalid input · 403 Scope, access or subscription · 404 Not found · 422 Cannot be applied. Every error has error, message and code.
/api/reports/{report_id}/tools/{name}Read one agent tool
workspace:readAny access to the page · reaches docsRequest and response
Parameters
report_idpath · stringRequirednamepath · stringRequired
Response 200
namestringOptionaldescriptionstringOptionalaccessstringOptional- enum:
["view","edit"] readOnlybooleanOptionalThe tool only reads: a workspace:read key may call it.
reacharray<string>OptionalavailablebooleanOptionalunavailableReasonstringOptionalinputSchemaobjectOptionalThe 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.
/mcpModel Context Protocol endpoint
workspace:writeAny access to the page · reaches docs, files, history, model, pages, report, sourceRequest 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 · stringOptionalBind the server to one report.
Body
jsonrpcstringRequired- enum:
["2.0"] idvalueOptionalRequest 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
{
"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.
jsonrpcstringOptionalidvalueOptionalresultobjectOptionalerrorobjectOptional
Errors
400 Invalid input · 403 Scope, access or subscription. Every error has error, message and code.
/mcpMCP server stream (not offered)
workspace:readAny signed-in account · reaches docsRequest 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.
/.well-known/oauth-authorization-serverAuthorization server metadata
No Unity token required; endpoint checks may applyNo sign-in · reaches account/.well-known/oauth-protected-resourceProtected resource metadata
No Unity token required; endpoint checks may applyNo sign-in · reaches account/.well-known/oauth-protected-resource/mcpProtected resource metadata
No Unity token required; endpoint checks may applyNo sign-in · reaches account/oauth/authorizeAuthorize
No Unity token required; endpoint checks may applyNo sign-in · reaches account/oauth/registerRegister
No Unity token required; endpoint checks may applyNo sign-in · reaches account/oauth/revokeRevoke
No Unity token required; endpoint checks may applyNo sign-in · reaches account/oauth/tokenToken
No Unity token required; endpoint checks may applyNo sign-in · reaches accountConnected apps4 operations
The consent page's request and decision, and the account's connected apps (browser only).
/api/oauth/connectionsConnections
Browser session requiredAny signed-in account · reaches account/api/oauth/connections/{grant_id}Disconnect
Browser session requiredAny signed-in account · reaches accountPath: grant_id (string)
/api/oauth/requests/{request_id}Consent request
Browser session requiredAny signed-in account · reaches accountPath: request_id (string)
/api/oauth/requests/{request_id}/decisionConsent decision
Browser session requiredAny signed-in account · reaches accountPath: request_id (string)
Conversations3 operations
Report chats: transcripts and messages.
/api/datachat/messageUpdate a chat message's visual
workspace:writeView access · reaches chatRequest and response
The browser's inline chat-visual edits.
Response 200
/api/datachat/transcriptRead a conversation
workspace:readAny access to the page · reaches chatRequest 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 · stringRequireddataChatIdquery · integerRequired
Response 200
messagesarray<object>Optionalactionsarray<object>OptionalprojectionobjectOptional
Errors
400 Invalid input · 403 Scope, access or subscription · 404 Not found. Every error has error, message and code.
/api/datachats/updateRename a conversation
workspace:writeAny access to the page · reaches chatRequest and response
Body
reportIdstringRequireddataChatIdintegerRequirednewNamestringRequired
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.
/api/datachat/deleteDelete a conversation
workspace:writeAny access to the page · reaches chatRequest and response
Deletes your conversation and its history (202: cleanup continues). Refused while a run is active.
Body
reportIdstringRequiredidintegerRequiredDataChatID.
Response 202
messagestringOptionaldetailsobjectOptional
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.
/api/datachat/pull_visualAdd a chat visual to a page
workspace:writeEdit access · reaches chat, pagesRequest 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.
/api/html/pages/{page_uid}Read an HTML page
workspace:readAny access to the page · reaches pagesRequest 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 · stringRequiredThe HTML page UUID.
Response 200
An HTML page (or, for a report-wide read, every page the caller can see) with its version.
idstringOptionalReport ID.
reportIdstringOptionalReport ID.
pageIdstringOptionalThe page (single-page projection).
namestringOptionalReport name.
versionintegerOptionalThis 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"] accessLevelstringOptionaldocumentobjectOptionalnativePagesarray<object>OptionalfeedbackobjectOptionalupdatedAtstring | nullOptionalscopestringOptionalPresent for a page-only reader (page grants, no report access): the page is returned without queries, filters or renderer feedback.
enum:["pages"]dataContextstringOptionalAn 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.
/api/html/pages/{page_uid}/assets/{asset_id}/contentRead an image the page uses
workspace:readAny access to the page · reaches files, pagesRequest 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 · stringRequiredThe HTML page UUID.
asset_idpath · stringRequiredThe 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.
/api/html/pages/{page_uid}/operationsChange an HTML page
workspace:writeEdit access to the page · reaches pagesRequest 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 · stringRequiredThe HTML page UUID.
Body
baseVersionintegerRequiredoperationobjectRequiredOne 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.
labelstringOptionalHistory label.
clientRequestIdstringOptionalA 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
{
"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.
idstringOptionalReport ID.
reportIdstringOptionalReport ID.
pageIdstringOptionalThe page (single-page projection).
namestringOptionalReport name.
versionintegerOptionalThis 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"] accessLevelstringOptionaldocumentobjectOptionalnativePagesarray<object>OptionalfeedbackobjectOptionalupdatedAtstring | nullOptionalscopestringOptionalPresent for a page-only reader (page grants, no report access): the page is returned without queries, filters or renderer feedback.
enum:["pages"]dataContextstringOptionalAn opaque fingerprint of the page's data definitions and the filters as they apply to you. Data responses and renderer feedback repeat it.
receiptobjectOptionalReceipt: {resourceType: 'html', label, mutation, change: {before: {pageUid}, after: {pageUid, version}}, pageVersion, changedPageIds, verificationKeys}.
changedElementsarray<string>Optionalelement_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.
/api/html/pages/{page_uid}/script-saveSave text from a page's own script
workspace:writeEdit content access to the page · reaches pagesRequest 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 · stringRequiredThe HTML page UUID.
Body
uidstringRequiredThe element's data-unity-id.
textstringRequiredPlain text, up to 20,000 characters.
previousTextstringRequiredThe element's text as the saver's page last applied it (after its own earlier saves; not a change held back while they type).
clientRequestIdstringRequiredA 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
{
"uid": "k3m9xq",
"text": "Approved",
"previousText": "Pending",
"clientRequestId": "a-new-id-per-save"
}
Response 200
savedbooleanOptionalpageIdstringOptionaluidstringOptionalversionintegerOptionalThe page version holding the text.
appliedbooleanOptionalFalse 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.
/api/html/reports/{report_id}Read the HTML pages of a report
workspace:readView access · reaches pagesRequest 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.
idstringOptionalReport ID.
reportIdstringOptionalReport ID.
pageIdstringOptionalThe page (single-page projection).
namestringOptionalReport name.
versionintegerOptionalThis 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"] accessLevelstringOptionaldocumentobjectOptionalnativePagesarray<object>OptionalfeedbackobjectOptionalupdatedAtstring | nullOptionalscopestringOptionalPresent for a page-only reader (page grants, no report access): the page is returned without queries, filters or renderer feedback.
enum:["pages"]dataContextstringOptionalAn 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.
/api/html/reports/{report_id}/feedbackRecord renderer feedback
workspace:writeAny access to the page · reaches pagesRequest and response
The browser renderer's diagnostics; `revision` is the page's version.
Parameters
report_idpath · stringRequired
Response 200
/api/html/reports/{report_id}/pages/{page_id}/dataRead an HTML page's data
workspace:readAny access to the page · reaches model, pagesRequest 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 · stringRequiredpage_idpath · stringRequiredThe HTML page UUID.
statequery · stringOptionalJSON 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 · stringOptionalOne dataset or visual ID.
Response 200
versionintegerOptionalcontextobjectOptionalresultsobjectOptional
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.
/api/html/reports/{report_id}/pages/{page_id}/data-streamStream an HTML page's data
workspace:readAny access to the page · reaches model, pagesRequest and response
NDJSON: {context, keys}, then {results} as datasets finish, {jobs} for reads continuing as read jobs, then {done: true}.
Parameters
report_idpath · stringRequiredpage_idpath · stringRequiredstatequery · stringOptional
Response 200 (application/x-ndjson)
Errors
400 Invalid input · 403 Scope, access or subscription. Every error has error, message and code.
/api/html/reports/{report_id}/queryQuery data for HTML authoring
workspace:writeEdit access · reaches modelRequest 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
queryobjectRequiredA visual query, as a dataset takes it.
pageIdstringOptionalfiltersarray<value>OptionalDataset 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.
/api/pages/{page_uid}/holdStart editing a page or a chart
Browser session requiredEdit access to the page · reaches pagesRequest 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 · stringRequiredThe HTML page UUID.
Body
targetstringOptionalNative 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.
pageUidstringOptionaltargetstringOptional`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"]holdIdstringOptionalOnly the holder sees it: send it with every renew, leave and answer (a stale one answers 409 hold_lost).
holderobjectOptionalsincestringOptionalkindsarray<string>OptionalWho is acting under the hold.
minebooleanOptionalThe caller is the holder.
expiresAtstringOptionalThe hold lapses then unless a participant renews.
participantsarray<object>OptionalThe holder's live participants (holder only).
takeoverRequestedbooleanOptionaltakeoverRequestedByobject | nullOptionaltakeoverDeadlinestring | nullOptionalServer 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.
/api/pages/{page_uid}/holdStop editing a page or a chart
Browser session requiredEdit access to the page · reaches pagesRequest 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 · stringRequiredThe 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.
/api/pages/{page_uid}/holdKeep editing a page or a chart
Browser session requiredEdit access to the page · reaches pagesRequest 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 · stringRequiredThe 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.
pageUidstringOptionaltargetstringOptional`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"]holdIdstringOptionalOnly the holder sees it: send it with every renew, leave and answer (a stale one answers 409 hold_lost).
holderobjectOptionalsincestringOptionalkindsarray<string>OptionalWho is acting under the hold.
minebooleanOptionalThe caller is the holder.
expiresAtstringOptionalThe hold lapses then unless a participant renews.
participantsarray<object>OptionalThe holder's live participants (holder only).
takeoverRequestedbooleanOptionaltakeoverRequestedByobject | nullOptionaltakeoverDeadlinestring | nullOptionalServer 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.
/api/pages/{page_uid}/holdRead the leases on a page and who is on it
workspace:readAny access to the page · reaches pagesRequest 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 · stringRequiredThe HTML page UUID.
Response 200
granularitystringOptional- enum:
["page","element"] holdobject | nullOptionalOne 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>Optionalpresencearray<object>Optional
Errors
403 Scope, access or subscription. Every error has error, message and code.
/api/pages/{page_uid}/hold/takeoverAsk to edit an HTML page someone else holds, or end chart leases
Browser session requiredEdit access to the page · reaches pagesRequest 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 · stringRequiredThe HTML page UUID.
Body
forcebooleanOptionaltargetstringOptionalNative 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.
pageUidstringOptionaltargetstringOptional`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"]holdIdstringOptionalOnly the holder sees it: send it with every renew, leave and answer (a stale one answers 409 hold_lost).
holderobjectOptionalsincestringOptionalkindsarray<string>OptionalWho is acting under the hold.
minebooleanOptionalThe caller is the holder.
expiresAtstringOptionalThe hold lapses then unless a participant renews.
participantsarray<object>OptionalThe holder's live participants (holder only).
takeoverRequestedbooleanOptionaltakeoverRequestedByobject | nullOptionaltakeoverDeadlinestring | nullOptionalServer 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.
/api/pages/{page_uid}/hold/takeover/answerAnswer a request to take over an HTML page
Browser session requiredEdit access to the page · reaches pagesRequest 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 · stringRequiredThe HTML page UUID.
Body
holdIdstringRequiredreleasebooleanRequired
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.
pageUidstringOptionaltargetstringOptional`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"]holdIdstringOptionalOnly the holder sees it: send it with every renew, leave and answer (a stale one answers 409 hold_lost).
holderobjectOptionalsincestringOptionalkindsarray<string>OptionalWho is acting under the hold.
minebooleanOptionalThe caller is the holder.
expiresAtstringOptionalThe hold lapses then unless a participant renews.
participantsarray<object>OptionalThe holder's live participants (holder only).
takeoverRequestedbooleanOptionaltakeoverRequestedByobject | nullOptionaltakeoverDeadlinestring | nullOptionalServer 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.
/api/pages/{page_uid}/liveRead what changed on a page since a version (live viewing)
workspace:readAny access to the page · reaches pagesRequest 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 · stringRequiredThe HTML page UUID.
afterquery · integerRequiredThe page version the viewer shows.
Response 200
pageUidstringOptionalfromVersionintegerOptionalversionintegerOptionalrebuildbooleanOptionalreasonstringOptionalWhy 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.
/api/pages/{page_uid}/presenceSay you are on a page and what you selected
Browser session requiredAny access to the page · reaches pagesRequest 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 · stringRequiredThe 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.
/api/pages/{page_uid}/presenceLeave a page
Browser session requiredAny access to the page · reaches pagesRequest 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 · stringRequiredThe 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.
/api/reports/{report_id}/assetsList report images
workspace:readEdit access · reaches filesRequest 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.
/api/reports/{report_id}/assets/{asset_id}/contentRead a report image
workspace:readEdit access · reaches filesRequest 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 · stringRequiredasset_idpath · stringRequired
Response 200 (image/png)
Errors
403 Scope, access or subscription · 404 Not found. Every error has error, message and code.
/api/reports/{report_id}/filesList a report's files
workspace:readEdit access · reaches filesRequest 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>OptionalmaxBytesintegerOptionalmaxAttachmentsintegerOptionalextensionsarray<string>Optional
Errors
403 Scope, access or subscription. Every error has error, message and code.
/api/reports/{report_id}/filesUpload a reference file
workspace:writeEdit access · reaches filesRequest 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)
filestringRequiredfileIdstringOptionalOptional: replace this file.
Response 200
idstringOptionalnamestringOptionaltypestringOptionalsizeBytesintegerOptionalcreatedAtstringOptional
Errors
400 Invalid input · 403 Scope, access or subscription · 413 Too large. Every error has error, message and code.
/api/reports/{report_id}/files/{file_id}Delete a file
workspace:writeEdit access · reaches filesRequest and response
Parameters
report_idpath · stringRequiredfile_idpath · stringRequired
Response 200
deletedbooleanOptional
Errors
403 Scope, access or subscription · 404 Not found. Every error has error, message and code.
/api/reports/{report_id}/files/{file_id}Inspect a file
workspace:readEdit access · reaches filesRequest and response
Sections (pages, slides, sheets), an HTML/CSS outline and the embedded image inventory. Report Edit, Admin or Owner only.
Parameters
report_idpath · stringRequiredfile_idpath · stringRequired
Response 200
Errors
403 Scope, access or subscription · 404 Not found. Every error has error, message and code.
/api/reports/{report_id}/files/{file_id}/assets/{asset_id}/previewRead an embedded image
workspace:readEdit access · reaches filesRequest and response
Report Edit, Admin or Owner only.
Parameters
report_idpath · stringRequiredfile_idpath · stringRequiredasset_idpath · stringRequired
Response 200 (image/png)
Errors
403 Scope, access or subscription · 404 Not found. Every error has error, message and code.
/api/reports/{report_id}/files/{file_id}/assets/{asset_id}/reuseImport an image from a file
workspace:writeEdit access · reaches filesRequest 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 · stringRequiredfile_idpath · stringRequiredasset_idpath · stringRequired
Response 200
Errors
403 Scope, access or subscription · 404 Not found. Every error has error, message and code.
/api/reports/{report_id}/files/{file_id}/contentRead a file's text
workspace:readEdit access · reaches filesRequest 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 · stringRequiredfile_idpath · stringRequiredsectionIdquery · stringOptionaloffsetquery · integerOptionallimitquery · integerOptionalcolumnOffsetquery · integerOptional
Response 200
Errors
400 Invalid input · 403 Scope, access or subscription · 404 Not found. Every error has error, message and code.
/api/reports/{report_id}/files/{file_id}/downloadDownload a file
workspace:readEdit access · reaches filesRequest and response
Report Edit, Admin or Owner only.
Parameters
report_idpath · stringRequiredfile_idpath · stringRequired
Response 200 (application/octet-stream)
Errors
403 Scope, access or subscription · 404 Not found. Every error has error, message and code.
/api/reports/{report_id}/files/{file_id}/previewRender a file page or image
workspace:writeEdit access · reaches filesRequest 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 · stringRequiredfile_idpath · stringRequired
Body
pageintegerOptionalassetIdstringOptional
Response 200
Errors
400 Invalid input · 403 Scope, access or subscription · 404 Not found. Every error has error, message and code.
/api/reports/{report_id}/files/{file_id}/previews/{page}Read a rendered page image
workspace:readEdit access · reaches filesRequest and response
Report Edit, Admin or Owner only.
Parameters
report_idpath · stringRequiredfile_idpath · stringRequiredpagepath · integerRequired
Response 200 (image/png)
Errors
403 Scope, access or subscription · 404 Not found. Every error has error, message and code.
/api/reports/{report_id}/files/{file_id}/searchSearch a file
workspace:readEdit access · reaches filesRequest and response
Report Edit, Admin or Owner only.
Parameters
report_idpath · stringRequiredfile_idpath · stringRequiredqueryquery · stringRequiredsectionIdquery · stringOptionaloffsetquery · integerOptionallimitquery · integerOptionalcaseSensitivequery · 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.
/api/file/datasetsStart a CSV import
workspace:writeEdit access · reaches modelRequest 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
reportIdstringRequiredfileNamestringRequiredA .csv name.
sizeBytesintegerRequiredtableNamestringOptionalEntity name; defaults to the file name.
Response 201
uploadIdstringOptionalstatusstringOptionalFollow it until ready (or failed).
fileNamestringOptionaltableNamestringOptionalrowCountinteger | nullOptionalrowsProcessedinteger | nullOptionalprogressinteger | nullOptionalerrorstring | nullOptionalconnectionIdinteger | nullOptionalSet when ready: the queryable file connection.
previewobject | nullOptionalfirstSpellingsobject | nullOptionalSet 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 | nullOptionaluploadUrlstringOptionalmaxBytesintegerOptional
Errors
400 Invalid input · 403 Scope, access or subscription. Every error has error, message and code.
/api/file/datasetsList a report's unfinished CSV imports
workspace:readEdit access · reaches modelRequest 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.
/api/file/datasets/{dataset_id}Cancel a CSV import
workspace:writeEdit access · reaches modelRequest 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.
/api/file/datasets/{dataset_id}Follow a CSV import
workspace:readEdit access · reaches modelRequest and response
Parameters
dataset_idpath · stringRequired
Response 200
uploadIdstringOptionalstatusstringOptionalFollow it until ready (or failed).
fileNamestringOptionaltableNamestringOptionalrowCountinteger | nullOptionalrowsProcessedinteger | nullOptionalprogressinteger | nullOptionalerrorstring | nullOptionalconnectionIdinteger | nullOptionalSet when ready: the queryable file connection.
previewobject | nullOptionalfirstSpellingsobject | nullOptionalSet 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.
/api/file/datasets/{dataset_id}/importImport a CSV with column types
workspace:writeEdit access · reaches modelRequest and response
Step 3. One type per preview column; the import continues in the background (poll to ready).
Parameters
dataset_idpath · stringRequired
Body
columnMappingsobjectRequiredPreview column name to type.
Example request body
{
"columnMappings": {
"date": "date",
"amount": "decimal",
"category": "string"
}
}
Response 202
uploadIdstringOptionalstatusstringOptionalFollow it until ready (or failed).
fileNamestringOptionaltableNamestringOptionalrowCountinteger | nullOptionalrowsProcessedinteger | nullOptionalprogressinteger | nullOptionalerrorstring | nullOptionalconnectionIdinteger | nullOptionalSet when ready: the queryable file connection.
previewobject | nullOptionalfirstSpellingsobject | nullOptionalSet 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.
/api/file/datasets/{dataset_id}/uploadedConfirm an uploaded CSV
workspace:writeEdit access · reaches modelRequest and response
Step 2. Checks the stored size and starts profiling; poll until preview appears.
Parameters
dataset_idpath · stringRequired
Response 202
uploadIdstringOptionalstatusstringOptionalFollow it until ready (or failed).
fileNamestringOptionaltableNamestringOptionalrowCountinteger | nullOptionalrowsProcessedinteger | nullOptionalprogressinteger | nullOptionalerrorstring | nullOptionalconnectionIdinteger | nullOptionalSet when ready: the queryable file connection.
previewobject | nullOptionalfirstSpellingsobject | nullOptionalSet 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.
/api/file/datasets/limitsRead CSV import limits
workspace:readAny signed-in account · reaches modelRequest and response
Response 200
maxBytesintegerOptionalmaxColumnsintegerOptional
Text boxes and shapes (compatibility)6 operations
Older text box and shape endpoints.
/api/shapes/addAdd a shape Compatibility · use POST /api/visuals/create with type shape
workspace:writeEdit access to the page · reaches pagesRequest and response
Response 200
/api/shapes/deleteDelete a shape Compatibility · use POST /api/visuals/delete
workspace:writeEdit access to the page · reaches pagesRequest and response
Response 200
/api/shapes/updateUpdate a shape Compatibility · use POST /api/visuals/update
workspace:writeEdit access to the page · reaches pagesRequest and response
Response 200
/api/textboxes/addAdd a text box Compatibility · use POST /api/visuals/create with type textBox
workspace:writeEdit access to the page · reaches pagesRequest and response
Response 200
/api/textboxes/deleteDelete a text box Compatibility · use POST /api/visuals/delete
workspace:writeEdit access to the page · reaches pagesRequest and response
Response 200
/api/textboxes/updateUpdate a text box Compatibility · use POST /api/visuals/update
workspace:writeEdit access to the page · reaches pagesRequest and response
Response 200
Chart preset routes (compatibility)10 operations
Older per-chart data and delete endpoints.
/api/bargraphs/dataRead a chart preset's data Compatibility · use POST /api/reports/{report_id}/visual-data
workspace:readAny access to the page · reaches model, pagesRequest and response
Response 200
/api/bargraphs/deleteDelete a chart preset Compatibility · use POST /api/visuals/delete
workspace:writeEdit access to the page · reaches pagesRequest and response
Response 200
/api/datacards/dataRead a chart preset's data Compatibility · use POST /api/reports/{report_id}/visual-data
workspace:readAny access to the page · reaches model, pagesRequest and response
Response 200
/api/datacards/deleteDelete a chart preset Compatibility · use POST /api/visuals/delete
workspace:writeEdit access to the page · reaches pagesRequest and response
Response 200
/api/linegraphs/dataRead a chart preset's data Compatibility · use POST /api/reports/{report_id}/visual-data
workspace:readAny access to the page · reaches model, pagesRequest and response
Response 200
/api/linegraphs/deleteDelete a chart preset Compatibility · use POST /api/visuals/delete
workspace:writeEdit access to the page · reaches pagesRequest and response
Response 200
/api/piecharts/dataRead a chart preset's data Compatibility · use POST /api/reports/{report_id}/visual-data
workspace:readAny access to the page · reaches model, pagesRequest and response
Response 200
/api/piecharts/deleteDelete a chart preset Compatibility · use POST /api/visuals/delete
workspace:writeEdit access to the page · reaches pagesRequest and response
Response 200
/api/scatterplots/dataRead a chart preset's data Compatibility · use POST /api/reports/{report_id}/visual-data
workspace:readAny access to the page · reaches model, pagesRequest and response
Response 200
/api/scatterplots/deleteDelete a chart preset Compatibility · use POST /api/visuals/delete
workspace:writeEdit access to the page · reaches pagesRequest and response
Response 200
Data tables (compatibility)4 operations
Older data table endpoints.
/api/datatables/create-from-entityCreate a table from an entity
workspace:writeEdit access · reaches model, pagesRequest 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
reportIdstringRequiredpageIdstringRequiredUUID or numeric page ID.
entityKeystringRequiredcolumnNamesarray<string>RequiredtitlestringOptionalpositionobjectOptionaldimensionsobjectOptional
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.
/api/datatables/dataRead a table page Compatibility · use POST /api/reports/{report_id}/visual-data
workspace:readAny access to the page · reaches model, pagesRequest and response
Response 200
/api/datatables/deleteDelete a table Compatibility · use POST /api/visuals/delete
workspace:writeEdit access to the page · reaches pagesRequest and response
Response 200
/api/datatables/exportExport a table's rows
workspace:readAny access to the page · reaches model, pagesRequest 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 · stringRequiredReport ID.
pageIdquery · stringOptionalThe table's page: UUID or numeric ID.
dataTableIdquery · stringRequiredThe 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.
/api/ui/preferencesRead workspace preferences
workspace:readAny signed-in account · reaches accountRequest and response
The account's browser workspace preferences.
Response 200
preferencesobjectOptionalupdatedAtstringOptional
/api/ui/preferencesSave workspace preferences
workspace:writeAny signed-in account · reaches accountRequest and response
Body
preferencesobjectRequired
Response 200
preferencesobjectOptionalupdatedAtstringOptional
Workspaces1 operations
The account's workspaces.
/api/workspacesList workspaces
workspace:readAny signed-in account · reaches reportRequest and response
The account's personal workspaces.
Response 200
Service2 operations
Health and the API description.
/api/openapi.jsonRead the OpenAPI document
workspace:readAny signed-in account · reaches docsRequest 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.
/healthCheck service health
No Unity token required; endpoint checks may applyNo sign-in · reaches platformRequest and response
Answers while the web process is serving. It does not check the database or sources.
Response 200
statusstringOptional- enum:
["healthy"]
Example response
{
"status": "healthy"
}
Sign-in and API keys19 operations
Browser sign-in, sessions and API key management.
/api/auth/email-loginEmail login
No Unity token required; endpoint checks may applyNo sign-in · reaches account/api/auth/email-login/verifyVerify email login
No Unity token required; endpoint checks may applyNo sign-in · reaches account/api/auth/googleGoogle login
No Unity token required; endpoint checks may applyNo sign-in · reaches account/api/auth/logoutLogout
Browser session requiredAny signed-in account · reaches account/api/auth/logout-allLogout all
Browser session requiredAny signed-in account · reaches account/api/auth/register-and-checkoutRegister and checkout
No Unity token required; endpoint checks may applyNo sign-in · reaches account/api/auth/registration/startStart registration
No Unity token required; endpoint checks may applyNo sign-in · reaches account/api/auth/registration/verifyVerify registration
No Unity token required; endpoint checks may applyNo sign-in · reaches account/api/auth/request-password-resetRequest password reset
No Unity token required; endpoint checks may applyNo sign-in · reaches account/api/auth/reset-passwordReset password
No Unity token required; endpoint checks may applyNo sign-in · reaches account/api/auth/sessionSession details
Browser session requiredAny signed-in account · reaches account/api/auth/sessionsBrowser sessions
Browser session requiredAny signed-in account · reaches account/api/auth/sessions/{credential_id}End browser session
Browser session requiredAny signed-in account · reaches accountPath: credential_id (string)
/api/auth/tokensAPI tokens
Browser session requiredAny signed-in account · reaches account/api/auth/tokensAPI tokens
Browser session requiredAny signed-in account · reaches account/api/auth/tokens/{credential_id}Revoke token
Browser session requiredAny signed-in account · reaches accountPath: credential_id (string)
/api/auth/validateValidate session
Browser session requiredAny signed-in account · reaches account/loginLogin
No Unity token required; endpoint checks may applyNo sign-in · reaches account/registerRegister
No Unity token required; endpoint checks may applyNo sign-in · reaches accountOrganizations and teams29 operations
Organizations, teams, members and invitations.
/api/collaborationOverview
Browser session requiredAny signed-in account · reaches organization/api/collaboration/invitations/{invitation_id}Revoke invitation
Browser session requiredAdmin or Owner · reaches organizationPath: invitation_id (string)
/api/collaboration/invitations/acceptAccept invitation
Browser session requiredAny signed-in account · reaches organization/api/collaboration/organizationsCreate organization
Browser session requiredAny signed-in account · reaches organization/api/collaboration/organizations/{org_id}Organization details
Browser session requiredAny signed-in account · reaches organizationPath: org_id (string)
/api/collaboration/organizations/{org_id}Update organization
Browser session requiredAdmin or Owner · reaches organizationPath: org_id (string)
/api/collaboration/organizations/{org_id}/auditAudit events
Browser session requiredAdmin or Owner · reaches organizationPath: org_id (string)
/api/collaboration/organizations/{org_id}/invitationsInvite org
Browser session requiredAdmin or Owner · reaches organizationPath: org_id (string)
/api/collaboration/organizations/{org_id}/members/{member_id}Update org member
Browser session requiredAdmin or Owner · reaches organizationPath: org_id (string), member_id (string)
/api/collaboration/organizations/{org_id}/recover-reportRecover report
Browser session requiredOwner · reaches organization, sharingPath: org_id (string)
/api/collaboration/organizations/{org_id}/teamsCreate team
Browser session requiredAdmin or Owner · reaches organizationPath: org_id (string)
/api/collaboration/organizations/{org_id}/teams/{team_id}/invitationsInvite team
Browser session requiredAdmin or Owner · reaches organizationPath: org_id (string), team_id (string)
/api/collaboration/reports/{report_id}/ownerTransfer owner
Browser session requiredOwner · reaches sharingPath: report_id (string)
/api/collaboration/reports/{report_id}/page-sharesReport page shares
Browser session requiredAdmin or Owner · reaches pages, sharingPath: report_id (string)
/api/collaboration/reports/{report_id}/pages/{page_id}/sharingPage sharing summary
Browser session requiredAny access to the page · reaches pages, sharingPath: report_id (string), page_id (string)
/api/collaboration/reports/{report_id}/pages/{page_id}/sharing/modeSet page mode
Browser session requiredAdmin or Owner · reaches pages, sharingPath: report_id (string), page_id (string)
/api/collaboration/reports/{report_id}/pages/{page_id}/sharing/teams/{team_id}Share page team
Browser session requiredAdmin or Owner · reaches organization, pages, sharingPath: report_id (string), page_id (string), team_id (string)
/api/collaboration/reports/{report_id}/pages/{page_id}/sharing/teams/{team_id}Share page team
Browser session requiredAdmin or Owner · reaches organization, pages, sharingPath: report_id (string), page_id (string), team_id (string)
/api/collaboration/reports/{report_id}/pages/{page_id}/sharing/users/{grantee_id}Share page user
Browser session requiredAdmin or Owner · reaches pages, sharingPath: report_id (string), page_id (string), grantee_id (string)
/api/collaboration/reports/{report_id}/pages/{page_id}/sharing/users/{grantee_id}Share page user
Browser session requiredAdmin or Owner · reaches pages, sharingPath: report_id (string), page_id (string), grantee_id (string)
/api/collaboration/reports/{report_id}/sharingReport sharing
Browser session requiredView access · reaches sharingPath: report_id (string)
/api/collaboration/reports/{report_id}/teams/{team_id}Share team
Browser session requiredAdmin or Owner · reaches organization, sharingPath: report_id (string), team_id (string)
/api/collaboration/reports/{report_id}/teams/{team_id}Share team
Browser session requiredAdmin or Owner · reaches organization, sharingPath: report_id (string), team_id (string)
/api/collaboration/reports/{report_id}/users/{grantee_id}Share user
Browser session requiredAdmin or Owner · reaches sharingPath: report_id (string), grantee_id (string)
/api/collaboration/reports/{report_id}/users/{grantee_id}Share user
Browser session requiredAdmin or Owner · reaches sharingPath: report_id (string), grantee_id (string)
/api/collaboration/teams/{team_id}Team details
Browser session requiredAny signed-in account · reaches organizationPath: team_id (string)
/api/collaboration/teams/{team_id}Update team
Browser session requiredAdmin or Owner · reaches organizationPath: team_id (string)
/api/collaboration/teams/{team_id}/members/{member_id}Update team member
Browser session requiredAdmin or Owner · reaches organizationPath: team_id (string), member_id (string)
/api/collaboration/users/by-emailUser by email
Browser session requiredAdmin or Owner · reaches sharingPublic page links6 operations
Anonymous, read-only viewing of one HTML page by its link token (no sign-in).
/api/public/pages/{token}/assets/{asset_id}Asset
No Unity token required; endpoint checks may applyNo sign-in · reaches files, pagesPath: token (string), asset_id (string)
/api/public/pages/{token}/dataData
No Unity token required; endpoint checks may applyNo sign-in · reaches model, pages, sourcePath: token (string)
/api/public/pages/{token}/filter-valuesFilter values
No Unity token required; endpoint checks may applyNo sign-in · reaches model, pages, sourcePath: token (string)
/api/public/pages/{token}/liveLive
No Unity token required; endpoint checks may applyNo sign-in · reaches pagesPath: token (string)
/api/public/pages/{token}/pagePage
No Unity token required; endpoint checks may applyNo sign-in · reaches pagesPath: token (string)
/api/public/pages/{token}/versionVersion
No Unity token required; endpoint checks may applyNo sign-in · reaches pagesPath: token (string)
Public page link management4 operations
Create and remove a page's public link (browser only).
/api/collaboration/public-link/openOpen link
Browser session requiredAny signed-in account · reaches pages/api/collaboration/reports/{report_id}/pages/{page_id}/public-linkCreate link
Browser session requiredAdmin or Owner · reaches pages, sharingPath: report_id (string), page_id (string)
/api/collaboration/reports/{report_id}/pages/{page_id}/public-linkRead link
Browser session requiredAdmin or Owner · reaches pages, sharingPath: report_id (string), page_id (string)
/api/collaboration/reports/{report_id}/pages/{page_id}/public-linkRevoke link
Browser session requiredAdmin or Owner · reaches pages, sharingPath: report_id (string), page_id (string)
Account administration12 operations
Platform administration.
/api/admin/assistant-modelAssistant model
Browser session requiredPlatform administrator · reaches platform/api/admin/assistant-modelAssistant model
Browser session requiredPlatform administrator · reaches platform/api/admin/context-registryGet context registry
Browser session requiredPlatform administrator · reaches chat, platform/api/demo-info-nukeDemo info nuke
Browser session requiredPlatform administrator · reaches account, platform/api/subscription-planGet active plan
No Unity token required; endpoint checks may applyNo sign-in · reaches account/api/subscription-planSet active plan
Browser session requiredPlatform administrator · reaches platform/api/usersGet all users
Browser session requiredPlatform administrator · reaches account, platform/api/users/admin/promotePromote user to admin
Browser session requiredPlatform administrator · reaches account, platform/api/users/deleteDelete user
Browser session requiredPlatform administrator · reaches account, platform/api/users/subscription/activateActivate subscription
Browser session requiredPlatform administrator · reaches account, platform/api/users/subscription/cancelCancel subscription
Browser session requiredPlatform administrator · reaches account, platform/api/users/testersCreate tester
Browser session requiredPlatform administrator · reaches account, organization, platformBilling6 operations
Subscriptions and checkout.
/api/stripe/cancel-subscriptionCancel subscription
Browser session requiredAny signed-in account · reaches account/api/stripe/create-checkout-sessionCreate checkout session
Browser session requiredAny signed-in account · reaches account/api/stripe/create-portal-sessionCreate portal session
Browser session requiredAny signed-in account · reaches account/api/stripe/renew-subscriptionRenew subscription
Browser session requiredAny signed-in account · reaches account/api/stripe/subscription-detailsGet subscription details
Browser session requiredAny signed-in account · reaches account/api/stripe/webhookStripe webhook
No Unity token required; endpoint checks may applyNo sign-in · reaches accountAnalysis Services sign-in5 operations
Browser sign-in to Analysis Services.
/api/connections/analysis-services/auth/callbackCallback
Browser session requiredAny signed-in account · reaches account/api/connections/analysis-services/auth/cancelCancel
Browser session requiredAny signed-in account · reaches account/api/connections/analysis-services/auth/disconnectDisconnect
Browser session requiredAny signed-in account · reaches account/api/connections/analysis-services/auth/startStart
Browser session requiredAny signed-in account · reaches account/api/connections/analysis-services/auth/statusStatus
Browser session requiredAny signed-in account · reaches accountSource sign-in6 operations
Browser sign-in to data sources.
/api/connections/browser-auth/callbackCallback
Browser session requiredAny signed-in account · reaches account/api/connections/browser-auth/cancelCancel
Browser session requiredAny signed-in account · reaches account/api/connections/browser-auth/disconnectDisconnect
Browser session requiredAny signed-in account · reaches account/api/connections/browser-auth/settingsSettings
Browser session requiredAny signed-in account · reaches source/api/connections/browser-auth/startStart
Browser session requiredAny signed-in account · reaches account/api/connections/browser-auth/statusStatus
Browser session requiredAny signed-in account · reaches accountContact1 operations
The public contact form.
/api/contactContact form
No Unity token required; endpoint checks may applyNo sign-in · reaches platformSite telemetry1 operations
Anonymous page hits.
/api/page-hitRecord page hit
No Unity token required; endpoint checks may applyNo sign-in · reaches platformQuestions about your environment? Contact us.