Goals
Goals with targets that show how far a team or a person has got. A goal has an owner, a period and up to 20 targets; its progress is the weighted average of its targets. A target is a number, a currency amount, a boolean or a tasks target counted from lists and tasks. A goal is private (its owner), people (its owner and the people it is shared with) or workspace (every member; a guest only when named). Guests can read goals shared with them and cannot create one. A token limited to projects cannot use these routes. A write made with an agent's token follows the rules that hold that agent.
List goals
GET /api/v2/goals · beta
Lists the goals the caller can read, by name.
A counted target is answered with the numbers last counted; a count that is due is made again behind the answer.
| Auth | Session or API token with the read scope |
| Token limited to projects | Refused |
| Permission | An active seat in the workspace. Only goals the caller can read are listed |
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
archived | boolean | true lists the archived goals instead of the live ones. | |
mine | boolean | true keeps the goals the caller owns or is named on. |
Request
GET /api/v2/goals
Authorization: Bearer <token>
companyid: <company id>Response
{
"status": true,
"statusText": "Goals fetched successfully.",
"data": [
{
"_id": "<goal id>",
"name": "Launch 2.0",
"description": "",
"ownerUserId": "<user id>",
"periodStart": "2026-10-01",
"periodEnd": "2026-12-31",
"visibility": "workspace",
"sharedWith": [],
"sharedWithMe": false,
"isOwner": true,
"color": "#2F3990",
"progressPct": 40,
"targets": [
{
"id": "<target id>",
"name": "Revenue",
"kind": "currency",
"weight": 1,
"progressPct": 40,
"reachedAt": null,
"start": 0,
"target": 50000,
"current": 20000,
"unit": "",
"currencyCode": "USD",
"updatedBy": "<user id>",
"updatedAt": "2026-10-01T09:30:00.000Z"
}
],
"archived": false,
"canEdit": true,
"canSetValue": true,
"createdBy": "<user id>",
"createdAt": "2026-10-01T09:30:00.000Z",
"updatedAt": "2026-10-01T09:30:00.000Z"
}
]
}data is the goal as the caller may see it; the example shows one currency target. A boolean target carries done; a tasks target carries sources, counted, notCounted, dirty, updating and sourceNames in place of start, target and current. sharedWith lists people only for someone who can change the goal. canEdit and canSetValue say what the caller may do with it. A goal that has been summarised carries summary: its text, when it was made (madeAt) and whether the numbers have changed since (stale).
Paging
None. The whole list is returned.
Errors
| Status | When |
|---|---|
| 400 | archived or mine is not true or false. |
| 401 | No token, a token that is invalid, expired or revoked, or no valid companyid header. |
| 403 | The token lacks the read scope, or its person is no longer a member of the workspace. A token limited to projects is refused here. The caller has no active seat in the workspace. |
| 429 | Too many requests from this address. Wait retryAfter seconds and send it again. |
Create a goal
POST /api/v2/goals · beta
Creates a goal, with its targets if they are sent.
The caller becomes its owner. A goal starts private unless visibility says otherwise. A tasks target is counted before the answer.
| Auth | Session or API token with the write scope |
| Token limited to projects | Refused |
| Permission | An active seat in the workspace that is not a guest |
Body
| Field | Type | Required | Description |
|---|---|---|---|
name | string | yes | The goal's name, 1 to 120 characters. |
description | string | Up to 2000 characters. | |
periodStart | date | The first day, written YYYY-MM-DD, or empty. | |
periodEnd | date | The last day, written YYYY-MM-DD, or empty. Not before periodStart. | |
visibility | string | private, people or workspace. Defaults to private. | |
sharedWith | id[] | Up to 100 active members to share the goal with. It must be empty for a private goal. | |
color | string | A colour written #rrggbb, or empty. | |
targets | object[] | Up to 20 targets, each as described under Add a target without the goal. |
Any other key is refused.
Request
POST /api/v2/goals
Authorization: Bearer <token>
companyid: <company id>
Content-Type: application/json
{
"name": "Launch 2.0",
"visibility": "workspace",
"periodStart": "2026-10-01",
"periodEnd": "2026-12-31",
"targets": [
{
"name": "Revenue",
"kind": "currency",
"currencyCode": "USD",
"start": 0,
"target": 50000
}
]
}Response
{
"status": true,
"statusText": "Goal saved.",
"data": {
"_id": "<goal id>",
"name": "Launch 2.0",
"description": "",
"ownerUserId": "<user id>",
"periodStart": "2026-10-01",
"periodEnd": "2026-12-31",
"visibility": "workspace",
"sharedWith": [],
"sharedWithMe": false,
"isOwner": true,
"color": "#2F3990",
"progressPct": 40,
"targets": [
{
"id": "<target id>",
"name": "Revenue",
"kind": "currency",
"weight": 1,
"progressPct": 40,
"reachedAt": null,
"start": 0,
"target": 50000,
"current": 20000,
"unit": "",
"currencyCode": "USD",
"updatedBy": "<user id>",
"updatedAt": "2026-10-01T09:30:00.000Z"
}
],
"archived": false,
"canEdit": true,
"canSetValue": true,
"createdBy": "<user id>",
"createdAt": "2026-10-01T09:30:00.000Z",
"updatedAt": "2026-10-01T09:30:00.000Z"
}
}data is the goal as the caller may see it; the example shows one currency target. A boolean target carries done; a tasks target carries sources, counted, notCounted, dirty, updating and sourceNames in place of start, target and current. sharedWith lists people only for someone who can change the goal. canEdit and canSetValue say what the caller may do with it. A goal that has been summarised carries summary: its text, when it was made (madeAt) and whether the numbers have changed since (stale).
Errors
| Status | When |
|---|---|
| 400 | A key that is not known, a value of the wrong type or size, or a body that changes nothing. The answer names the field that was refused. A person can own at most 200 goals. |
| 401 | No token, a token that is invalid, expired or revoked, or no valid companyid header. |
| 403 | The token lacks the write scope, or its person is no longer a member of the workspace. A token limited to projects is refused here. The caller has no active seat in the workspace. |
| 429 | Too many requests from this address. Wait retryAfter seconds and send it again. |
List the goals a task counts towards
GET /api/v2/goals/for-task/:taskId · beta
Lists the targets that count a task, with the goal each belongs to.
A target counts a task when it names the task, or names its list and the task is a top-level task. Only live goals the caller can read are listed.
| Auth | Session or API token with the read scope |
| Token limited to projects | Refused |
| Permission | An active seat in the workspace. The task must be one the caller can open |
Path parameters
| Name | Type | Description |
|---|---|---|
taskId | id | The task. |
Request
GET /api/v2/goals/for-task/<taskId>
Authorization: Bearer <token>
companyid: <company id>Response
{
"status": true,
"statusText": "Goals fetched successfully.",
"data": [
{
"goalId": "<goal id>",
"goalName": "Launch 2.0",
"color": "#2F3990",
"progressPct": 40,
"targetId": "<target id>",
"targetName": "Ship the tasks",
"targetProgressPct": 60,
"through": "task"
}
]
}through is task when the target names the task and list when it counts the task's list. The rows are ordered by goal name, then target name.
Paging
None.
Errors
| Status | When |
|---|---|
| 401 | No token, a token that is invalid, expired or revoked, or no valid companyid header. |
| 403 | The token lacks the read scope, or its person is no longer a member of the workspace. A token limited to projects is refused here. The caller has no active seat in the workspace. |
| 404 | The task does not exist, or the caller cannot open it. |
| 429 | Too many requests from this address. Wait retryAfter seconds and send it again. |
Read a goal
GET /api/v2/goals/:id · beta
Returns one goal, live or archived.
Needs an active seat in the workspace; a token limited to some projects is refused with 403. A goal is readable by its owner, by people it is shared with by name, and, when its visibility is workspace, by every member except guests, who need to be named. A goal the caller cannot read answers 404 as one that does not exist does. Answers with data: the goal, live or archived, with its targets, progressPct, and canEdit.
| Auth | Session or API token with the read scope |
| Token limited to projects | Refused |
| Permission | An active seat in the workspace. The goal must be one the caller can read |
Path parameters
| Name | Type | Description |
|---|---|---|
id | id | The goal. |
Request
GET /api/v2/goals/<id>
Authorization: Bearer <token>
companyid: <company id>Response
{
"status": true,
"statusText": "Goal fetched successfully.",
"data": {
"_id": "<goal id>",
"name": "Launch 2.0",
"description": "",
"ownerUserId": "<user id>",
"periodStart": "2026-10-01",
"periodEnd": "2026-12-31",
"visibility": "workspace",
"sharedWith": [],
"sharedWithMe": false,
"isOwner": true,
"color": "#2F3990",
"progressPct": 40,
"targets": [
{
"id": "<target id>",
"name": "Revenue",
"kind": "currency",
"weight": 1,
"progressPct": 40,
"reachedAt": null,
"start": 0,
"target": 50000,
"current": 20000,
"unit": "",
"currencyCode": "USD",
"updatedBy": "<user id>",
"updatedAt": "2026-10-01T09:30:00.000Z"
}
],
"archived": false,
"canEdit": true,
"canSetValue": true,
"createdBy": "<user id>",
"createdAt": "2026-10-01T09:30:00.000Z",
"updatedAt": "2026-10-01T09:30:00.000Z"
}
}data is the goal as the caller may see it; the example shows one currency target. A boolean target carries done; a tasks target carries sources, counted, notCounted, dirty, updating and sourceNames in place of start, target and current. sharedWith lists people only for someone who can change the goal. canEdit and canSetValue say what the caller may do with it. A goal that has been summarised carries summary: its text, when it was made (madeAt) and whether the numbers have changed since (stale).
Errors
| Status | When |
|---|---|
| 401 | No token, a token that is invalid, expired or revoked, or no valid companyid header. |
| 403 | The token lacks the read scope, or its person is no longer a member of the workspace. A token limited to projects is refused here. The caller has no active seat in the workspace. |
| 404 | The goal does not exist, or the caller cannot read it. |
| 429 | Too many requests from this address. Wait retryAfter seconds and send it again. |
Change a goal
PATCH /api/v2/goals/:id · beta
Changes a goal's name, period, audience, colour or owner. Only the keys sent are changed.
Targets have routes of their own. Changing visibility, sharedWith or ownerUserId is refused with the code sources_would_drop, and the sources that would drop out, when the goal counts tasks that not everyone who would then read it can open. Making a goal private empties sharedWith.
| Auth | Session or API token with the write scope |
| Token limited to projects | Refused |
| Permission | An active seat in the workspace. The goal must be one the caller can read, and one the caller can change: its owner, or an owner or admin when the goal is visible to the workspace |
Path parameters
| Name | Type | Description |
|---|---|---|
id | id | The goal. |
Body
| Field | Type | Required | Description |
|---|---|---|---|
name | string | 1 to 120 characters. | |
description | string | Up to 2000 characters. | |
periodStart | date | Written YYYY-MM-DD, or empty. | |
periodEnd | date | Written YYYY-MM-DD, or empty. Not before periodStart. | |
visibility | string | private, people or workspace. | |
sharedWith | id[] | Up to 100 active members. It must be empty for a private goal. | |
color | string | A colour written #rrggbb, or empty. | |
ownerUserId | id | The new owner: an active member who is not a guest. |
Any other key is refused.
Request
PATCH /api/v2/goals/<id>
Authorization: Bearer <token>
companyid: <company id>
Content-Type: application/json
{ "visibility": "people", "sharedWith": ["<user id>"] }Response
{
"status": true,
"statusText": "Goal saved.",
"data": {
"_id": "<goal id>",
"name": "Launch 2.0",
"description": "",
"ownerUserId": "<user id>",
"periodStart": "2026-10-01",
"periodEnd": "2026-12-31",
"visibility": "workspace",
"sharedWith": [],
"sharedWithMe": false,
"isOwner": true,
"color": "#2F3990",
"progressPct": 40,
"targets": [
{
"id": "<target id>",
"name": "Revenue",
"kind": "currency",
"weight": 1,
"progressPct": 40,
"reachedAt": null,
"start": 0,
"target": 50000,
"current": 20000,
"unit": "",
"currencyCode": "USD",
"updatedBy": "<user id>",
"updatedAt": "2026-10-01T09:30:00.000Z"
}
],
"archived": false,
"canEdit": true,
"canSetValue": true,
"createdBy": "<user id>",
"createdAt": "2026-10-01T09:30:00.000Z",
"updatedAt": "2026-10-01T09:30:00.000Z"
}
}data is the goal as the caller may see it; the example shows one currency target. A boolean target carries done; a tasks target carries sources, counted, notCounted, dirty, updating and sourceNames in place of start, target and current. sharedWith lists people only for someone who can change the goal. canEdit and canSetValue say what the caller may do with it. A goal that has been summarised carries summary: its text, when it was made (madeAt) and whether the numbers have changed since (stale).
Errors
| Status | When |
|---|---|
| 400 | A key that is not known, a value of the wrong type or size, or a body that changes nothing. The answer names the field that was refused. |
| 401 | No token, a token that is invalid, expired or revoked, or no valid companyid header. |
| 403 | The token lacks the write scope, or its person is no longer a member of the workspace. A token limited to projects is refused here. The caller has no active seat in the workspace. |
| 404 | The goal does not exist, or the caller cannot read it. |
| 409 | The goal is archived. Restore it first. The goal was changed at the same moment. Send the request again. |
| 429 | Too many requests from this address. Wait retryAfter seconds and send it again. |
Summarise a goal
POST /api/v2/goals/:id/summary · beta
Writes a short summary of a goal's progress with the workspace's AI, keeps it on the goal and answers with the whole goal.
The summary is made only when this route is called, from the goal's name, its period and its targets with their numbers. It is kept until the next one is made; stale says the numbers have changed since.
It needs AI switched on for the workspace and a model the server can reach, and it is booked to the workspace's AI budget.
| Auth | Session or API token with the write scope |
| Token limited to projects | Refused |
| Permission | An active seat in the workspace. The goal must be one the caller can read, and one the caller can change: its owner, or an owner or admin when the goal is visible to the workspace |
Path parameters
| Name | Type | Description |
|---|---|---|
id | id | The goal. |
The body must be empty.
Request
POST /api/v2/goals/<id>/summary
Authorization: Bearer <token>
companyid: <company id>Response
{
"status": true,
"statusText": "Summary saved.",
"data": {
"_id": "<goal id>",
"name": "Launch 2.0",
"description": "",
"ownerUserId": "<user id>",
"periodStart": "2026-10-01",
"periodEnd": "2026-12-31",
"visibility": "workspace",
"sharedWith": [],
"sharedWithMe": false,
"isOwner": true,
"color": "#2F3990",
"progressPct": 40,
"targets": [
{
"id": "<target id>",
"name": "Revenue",
"kind": "currency",
"weight": 1,
"progressPct": 40,
"reachedAt": null,
"start": 0,
"target": 50000,
"current": 20000,
"unit": "",
"currencyCode": "USD",
"updatedBy": "<user id>",
"updatedAt": "2026-10-01T09:30:00.000Z"
}
],
"archived": false,
"canEdit": true,
"canSetValue": true,
"createdBy": "<user id>",
"createdAt": "2026-10-01T09:30:00.000Z",
"updatedAt": "2026-10-01T09:30:00.000Z",
"summary": {
"text": "Launch 2.0 is 40% of the way. Revenue stands at 20,000 of 50,000 USD with the period ending on 31 December.",
"madeAt": "2026-10-01T09:30:00.000Z",
"stale": false
}
}
}data is the goal as in Read a goal, with its new summary.
Errors
| Status | When |
|---|---|
| 400 | The body is not empty. |
| 401 | No token, a token that is invalid, expired or revoked, or no valid companyid header. |
| 402 | The workspace's AI budget is spent. The answer has code: "ai_budget_exhausted". |
| 403 | The token lacks the write scope, or its person is no longer a member of the workspace. A token limited to projects is refused here. The caller has no active seat in the workspace, or can read the goal and may not change it. |
| 404 | The goal does not exist, or the caller cannot read it. |
| 409 | The goal is archived, or AI is switched off or not set up for the workspace (code: "ai_unavailable"). |
| 429 | Too many requests from this address. Wait retryAfter seconds and send it again. |
| 502 | The model gave no usable answer (code: "summary_failed"). Send the request again. |
Archive a goal
POST /api/v2/goals/:id/archive · beta
Archives a goal. It leaves the live list and can be restored.
Allowed for the goal's owner, and for owners and admins when the goal's visibility is workspace; a goal the caller can read but not change answers 403. A token limited to some projects is refused. The body must be empty. Answers with data: the archived goal.
| Auth | Session or API token with the write scope |
| Token limited to projects | Refused |
| Permission | An active seat in the workspace. The goal must be one the caller can read, and one the caller can change: its owner, or an owner or admin when the goal is visible to the workspace |
Path parameters
| Name | Type | Description |
|---|---|---|
id | id | The goal. |
The body must be empty.
Request
POST /api/v2/goals/<id>/archive
Authorization: Bearer <token>
companyid: <company id>Response
{
"status": true,
"statusText": "Goal archived.",
"data": {
"_id": "<goal id>",
"name": "Launch 2.0",
"description": "",
"ownerUserId": "<user id>",
"periodStart": "2026-10-01",
"periodEnd": "2026-12-31",
"visibility": "workspace",
"sharedWith": [],
"sharedWithMe": false,
"isOwner": true,
"color": "#2F3990",
"progressPct": 40,
"targets": [
{
"id": "<target id>",
"name": "Revenue",
"kind": "currency",
"weight": 1,
"progressPct": 40,
"reachedAt": null,
"start": 0,
"target": 50000,
"current": 20000,
"unit": "",
"currencyCode": "USD",
"updatedBy": "<user id>",
"updatedAt": "2026-10-01T09:30:00.000Z"
}
],
"archived": true,
"canEdit": true,
"canSetValue": true,
"createdBy": "<user id>",
"createdAt": "2026-10-01T09:30:00.000Z",
"updatedAt": "2026-10-01T09:30:00.000Z"
}
}data is the goal as the caller may see it; the example shows one currency target. A boolean target carries done; a tasks target carries sources, counted, notCounted, dirty, updating and sourceNames in place of start, target and current. sharedWith lists people only for someone who can change the goal. canEdit and canSetValue say what the caller may do with it. A goal that has been summarised carries summary: its text, when it was made (madeAt) and whether the numbers have changed since (stale).
Errors
| Status | When |
|---|---|
| 400 | The body is not empty. |
| 401 | No token, a token that is invalid, expired or revoked, or no valid companyid header. |
| 403 | The token lacks the write scope, or its person is no longer a member of the workspace. A token limited to projects is refused here. The caller has no active seat in the workspace. |
| 404 | The goal does not exist, or the caller cannot read it. |
| 409 | The goal was changed at the same moment. Send the request again. |
| 429 | Too many requests from this address. Wait retryAfter seconds and send it again. |
Restore a goal
POST /api/v2/goals/:id/restore · beta
Brings an archived goal back to the live list.
Allowed for the goal's owner, and for owners and admins when the goal's visibility is workspace; a goal the caller can read but not change answers 403. A token limited to some projects is refused. The body must be empty. Answers with data: the goal, live again.
| Auth | Session or API token with the write scope |
| Token limited to projects | Refused |
| Permission | An active seat in the workspace. The goal must be one the caller can read, and one the caller can change: its owner, or an owner or admin when the goal is visible to the workspace |
Path parameters
| Name | Type | Description |
|---|---|---|
id | id | The goal. |
The body must be empty.
Request
POST /api/v2/goals/<id>/restore
Authorization: Bearer <token>
companyid: <company id>Response
{
"status": true,
"statusText": "Goal restored.",
"data": {
"_id": "<goal id>",
"name": "Launch 2.0",
"description": "",
"ownerUserId": "<user id>",
"periodStart": "2026-10-01",
"periodEnd": "2026-12-31",
"visibility": "workspace",
"sharedWith": [],
"sharedWithMe": false,
"isOwner": true,
"color": "#2F3990",
"progressPct": 40,
"targets": [
{
"id": "<target id>",
"name": "Revenue",
"kind": "currency",
"weight": 1,
"progressPct": 40,
"reachedAt": null,
"start": 0,
"target": 50000,
"current": 20000,
"unit": "",
"currencyCode": "USD",
"updatedBy": "<user id>",
"updatedAt": "2026-10-01T09:30:00.000Z"
}
],
"archived": false,
"canEdit": true,
"canSetValue": true,
"createdBy": "<user id>",
"createdAt": "2026-10-01T09:30:00.000Z",
"updatedAt": "2026-10-01T09:30:00.000Z"
}
}data is the goal as the caller may see it; the example shows one currency target. A boolean target carries done; a tasks target carries sources, counted, notCounted, dirty, updating and sourceNames in place of start, target and current. sharedWith lists people only for someone who can change the goal. canEdit and canSetValue say what the caller may do with it. A goal that has been summarised carries summary: its text, when it was made (madeAt) and whether the numbers have changed since (stale).
Errors
| Status | When |
|---|---|
| 400 | The body is not empty. |
| 401 | No token, a token that is invalid, expired or revoked, or no valid companyid header. |
| 403 | The token lacks the write scope, or its person is no longer a member of the workspace. A token limited to projects is refused here. The caller has no active seat in the workspace. |
| 404 | The goal does not exist, or the caller cannot read it. |
| 409 | The goal was changed at the same moment. Send the request again. |
| 429 | Too many requests from this address. Wait retryAfter seconds and send it again. |
Add a target
POST /api/v2/goals/:id/targets · beta
Adds a target to a goal and answers with the whole goal.
A goal holds at most 20 targets. A tasks target is counted before the answer.
| Auth | Session or API token with the write scope |
| Token limited to projects | Refused |
| Permission | An active seat in the workspace. The goal must be one the caller can read, and one the caller can change: its owner, or an owner or admin when the goal is visible to the workspace |
Path parameters
| Name | Type | Description |
|---|---|---|
id | id | The goal. |
Body
| Field | Type | Required | Description |
|---|---|---|---|
name | string | yes | The target's name, 1 to 120 characters. |
kind | string | yes | number, currency, boolean or tasks. It cannot be changed afterwards. |
weight | integer | How much the target counts towards the goal, 1 to 100. Defaults to 1. | |
start | number | For number and currency: where the range starts. Defaults to 0. | |
target | number | For number and currency: where the range ends. Required, and different from start. | |
current | number | For number and currency: the value now. Defaults to start. | |
unit | string | For number and currency: a label, up to 20 characters. | |
currencyCode | string | For currency: a three-letter code of a currency the workspace uses. Defaults to the workspace's own currency. | |
done | boolean | For boolean: whether it is done. Defaults to false. | |
sources | object | For a tasks target: { sprintIds, taskIds }, at most 20 lists and 100 tasks. Each must be one the caller can open and every reader of the goal can open. |
Only the keys of the target's kind are accepted; any other key is refused.
Request
POST /api/v2/goals/<id>/targets
Authorization: Bearer <token>
companyid: <company id>
Content-Type: application/json
{
"name": "Revenue",
"kind": "currency",
"currencyCode": "USD",
"start": 0,
"target": 50000
}Response
{
"status": true,
"statusText": "Target added.",
"data": {
"_id": "<goal id>",
"name": "Launch 2.0",
"description": "",
"ownerUserId": "<user id>",
"periodStart": "2026-10-01",
"periodEnd": "2026-12-31",
"visibility": "workspace",
"sharedWith": [],
"sharedWithMe": false,
"isOwner": true,
"color": "#2F3990",
"progressPct": 40,
"targets": [
{
"id": "<target id>",
"name": "Revenue",
"kind": "currency",
"weight": 1,
"progressPct": 40,
"reachedAt": null,
"start": 0,
"target": 50000,
"current": 20000,
"unit": "",
"currencyCode": "USD",
"updatedBy": "<user id>",
"updatedAt": "2026-10-01T09:30:00.000Z"
}
],
"archived": false,
"canEdit": true,
"canSetValue": true,
"createdBy": "<user id>",
"createdAt": "2026-10-01T09:30:00.000Z",
"updatedAt": "2026-10-01T09:30:00.000Z"
}
}data is the goal as the caller may see it; the example shows one currency target. A boolean target carries done; a tasks target carries sources, counted, notCounted, dirty, updating and sourceNames in place of start, target and current. sharedWith lists people only for someone who can change the goal. canEdit and canSetValue say what the caller may do with it. A goal that has been summarised carries summary: its text, when it was made (madeAt) and whether the numbers have changed since (stale).
Errors
| Status | When |
|---|---|
| 400 | A key that is not known, a value of the wrong type or size, or a body that changes nothing. The answer names the field that was refused. The goal already holds 20 targets, a currency is not one of the workspace's, or a tasks source is not one the caller can open and every reader of the goal can open (the code is source_not_found or source_not_shared). |
| 401 | No token, a token that is invalid, expired or revoked, or no valid companyid header. |
| 403 | The token lacks the write scope, or its person is no longer a member of the workspace. A token limited to projects is refused here. The caller has no active seat in the workspace. |
| 404 | The goal does not exist, or the caller cannot read it. |
| 409 | The goal is archived. Restore it first. The goal was changed at the same moment. Send the request again. |
| 429 | Too many requests from this address. Wait retryAfter seconds and send it again. |
Change a target
PATCH /api/v2/goals/:id/targets/:targetId · beta
Changes what a target is: its name, weight, range, unit, currency or sources. Its value has a route of its own.
The target's kind cannot change. Changing the sources of a tasks target counts it again before the answer.
| Auth | Session or API token with the write scope |
| Token limited to projects | Refused |
| Permission | An active seat in the workspace. The goal must be one the caller can read, and one the caller can change: its owner, or an owner or admin when the goal is visible to the workspace |
Path parameters
| Name | Type | Description |
|---|---|---|
id | id | The goal. |
targetId | id | The target. |
Body
| Field | Type | Required | Description |
|---|---|---|---|
name | string | The target's name, 1 to 120 characters. | |
weight | integer | How much the target counts towards the goal, 1 to 100. | |
start | number | For number and currency: where the range starts. | |
target | number | For number and currency: where the range ends. Different from start. | |
unit | string | For number and currency: a label, up to 20 characters. | |
currencyCode | string | For currency: a three-letter code of a currency the workspace uses. | |
sources | object | For a tasks target: { sprintIds, taskIds }, at most 20 lists and 100 tasks. Each must be one the caller can open and every reader of the goal can open. |
Only the keys of the target's kind are accepted, without its value; any other key is refused. The body must name something to change.
Request
PATCH /api/v2/goals/<id>/targets/<targetId>
Authorization: Bearer <token>
companyid: <company id>
Content-Type: application/json
{ "target": 60000 }Response
{
"status": true,
"statusText": "Target saved.",
"data": {
"_id": "<goal id>",
"name": "Launch 2.0",
"description": "",
"ownerUserId": "<user id>",
"periodStart": "2026-10-01",
"periodEnd": "2026-12-31",
"visibility": "workspace",
"sharedWith": [],
"sharedWithMe": false,
"isOwner": true,
"color": "#2F3990",
"progressPct": 40,
"targets": [
{
"id": "<target id>",
"name": "Revenue",
"kind": "currency",
"weight": 1,
"progressPct": 40,
"reachedAt": null,
"start": 0,
"target": 50000,
"current": 20000,
"unit": "",
"currencyCode": "USD",
"updatedBy": "<user id>",
"updatedAt": "2026-10-01T09:30:00.000Z"
}
],
"archived": false,
"canEdit": true,
"canSetValue": true,
"createdBy": "<user id>",
"createdAt": "2026-10-01T09:30:00.000Z",
"updatedAt": "2026-10-01T09:30:00.000Z"
}
}data is the goal as the caller may see it; the example shows one currency target. A boolean target carries done; a tasks target carries sources, counted, notCounted, dirty, updating and sourceNames in place of start, target and current. sharedWith lists people only for someone who can change the goal. canEdit and canSetValue say what the caller may do with it. A goal that has been summarised carries summary: its text, when it was made (madeAt) and whether the numbers have changed since (stale).
Errors
| Status | When |
|---|---|
| 400 | A key that is not known, a value of the wrong type or size, or a body that changes nothing. The answer names the field that was refused. A tasks source is not one the caller can open and every reader of the goal can open. |
| 401 | No token, a token that is invalid, expired or revoked, or no valid companyid header. |
| 403 | The token lacks the write scope, or its person is no longer a member of the workspace. A token limited to projects is refused here. The caller has no active seat in the workspace. |
| 404 | The goal does not exist, or the caller cannot read it. Or the goal has no such target. |
| 409 | The goal is archived. Restore it first. The goal was changed at the same moment. Send the request again. |
| 429 | Too many requests from this address. Wait retryAfter seconds and send it again. |
Remove a target
DELETE /api/v2/goals/:id/targets/:targetId · beta
Removes a target and answers with the whole goal.
Allowed for the goal's owner, and for owners and admins when the goal's visibility is workspace; a goal the caller can read but not change answers 403, and an archived goal answers 409. The body must be empty and an unknown targetId answers 404. Answers with data: the whole goal without that target.
| Auth | Session or API token with the write scope |
| Token limited to projects | Refused |
| Permission | An active seat in the workspace. The goal must be one the caller can read, and one the caller can change: its owner, or an owner or admin when the goal is visible to the workspace |
Path parameters
| Name | Type | Description |
|---|---|---|
id | id | The goal. |
targetId | id | The target. |
The body must be empty.
Request
DELETE /api/v2/goals/<id>/targets/<targetId>
Authorization: Bearer <token>
companyid: <company id>Response
{
"status": true,
"statusText": "Target removed.",
"data": {
"_id": "<goal id>",
"name": "Launch 2.0",
"description": "",
"ownerUserId": "<user id>",
"periodStart": "2026-10-01",
"periodEnd": "2026-12-31",
"visibility": "workspace",
"sharedWith": [],
"sharedWithMe": false,
"isOwner": true,
"color": "#2F3990",
"progressPct": 0,
"targets": [],
"archived": false,
"canEdit": true,
"canSetValue": true,
"createdBy": "<user id>",
"createdAt": "2026-10-01T09:30:00.000Z",
"updatedAt": "2026-10-01T09:30:00.000Z"
}
}data is the goal as the caller may see it; the example shows one currency target. A boolean target carries done; a tasks target carries sources, counted, notCounted, dirty, updating and sourceNames in place of start, target and current. sharedWith lists people only for someone who can change the goal. canEdit and canSetValue say what the caller may do with it. A goal that has been summarised carries summary: its text, when it was made (madeAt) and whether the numbers have changed since (stale).
Errors
| Status | When |
|---|---|
| 400 | The body is not empty. |
| 401 | No token, a token that is invalid, expired or revoked, or no valid companyid header. |
| 403 | The token lacks the write scope, or its person is no longer a member of the workspace. A token limited to projects is refused here. The caller has no active seat in the workspace. |
| 404 | The goal does not exist, or the caller cannot read it. Or the goal has no such target. |
| 409 | The goal is archived. Restore it first. The goal was changed at the same moment. Send the request again. |
| 429 | Too many requests from this address. Wait retryAfter seconds and send it again. |
Set a target's value
PUT /api/v2/goals/:id/targets/:targetId/value · beta
Sets the current value of a number or currency target, or whether a boolean target is done.
The goal's progress is worked out again. A tasks target is counted from its tasks and cannot be set by hand: the answer is a refusal with the code counted_from_tasks.
| Auth | Session or API token with the write scope |
| Token limited to projects | Refused |
| Permission | An active seat in the workspace. The goal must be one the caller can read, and one the caller can change: its owner, or an owner or admin when the goal is visible to the workspace |
Path parameters
| Name | Type | Description |
|---|---|---|
id | id | The goal. |
targetId | id | The target. |
Body
| Field | Type | Required | Description |
|---|---|---|---|
current | number | For a number or currency target: the value now. | |
done | boolean | For a boolean target: whether it is done. |
Send the one key the target's kind takes; any other key is refused.
Request
PUT /api/v2/goals/<id>/targets/<targetId>/value
Authorization: Bearer <token>
companyid: <company id>
Content-Type: application/json
{ "current": 25000 }Response
{
"status": true,
"statusText": "Target updated.",
"data": {
"_id": "<goal id>",
"name": "Launch 2.0",
"description": "",
"ownerUserId": "<user id>",
"periodStart": "2026-10-01",
"periodEnd": "2026-12-31",
"visibility": "workspace",
"sharedWith": [],
"sharedWithMe": false,
"isOwner": true,
"color": "#2F3990",
"progressPct": 40,
"targets": [
{
"id": "<target id>",
"name": "Revenue",
"kind": "currency",
"weight": 1,
"progressPct": 40,
"reachedAt": null,
"start": 0,
"target": 50000,
"current": 20000,
"unit": "",
"currencyCode": "USD",
"updatedBy": "<user id>",
"updatedAt": "2026-10-01T09:30:00.000Z"
}
],
"archived": false,
"canEdit": true,
"canSetValue": true,
"createdBy": "<user id>",
"createdAt": "2026-10-01T09:30:00.000Z",
"updatedAt": "2026-10-01T09:30:00.000Z"
}
}data is the goal as the caller may see it; the example shows one currency target. A boolean target carries done; a tasks target carries sources, counted, notCounted, dirty, updating and sourceNames in place of start, target and current. sharedWith lists people only for someone who can change the goal. canEdit and canSetValue say what the caller may do with it. A goal that has been summarised carries summary: its text, when it was made (madeAt) and whether the numbers have changed since (stale).
Errors
| Status | When |
|---|---|
| 400 | A key that is not known, a value of the wrong type or size, or a body that changes nothing. The answer names the field that was refused. The key the target needs is missing, or the target is counted from tasks. |
| 401 | No token, a token that is invalid, expired or revoked, or no valid companyid header. |
| 403 | The token lacks the write scope, or its person is no longer a member of the workspace. A token limited to projects is refused here. The caller has no active seat in the workspace. |
| 404 | The goal does not exist, or the caller cannot read it. Or the goal has no such target. |
| 409 | The goal is archived. Restore it first. The goal was changed at the same moment. Send the request again. |
| 429 | Too many requests from this address. Wait retryAfter seconds and send it again. |
