atteq API
  • Guides
  • Recipes
  • Cookbook
  • API Reference
Information
agents
    List AgentsgetCreate AgentpostDocument AttachmentsgetGet VersiongetEdit DraftpatchReplace Draft GraphputPublish VersionpostGet AgentgetDelete AgentdeleteCopy AgentpostGet DraftgetGet Agent MapgetPending ChangesgetList PlacementsgetRestore VersionpostList VersionsgetGet Mapget
voice_agent
    Open Browser CallpostEnd Browser CalldeleteGet Agent Test LinkgetGet Bridge CeilinggetSet Bridge Ceilingpatch
ai_profiles
    Get Ai Profile CapabilitiesgetList Live SettingsgetCreate Live SettingspostDelete Live SettingsdeleteUpdate Live SettingspatchList Llm SettingsgetCreate Llm SettingspostDelete Llm SettingsdeleteUpdate Llm SettingspatchList ProfilesgetCreate ProfilepostGet ProfilegetDelete ProfiledeleteUpdate ProfilepatchCopy ProfilepostSet Text SectionputSet Voice SectionputList Stt SettingsgetCreate Stt SettingspostDelete Stt SettingsdeleteUpdate Stt SettingspatchList Tts SettingsgetCreate Tts SettingspostDelete Tts SettingsdeleteUpdate Tts SettingspatchList Vad SettingsgetCreate Vad SettingspostDelete Vad SettingsdeleteUpdate Vad Settingspatch
analyst
    List Agent FindingsgetCall Back FindingpostDismiss FindingpostUndo Finding DismissaldeleteTeach FindingpostWatch FindingpostList Question ChartsgetList Tracked QuestionsgetCreate Tracked QuestionpostGet Question Search CostgetSearch For Tracked QuestionpostPropose Tracked QuestionpostDelete Tracked QuestiondeleteUpdate Tracked QuestionpatchGet Reading SwitchgetSet Reading SwitchputGet Agent Summaryget
analytics
    List ChartsgetCreate ChartpostPreview ChartpostGet ChartgetDelete ChartdeleteUpdate ChartpatchRun ChartpostList DatasetsgetList BoardsgetCreate BoardpostGet TraversalgetGet BoardgetDelete BoarddeleteUpdate Boardpatch
authentication
    List InvitationsgetInvite MemberpostRevoke InvitationdeleteResend InvitationpostList MembersgetRemove MemberdeleteGet Member Conversation AccessgetSet Member Conversation AccesspatchSet Member FlagspatchSet Member RolepatchGet OrganizationgetUpdate OrganizationpatchGet Role FlagsgetSet Role Flagspatch
automations
    List AutomationsgetCreate AutomationpostGet AutomationgetDelete AutomationdeleteUpdate AutomationpatchSet Automation EnabledputGet Automation MapgetRun AutomationpostList Automation RunsgetGet Automation Runget
billable-metrics
    List MetricsgetUsage SummarygetGet Metricget
outbound_calls
    Place CallpostList CampaignsgetCreate CampaignpostGet CampaigngetDelete CampaigndeleteUpdate CampaignpatchActivate CampaignpostLink CollectionpostAdd ContactspostAdd Contacts From CollectionpostRemove Contacts From CollectionpostSet Campaign HoursputPreview Campaign HourspostPause CampaignpostGet Campaign SummarygetExclude ContactpostInclude Contactpost
channels
    List ChannelsgetCreate ChannelpostList Thread SubjectsgetClose Channel ThreadpostList Thread DecisionsgetGet Thread Contact FilegetHand Thread To AgentpostList Thread MailgetGet Prepared ReplygetAsk Again For Prepared ReplypostDiscard Prepared ReplypostSend Prepared ReplypostReply On Channel ThreadpostGet ChannelgetDelete ChanneldeleteUpdate ChannelpatchSend On ChannelpostList Channel ThreadsgetList RostergetCreate Roster EntrypostGet Own Roster EntrygetGet Roster EntrygetDelete Roster EntrydeleteUpdate Roster EntrypatchAdd Roster AddresspostChange Roster AddressputRemove Roster Addressdelete
custom-data
    List CollectionsgetCreate CollectionpostList Collection NamesgetGet CollectiongetDelete CollectiondeleteUpdate CollectionpatchAdd FieldpostDelete FielddeleteUpdate FieldpatchImport RecordspostPlan ImportpostPropose ImportpostGet ImportgetList RecordsgetCreate RecordpostBulk Delete RecordspostBulk Set FieldpostCount RecordsgetList Records Of ContactgetDelete Records Of ContactdeleteGet RecordgetDelete RecorddeleteUpdate Recordpatch
connections
    List ConnectionsgetCreate ConnectionpostCreate Forwarded AddresspostCreate Mail ServerpostDiscover Mail ServerpostAuthorize Microsoft MailboxpostList ProvidersgetGet ConnectiongetDelete ConnectiondeleteUpdate ConnectionpatchGet Forwarded AddressgetCheck Forwarded AddresspostList Person GrantsgetSet Person GrantputRemove Person GrantdeleteGet Mail ServergetUpdate Mail ServerpatchList Mail Server FoldersgetEnter Mail Server PasswordputChange Mail Server ServersputTest Mail Server AgainpostGet Microsoft MailboxgetUpdate Microsoft MailboxpatchList Microsoft Mailbox FoldersgetConsent To Microsoft Mailbox WritespostWithdraw Microsoft Mailbox Writesdelete
custom-tools
    List Custom ToolsgetCreate Custom ToolpostGet Custom ToolgetDelete Custom TooldeleteGet Custom Tool DraftgetEdit Custom Tool DraftpatchPublish Custom ToolpostRestore Custom Tool VersionpostTry Custom ToolpostList Custom Tool Versionsget
rag
    List DocumentsgetUpload DocumentpostSearch DocumentspostGet DocumentgetDelete DocumentdeleteDownload DocumentgetReingest Documentpost
flows
    List FlowsgetCreate FlowpostGet FlowgetDelete FlowdeleteRename FlowpatchAdd Flow EdgepostDelete Flow EdgedeleteSet Entry SteppatchAdd SteppostDelete StepdeleteUpdate SteppatchTest FlowpostList Flow Testsget
dynamic_context
    Create GraphpostGet GraphgetDelete GraphdeleteAdd EdgepostDelete EdgedeleteAdd NodepostDelete NodedeleteUpdate NodepatchSet Rootput
inbox
    Get Inbox Open CountgetSet Inbox PreferencespatchGet Inbox RailgetCreate Inbox ViewpostDelete Inbox ViewdeleteUpdate Inbox Viewpatch
handoff
    Assign Threadpost
interactions
    List InteractionsgetCount InteractionsgetGet InteractiongetSet Conversation LabelspostGet TracegetGet TranscriptgetList LabelsgetCreate LabelpostDelete LabeldeleteUpdate Labelpatch
legal
    Agree To Processing AgreementpostAgree To TermspostLegal BoxesgetList Legal DocumentsgetRead Legal DocumentgetList Legal VersionsgetRead Legal VersiongetDownload Legal VersiongetOrganization Legal HistorygetOwn Legal HistorygetObject To SubprocessorspostWithdraw ObjectionpostLegal Pendingget
not-a-tool
    Agree To Processing AgreementpostAgree To TermspostObject To SubprocessorspostWithdraw Objectionpost
memory
    List MemoriesgetList Memory LinesgetCreate Memory LinepostDelete Memory LinedeleteUpdate Memory LinepatchList Memory PeoplegetGet Memory PersongetForget PersondeleteGet Memory SwitchgetSet Memory SwitchputWipe ContactdeleteGet Conversation MemorygetRecall MemoriespostGet MemorygetDelete MemorydeletePatch Memorypatch
notifications
    List InboxgetGet Unread CountgetMark ReadpostMark Unreaddelete
recipes
    List RecipesgetList Installed RecipesgetGet Installed RecipegetUninstall RecipedeleteSet Recipe EnabledputUpdate Recipe ParameterspatchUpdate RecipepostInstall Recipepost
data-retention
    Get RetentiongetSet Retentionpatch
text
    Open ConversationpostClose ConversationpostAnswer ConfirmationpostGet Sent FilegetSend MessagepostSet Modepatch
tools
    List ToolsgetCreate ToolpostList BuiltinsgetImport Mcp ServerpostImport OpenapipostPreview Openapi ImportpostSuggest Tool ExamplespostGet ToolgetDelete TooldeleteUpdate ToolpatchTest ToolpostList Tool Testsget
trunks
    List Transfer DirectorygetCreate Transfer Directory EntrypostGet Transfer Directory EntrygetDelete Transfer Directory EntrydeleteUpdate Transfer Directory EntrypatchList TrunksgetCreate TrunkpostGet TrunkgetDelete TrunkdeleteUpdate TrunkpatchList Forward Recordsget
Schemas
powered by Zudoku
attek API
attek API

analytics


List Charts

GET
/api/v1/analytics/charts

Every chart this organization has saved, by name, each with the spec it runs. Use when listing what is already saved, before picking one to run or edit. Changes nothing; run one with POST /analytics/charts/{chart_id}/run.

List Charts › Responses

200

Successful Response

​ChartOut[]
ChartOut
created_at
​string · date-time · required
​required
description
​string · required
id
​string · uuid · required
name
​string · required
org_id
​string · uuid · required
​ChartSpec · required

A chart's whole definition — what analytics_charts.spec stores, and what POST /analytics/charts/preview runs unsaved. dataset is one of the catalogue's keys (GET /analytics/datasets lists them): "interactions", "tool_executions", "node_traversal", "usage", the Analyst's "analyst_readings" and "analyst_answers", or "collection:<uuid>" for one of the organization's own custom_data collections.

There is no tz here, and its absence is the design. docs/features/analytics.md: "a chart's days belong to whoever is looking at it — the zone is resolved every time a chart is read, and is never saved with it" (owner, 2026-09-15). This is the same rule window already obeys one field up: what is stored is the question that was asked, not what that question happened to mean at the moment of saving. The zone arrives instead as a per-request argument to service.run_spec/run_chart, resolved at the edge by backend.api.deps.get_person_timezone from the person doing the reading.

A spec read back out of JSONB may still carry a tz key, and it is ignored. Pydantic's default extra="ignore" does that with no branch to maintain and nothing to remove later; DECISIONS.md records why this shape is tolerated where the pre-series shape was rewritten by a migration instead.

updated_at
​string · date-time · required
GET/api/v1/analytics/charts
curl /api/v1/analytics/charts \ --header 'Authorization: Bearer <token>'
Example Responses
[ { "created_at": "2024-08-25T15:00:00Z", "created_by_person_id": "00000000-0000-0000-0000-000000000000", "description": "description", "id": "00000000-0000-0000-0000-000000000000", "name": "name", "org_id": "00000000-0000-0000-0000-000000000000", "spec": { "chart_type": "bar", "dataset": "dataset", "dimension": { "bucket": "hour", "column": "column" }, "series": [ { "filters": [ { "column": "column", "generated": false, "op": "eq", "value": {} } ], "measure": { "agg": "count", "column": "string", "scale": "seconds_to_minutes" }, "name": "name" } ], "window": { "since": "2024-08-25T15:00:00Z", "until": "2024-08-25T15:00:00Z" } }, "updated_at": "2024-08-25T15:00:00Z" } ]
json
application/json

Create Chart

POST
/api/v1/analytics/charts

Save a chart, its spec validated against the dataset catalogue exactly like preview_chart's. Use once a previewed spec is worth keeping and running again later. No zone is resolved or stored; whoever opens it later reads it in their own.

Create Chart › Request Body

ChartIn
name
​string · minLength: 1 · maxLength: 200 · required
​ChartSpec · required

A chart's whole definition — what analytics_charts.spec stores, and what POST /analytics/charts/preview runs unsaved. dataset is one of the catalogue's keys (GET /analytics/datasets lists them): "interactions", "tool_executions", "node_traversal", "usage", the Analyst's "analyst_readings" and "analyst_answers", or "collection:<uuid>" for one of the organization's own custom_data collections.

There is no tz here, and its absence is the design. docs/features/analytics.md: "a chart's days belong to whoever is looking at it — the zone is resolved every time a chart is read, and is never saved with it" (owner, 2026-09-15). This is the same rule window already obeys one field up: what is stored is the question that was asked, not what that question happened to mean at the moment of saving. The zone arrives instead as a per-request argument to service.run_spec/run_chart, resolved at the edge by backend.api.deps.get_person_timezone from the person doing the reading.

A spec read back out of JSONB may still carry a tz key, and it is ignored. Pydantic's default extra="ignore" does that with no branch to maintain and nothing to remove later; DECISIONS.md records why this shape is tolerated where the pre-series shape was rewritten by a migration instead.

description
​string
Default:

Create Chart › Responses

Successful Response

ChartOut
created_at
​string · date-time · required
​required
description
​string · required
id
​string · uuid · required
name
​string · required
org_id
​string · uuid · required
​ChartSpec · required

A chart's whole definition — what analytics_charts.spec stores, and what POST /analytics/charts/preview runs unsaved. dataset is one of the catalogue's keys (GET /analytics/datasets lists them): "interactions", "tool_executions", "node_traversal", "usage", the Analyst's "analyst_readings" and "analyst_answers", or "collection:<uuid>" for one of the organization's own custom_data collections.

There is no tz here, and its absence is the design. docs/features/analytics.md: "a chart's days belong to whoever is looking at it — the zone is resolved every time a chart is read, and is never saved with it" (owner, 2026-09-15). This is the same rule window already obeys one field up: what is stored is the question that was asked, not what that question happened to mean at the moment of saving. The zone arrives instead as a per-request argument to service.run_spec/run_chart, resolved at the edge by backend.api.deps.get_person_timezone from the person doing the reading.

A spec read back out of JSONB may still carry a tz key, and it is ignored. Pydantic's default extra="ignore" does that with no branch to maintain and nothing to remove later; DECISIONS.md records why this shape is tolerated where the pre-series shape was rewritten by a migration instead.

updated_at
​string · date-time · required
POST/api/v1/analytics/charts
curl /api/v1/analytics/charts \ --request POST \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer <token>' \ --data '{ "description": "", "name": "name", "spec": { "chart_type": "bar", "dataset": "dataset", "dimension": { "bucket": "hour", "column": "column" }, "series": [ { "filters": [ { "column": "column", "generated": false, "op": "eq", "value": {} } ], "measure": { "agg": "count", "column": "string", "scale": "seconds_to_minutes" }, "name": "name" } ], "window": { "since": "2024-08-25T15:00:00Z", "until": "2024-08-25T15:00:00Z" } } }'
Example Request Body
{ "description": "", "name": "name", "spec": { "chart_type": "bar", "dataset": "dataset", "dimension": { "bucket": "hour", "column": "column" }, "series": [ { "filters": [ { "column": "column", "generated": false, "op": "eq", "value": {} } ], "measure": { "agg": "count", "column": "string", "scale": "seconds_to_minutes" }, "name": "name" } ], "window": { "since": "2024-08-25T15:00:00Z", "until": "2024-08-25T15:00:00Z" } } }
json
Example Responses
{ "created_at": "2024-08-25T15:00:00Z", "created_by_person_id": "00000000-0000-0000-0000-000000000000", "description": "description", "id": "00000000-0000-0000-0000-000000000000", "name": "name", "org_id": "00000000-0000-0000-0000-000000000000", "spec": { "chart_type": "bar", "dataset": "dataset", "dimension": { "bucket": "hour", "column": "column" }, "series": [ { "filters": [ { "column": "column", "generated": false, "op": "eq", "value": {} } ], "measure": { "agg": "count", "column": "string", "scale": "seconds_to_minutes" }, "name": "name" } ], "window": { "since": "2024-08-25T15:00:00Z", "until": "2024-08-25T15:00:00Z" } }, "updated_at": "2024-08-25T15:00:00Z" }
json
application/json

Preview Chart

POST
/api/v1/analytics/charts/preview

Execute an unsaved chart spec — the builder's engine; nothing needs to be saved to build, demo or test a chart. Use while shaping a chart, before deciding it is worth saving with create_chart.

The spec carries no timezone; days are cut in the acting person's own zone, resolved here (PersonTimezoneDep: stated person, else the organization's, else UTC) — analytics.md, "a chart's days belong to whoever is looking at it".

Preview Chart › Request Body

A chart's whole definition — what `analytics_charts.spec` stores, and what `POST /analytics/charts/preview` runs unsaved. `dataset` is one of the catalogue's keys (`GET /analytics/datasets` lists them): `"interactions"`, `"tool_executions"`, `"node_traversal"`, `"usage"`, the Analyst's `"analyst_readings"` and `"analyst_answers"`, or `"collection:<uuid>"` for one of the organization's own `custom_data` collections. **There is no `tz` here, and its absence is the design.** `docs/features/analytics.md`: "a chart's days belong to whoever is looking at it — the zone is resolved every time a chart is read, and is never saved with it" (owner, 2026-09-15). This is the same rule `window` already obeys one field up: what is stored is the question that was asked, not what that question happened to mean at the moment of saving. The zone arrives instead as a per-request argument to `service.run_spec`/`run_chart`, resolved at the edge by `backend.api.deps.get_person_timezone` from the person doing the reading. **A spec read back out of JSONB may still carry a `tz` key, and it is ignored.** Pydantic's default `extra="ignore"` does that with no branch to maintain and nothing to remove later; `DECISIONS.md` records why this shape is tolerated where the pre-series shape was rewritten by a migration instead.
ChartSpec
chart_type
​ChartType · enum · required
Enum values:
bar
line
area
pie
donut
funnel
stat
dataset
​string · required
​ChartSeries[] · minItems: 1 · maxItems: 8 · required
​required
​

Preview Chart › Responses

Successful Response

A bounded chart run: per series, the largest `cap` groups by value, and whether more existed. Never silent (`docs/legacy-delta.md` REG-08's disposition, read as "keep the caps, lose the silence"). `truncated` is the **chart's**, not one series' — true when any series hit the cap. A reader is being told "this picture is incomplete", and a picture with one clipped line in it is incomplete whichever line it was.
ChartResult
cap
​integer · required
​ChartSeriesResult[] · required
truncated
​boolean · required
POST/api/v1/analytics/charts/preview
curl /api/v1/analytics/charts/preview \ --request POST \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer <token>' \ --data '{ "chart_type": "bar", "dataset": "dataset", "dimension": { "bucket": "hour", "column": "column" }, "series": [ { "filters": [ { "column": "column", "generated": false, "op": "eq", "value": {} } ], "measure": { "agg": "count", "column": "string", "scale": "seconds_to_minutes" }, "name": "name" } ], "window": { "since": "2024-08-25T15:00:00Z", "until": "2024-08-25T15:00:00Z" } }'
Example Request Body
{ "chart_type": "bar", "dataset": "dataset", "dimension": { "bucket": "hour", "column": "column" }, "series": [ { "filters": [ { "column": "column", "generated": false, "op": "eq", "value": {} } ], "measure": { "agg": "count", "column": "string", "scale": "seconds_to_minutes" }, "name": "name" } ], "window": { "since": "2024-08-25T15:00:00Z", "until": "2024-08-25T15:00:00Z" } }
json
Example Responses
{ "cap": 0, "series": [ { "name": "name", "rows": [ { "bucket": "2024-08-25T15:00:00Z", "group": {}, "value": "value" } ] } ], "truncated": true }
json
application/json

Get Chart

GET
/api/v1/analytics/charts/{chart_id}

One saved chart and its spec — what it is called, what it measures and the window rule it covers. Use when opening a specific saved chart by id. Changes nothing. 404 for a chart of another organization, the same as for one that does not exist.

Get Chart › path Parameters

chart_id
​string · uuid · required

Get Chart › Responses

Successful Response

ChartOut
created_at
​string · date-time · required
​required
description
​string · required
id
​string · uuid · required
name
​string · required
org_id
​string · uuid · required
​ChartSpec · required

A chart's whole definition — what analytics_charts.spec stores, and what POST /analytics/charts/preview runs unsaved. dataset is one of the catalogue's keys (GET /analytics/datasets lists them): "interactions", "tool_executions", "node_traversal", "usage", the Analyst's "analyst_readings" and "analyst_answers", or "collection:<uuid>" for one of the organization's own custom_data collections.

There is no tz here, and its absence is the design. docs/features/analytics.md: "a chart's days belong to whoever is looking at it — the zone is resolved every time a chart is read, and is never saved with it" (owner, 2026-09-15). This is the same rule window already obeys one field up: what is stored is the question that was asked, not what that question happened to mean at the moment of saving. The zone arrives instead as a per-request argument to service.run_spec/run_chart, resolved at the edge by backend.api.deps.get_person_timezone from the person doing the reading.

A spec read back out of JSONB may still carry a tz key, and it is ignored. Pydantic's default extra="ignore" does that with no branch to maintain and nothing to remove later; DECISIONS.md records why this shape is tolerated where the pre-series shape was rewritten by a migration instead.

updated_at
​string · date-time · required
GET/api/v1/analytics/charts/{chart_id}
curl /api/v1/analytics/charts/:chart_id \ --header 'Authorization: Bearer <token>'
Example Responses
{ "created_at": "2024-08-25T15:00:00Z", "created_by_person_id": "00000000-0000-0000-0000-000000000000", "description": "description", "id": "00000000-0000-0000-0000-000000000000", "name": "name", "org_id": "00000000-0000-0000-0000-000000000000", "spec": { "chart_type": "bar", "dataset": "dataset", "dimension": { "bucket": "hour", "column": "column" }, "series": [ { "filters": [ { "column": "column", "generated": false, "op": "eq", "value": {} } ], "measure": { "agg": "count", "column": "string", "scale": "seconds_to_minutes" }, "name": "name" } ], "window": { "since": "2024-08-25T15:00:00Z", "until": "2024-08-25T15:00:00Z" } }, "updated_at": "2024-08-25T15:00:00Z" }
json
application/json

Delete Chart

DELETE
/api/v1/analytics/charts/{chart_id}

Delete a saved chart, everywhere. Use when the chart itself should stop existing, not just come off one board — there is no undo. It stops drawing on every board it was placed on, and nothing brings it back — taking it off one board is a different act, an edit to that board's layout.

Delete Chart › path Parameters

chart_id
​string · uuid · required

Delete Chart › Responses

Successful Response

No data returned
DELETE/api/v1/analytics/charts/{chart_id}
curl /api/v1/analytics/charts/:chart_id \ --request DELETE \ --header 'Authorization: Bearer <token>'
Example Responses
No example specified for this content type

Update Chart

PATCH
/api/v1/analytics/charts/{chart_id}

Change a chart's name, description or spec — only the fields given. Use to rename a chart or rework what it measures without losing which boards it is placed on. A new spec is validated like create_chart's and resolves no zone.

Update Chart › path Parameters

chart_id
​string · uuid · required

Update Chart › Request Body

Partial edit — only the provided fields change.
ChartUpdate
​
​
​

Update Chart › Responses

Successful Response

ChartOut
created_at
​string · date-time · required
​required
description
​string · required
id
​string · uuid · required
name
​string · required
org_id
​string · uuid · required
​ChartSpec · required

A chart's whole definition — what analytics_charts.spec stores, and what POST /analytics/charts/preview runs unsaved. dataset is one of the catalogue's keys (GET /analytics/datasets lists them): "interactions", "tool_executions", "node_traversal", "usage", the Analyst's "analyst_readings" and "analyst_answers", or "collection:<uuid>" for one of the organization's own custom_data collections.

There is no tz here, and its absence is the design. docs/features/analytics.md: "a chart's days belong to whoever is looking at it — the zone is resolved every time a chart is read, and is never saved with it" (owner, 2026-09-15). This is the same rule window already obeys one field up: what is stored is the question that was asked, not what that question happened to mean at the moment of saving. The zone arrives instead as a per-request argument to service.run_spec/run_chart, resolved at the edge by backend.api.deps.get_person_timezone from the person doing the reading.

A spec read back out of JSONB may still carry a tz key, and it is ignored. Pydantic's default extra="ignore" does that with no branch to maintain and nothing to remove later; DECISIONS.md records why this shape is tolerated where the pre-series shape was rewritten by a migration instead.

updated_at
​string · date-time · required
PATCH/api/v1/analytics/charts/{chart_id}
curl /api/v1/analytics/charts/:chart_id \ --request PATCH \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer <token>' \ --data '{ "description": "string", "name": "string", "spec": { "chart_type": "bar", "dataset": "dataset", "dimension": { "bucket": "hour", "column": "column" }, "series": [ { "filters": [ { "column": "column", "generated": false, "op": "eq", "value": {} } ], "measure": { "agg": "count", "column": "string", "scale": "seconds_to_minutes" }, "name": "name" } ], "window": { "since": "2024-08-25T15:00:00Z", "until": "2024-08-25T15:00:00Z" } } }'
Example Request Body
{ "description": "string", "name": "string", "spec": { "chart_type": "bar", "dataset": "dataset", "dimension": { "bucket": "hour", "column": "column" }, "series": [ { "filters": [ { "column": "column", "generated": false, "op": "eq", "value": {} } ], "measure": { "agg": "count", "column": "string", "scale": "seconds_to_minutes" }, "name": "name" } ], "window": { "since": "2024-08-25T15:00:00Z", "until": "2024-08-25T15:00:00Z" } } }
json
Example Responses
{ "created_at": "2024-08-25T15:00:00Z", "created_by_person_id": "00000000-0000-0000-0000-000000000000", "description": "description", "id": "00000000-0000-0000-0000-000000000000", "name": "name", "org_id": "00000000-0000-0000-0000-000000000000", "spec": { "chart_type": "bar", "dataset": "dataset", "dimension": { "bucket": "hour", "column": "column" }, "series": [ { "filters": [ { "column": "column", "generated": false, "op": "eq", "value": {} } ], "measure": { "agg": "count", "column": "string", "scale": "seconds_to_minutes" }, "name": "name" } ], "window": { "since": "2024-08-25T15:00:00Z", "until": "2024-08-25T15:00:00Z" } }, "updated_at": "2024-08-25T15:00:00Z" }
json
application/json

Run Chart

POST
/api/v1/analytics/charts/{chart_id}/run

Execute a saved chart. Use when actually drawing a saved chart for someone to look at. The body may override its window and add filters for this run only — a board's own global filters, when this is called for a chart placed on one — and neither is written back to the saved chart.

The days are the reader's, every time. The zone is resolved here from whoever is asking, never from the chart, so the same saved chart opened by two people in one organization is cut into each of their own days.

Run Chart › path Parameters

chart_id
​string · uuid · required

Run Chart › Request Body

anyOf
At least one variant must match. Multiple variants may match simultaneously.

Decision Table

VariantMatching Criteria
type = object
type = null
Properties for ChartRunIn:
`POST /analytics/charts/{chart_id}/run`'s body: an optional window override, and additional filters, for this run only — neither is ever written back to the saved chart. `filters` is how a board's own global filters (`BoardLayout.filters`) reach a chart run from the client: it reads a board, then runs one of its charts with the board's filters attached here (`docs/features/dashboard.md:7`).
ChartRunIn
​Filter[]
​

Run Chart › Responses

Successful Response

A bounded chart run: per series, the largest `cap` groups by value, and whether more existed. Never silent (`docs/legacy-delta.md` REG-08's disposition, read as "keep the caps, lose the silence"). `truncated` is the **chart's**, not one series' — true when any series hit the cap. A reader is being told "this picture is incomplete", and a picture with one clipped line in it is incomplete whichever line it was.
ChartResult
cap
​integer · required
​ChartSeriesResult[] · required
truncated
​boolean · required
POST/api/v1/analytics/charts/{chart_id}/run
curl /api/v1/analytics/charts/:chart_id/run \ --request POST \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer <token>' \ --data '{ "filters": [ { "column": "column", "generated": false, "op": "eq", "value": {} } ], "window": { "since": "2024-08-25T15:00:00Z", "until": "2024-08-25T15:00:00Z" } }'
Example Request Body
{ "filters": [ { "column": "column", "generated": false, "op": "eq", "value": {} } ], "window": { "since": "2024-08-25T15:00:00Z", "until": "2024-08-25T15:00:00Z" } }
json
Example Responses
{ "cap": 0, "series": [ { "name": "name", "rows": [ { "bucket": "2024-08-25T15:00:00Z", "group": {}, "value": "value" } ] } ], "truncated": true }
json
application/json

List Datasets

GET
/api/v1/analytics/datasets

The dataset catalogue this organization may chart over: which datasets exist, their dimensions, their measures and their filterable columns. Use when building a chart spec, to know what fields are available to measure and filter on. The chart editor's entire vocabulary is data-driven from this.

List Datasets › Responses

200

Successful Response

​DatasetOut[]
One dataset's catalogue entry — `GET /analytics/datasets`' whole answer, one of these per dataset. The chart editor's entire left-hand side is data-driven from this: which datasets exist, their dimensions, their measures, their filterable columns and the operators each supports.
DatasetOut
dataset
​string · required
​DatasetDimensionOut[] · required
​DatasetFilterOut[] · required
label
​string · required
​DatasetMeasureOut[] · required
GET/api/v1/analytics/datasets
curl /api/v1/analytics/datasets \ --header 'Authorization: Bearer <token>'
Example Responses
[ { "dataset": "dataset", "dimensions": [ { "bucketable": true, "column": "column", "label": "label" } ], "filters": [ { "column": "column", "kind": "text", "label": "label", "ops": [ "eq" ], "options": [ "string" ] } ], "label": "label", "measures": [ { "agg": "count", "column": "string", "label": "label", "scales": [ "seconds_to_minutes" ] } ] } ]
json
application/json

List Boards

GET
/api/v1/boards

Every board this organization has saved, by name, each with its layout and its global filters. Use when listing saved dashboards before opening one. Changes nothing.

List Boards › Responses

200

Successful Response

​BoardOut[]
BoardOut
created_at
​string · date-time · required
id
​string · uuid · required
​BoardLayout · required

A board's arrangement, and its own global filters (docs/features/dashboard.md:7) — merged into every chart's spec at run time by run_chart/get_board and never written back into the chart itself (§3.5 of the design study).

name
​string · required
org_id
​string · uuid · required
​required
updated_at
​string · date-time · required
GET/api/v1/boards
curl /api/v1/boards \ --header 'Authorization: Bearer <token>'
Example Responses
[ { "created_at": "2024-08-25T15:00:00Z", "id": "00000000-0000-0000-0000-000000000000", "layout": { "charts": [ { "agent_id": "00000000-0000-0000-0000-000000000000", "chart_id": "00000000-0000-0000-0000-000000000000", "h": 0, "kind": "chart", "w": 0, "window": { "since": "2024-08-25T15:00:00Z", "until": "2024-08-25T15:00:00Z" }, "x": 0, "y": 0 } ], "filters": [ { "column": "column", "generated": false, "op": "eq", "value": {} } ] }, "name": "name", "org_id": "00000000-0000-0000-0000-000000000000", "owner_person_id": "00000000-0000-0000-0000-000000000000", "updated_at": "2024-08-25T15:00:00Z" } ]
json
application/json

Create Board

POST
/api/v1/boards

Save a board: an arrangement of saved charts, and the board's own global filters. Use when putting together a dashboard view out of charts that already exist. Every chart id the layout names is checked against this organization before it is written.

Create Board › Request Body

BoardIn
name
​string · minLength: 1 · maxLength: 200 · required
​BoardLayout

A board's arrangement, and its own global filters (docs/features/dashboard.md:7) — merged into every chart's spec at run time by run_chart/get_board and never written back into the chart itself (§3.5 of the design study).

Create Board › Responses

Successful Response

BoardOut
created_at
​string · date-time · required
id
​string · uuid · required
​BoardLayout · required

A board's arrangement, and its own global filters (docs/features/dashboard.md:7) — merged into every chart's spec at run time by run_chart/get_board and never written back into the chart itself (§3.5 of the design study).

name
​string · required
org_id
​string · uuid · required
​required
updated_at
​string · date-time · required
POST/api/v1/boards
curl /api/v1/boards \ --request POST \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer <token>' \ --data '{ "layout": { "charts": [ { "agent_id": "00000000-0000-0000-0000-000000000000", "chart_id": "00000000-0000-0000-0000-000000000000", "h": 0, "kind": "chart", "w": 0, "window": { "since": "2024-08-25T15:00:00Z", "until": "2024-08-25T15:00:00Z" }, "x": 0, "y": 0 } ], "filters": [ { "column": "column", "generated": false, "op": "eq", "value": {} } ] }, "name": "name" }'
Example Request Body
{ "layout": { "charts": [ { "agent_id": "00000000-0000-0000-0000-000000000000", "chart_id": "00000000-0000-0000-0000-000000000000", "h": 0, "kind": "chart", "w": 0, "window": { "since": "2024-08-25T15:00:00Z", "until": "2024-08-25T15:00:00Z" }, "x": 0, "y": 0 } ], "filters": [ { "column": "column", "generated": false, "op": "eq", "value": {} } ] }, "name": "name" }
json
Example Responses
{ "created_at": "2024-08-25T15:00:00Z", "id": "00000000-0000-0000-0000-000000000000", "layout": { "charts": [ { "agent_id": "00000000-0000-0000-0000-000000000000", "chart_id": "00000000-0000-0000-0000-000000000000", "h": 0, "kind": "chart", "w": 0, "window": { "since": "2024-08-25T15:00:00Z", "until": "2024-08-25T15:00:00Z" }, "x": 0, "y": 0 } ], "filters": [ { "column": "column", "generated": false, "op": "eq", "value": {} } ] }, "name": "name", "org_id": "00000000-0000-0000-0000-000000000000", "owner_person_id": "00000000-0000-0000-0000-000000000000", "updated_at": "2024-08-25T15:00:00Z" }
json
application/json

Get Traversal

GET
/api/v1/boards/traversal

The dashboard tree graph: one agent's aggregate node-traversal — entries, transitions and drops per node — over one window. Use when showing how conversations flowed through an agent's flow over time. Changes nothing. An agent with no traversal in the window answers with empty nodes/edges; an agent_id that is not one of this organization's agents — another organization's, a deleted one, or none at all — is a 404.

The window is the same three shapes a chart's is — an absolute since+until, a relative last+unit, or all_time — because dashboard.md makes the tree graph a widget like any other, carrying its own period, and a board that stored one as a rule (BoardChartPlacement .window) must be able to send that rule rather than the dates it meant. Resolving it in the browser instead would put this slice's calendar arithmetic into a second implementation nobody checks — see service._minus for why months are not thirty-day blocks.

Exactly one shape, or none (the last 30 days). Half a shape — one of since/until, one of last/unit — is refused (422) rather than silently answered about a different window than the one asked for.

since and until must each carry a UTC offset (2026-01-01T00:00:00Z or 2026-01-01T01:00:00+01:00). A timestamp without one is refused with 422 naming the field, rather than being guessed at.

include_tests=true counts the conversations marked as a test against a draft as well; they are left out otherwise, as they are from every chart (analytics.md rule 12, #571).

Get Traversal › query Parameters

agent_id
​string · uuid · required
since
​
until
​
last
​
unit
​
all_time
​boolean
Default: false
include_tests
​boolean
Default: false

Get Traversal › Responses

Successful Response

`GET /boards/traversal`'s whole answer — the dashboard tree graph. Totals over the requested window, no time dimension (`dashboard.md`'s "aggregate node-traversal visualization", not a time series). An empty window, or an agent with no traversal in it, answers with two empty lists, never a 404. `truncated` and `cap` are `ChartResult`'s, for the same reason (#462): entries and transitions are each bounded at `cap` groups, and `truncated` is true when either bound bit -- the graph is then the busiest part of the agent's, not all of it, and a reader has to be able to say so.
TraversalOut
​TraversalEdgeOut[] · required
​TraversalNodeOut[] · required
cap
​integer
Default: 200
truncated
​boolean
Default: false
GET/api/v1/boards/traversal
curl '/api/v1/boards/traversal?agent_id=<string>' \ --header 'Authorization: Bearer <token>'
Example Responses
{ "cap": 200, "edges": [ { "count": 0, "from_origin": "00000000-0000-0000-0000-000000000000", "to_origin": "00000000-0000-0000-0000-000000000000" } ], "nodes": [ { "drops": 0, "entries": 0, "exits": 0, "label": "label", "origin_id": "00000000-0000-0000-0000-000000000000", "untitled": true } ], "truncated": false }
json
application/json

Get Board

GET
/api/v1/boards/{board_id}

The board's layout and the charts it names, by id. Use when opening a saved dashboard to render it. Changes nothing. A client reads each named chart through the chart routes; running one with this board's filters attached is POST /analytics/charts/{chart_id}/run's filters.

Get Board › path Parameters

board_id
​string · uuid · required

Get Board › Responses

Successful Response

BoardOut
created_at
​string · date-time · required
id
​string · uuid · required
​BoardLayout · required

A board's arrangement, and its own global filters (docs/features/dashboard.md:7) — merged into every chart's spec at run time by run_chart/get_board and never written back into the chart itself (§3.5 of the design study).

name
​string · required
org_id
​string · uuid · required
​required
updated_at
​string · date-time · required
GET/api/v1/boards/{board_id}
curl /api/v1/boards/:board_id \ --header 'Authorization: Bearer <token>'
Example Responses
{ "created_at": "2024-08-25T15:00:00Z", "id": "00000000-0000-0000-0000-000000000000", "layout": { "charts": [ { "agent_id": "00000000-0000-0000-0000-000000000000", "chart_id": "00000000-0000-0000-0000-000000000000", "h": 0, "kind": "chart", "w": 0, "window": { "since": "2024-08-25T15:00:00Z", "until": "2024-08-25T15:00:00Z" }, "x": 0, "y": 0 } ], "filters": [ { "column": "column", "generated": false, "op": "eq", "value": {} } ] }, "name": "name", "org_id": "00000000-0000-0000-0000-000000000000", "owner_person_id": "00000000-0000-0000-0000-000000000000", "updated_at": "2024-08-25T15:00:00Z" }
json
application/json

Delete Board

DELETE
/api/v1/boards/{board_id}

Delete a board: its layout and its global filters. Use when a dashboard arrangement itself should stop existing. The charts it placed are the organization's own objects and survive it — this deletes the arrangement, not what was arranged.

Delete Board › path Parameters

board_id
​string · uuid · required

Delete Board › Responses

Successful Response

No data returned
DELETE/api/v1/boards/{board_id}
curl /api/v1/boards/:board_id \ --request DELETE \ --header 'Authorization: Bearer <token>'
Example Responses
No example specified for this content type

Update Board

PATCH
/api/v1/boards/{board_id}

Change a board's name or layout — only the fields given. Use when rearranging a dashboard's charts or renaming it.

Update Board › path Parameters

board_id
​string · uuid · required

Update Board › Request Body

Partial edit — only the provided fields change. No board is anyone's default (#525): which board a campaign shows is the campaign's own field.
BoardUpdate
​
​

Update Board › Responses

Successful Response

BoardOut
created_at
​string · date-time · required
id
​string · uuid · required
​BoardLayout · required

A board's arrangement, and its own global filters (docs/features/dashboard.md:7) — merged into every chart's spec at run time by run_chart/get_board and never written back into the chart itself (§3.5 of the design study).

name
​string · required
org_id
​string · uuid · required
​required
updated_at
​string · date-time · required
PATCH/api/v1/boards/{board_id}
curl /api/v1/boards/:board_id \ --request PATCH \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer <token>' \ --data '{ "layout": { "charts": [ { "agent_id": "00000000-0000-0000-0000-000000000000", "chart_id": "00000000-0000-0000-0000-000000000000", "h": 0, "kind": "chart", "w": 0, "window": { "since": "2024-08-25T15:00:00Z", "until": "2024-08-25T15:00:00Z" }, "x": 0, "y": 0 } ], "filters": [ { "column": "column", "generated": false, "op": "eq", "value": {} } ] }, "name": "string" }'
Example Request Body
{ "layout": { "charts": [ { "agent_id": "00000000-0000-0000-0000-000000000000", "chart_id": "00000000-0000-0000-0000-000000000000", "h": 0, "kind": "chart", "w": 0, "window": { "since": "2024-08-25T15:00:00Z", "until": "2024-08-25T15:00:00Z" }, "x": 0, "y": 0 } ], "filters": [ { "column": "column", "generated": false, "op": "eq", "value": {} } ] }, "name": "string" }
json
Example Responses
{ "created_at": "2024-08-25T15:00:00Z", "id": "00000000-0000-0000-0000-000000000000", "layout": { "charts": [ { "agent_id": "00000000-0000-0000-0000-000000000000", "chart_id": "00000000-0000-0000-0000-000000000000", "h": 0, "kind": "chart", "w": 0, "window": { "since": "2024-08-25T15:00:00Z", "until": "2024-08-25T15:00:00Z" }, "x": 0, "y": 0 } ], "filters": [ { "column": "column", "generated": false, "op": "eq", "value": {} } ] }, "name": "name", "org_id": "00000000-0000-0000-0000-000000000000", "owner_person_id": "00000000-0000-0000-0000-000000000000", "updated_at": "2024-08-25T15:00:00Z" }
json
application/json

analystauthentication