Actions
List, read, create, update and delete the Actions that move Goals and Objectives forward.
An Action is a piece of work that moves an Objective or a Goal forward. Every Action created through the API must link to an Objective (objectiveId), a Goal (goalId), or both.
| Method | Path | Scope | Webhook |
|---|---|---|---|
GET |
/actions |
actions:read |
|
GET |
/objectives/{objectiveId}/actions |
actions:read |
|
GET |
/goals/{goalId}/actions |
actions:read |
|
GET |
/actions/{id} |
actions:read |
|
POST |
/actions |
actions:write |
action.created |
PATCH |
/actions/{id} |
actions:write |
action.updated |
DELETE |
/actions/{id} |
actions:write |
action.deleted |
Related: Action comments.
The JavaScript examples assume a headers object holding your key:
const headers = {
'X-API-Key': process.env.GPS_API_KEY_ID,
'X-API-Secret': process.env.GPS_API_SECRET,
};
The Action object#
| Field | Type | Notes |
|---|---|---|
id |
string | Action ID. |
title |
string | |
description |
string or null | |
notes |
string or null | |
objectiveId |
string or null | The Objective it belongs to. |
goalId |
string or null | The Goal it belongs to. |
assignees |
string[] | Member IDs of the people doing it. |
priority |
string or null | High, Medium or Low. |
status |
string | to_do, started, on_track, off_track, completed, cancelled or archived. Some older Actions store To Do, which means to_do. |
startDate |
string or null | ISO 8601 timestamp. |
dueDate |
string or null | ISO 8601 timestamp. |
completedDate |
string or null | ISO 8601 timestamp. |
reminderDate |
string or null | When GPS reminds the assignees. Set in GPS. |
reminderFrequency |
string or null | daily, weekly or monthly. Set in GPS. |
reminderSent |
boolean | Whether the reminder has gone out. |
emailReminder |
boolean | Whether the reminder is emailed. |
appReminder |
boolean | Whether the reminder shows in GPS. |
isRepeatable |
boolean | Whether GPS offers to repeat the Action once it's done. Always false for Actions created through the API. |
repeatFrequency |
string or null | weekly or monthly. |
repeatDay |
integer or null | Day of the week (1 = Monday, 7 = Sunday) or day of the month (1–31) to repeat on. |
isPrivate |
boolean | Private in GPS. API keys still see private Actions. |
createdBy |
string or null | Member ID of the creator. |
sourceMeetingId |
string or null | The Meeting it was captured in, if any. |
portalOriginMasterUserId |
string or null | Set when a consultant raised the Action from myPortal. Read-only. |
positionInSet |
integer or null | Its place in a set of Actions sent together from myPortal. |
createdAt |
string | ISO 8601 timestamp. |
updatedAt |
string | ISO 8601 timestamp. |
List Actions#
GET /actions
Returns every Action linked to one of the organization's Goals or Objectives that isn't archived. Order isn't guaranteed.
Scope: actions:read
Query parameters
| Parameter | Type | Notes |
|---|---|---|
status |
string | One of to_do, started, on_track, off_track, completed, cancelled, archived. To Do is accepted for to_do. |
objectiveId |
string | Only Actions with this objectiveId. |
goalId |
string | Only Actions with this goalId. |
limit |
integer | 1–200, default 50. |
offset |
integer | Default 0. |
curl "https://plan.empiraa.app/api/v1/actions?status=to_do&objectiveId=c7e9a1b3-4d5f-4a6b-9c8d-1e2f3a4b5c6d" \
-H "X-API-Key: $GPS_API_KEY_ID" \
-H "X-API-Secret: $GPS_API_SECRET"
const params = new URLSearchParams({ status: 'to_do', objectiveId: 'c7e9a1b3-4d5f-4a6b-9c8d-1e2f3a4b5c6d' });
const res = await fetch(`https://plan.empiraa.app/api/v1/actions?${params}`, { headers });
const { data: actions, meta } = await res.json();
Response 200
{
"data": [
{
"id": "e5a7c9e1-6f8b-4c2d-8e9f-3a4b5c6d7e8f",
"title": "Send renewal offers to the top 20 clients",
"description": null,
"notes": "Use the annual pricing sheet.",
"objectiveId": "c7e9a1b3-4d5f-4a6b-9c8d-1e2f3a4b5c6d",
"goalId": null,
"assignees": ["5d7f9b1d-3e5a-4c7e-9f1a-2b3c4d5e6f70"],
"priority": "High",
"status": "to_do",
"startDate": null,
"dueDate": "2026-11-28T00:00:00.000Z",
"completedDate": null,
"reminderDate": null,
"reminderFrequency": null,
"reminderSent": false,
"emailReminder": false,
"appReminder": true,
"isRepeatable": false,
"repeatFrequency": null,
"repeatDay": null,
"isPrivate": false,
"createdBy": "5d7f9b1d-3e5a-4c7e-9f1a-2b3c4d5e6f70",
"sourceMeetingId": null,
"portalOriginMasterUserId": null,
"positionInSet": null,
"createdAt": "2026-11-10T23:00:00.000Z",
"updatedAt": "2026-11-10T23:00:00.000Z"
}
],
"meta": { "total": 1, "limit": 50, "offset": 0 }
}
Errors: 400 INVALID_STATUS_QUERY for an unknown status; 422 VALIDATION_ERROR for a bad limit or offset.
List an Objective's Actions#
GET /objectives/{objectiveId}/actions
Returns the Actions whose objectiveId is this Objective. Order isn't guaranteed.
Scope: actions:read
| Parameter | In | Notes |
|---|---|---|
objectiveId |
path | Objective ID. |
status |
query | Same values as List Actions. |
limit, offset |
query | See Pagination. |
curl https://plan.empiraa.app/api/v1/objectives/c7e9a1b3-4d5f-4a6b-9c8d-1e2f3a4b5c6d/actions \
-H "X-API-Key: $GPS_API_KEY_ID" \
-H "X-API-Secret: $GPS_API_SECRET"
const res = await fetch(
'https://plan.empiraa.app/api/v1/objectives/c7e9a1b3-4d5f-4a6b-9c8d-1e2f3a4b5c6d/actions',
{ headers },
);
const { data: actions, meta } = await res.json();
Response 200: a list of Action objects with meta, as in List Actions.
Errors: 404 NOT_FOUND if the Objective doesn't exist, is in another organization or is archived; 400 INVALID_STATUS_QUERY; 422 VALIDATION_ERROR for a bad limit or offset.
List a Goal's Actions#
GET /goals/{goalId}/actions
Returns the Actions linked directly to the Goal through goalId. Actions that link only to one of the Goal's Objectives aren't included; use List an Objective's Actions for those. Order isn't guaranteed.
Scope: actions:read
| Parameter | In | Notes |
|---|---|---|
goalId |
path | Goal ID. |
status |
query | Same values as List Actions. |
limit, offset |
query | See Pagination. |
curl https://plan.empiraa.app/api/v1/goals/a1f3c5e7-2b4d-4f6a-8c9e-0b1d3f5a7c9e/actions \
-H "X-API-Key: $GPS_API_KEY_ID" \
-H "X-API-Secret: $GPS_API_SECRET"
const res = await fetch(
'https://plan.empiraa.app/api/v1/goals/a1f3c5e7-2b4d-4f6a-8c9e-0b1d3f5a7c9e/actions',
{ headers },
);
const { data: actions, meta } = await res.json();
Response 200: a list of Action objects with meta, as in List Actions.
Errors: 404 NOT_FOUND if the Goal doesn't exist or is in another organization; 400 INVALID_STATUS_QUERY; 422 VALIDATION_ERROR for a bad limit or offset.
Get an Action#
GET /actions/{id}
Scope: actions:read
| Path parameter | Notes |
|---|---|
id |
Action ID. |
curl https://plan.empiraa.app/api/v1/actions/e5a7c9e1-6f8b-4c2d-8e9f-3a4b5c6d7e8f \
-H "X-API-Key: $GPS_API_KEY_ID" \
-H "X-API-Secret: $GPS_API_SECRET"
const res = await fetch('https://plan.empiraa.app/api/v1/actions/e5a7c9e1-6f8b-4c2d-8e9f-3a4b5c6d7e8f', { headers });
const { data: action } = await res.json();
Response 200: { "data": <Action> }, with the same fields as the item in List Actions.
Errors: 404 NOT_FOUND if the Action doesn't exist, is in another organization, or its Goal or Objective is archived.
Create an Action#
POST /actions
Scope: actions:write · Webhook: action.created, with the new Action as data.
Request body
| Field | Type | Required | Allowed values | Notes |
|---|---|---|---|---|
title |
string | Yes | At least 1 character after trimming | |
objectiveId |
string or null | One of objectiveId or goalId |
An Objective in your organization | |
goalId |
string or null | One of objectiveId or goalId |
A Goal in your organization | |
description |
string or null | No | ||
notes |
string or null | No | ||
status |
string | No | to_do, started, on_track, off_track, completed, cancelled, archived (or To Do) |
Default started. |
priority |
string or null | No | High, Medium, Low |
Default Medium. |
assignees |
string[] | No | Active member IDs | Default []. |
startDate |
string or null | No | ISO 8601 | |
dueDate |
string or null | No | ISO 8601 | |
completedDate |
string or null | No | ISO 8601 | |
isPrivate |
boolean | No | Default false. |
|
onBehalfOf |
string | No | Active member ID | Who the Action is created by. See Attribution. |
Reminders and repeat settings can't be set through the API.
curl -X POST https://plan.empiraa.app/api/v1/actions \
-H "X-API-Key: $GPS_API_KEY_ID" \
-H "X-API-Secret: $GPS_API_SECRET" \
-H "Content-Type: application/json" \
-d '{
"title": "Send renewal offers to the top 20 clients",
"objectiveId": "c7e9a1b3-4d5f-4a6b-9c8d-1e2f3a4b5c6d",
"status": "to_do",
"priority": "High",
"dueDate": "2026-11-28",
"assignees": ["5d7f9b1d-3e5a-4c7e-9f1a-2b3c4d5e6f70"]
}'
const res = await fetch('https://plan.empiraa.app/api/v1/actions', {
method: 'POST',
headers: { ...headers, 'Content-Type': 'application/json' },
body: JSON.stringify({
title: 'Send renewal offers to the top 20 clients',
objectiveId: 'c7e9a1b3-4d5f-4a6b-9c8d-1e2f3a4b5c6d',
status: 'to_do',
priority: 'High',
dueDate: '2026-11-28',
assignees: ['5d7f9b1d-3e5a-4c7e-9f1a-2b3c4d5e6f70'],
}),
});
const { data: action } = await res.json();
Response 201
{
"data": {
"id": "e5a7c9e1-6f8b-4c2d-8e9f-3a4b5c6d7e8f",
"title": "Send renewal offers to the top 20 clients",
"description": null,
"notes": null,
"objectiveId": "c7e9a1b3-4d5f-4a6b-9c8d-1e2f3a4b5c6d",
"goalId": null,
"assignees": ["5d7f9b1d-3e5a-4c7e-9f1a-2b3c4d5e6f70"],
"priority": "High",
"status": "to_do",
"startDate": null,
"dueDate": "2026-11-28T00:00:00.000Z",
"completedDate": null,
"reminderDate": null,
"reminderFrequency": null,
"reminderSent": false,
"emailReminder": false,
"appReminder": true,
"isRepeatable": false,
"repeatFrequency": null,
"repeatDay": null,
"isPrivate": false,
"createdBy": "5d7f9b1d-3e5a-4c7e-9f1a-2b3c4d5e6f70",
"sourceMeetingId": null,
"portalOriginMasterUserId": null,
"positionInSet": null,
"createdAt": "2026-11-12T03:17:30.004Z",
"updatedAt": "2026-11-12T03:17:30.004Z"
}
}
Errors
| Status | code |
When |
|---|---|---|
| 422 | VALIDATION_ERROR |
Missing title; neither objectiveId nor goalId; a value outside the allowed list. |
| 422 | INVALID_REFERENCE |
objectiveId or goalId isn't in your organization (or is archived). |
| 422 | INVALID_USERS |
An assignees or onBehalfOf ID isn't an active member. |
| 422 | NO_KEY_OWNER |
No onBehalfOf, and the key's creator is no longer a member. |
Update an Action#
PATCH /actions/{id}
Changes only the fields you send. After the change the Action must still link to an Objective or a Goal, so you can clear one of objectiveId and goalId (set it to null) but not both.
Scope: actions:write · Webhook: action.updated, with the updated Action as data.
| Path parameter | Notes |
|---|---|
id |
Action ID. |
Request body: any field from Create an Action except onBehalfOf, with the same rules. assignees replaces the whole list.
Send at least one field.
curl -X PATCH https://plan.empiraa.app/api/v1/actions/e5a7c9e1-6f8b-4c2d-8e9f-3a4b5c6d7e8f \
-H "X-API-Key: $GPS_API_KEY_ID" \
-H "X-API-Secret: $GPS_API_SECRET" \
-H "Content-Type: application/json" \
-d '{ "status": "completed", "completedDate": "2026-11-12" }'
const res = await fetch('https://plan.empiraa.app/api/v1/actions/e5a7c9e1-6f8b-4c2d-8e9f-3a4b5c6d7e8f', {
method: 'PATCH',
headers: { ...headers, 'Content-Type': 'application/json' },
body: JSON.stringify({ status: 'completed', completedDate: '2026-11-12' }),
});
const { data: action } = await res.json();
Response 200: { "data": <Action> } with the changes applied, for example "status": "completed" and "completedDate": "2026-11-12T00:00:00.000Z". Every other field is as in List Actions.
Errors
| Status | code |
When |
|---|---|---|
| 404 | NOT_FOUND |
The Action doesn't exist, is in another organization, or its Goal or Objective is archived. |
| 422 | VALIDATION_ERROR |
A value outside the allowed list, or the change would leave neither objectiveId nor goalId. |
| 422 | INVALID_REFERENCE |
A new objectiveId or goalId isn't in your organization. |
| 422 | INVALID_USERS |
An assignees ID isn't an active member. |
Delete an Action#
DELETE /actions/{id}
Permanently deletes the Action, its comments and its reminders.
Scope: actions:write · Webhook: action.deleted, with data set to { "id": "<action id>" }.
| Path parameter | Notes |
|---|---|
id |
Action ID. |
curl -X DELETE https://plan.empiraa.app/api/v1/actions/e5a7c9e1-6f8b-4c2d-8e9f-3a4b5c6d7e8f \
-H "X-API-Key: $GPS_API_KEY_ID" \
-H "X-API-Secret: $GPS_API_SECRET"
const res = await fetch('https://plan.empiraa.app/api/v1/actions/e5a7c9e1-6f8b-4c2d-8e9f-3a4b5c6d7e8f', {
method: 'DELETE',
headers,
});
console.log(res.status); // 204
Response 204: no body.
Errors: 404 NOT_FOUND if the Action doesn't exist, is in another organization, or its Goal or Objective is archived.

