Overview
A project in Xenia is a recurring schedule that generates tasks over time. It is not a task itself — it is the rule that keeps producing them, plus the history of everything it has produced. Through a client key you can browse your workspace’s projects, read one in full, inspect the schedules and tasks a project has generated, pull its status analytics, edit it, pause or resume it, end it so it stops generating new work, and delete it outright. Creating a project is done through the task endpoint, not a project endpoint — see Create a project. Projects require the Projects feature on your workspace. Every route in this guide returns403 without it.
Authentication & base URL
All requests go tohttps://api.xenia.team and every path starts with /api/v1. Authenticate with
your client credentials (see Client Key Setup):
{workspaceId} in each path must be your key’s own
workspace. Always include the /workspaces/{workspaceId} segment — the unscoped project variants
are not available to API keys and return 403.
Project routes use the
extra_meta envelope: a data payload plus an extra_meta object that
carries a human-readable message on the lifecycle calls. The one exception is
Search Projects, which also returns a meta object with pagination counts.
Successful POST and PUT calls return HTTP 200.Every route addressed by a
{projectId} honours that project’s access list. A project with no
access list is visible to everyone in the workspace; once an access list exists, the key’s user must
match it by user id, one of their team ids, or their role id, and gets 403 otherwise.Create a project
There is noPOST /projects. A project is created by calling
Create Task with "isProject": true:
projectType as user, asset or role and supply the matching target: assignees for
user, assets for asset, assigneesRoles.roles for role. A missing target returns 400
(Assignees are required for project, Assets are required for project or
Role is required for project), and any other projectType returns 400 Unsupported project type.
The call returns as soon as the project row exists; its schedules are generated in the background.
Until that finishes the project’s state is not ready, and the lifecycle routes below return
400 Project is under processing. Poll Get Project until state is ready.
See Recurring projects in the task guide for
the full create-body contract.
List projects
Returns every project the key’s user can access, each with its schedule-status breakdown. This endpoint is not paginated — it returns the full set.
It is compared against the literal string
true; any other value counts as false.
Each row carries an analytics array with that project’s schedule-status counts, so a single call
is usually enough to build a dashboard.
Search projects
Filtered, sorted and offset-paged search. It is aPOST because the filters travel in the body —
it creates nothing.
offset (0), limit (10), searchText (""), sortField (createdAt),
sortOrder (DESC), status (ALL) and advanceFilters (null). status accepts ALL,
ACTIVE, PAUSED or EXPIRED. Unknown fields are ignored.
This is the one project route that returns a meta object alongside data, carrying total (how
many projects matched the filter in total), filtered (how many are in this page) and the offset,
limit, searchText, sortField and sortOrder the query actually ran with. Page by increasing
offset until offset + filtered reaches total.
Project details
Returns one project with its next upcoming task (NextTask), its currently active task
(ActiveTask), its access list, and a server-computed isEditable flag.
Requires Manage Tasks. An id that does not exist in your workspace returns
403, not 404 — the project access check runs before the handler and denies when it cannot load the project.
Schedules and generated tasks
Returns every schedule on the project, the tasks each schedule has generated grouped by schedule, and astats block.
data.stats gives totalTasks, completedTasks and completionRate. data.tasksBySchedule maps
each seriesId to the tasks it produced, which is how you tell which schedule inside a project is
falling behind.
Analytics
Two endpoints, bothPOST with no request body:
data) and its share of the total
(percentage), including statuses with data: 0. Task analytics returns one row per status
with a count only, omits statuses with no tasks, and returns data as a string because it comes
straight from a SQL COUNT.
Both require Manage Tasks.
Edit a project
Updates the project and, optionally, the tasks it has already generated.title, description, additionalDescription, priority, taskStatus,
startTime, dueTime, recurringOnDay, recurringDueDay, recurringByEvery, intervalWeek,
dueIntervalWeek, isRangedTask, dueCycleOffset, requestThisTask, notification,
LocationId, AssetId, ChecklistLogId, assignees, assigneesRoles, isChecklistRequired,
isTimeBound. Anything else in the body is ignored.
targetTasksStatus decides which already-generated tasks the change is applied to — e.g.
["Open"] updates open tasks and leaves completed ones alone. Omit it to change only the project
going forward.
Two other cases return 400: a project whose state is not yet ready
(Project is under processing), and a non-recurring project that already has active one-off tasks
(Can not edit project with active one-off tasks!). On success the project’s state becomes
updating while its schedules regenerate in the background.
Requires Edit Project and Manage Tasks.
Pause or resume a project
Pausing stops the project generating new tasks; resuming starts it again.extra_meta.message states which way it went
(Project has been paused / Project has been resumed). Requires Pause/Resume Project and
Manage Tasks. Returns 400 Project is under processing if state is not yet ready.
End a project
Ends every schedule on the project so it stops generating work, while leaving the project and every task it has already produced intact and reportable.data is always an empty object on success. Requires Manage Tasks, and
returns 400 Project is under processing if state is not yet ready.
Ending is permanent — there is no “un-end” call — but it is not destructive: nothing is deleted. If
you only want to stop work temporarily, use pause instead.
Delete a project
title before deleting, so a mistyped id fails safely instead of
succeeding on the wrong project.
Requires Delete Project and Manage Tasks.
Permissions
Each route enforces the key’s default-user role (or the user named inx-client-user), on top of
the Projects feature and an active subscription:
What you can’t do via API key
These project operations exist in Xenia but are not reachable with a client key — they return403 Forbidden: API key not authorized for this route. Use the web or mobile app for them:
- Add a schedule to a project (
POST …/projects/{projectId}/add-schedule) - Attach a new task to a one-off project (
POST …/projects/{projectId}/tasks/add) - Change a project’s access list (
PUT …/projects/{projectId}/access)
"isProject": true.
Related Guides
- Task Management — create the tasks and projects this guide reads
- Data Extraction & Reporting — task analytics and BI integration
- User Lifecycle — manage the users projects assign work to