Skip to main content

Overview

This is the reference for extracting operational data from Xenia into dashboards and BI tools (Power BI, Looker Studio, custom warehouses). Everything here is reachable with a client key and falls into four groups:
  • Submission records & counts — raw submission (checklist log) data and status breakdowns
  • Task analytics — pre-aggregated task/compliance metrics (counts, trends, on-time rates)
  • Submission exports — Excel/PDF/spreadsheet generation
  • Grid reports & scheduled reports — saved report definitions, spreadsheet exports, and automated delivery

Authentication & base URL

Base URL is https://api.xenia.team; every path starts with /api/v1. Authenticate with your client credentials (see Client Key Setup):
The workspace is derived from the key — you don’t send a workspace-id header. Where a path contains {workspaceId} it must be your key’s own workspace; the ops reporting endpoints also accept an unscoped form (/api/v1/ops/...) and resolve the workspace from the key automatically. Each route enforces the key’s default-user permission — task analytics and grid / scheduled-report reads require CAN_VIEW_REPORTING (grid / scheduled-report writes require CAN_MANAGE_DASHBOARDS), while submission records and counts are instead scoped to the key user’s authorized locations (no CAN_VIEW_REPORTING gate).
Responses use Xenia’s standard envelope: a data payload plus a meta object. There is no status, statusCode, success, or requestId field, and successful POST calls return HTTP 200 (report-schedule creation returns 201; PDF generation returns 202). Analytics/report meta is typically empty ({}) — the payload and any pagination live under data. Requests are bounded by an ALB timeout of roughly 60 seconds, so filter and paginate aggressively.

Submission Records

Raw submission (checklist log) records — the backbone of most BI pulls. All fields are optional; always set an explicit limit (the default is enormous). Endpoint: POST /api/v1/ops/template-submissions
Request Body (all optional): Response:
Page against meta.totalCount (the total matching-row count). meta.count is an object — a per-status breakdown — not a number. Set includeItems: false for lighter payloads when you only need record-level fields.

Submission Count by Status

Status counts using the same filters as submission records — a cheap way to power a status tile. Endpoint: POST /api/v1/ops/submissions-count-by-status
Request Body (all optional): checklists, fromDate, toDate, users, lastItemUpdatedBy, statuses, locations, searchText. Response:

Task Analytics

Pre-aggregated task and compliance metrics. All are POST, all respond with { data, meta: {} }, and none of the request bodies are strictly validated (every field is optional).
There are two body shapes. The three “count-by” endpoints take a flat filter object (fromDate, toDate, locations, assignees, taskStatuses, categories, priorities, …). The four location/trend endpoints take a nested filters object with keys location (singular), dateRange ([from, to]), dueDate, schedules, projects, and roles.

Task Count by Status

Endpoint: POST /api/v1/ops/reports/tasks/count-by-status
Response — an object keyed by task status (the Open bucket also carries a trend):

Task Count by Assignees

Endpoint: POST /api/v1/ops/reports/tasks/count-by-assignees Same flat filter body, plus optional assigneeType ("user" | "team" | "location").
Response — array ordered by count desc:

Task Count by Categories

Endpoint: POST /api/v1/ops/reports/tasks/count-by-categories Same flat filter body. Response — array ordered by count desc:

Weekly Completion Trend

Endpoint: POST /api/v1/ops/reports/tasks/weekly-completion
Request Body: filters (nested); view ("schedules" default, or "projects"); page (default 0; negative = past 4-week blocks, positive = future). Response:

Schedule Completion by Location

Endpoint: POST /api/v1/ops/reports/tasks/schedule-completion-by-location
Request Body: filters (nested); optional locationLevelId (roll stats up to a location level). Response:

On-Time vs Late by Location

Endpoint: POST /api/v1/ops/reports/tasks/on-time-late-submission-by-location
Response (onTime/overdue are percentages):

Daily Compliance

Endpoint: POST /api/v1/ops/reports/tasks/daily-compliance Uses its own nested filters keys.
Request Body: filters.date (single date; defaults to today in the user’s timezone), filters.location (LocationId[]; empty ⇒ the key user’s authorized locations), filters.project (ProjectId[]), filters.onlyMissed (boolean — keep only missed tasks). ResponseTaskState is one of Completed, Missed, OverDue, Open:

Submission Exports

Generate downloadable files from submissions. See the Submission Exports guide for full detail; the essentials:
The logs-pdf and public-PDF endpoints are the two exceptions to the standard envelope: they return a raw { status, code, message, data } body with HTTP 202 (or 200 when a PDF is already rendered).

Grid Reports

Saved, composable report definitions with per-view configuration, thresholds, and spreadsheet export. Grid reports require the Advanced Dashboards feature on the workspace, plus CAN_VIEW_REPORTING (reads) or CAN_MANAGE_DASHBOARDS (writes).

List Grid Reports

Endpoint: GET /api/v1/mgt/grid-reports
Query: offset (default 0), limit (1–100, default 100). Response: { "data": { "gridReports": [ { "id": "...", "name": "...", "description": "..." } ] }, "meta": {} }
A workspace-scoped form GET /api/v1/mgt/workspaces/{workspaceId}/grid-reports also exists and behaves identically (workspace is otherwise taken from your key).

Create Grid Report

Endpoint: POST /api/v1/mgt/grid-reports
Request Body (both optional): name (≤255), description (≤1000). Returns HTTP 200 { "data": { "gridReport": { ... } }, "meta": {} }.

Create a View

Endpoint: POST /api/v1/mgt/grid-reports/{gridReportId}/view A view captures the metric, grouping, date range, and filters for a grid report. Common fields (all optional, with sensible defaults): Returns { "data": { "gridReportView": { ... }, "viewOrder": ["view-uuid", ...] }, "meta": {} }.

Export a View to Spreadsheet

Endpoint: GET /api/v1/mgt/grid-report-views/{gridReportViewId}/spreadsheet
Returns the raw XLSX file (not a JSON envelope): Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet with a Content-Disposition: attachment filename.

Configure Thresholds

Attach a color-coded threshold to a view. Endpoint: POST /api/v1/mgt/grid-report-views/{gridReportViewId}/thresholds
Request Body: color (required), label (required), comparator (required — one of eq, gt, gte, lt, lte, btn), value (required number), secondValue (used with btn). Returns { "data": { "gridReportViewThreshold": { ... } }, "meta": {} }.

Scheduled Reports

Automate generation and delivery of grid reports, task exports, and submission exports on a recurring schedule. Reads need CAN_VIEW_REPORTING; writes need CAN_MANAGE_DASHBOARDS. These routes are workspace-scoped — the /workspaces/{workspaceId} segment is required.

List Report Schedules

Endpoint: GET /api/v1/mgt/workspaces/{workspaceId}/report-schedules
Query (optional): page (default 1), limit (1–100, default 20), search, isActive, frequency (DAILY/WEEKLY/MONTHLY), sortBy, sortOrder. Response:

Create Report Schedule

Endpoint: POST /api/v1/mgt/workspaces/{workspaceId}/report-schedules
Request Body:
recipients are workspace entities ({ type, id }), not email addresses. There is no schedule wrapper and no top-level format field — frequency, frequencyConfig, deliveryTime, timezone, dateRangeFilter, and dataVisibility are all top-level, and export format lives in reportMetadata.exportFormat.
Returns HTTP 201 { "data": { "reportSchedule": { ..., "ReportScheduleRecipients": [...] } }, "meta": {} }.

Pause / Resume

Endpoint: POST /api/v1/mgt/workspaces/{workspaceId}/report-schedules/{scheduleId}/toggle Body { "isActive": true } (required boolean). Returns { "data": { "reportSchedule": { ... } }, "meta": {} } (the response body carries no message field).

Run Now

Endpoint: POST /api/v1/mgt/workspaces/{workspaceId}/report-schedules/{scheduleId}/run-now Optional body { "force": true } (bypasses the duplicate-run check). Returns:
(400 if the schedule has no recipients; 404 if the schedule doesn’t exist.)

Execution History

Endpoint: GET /api/v1/mgt/workspaces/{workspaceId}/report-schedules/{scheduleId}/executions Query (optional): page (default 1), limit (1–100, default 20), status (PENDING/RUNNING/COMPLETED/FAILED), sortBy, sortOrder. Response:

Power BI

For a complete, step-by-step Power BI walkthrough — creating credentials, verifying them, the Power Query (M) examples for POST/GET endpoints and keyed-object responses, scheduled refresh in the Power BI Service, and troubleshooting — see the dedicated Connecting Xenia Data to Power BI guide. In short: use Power BI’s Web connector with a static BaseUrl + RelativePath, put x-client-key / x-client-secret in the request Headers, and set the credential type to Anonymous. Keep queries filtered — the server caps requests at ~60 seconds.

Best Practices

Submission records default to an enormous limit. Always send fromDate/toDate and an explicit limit, and page against meta.totalCount. Unbounded pulls risk the ~60s timeout.
Don’t recompute compliance/completion in your BI tool from raw records when a /reports/tasks/... endpoint already returns the aggregate — it’s far cheaper and faster.
For recurring delivery to people, use scheduled reports (recipients are USER/TEAM/ROLE entities). For live dashboards, pull the analytics/records endpoints on your BI tool’s refresh cadence.
The count-by-* endpoints take a flat filter object; the location/trend endpoints take a nested filters object with location (singular) and dateRange. Mixing them silently drops filters.